diff --git a/src/components.d.ts b/src/components.d.ts index ecf24839b..3d2f418b3 100644 --- a/src/components.d.ts +++ b/src/components.d.ts @@ -1982,7 +1982,7 @@ declare namespace LocalJSX { /** * Emitted when the icon failed to load. */ - "onSl-error"?: (event: CustomEvent) => void; + "onSl-error"?: (event: CustomEvent<{ status?: number }>) => void; /** * Emitted when the icon has loaded. */ @@ -2046,7 +2046,7 @@ declare namespace LocalJSX { /** * Emitted when the included file fails to load due to an error. */ - "onSl-error"?: (event: CustomEvent<{ status: number }>) => void; + "onSl-error"?: (event: CustomEvent<{ status?: number }>) => void; /** * Emitted when the included file is loaded. */ diff --git a/src/components/icon/icon.tsx b/src/components/icon/icon.tsx index 1553290a5..8ee1c0360 100644 --- a/src/components/icon/icon.tsx +++ b/src/components/icon/icon.tsx @@ -38,7 +38,7 @@ export class Icon { @Event({ eventName: 'sl-load' }) slLoad: EventEmitter; /** Emitted when the icon failed to load. */ - @Event({ eventName: 'sl-error' }) slError: EventEmitter; + @Event({ eventName: 'sl-error' }) slError: EventEmitter<{ status?: number }>; @Watch('name') @Watch('src') @@ -79,7 +79,7 @@ export class Icon { return label; } - setIcon() { + async setIcon() { const library = getLibrary(this.library); let url = this.src; @@ -88,9 +88,10 @@ export class Icon { } if (url) { - requestIcon(url) - .then(source => { - const doc = parser.parseFromString(source, 'text/html'); + try { + const file = await requestIcon(url); + if (file.ok) { + const doc = parser.parseFromString(file.svg, 'text/html'); const svg = doc.body.querySelector('svg'); if (svg) { @@ -102,10 +103,12 @@ export class Icon { this.slLoad.emit(); } else { this.svg = ''; - this.slError.emit(); + this.slError.emit({ status: file.status }); } - }) - .catch(error => this.slError.emit(error)); + } + } catch { + this.slError.emit(); + } } } diff --git a/src/components/icon/request.ts b/src/components/icon/request.ts index 2d33e83e3..0f16d3e94 100644 --- a/src/components/icon/request.ts +++ b/src/components/icon/request.ts @@ -1,30 +1,36 @@ -const cache = new Map(); -const requests = new Map>(); +interface IconFile { + ok: boolean; + status: number; + svg: string; +} + +const iconFiles = new Map>(); export const requestIcon = (url: string) => { - let req = requests.get(url); - - if (!req) { - req = fetch(url).then(async res => { - if (res.ok) { + if (iconFiles.has(url)) { + return iconFiles.get(url); + } else { + const request = fetch(url).then(async response => { + if (response.ok) { const div = document.createElement('div'); - div.innerHTML = await res.text(); - + div.innerHTML = await response.text(); const svg = div.firstElementChild; - if (svg && svg.tagName.toLowerCase() === 'svg') { - cache.set(url, div.innerHTML); - return svg.outerHTML; - } else { - console.warn(`Invalid SVG icon: ${url}`); - return ''; - } + + return { + ok: response.ok, + status: response.status, + svg: svg && svg.tagName.toLowerCase() === 'svg' ? svg.outerHTML : '' + }; } else { - return ''; + return { + ok: response.ok, + status: response.status, + svg: null + }; } }); - requests.set(url, req); + iconFiles.set(url, request); + return request; } - - return req; };