From bc8fb52a7e2e68f1804bc7241374ab8e1e1920d5 Mon Sep 17 00:00:00 2001 From: Lukas Maurer Date: Thu, 30 Jan 2025 10:32:21 +0100 Subject: [PATCH 01/18] post merge --- .changeset/fuzzy-carrots-drive.md | 5 ++ README.md | 21 +++++++- src/components/icon/resolveIcon.ts | 54 ++++++++++++++++++- src/components/icon/test/ix-icon.spec.tsx | 2 +- src/components/icon/test/resolveIcon.spec.ts | 33 +++++++++--- .../{rocker-example.ts => rocket-example.ts} | 0 src/index.ts | 1 + 7 files changed, 104 insertions(+), 12 deletions(-) create mode 100644 .changeset/fuzzy-carrots-drive.md rename src/components/icon/test/{rocker-example.ts => rocket-example.ts} (100%) diff --git a/.changeset/fuzzy-carrots-drive.md b/.changeset/fuzzy-carrots-drive.md new file mode 100644 index 00000000..8b4aa664 --- /dev/null +++ b/.changeset/fuzzy-carrots-drive.md @@ -0,0 +1,5 @@ +--- +"@siemens/ix-icons": minor +--- + +Allow preloading of specific icons. diff --git a/README.md b/README.md index c5cf469d..c9e6dcfa 100755 --- a/README.md +++ b/README.md @@ -12,9 +12,11 @@ SPDX-License-Identifier: MIT ## Usage -Using icons within your project. You need to: +### Installation + +First install the package `@siemens/ix-icons` in your project (e.g. `npm install --save @siemens/ix-icons`). -- Install `@siemens/ix-icons` e.g. `npm install --save @siemens/ix-icons` +Then load the icon component: ```javascript import { defineCustomElements } from '@siemens/ix-icons/loader'; @@ -24,6 +26,21 @@ import { defineCustomElements } from '@siemens/ix-icons/loader'; })(); ``` +Icons are loaded once and then cached for the entire duration of the single-page application. +Additionally, icons can be preloaded to ensure they are immediately available from the cache when needed later: + +```javascript +import { loadIcons } from '@siemens/ix-icons'; + +const icons = [ + 'star', + 'star-filled', + // ... +]; + +loadIcons(icons) +``` + ### Angular / Web Components ```html diff --git a/src/components/icon/resolveIcon.ts b/src/components/icon/resolveIcon.ts index ba4ece75..70db8fe4 100644 --- a/src/components/icon/resolveIcon.ts +++ b/src/components/icon/resolveIcon.ts @@ -28,6 +28,7 @@ export const getIconCacheMap = (): Map => { window.IxIcons = window.IxIcons || {}; fetchCache = window.IxIcons.map = window.IxIcons.map || new Map(); } + return fetchCache; }; @@ -85,12 +86,15 @@ async function fetchSVG(url: string) { const svgContent = parseSVGDataContent(responseText); cache.set(url, svgContent); + requests.delete(url); + return svgContent; }); requests.set(url, fetching); return fetching; } + const urlRegex = /^(?:(?:https?|ftp):\/\/)?(?:\S+(?::\S*)?@)?(?:www\.)?(?:\S+\.\S+)(?:\S*)$/i; function isValidUrl(url: string) { @@ -99,11 +103,13 @@ function isValidUrl(url: string) { export function getIconUrl(name: string) { const customAssetUrl = getCustomAssetUrl(); + if (customAssetUrl) { return `${customAssetUrl}/${name}.svg`; } let url: string = `svg/${name}.svg`; + try { url = getAssetPath(url); } catch (error) { @@ -124,6 +130,16 @@ export async function resolveIcon(iconName: string) { return parseSVGDataContent(iconName); } + return await loadIcon(iconName); +} + +async function loadIcon(iconName: string) { + const cache = getIconCacheMap(); + + if (cache.has(iconName)) { + return cache.get(iconName); + } + if (isValidUrl(iconName)) { try { return fetchSVG(iconName); @@ -135,6 +151,42 @@ export async function resolveIcon(iconName: string) { try { return fetchSVG(getIconUrl(iconName)); } catch (error) { - throw Error('Cannot resolve any icon'); + throw Error(`Could not resolve ${iconName}`); + } +} + +function removePrefix(name: string, prefix: string) { + if (name.startsWith(prefix)) { + name = name.slice(prefix.length); + return name.replace(/^(\w)/, (_match, p1) => p1.toLowerCase()); + } + + return name; +} + +export function addIcons(icons: { [name: string]: any }) { + Object.keys(icons).forEach(name => { + const icon = icons[name]; + name = removePrefix(name, 'icon'); + + addIconToCache(name, icon); + }); +} + +export function addIconToCache(name: string, icon: string) { + const cache = getIconCacheMap(); + + if (cache.has(name)) { + console.warn(`Icon name '${name}' already in cache. Overwritting with new icon data.`); + } + + const svg = parseSVGDataContent(icon); + + cache.set(name, svg); + + const toKebabCase = name.replace(/([a-z0-9]|(?=[A-Z]))([A-Z0-9])/g, '$1-$2').toLowerCase(); + + if (name != toKebabCase) { + cache.set(toKebabCase, svg); } } diff --git a/src/components/icon/test/ix-icon.spec.tsx b/src/components/icon/test/ix-icon.spec.tsx index f32bbe3d..40303431 100644 --- a/src/components/icon/test/ix-icon.spec.tsx +++ b/src/components/icon/test/ix-icon.spec.tsx @@ -3,7 +3,7 @@ */ import { newSpecPage } from '@stencil/core/testing'; import { Icon } from '../icon'; -import { rocket } from './rocker-example'; +import { rocket } from './rocket-example'; //@ts-ignore global.fetch = jest.fn(() => diff --git a/src/components/icon/test/resolveIcon.spec.ts b/src/components/icon/test/resolveIcon.spec.ts index 9d22b291..9fb960a1 100644 --- a/src/components/icon/test/resolveIcon.spec.ts +++ b/src/components/icon/test/resolveIcon.spec.ts @@ -1,8 +1,9 @@ /* * COPYRIGHT (c) Siemens AG 2018-2023 ALL RIGHTS RESERVED. */ -import { iconStar } from '../icons'; -import { resolveIcon, getIconCacheMap, getIconUrl, parseSVGDataContent } from '../resolveIcon'; +import { iconAdd, iconStar } from '../icons'; +import { resolveIcon, getIconCacheMap, getIconUrl, parseSVGDataContent, addIcons } from '../resolveIcon'; + const exampleSvg = ` @@ -22,6 +23,9 @@ const invalidexampleSvg = ` `; +const urlInvalid = 'http://localhost/invalid.svg'; +const urlTest = 'http://localhost/test.svg'; + jest.mock('../meta-tag'); jest.mock('../icons', () => ({ iconStar: exampleSvg, @@ -43,14 +47,14 @@ let fetch = (global.fetch = jest.fn((url: string) => { }); } - if (url === 'http://localhost/test.svg') { + if (url === urlTest) { return Promise.resolve({ text: () => Promise.resolve(exampleSvg), ok: true, }); } - if (url === 'http://localhost/invalid.svg') { + if (url === urlInvalid) { return Promise.resolve({ text: () => Promise.resolve(invalidexampleSvg), ok: true, @@ -72,7 +76,7 @@ describe('resolve icon', () => { }); it('should resolve svg from src', async () => { - const expectedName = await resolveIcon('http://localhost/test.svg'); + const expectedName = await resolveIcon(urlTest); expect(expectedName).toEqual( ` add `, @@ -80,7 +84,7 @@ describe('resolve icon', () => { }); it('should not resolve invalid svg from src', async () => { - const icon = 'http://localhost/invalid.svg'; + const icon = urlInvalid; await expect(resolveIcon(icon)).rejects.toThrow('No valid svg data provided'); }); @@ -92,8 +96,6 @@ test('fill cache map if not loaded', async () => { const cacheMap = getIconCacheMap(); cacheMap.clear(); - expect(cacheMap.size).toBe(0); - const data = await resolveIcon('star'); expect(data).toBe(parseSVGDataContent(iconStar)); @@ -111,3 +113,18 @@ test('preload custom icon', async () => { const data = await resolveIcon('star'); expect(data).toBe('Test'); }); + +test('add icons', async () => { + fetch.mockClear(); + + const cacheMap = getIconCacheMap(); + cacheMap.clear(); + + addIcons({ + iconAdd, + }); + + expect(cacheMap.size).toBe(2); + expect(cacheMap.has('iconAdd')).toBeTruthy(); + expect(cacheMap.has('add')).toBeTruthy(); +}); diff --git a/src/components/icon/test/rocker-example.ts b/src/components/icon/test/rocket-example.ts similarity index 100% rename from src/components/icon/test/rocker-example.ts rename to src/components/icon/test/rocket-example.ts diff --git a/src/index.ts b/src/index.ts index df11febd..5684bbdd 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,3 +1,4 @@ export type { Components, JSX } from './components'; export * from './components/icon/icon'; +export { addIcons, addIconToCache } from './components/icon/resolveIcon'; export { setAssetPath } from '@stencil/core'; From b2bcde71a237ebc0f24c8244210ec4b40b85a139 Mon Sep 17 00:00:00 2001 From: Lukas Maurer Date: Thu, 30 Jan 2025 10:40:20 +0100 Subject: [PATCH 02/18] test: update ct --- src/components/icon/test/resolveIcon.spec.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/icon/test/resolveIcon.spec.ts b/src/components/icon/test/resolveIcon.spec.ts index 9fb960a1..2f233728 100644 --- a/src/components/icon/test/resolveIcon.spec.ts +++ b/src/components/icon/test/resolveIcon.spec.ts @@ -1,7 +1,7 @@ /* * COPYRIGHT (c) Siemens AG 2018-2023 ALL RIGHTS RESERVED. */ -import { iconAdd, iconStar } from '../icons'; +import { iconStar, iconStarFilled } from '../icons'; import { resolveIcon, getIconCacheMap, getIconUrl, parseSVGDataContent, addIcons } from '../resolveIcon'; const exampleSvg = ` @@ -121,10 +121,10 @@ test('add icons', async () => { cacheMap.clear(); addIcons({ - iconAdd, + iconStarFilled, }); expect(cacheMap.size).toBe(2); - expect(cacheMap.has('iconAdd')).toBeTruthy(); - expect(cacheMap.has('add')).toBeTruthy(); + expect(cacheMap.has('starFilled')).toBeTruthy(); + expect(cacheMap.has('star-filled')).toBeTruthy(); }); From 640908ab45bf6c47a2fd37927766e1df711deba9 Mon Sep 17 00:00:00 2001 From: Lukas Maurer Date: Thu, 30 Jan 2025 10:45:36 +0100 Subject: [PATCH 03/18] docs: update readme.md --- .changeset/fuzzy-carrots-drive.md | 2 +- README.md | 15 --------------- 2 files changed, 1 insertion(+), 16 deletions(-) diff --git a/.changeset/fuzzy-carrots-drive.md b/.changeset/fuzzy-carrots-drive.md index 8b4aa664..2fc677b8 100644 --- a/.changeset/fuzzy-carrots-drive.md +++ b/.changeset/fuzzy-carrots-drive.md @@ -2,4 +2,4 @@ "@siemens/ix-icons": minor --- -Allow preloading of specific icons. +Allow users to put specific icons into the cache. diff --git a/README.md b/README.md index c9e6dcfa..ac46be2d 100755 --- a/README.md +++ b/README.md @@ -26,21 +26,6 @@ import { defineCustomElements } from '@siemens/ix-icons/loader'; })(); ``` -Icons are loaded once and then cached for the entire duration of the single-page application. -Additionally, icons can be preloaded to ensure they are immediately available from the cache when needed later: - -```javascript -import { loadIcons } from '@siemens/ix-icons'; - -const icons = [ - 'star', - 'star-filled', - // ... -]; - -loadIcons(icons) -``` - ### Angular / Web Components ```html From a39c758c95290c1c5619b02a4503f344ee205996 Mon Sep 17 00:00:00 2001 From: Lukas Maurer Date: Thu, 30 Jan 2025 14:09:20 +0100 Subject: [PATCH 04/18] ci: fix snapshot workflow --- .github/workflows/snapshot.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/snapshot.yml b/.github/workflows/snapshot.yml index 99eb6462..cb15873a 100644 --- a/.github/workflows/snapshot.yml +++ b/.github/workflows/snapshot.yml @@ -77,7 +77,7 @@ jobs: echo "$(git diff --name-only --diff-filter=A ${{ steps.comment-branch.outputs.base_sha }} ${{ steps.parse-sha.outputs.sha }} .changeset/*.md)" >> "${GITHUB_OUTPUT}" echo "${delimiter}" >> "${GITHUB_OUTPUT}" - - uses: ./.github/workflows/actions/turbo + - uses: ./.github/workflows/actions/build - name: Check for pre.json file existence id: check_files From 95e6c1da46a79b0cf8362ca2d55f366a4cd7fc39 Mon Sep 17 00:00:00 2001 From: Lukas Maurer Date: Thu, 30 Jan 2025 15:03:43 +0100 Subject: [PATCH 05/18] ci: fix version --- .github/workflows/snapshot.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/snapshot.yml b/.github/workflows/snapshot.yml index cb15873a..0af2ed95 100644 --- a/.github/workflows/snapshot.yml +++ b/.github/workflows/snapshot.yml @@ -114,7 +114,7 @@ jobs: - name: Get released version if: ${{ steps.added-files.outputs.changesets != '' }} id: get-version - run: echo "version=$(node -p "require('./packages/core/package.json').version")" >> "$GITHUB_OUTPUT" + run: echo "version=$(node -p "require('./package.json').version")" >> "$GITHUB_OUTPUT" - name: Create comment if: ${{ steps.added-files.outputs.changesets != '' }} From 6f066d422917e1c44ec56db3293f4caae8310d76 Mon Sep 17 00:00:00 2001 From: Daniel Leroux Date: Fri, 31 Jan 2025 14:40:04 +0100 Subject: [PATCH 06/18] docs: update readme --- README.md | 55 ++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 40 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index ac46be2d..37c2c2b8 100755 --- a/README.md +++ b/README.md @@ -12,38 +12,63 @@ SPDX-License-Identifier: MIT ## Usage -### Installation +If you're using [Siemens Industrial Experience](https://github.com/siemens/ix/) library you don't have to setup your project this will be done via `@siemens/ix-angular`, `@siemens/ix-react` or `@siemens/ix-vue`, so no additional setup is necessary. -First install the package `@siemens/ix-icons` in your project (e.g. `npm install --save @siemens/ix-icons`). +You want to use `@siemens/ix-icons` without `@siemens/ix` you need to follow these steps. -Then load the icon component: +### Using CDN -```javascript -import { defineCustomElements } from '@siemens/ix-icons/loader'; +Place the following `
@@ -51,7 +51,8 @@ describe('ix-icon', () => { global.fetch = jest.fn(() => Promise.resolve({ ok: false, - text: () => Promise.resolve(`ERROR!`), + text: () => 'error', + status: '500', }), ); @@ -60,7 +61,7 @@ describe('ix-icon', () => { html: ``, }); - expect(page.root.shadowRoot).toEqualHtml(` + expect(page.root!.shadowRoot).toEqualHtml(`
diff --git a/src/components/icon/test/resolveIcon.spec.ts b/src/components/icon/test/resolveIcon.spec.ts index 2f233728..83ac4f00 100644 --- a/src/components/icon/test/resolveIcon.spec.ts +++ b/src/components/icon/test/resolveIcon.spec.ts @@ -1,8 +1,13 @@ /* * COPYRIGHT (c) Siemens AG 2018-2023 ALL RIGHTS RESERVED. */ -import { iconStar, iconStarFilled } from '../icons'; -import { resolveIcon, getIconCacheMap, getIconUrl, parseSVGDataContent, addIcons } from '../resolveIcon'; +import { resolveIcon, getIconCacheMap, getIconUrl, addIcons } from '../resolveIcon'; +import { parseSVGDataContent } from '../parser'; + +export const iconStarFilled = + "data:image/svg+xml;utf8,"; +export const iconStar = + "data:image/svg+xml;utf8,"; const exampleSvg = ` @@ -31,8 +36,6 @@ jest.mock('../icons', () => ({ iconStar: exampleSvg, })); let fetch = (global.fetch = jest.fn((url: string) => { - console.log(url); - if (url === '/svg/star.svg') { return Promise.resolve({ text: () => Promise.resolve(iconStar), @@ -63,12 +66,15 @@ let fetch = (global.fetch = jest.fn((url: string) => { }) as jest.Mock); describe('resolve icon', () => { + let element: HTMLIxIconElement = null!; + beforeEach(() => { fetch.mockClear(); + element = document.createElement('ix-icon'); }); it('should resolve svg from name', async () => { - const data = await resolveIcon('bulb'); + const data = await resolveIcon(element, 'bulb'); expect(data).toBe( ` add `, @@ -76,7 +82,7 @@ describe('resolve icon', () => { }); it('should resolve svg from src', async () => { - const expectedName = await resolveIcon(urlTest); + const expectedName = await resolveIcon(element, urlTest); expect(expectedName).toEqual( ` add `, @@ -86,23 +92,26 @@ describe('resolve icon', () => { it('should not resolve invalid svg from src', async () => { const icon = urlInvalid; - await expect(resolveIcon(icon)).rejects.toThrow('No valid svg data provided'); + const content = await resolveIcon(element, icon); + expect(content).toEqual(''); }); }); test('fill cache map if not loaded', async () => { + const element = document.createElement('ix-icon'); fetch.mockClear(); const cacheMap = getIconCacheMap(); cacheMap.clear(); - const data = await resolveIcon('star'); + const data = await resolveIcon(element, 'star'); expect(data).toBe(parseSVGDataContent(iconStar)); expect(cacheMap.get(getIconUrl('star'))).toBe(parseSVGDataContent(iconStar)); }); test('preload custom icon', async () => { + const element = document.createElement('ix-icon'); fetch.mockClear(); const cacheMap = getIconCacheMap(); @@ -110,7 +119,7 @@ test('preload custom icon', async () => { cacheMap.set(getIconUrl('star'), 'Test'); - const data = await resolveIcon('star'); + const data = await resolveIcon(element, 'star'); expect(data).toBe('Test'); }); diff --git a/tsconfig.json b/tsconfig.json index 5971d5da..a8815317 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -11,7 +11,8 @@ "noUnusedLocals": true, "noUnusedParameters": true, "jsx": "react", - "jsxFactory": "h" + "jsxFactory": "h", + "strict": true }, "include": ["src"], "exclude": ["node_modules"] From b06998a0e6aeaf8476c80342729f379697bddbbe Mon Sep 17 00:00:00 2001 From: Daniel Leroux Date: Wed, 5 Feb 2025 15:43:09 +0100 Subject: [PATCH 12/18] test: remove unused mock --- src/components/icon/test/resolveIcon.spec.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/components/icon/test/resolveIcon.spec.ts b/src/components/icon/test/resolveIcon.spec.ts index 83ac4f00..80570fad 100644 --- a/src/components/icon/test/resolveIcon.spec.ts +++ b/src/components/icon/test/resolveIcon.spec.ts @@ -32,9 +32,7 @@ const urlInvalid = 'http://localhost/invalid.svg'; const urlTest = 'http://localhost/test.svg'; jest.mock('../meta-tag'); -jest.mock('../icons', () => ({ - iconStar: exampleSvg, -})); + let fetch = (global.fetch = jest.fn((url: string) => { if (url === '/svg/star.svg') { return Promise.resolve({ From 9917f3be765852bd4ef863c4bc6a45299d7491cd Mon Sep 17 00:00:00 2001 From: Daniel Leroux Date: Wed, 5 Feb 2025 16:24:19 +0100 Subject: [PATCH 13/18] fix: fix error branch which results in object string --- src/components/icon/resolveIcon.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/components/icon/resolveIcon.ts b/src/components/icon/resolveIcon.ts index e0eb28a1..9e52218f 100644 --- a/src/components/icon/resolveIcon.ts +++ b/src/components/icon/resolveIcon.ts @@ -129,7 +129,13 @@ async function loadIcon(iconName: string): Promise { return fetchSVG(iconName); } - return fetchSVG(getIconUrl(iconName)); + const iconUrl = getIconUrl(iconName); + + if (!iconUrl) { + return ''; + } + + return fetchSVG(iconUrl); } function removePrefix(name: string, prefix: string) { From 15af3002364de8e6b8cba8e12ed91b6a6e771b58 Mon Sep 17 00:00:00 2001 From: Daniel Leroux Date: Wed, 26 Feb 2025 16:51:30 +0100 Subject: [PATCH 14/18] feat: improve error logging --- src/components/icon/parser.ts | 1 - src/components/icon/resolveIcon.ts | 27 ++++++++++++-------- src/components/icon/test/resolveIcon.spec.ts | 4 +-- 3 files changed, 18 insertions(+), 14 deletions(-) diff --git a/src/components/icon/parser.ts b/src/components/icon/parser.ts index f0ae5549..ddb23a29 100644 --- a/src/components/icon/parser.ts +++ b/src/components/icon/parser.ts @@ -21,7 +21,6 @@ export function parseSVGDataContent(content: string): string { const svgElement = svgDocument.querySelector('svg') as HTMLElement; if (!svgElement) { - console.error('No valid svg data provided'); return ''; } diff --git a/src/components/icon/resolveIcon.ts b/src/components/icon/resolveIcon.ts index 9e52218f..8d8567ec 100644 --- a/src/components/icon/resolveIcon.ts +++ b/src/components/icon/resolveIcon.ts @@ -44,7 +44,7 @@ export const isSvgDataUrl = (url: string) => { return url.startsWith('data:image/svg+xml'); }; -async function fetchSVG(url: string) { +async function fetchSVG(url: string, element: HTMLIxIconElement) { const cache = getIconCacheMap(); if (cache.has(url)) { @@ -64,13 +64,13 @@ async function fetchSVG(url: string) { svgContent = parseSVGDataContent(responseText); cache.set(url, svgContent); } else { - console.error('Failed to request svg data from', url, 'with status code', response.status); + console.error('Failed to request svg data from', url, 'with status code', response.status, element); } return svgContent; }) .catch(() => { - console.error('Failed to fetch svg data:', url); + console.error('Failed to fetch svg data:', url, element); cache.set(url, ''); return ''; }) @@ -87,7 +87,7 @@ function isValidUrl(url: string) { return urlRegex.test(url); } -export function getIconUrl(name: string) { +export function getIconUrl(name: string, element: HTMLIxIconElement) { const customAssetUrl = getCustomAssetUrl(); if (customAssetUrl) { @@ -99,7 +99,7 @@ export function getIconUrl(name: string) { try { url = getAssetPath(url); } catch (error) { - console.warn(`Could not load icon with name "${name}". Ensure that the icon is registered using addIcons or that the icon SVG data is passed directly to property.`); + console.warn(`Could not load icon with name "${name}". Ensure that the icon is registered using addIcons or that the icon SVG data is passed directly to property.`, element); } return url; @@ -112,13 +112,18 @@ export async function resolveIcon(element: HTMLIxIconElement, iconName?: string) } if (isSvgDataUrl(iconName)) { - return parseSVGDataContent(iconName); + const content = parseSVGDataContent(iconName); + + if (!content) { + console.error('Failed to parse icon data', element); + } + return content; } - return loadIcon(iconName); + return loadIcon(iconName, element); } -async function loadIcon(iconName: string): Promise { +async function loadIcon(iconName: string, element: HTMLIxIconElement): Promise { const cache = getIconCacheMap(); if (cache.has(iconName)) { @@ -126,16 +131,16 @@ async function loadIcon(iconName: string): Promise { } if (isValidUrl(iconName)) { - return fetchSVG(iconName); + return fetchSVG(iconName, element); } - const iconUrl = getIconUrl(iconName); + const iconUrl = getIconUrl(iconName, element); if (!iconUrl) { return ''; } - return fetchSVG(iconUrl); + return fetchSVG(iconUrl, element); } function removePrefix(name: string, prefix: string) { diff --git a/src/components/icon/test/resolveIcon.spec.ts b/src/components/icon/test/resolveIcon.spec.ts index 80570fad..c37ffccb 100644 --- a/src/components/icon/test/resolveIcon.spec.ts +++ b/src/components/icon/test/resolveIcon.spec.ts @@ -105,7 +105,7 @@ test('fill cache map if not loaded', async () => { const data = await resolveIcon(element, 'star'); expect(data).toBe(parseSVGDataContent(iconStar)); - expect(cacheMap.get(getIconUrl('star'))).toBe(parseSVGDataContent(iconStar)); + expect(cacheMap.get(getIconUrl('star', element))).toBe(parseSVGDataContent(iconStar)); }); test('preload custom icon', async () => { @@ -115,7 +115,7 @@ test('preload custom icon', async () => { const cacheMap = getIconCacheMap(); cacheMap.clear(); - cacheMap.set(getIconUrl('star'), 'Test'); + cacheMap.set(getIconUrl('star', element), 'Test'); const data = await resolveIcon(element, 'star'); expect(data).toBe('Test'); From 5174fb30c1469a7b18ee1922d3fee110da422298 Mon Sep 17 00:00:00 2001 From: Daniel Leroux Date: Wed, 26 Feb 2025 17:01:08 +0100 Subject: [PATCH 15/18] update stencil version --- package.json | 2 +- pnpm-lock.yaml | 16 ++++++++-------- src/components.d.ts | 8 ++++++++ 3 files changed, 17 insertions(+), 9 deletions(-) diff --git a/package.json b/package.json index f6ed9657..42d875cb 100644 --- a/package.json +++ b/package.json @@ -45,7 +45,7 @@ "ci:publish": "pnpm changeset publish" }, "dependencies": { - "@stencil/core": "^4.25.1" + "@stencil/core": "^4.27.1" }, "devDependencies": { "@changesets/changelog-github": "^0.5.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 75db3aa5..b4e47cc2 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -9,8 +9,8 @@ importers: .: dependencies: '@stencil/core': - specifier: ^4.25.1 - version: 4.25.1 + specifier: ^4.27.1 + version: 4.27.1 devDependencies: '@changesets/changelog-github': specifier: ^0.5.0 @@ -23,7 +23,7 @@ importers: version: 1.50.0 '@stencil/sass': specifier: ^3.0.10 - version: 3.0.11(@stencil/core@4.25.1) + version: 3.0.11(@stencil/core@4.27.1) '@types/fs-extra': specifier: ^9.0.13 version: 9.0.13 @@ -436,8 +436,8 @@ packages: '@sinonjs/fake-timers@8.1.0': resolution: {integrity: sha512-OAPJUAtgeINhh/TAlUID4QTs53Njm7xzddaVlEs/SXwgtiD1tW22zAB/W1wdqfrpmikgaWQ9Fw6Ws+hsiRm5Vg==} - '@stencil/core@4.25.1': - resolution: {integrity: sha512-SJhAAN6nHj7l2n2F7H6NoOUFhXC5tYXSvOpAaNFi5As6c2jOvaDOvAH+om4OKmw8U2kHI9yihEqpZrtY1J20dQ==} + '@stencil/core@4.27.1': + resolution: {integrity: sha512-wJ+U3yJ9xSrME1PheHh8DnZrgFhjTlvF54mkA0tzTDXYdrEAYXIEAAeWbXx3munYX2Lqj3oDBEDsbsJNxDkwzA==} engines: {node: '>=16.0.0', npm: '>=7.10.0'} hasBin: true @@ -4333,11 +4333,11 @@ snapshots: dependencies: '@sinonjs/commons': 1.8.6 - '@stencil/core@4.25.1': {} + '@stencil/core@4.27.1': {} - '@stencil/sass@3.0.11(@stencil/core@4.25.1)': + '@stencil/sass@3.0.11(@stencil/core@4.27.1)': dependencies: - '@stencil/core': 4.25.1 + '@stencil/core': 4.27.1 '@tootallnate/once@1.1.2': {} diff --git a/src/components.d.ts b/src/components.d.ts index e251ee43..c4b255ce 100644 --- a/src/components.d.ts +++ b/src/components.d.ts @@ -15,6 +15,10 @@ export namespace Components { * Only fetch and parse svg data when icon is visible */ "lazyLoading": boolean; + /** + * @deprecated use camelCase instead. Support for dash-casing will be removed in Stencil v5. + */ + "lazy-loading"?: 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'; ``` */ @@ -46,6 +50,10 @@ declare namespace LocalJSX { * Only fetch and parse svg data when icon is visible */ "lazyLoading"?: boolean; + /** + * @deprecated use camelCase instead. Support for dash-casing will be removed in Stencil v5. + */ + "lazy-loading"?: 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'; ``` */ From f43cad7a3c326d5295dec9dcddc361d63a205ebe Mon Sep 17 00:00:00 2001 From: Daniel Leroux Date: Wed, 26 Feb 2025 17:13:34 +0100 Subject: [PATCH 16/18] add changeset --- .changeset/light-schools-buy.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .changeset/light-schools-buy.md diff --git a/.changeset/light-schools-buy.md b/.changeset/light-schools-buy.md new file mode 100644 index 00000000..fd6a0373 --- /dev/null +++ b/.changeset/light-schools-buy.md @@ -0,0 +1,6 @@ +--- +'@siemens/ix-icons': minor +--- + +- Improve logging include html element inside logging to identify which component creates the logging +- Update stencil version to 4.27.1 From 1053f27fb871dbb9a61dfa920cc67c7281bc9e24 Mon Sep 17 00:00:00 2001 From: Daniel Leroux Date: Thu, 27 Feb 2025 08:02:59 +0100 Subject: [PATCH 17/18] add logging to parser --- src/components/icon/parser.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/components/icon/parser.ts b/src/components/icon/parser.ts index f0ae5549..eac10efa 100644 --- a/src/components/icon/parser.ts +++ b/src/components/icon/parser.ts @@ -7,7 +7,7 @@ let parser: any = null; export const errorSymbol = "data:image/svg+xml;utf8,"; -export function parseSVGDataContent(content: string): string { +export function parseSVGDataContent(content: string, element?: HTMLElement): string { if (typeof window['DOMParser'] === 'undefined') { console.error('DOMParser not supported by your browser.'); return ''; @@ -21,7 +21,11 @@ export function parseSVGDataContent(content: string): string { const svgElement = svgDocument.querySelector('svg') as HTMLElement; if (!svgElement) { - console.error('No valid svg data provided'); + if (element) { + console.error('No valid svg data provided', element); + } else { + console.error('No valid svg data provided'); + } return ''; } From c13a04e960352a402cd9107bae0589eadbe56504 Mon Sep 17 00:00:00 2001 From: Daniel Leroux Date: Thu, 27 Feb 2025 08:13:53 +0100 Subject: [PATCH 18/18] pass through element --- src/components/icon/resolveIcon.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/icon/resolveIcon.ts b/src/components/icon/resolveIcon.ts index 8d8567ec..cfbfea21 100644 --- a/src/components/icon/resolveIcon.ts +++ b/src/components/icon/resolveIcon.ts @@ -61,7 +61,7 @@ async function fetchSVG(url: string, element: HTMLIxIconElement) { let svgContent = ''; if (response.ok) { - svgContent = parseSVGDataContent(responseText); + svgContent = parseSVGDataContent(responseText, element); cache.set(url, svgContent); } else { console.error('Failed to request svg data from', url, 'with status code', response.status, element); @@ -112,7 +112,7 @@ export async function resolveIcon(element: HTMLIxIconElement, iconName?: string) } if (isSvgDataUrl(iconName)) { - const content = parseSVGDataContent(iconName); + const content = parseSVGDataContent(iconName, element); if (!content) { console.error('Failed to parse icon data', element);