Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add addIcons function to load svg without static assets #69

Merged
merged 19 commits into from
Feb 14, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/fuzzy-carrots-drive.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@siemens/ix-icons": minor
---

Allow users to put specific icons into the cache.
63 changes: 47 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,36 +12,67 @@ SPDX-License-Identifier: MIT

## Usage

Using icons within your project. You need to:
### Settng up with Siemens Industrial Experience design system

- Install `@siemens/ix-icons` e.g. `npm install --save @siemens/ix-icons`
If you are also using the library [Siemens Industrial Experience](https://github.com/siemens/ix/), no additional project setup will be necessary. The packages `@siemens/ix-angular`, `@siemens/ix-react` or `@siemens/ix-vue` will take care of setting up the icon library for you.

```javascript
import { defineCustomElements } from '@siemens/ix-icons/loader';
### Setting up without Siemens Industrial Experience design system

If you want to use `@siemens/ix-icons` without `@siemens/ix` you need to follow these steps:

#### Using CDN

Place the following `<script>` near the end of your page, right before the closing </body> tag.

(async () => {
await defineCustomElements();
})();
```html
<script type="module" src="https://cdn.jsdelivr.net/npm/@siemens/ix-icons@%5E3.0.0/dist/ix-icons/ix-icons.esm.js"></script>
<script nomodule src="https://cdn.jsdelivr.net/npm/@siemens/ix-icons@%5E3.0.0/dist/ix-icons/ix-icons.js"></script>
```

### Angular / Web Components
Now you can render icons in your applicaton:

```html
<ix-icon name="rocket"></ix-icon>
<ix-icon name="star"></ix-icon>
```

### React and Vue
### Using a package manager like `npm`/`pnpm`/`yarn`

```tsx
import { rocket } from '@siemens/ix-icons/icons';
First install the package `@siemens/ix-icons@latest` in your project (e.g. `npm install --save @siemens/ix-icons`).

Then load the icon component:

```javascript
import { defineCustomElements } from '@siemens/ix-icons/loader';

<ix-icon name={rocket}></ix-icon>;
// Register Web Component <ix-icon></ix-icon>
defineCustomElements();
```

### Use `ix-icon` component with custom svg's
### Prepare your project

1. **Copy SVG Files:**
Copy all SVG files located under `node_modules/@siemens/ix-icons/svg` to an asset folder in your project. This allows the `ix-icon` component to fetch the images.

2. **Alternative Method:**
Alternatively, you can use the `addIcons` function to load specific icons directly in your code. For example:

```javascript
import { addIcons } from '@siemens/ix-icons';
import { iconStar } from '@siemens/ix-icons/icons';

addIcons({ iconStar });
```

```html
<ix-icon name="star"></ix-icon>
```

You only need to add the same icon once. Additional calls to `addIcons` will not add redundant copies of the same icons to the collection.

### Use the `ix-icon` component with custom SVG's

```tsx
<ix-icon name="/your/asset/path/my-icon.svg"></ix-icon>;
<ix-icon name="/your/asset/path/my-icon.svg"></ix-icon>
```

## Development
Expand All @@ -64,6 +95,6 @@ Contributions, issues and feature requests are welcome!

## πŸ“ License

Copyright Β© 2019–2023 [Siemens AG](https://www.siemens.com/).
Copyright Β© 2019–2025 [Siemens AG](https://www.siemens.com/).

This project is MIT licensed.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
"ci:publish": "pnpm changeset publish"
},
"dependencies": {
"@stencil/core": "^4.21.0"
"@stencil/core": "^4.25.1"
},
"devDependencies": {
"@changesets/changelog-github": "^0.5.0",
Expand Down
16 changes: 8 additions & 8 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 2 additions & 11 deletions scripts/build-icons.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ const __dirname = path.resolve();

const rootPath = path.join(__dirname);
const svgSrcPath = path.join(rootPath, 'incoming-svg');
const buildDistPath = path.join(rootPath, 'build-dist');
const pkgPath = path.join(rootPath, 'package.json');

const iconsDestPath = path.join(__dirname, 'icons');
Expand Down Expand Up @@ -134,17 +135,6 @@ async function buildIcons() {
await Promise.all([
...writeOptimizedSvg(iconCollection, path.join(rootPath, 'svg')),

writeIconCollectionFile(
iconCollection.map(i => ({
name: i.name,
originalIconName: i.originalIconName,
code: i.esm,
})),
path.join(rootPath, 'src', 'components', 'icon', 'icons.ts'),
version,
true,
),

writeIconCollectionFile(
iconCollection.map(i => ({
name: i.name,
Expand Down Expand Up @@ -176,6 +166,7 @@ async function buildIcons() {
),

writeIconSampleJson(iconCollection, path.join(rootPath, 'e2e'), version),
writeIconSampleJson(iconCollection, buildDistPath, version),
fs.writeFile(
iconsPkgPath,
JSON.stringify(
Expand Down
10 changes: 8 additions & 2 deletions src/components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,15 @@ export namespace Components {
/**
* Color of the icon
*/
"color": string;
"color"?: string;
/**
* Only fetch and parse svg data when icon is visible
*/
"lazyLoading": boolean;
/**
* Use one of our defined icon names e.g. `copy` https://ix.siemens.io/docs/icon-library/icons or the import variant ``` import { rocket } from '@siemens/ix-icons/icons'; <ix-icon name={rocket}></ix-icon> ```
*/
"name": string;
"name"?: string;
/**
* Size of the icon
*/
Expand All @@ -39,6 +42,9 @@ declare namespace LocalJSX {
* Color of the icon
*/
"color"?: string;
/**
* Only fetch and parse svg data when icon is visible
*/
"lazyLoading"?: boolean;
/**
* Use one of our defined icon names e.g. `copy` https://ix.siemens.io/docs/icon-library/icons or the import variant ``` import { rocket } from '@siemens/ix-icons/icons'; <ix-icon name={rocket}></ix-icon> ```
Expand Down
28 changes: 16 additions & 12 deletions src/components/icon/icon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,8 @@
* LICENSE file in the root directory of this source tree.
*/
import { Component, h, Host, Prop, State, Watch, Element, Build } from '@stencil/core';
import { parseSVGDataContent, resolveIcon } from './resolveIcon';

const iconMissingSymbol =
"data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='512' height='512' viewBox='0 0 512 512'><path fill-rule='evenodd' d='M384,0 L384,384 L0,384 L0,0 L384,0 Z M192,207.085 L57.751,341.333 L326.248,341.333 L192,207.085 Z M42.666,57.751 L42.666,326.248 L176.915,192 L42.666,57.751 Z M341.333,57.751 L207.085,192 L341.333,326.248 L341.333,57.751 Z M326.248,42.666 L57.751,42.666 L192,176.915 L326.248,42.666 Z' transform='translate(64 64)'/></svg>";
import { resolveIcon } from './resolveIcon';
import { errorSymbol, parseSVGDataContent } from './parser';

@Component({
tag: 'ix-icon',
Expand All @@ -19,17 +17,17 @@ const iconMissingSymbol =
assetsDirs: ['svg'],
})
export class Icon {
@Element() hostElement: HTMLIxIconElement;
@Element() hostElement!: HTMLIxIconElement;

/**
* Size of the icon
*/
@Prop() size: '12' | '16' | '24' | '32';
@Prop() size: '12' | '16' | '24' | '32' = '24';

/**
* Color of the icon
*/
@Prop() color: string;
@Prop() color?: string;

/**
* Use one of our defined icon names e.g. `copy`
Expand All @@ -44,8 +42,11 @@ export class Icon {
* <ix-icon name={rocket}></ix-icon>
* ```
*/
@Prop() name: string;
@Prop() name?: string;

/**
* Only fetch and parse svg data when icon is visible
*/
@Prop() lazyLoading = false;

@State() svgContent?: string;
Expand All @@ -60,11 +61,14 @@ export class Icon {

@Watch('name')
async loadIconContent() {
try {
this.svgContent = await resolveIcon(this.name);
} catch (error) {
this.svgContent = parseSVGDataContent(iconMissingSymbol);
const content = await resolveIcon(this.hostElement, this.name);

if (!content) {
this.svgContent = parseSVGDataContent(errorSymbol);
return;
}

this.svgContent = content;
}

private waitForRendering(onRender: () => void) {
Expand Down
Loading
Loading