UNPKG

@limetech/lime-elements

Version:
74 lines (73 loc) 2.38 kB
export class InMemoryIconCache { constructor() { /* * Cache of all loaded SVGs */ this.cache = {}; /* * Contains resolve functions for all unresolved promises that are waiting for SVG data. */ this.resolveFunctions = {}; } /** * Get icon data from the cache * * @param name - Name of the icon * @param path - Path on the server where the assets are located * @returns SVG markup */ async get(name, path = '') { if (!this.cache[name]) { this.cache[name] = await this.getIcon(name, path); } return this.cache[name]; } /* * Creates and returns a promise that will be resolved when SVG data is available */ getIcon(name, path) { return new Promise((resolve) => { if (!this.resolveFunctions[name]) { this.resolveFunctions[name] = []; this.fetchData(name, path); } this.resolveFunctions[name].push(resolve); }); } /* * Fetch SVG data from the server */ async fetchData(name, path) { let iconPath = path || ''; if (path && !path.endsWith('/')) { iconPath = `${path}/`; } const response = await fetch(`${iconPath}assets/icons/${name}.svg`); let svgData = await response.text(); // Some of the icons in the Icons8 library have hard coded black color on some of the paths. // In order to apply coloring with CSS, these have to be set to 'currentColor' svgData = svgData.replaceAll('#000000', 'currentColor'); if (!this.validSvg(svgData)) { throw new Error('Invalid SVG'); } this.resolvePromises(name, svgData); } /* * Check if the given data is a valid SVG document */ validSvg(data) { const parser = new DOMParser(); const svgDoc = parser.parseFromString(data, 'image/svg+xml'); return svgDoc.documentElement.tagName.toLowerCase() === 'svg'; } /* * Resolve all promises waiting for data for a specific icon */ resolvePromises(name, svgData) { const resolves = this.resolveFunctions[name]; for (const resolve of resolves) { resolve(svgData); } this.resolveFunctions[name] = null; } }