Skip to content

Commit

Permalink
feat: add addIcons function to load svg without static assets (#69)
Browse files Browse the repository at this point in the history
Co-authored-by: Daniel Leroux <daniel.leroux@siemens.com>
Co-authored-by: matthiashader <144090716+matthiashader@users.noreply.github.com>
  • Loading branch information
3 people authored Feb 14, 2025
1 parent d72909c commit 8a506b7
Show file tree
Hide file tree
Showing 16 changed files with 259 additions and 2,642 deletions.
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

0 comments on commit 8a506b7

Please sign in to comment.