UNPKG

@limetech/lime-elements

Version:
204 lines (197 loc) 6.64 kB
import { r as registerInstance, h, g as getElement } from './index-2714248e.js'; import { g as globalConfig } from './config-656a588f.js'; class CacheStorageIconCache { constructor(cache) { this.promises = {}; this.cache = cache; } /** * 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 = '') { const cache = await this.cache; const url = this.getUrl(name, path); let response = await cache.match(url); if (!response) { response = await this.fetchData(url, cache); } return this.getIcon(response); } async fetchData(url, cache) { let requestPromise = this.promises[url]; if (requestPromise === undefined) { requestPromise = cache.add(url); this.promises[url] = requestPromise; } await requestPromise; return cache.match(url); } /* * Get icon data from a response */ async getIcon(response) { 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'); } return 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'; } getUrl(name, path) { let iconPath = path || ''; if (path && !path.endsWith('/')) { iconPath = `${path}/`; } return `${iconPath}assets/icons/${name}.svg`; } } 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; } } const CACHE_NAME = '@limetech/lime-elements/icons'; function createIconCache() { try { const cache = caches.open(CACHE_NAME); return new CacheStorageIconCache(cache); } catch (_a) { return new InMemoryIconCache(); } } const iconCache = (() => { return createIconCache(); })(); const iconCss = ":host{background-color:var(--icon-background-color, transparent);border-radius:50%;display:inline-block;line-height:0;box-sizing:border-box}:host svg{fill:currentColor;height:100%;pointer-events:none;width:100%}:host div{margin:var(--limel-icon-svg-margin, 0)}:host([hidden]){display:none}:host([size=x-small]){height:1rem !important;width:1rem !important}:host([size=small]){height:1.25rem !important;width:1.25rem !important}:host([size=medium]){height:1.5rem !important;width:1.5rem !important}:host([size=large]){height:1.75rem !important;width:1.75rem !important}:host([badge][size=x-small]){height:1.5rem !important;width:1.5rem !important;--limel-icon-svg-margin:0.25rem}:host([badge][size=small]){height:1.75rem !important;width:1.75rem !important;--limel-icon-svg-margin:0.25rem}:host([badge][size=medium]){height:2.5rem !important;width:2.5rem !important;--limel-icon-svg-margin:0.5rem}:host([badge][size=large]){height:2.75rem !important;width:2.75rem !important;--limel-icon-svg-margin:0.5rem}"; const Icon = class { constructor(hostRef) { registerInstance(this, hostRef); this.size = undefined; this.name = undefined; this.badge = undefined; } componentDidLoad() { this.loadIcon(this.name); } render() { return h("div", { class: "container" }); } async loadIcon(name) { if (name === undefined || name === '') { return; } const svgData = await this.loadSvg(name); this.renderSvg(svgData); } /** * Load the SVG data for the icon from the icon cache * * @param name - name of the icon * @returns the icon SVG data */ loadSvg(name) { return iconCache.get(name, globalConfig.iconPath); } /* * There is no way to style external SVG files with CSS, i.e. SVGs loaded * with <img src="file.svg" /> or <object data="file.svg" type="image/svg+xml" /> * will remain the way they look in the file. * Therefore we inject the svg as inline markup instead. */ renderSvg(svgData) { const container = this.host.shadowRoot.querySelector('div.container'); if (container) { container.innerHTML = svgData; } } get host() { return getElement(this); } static get watchers() { return { "name": ["loadIcon"] }; } }; Icon.style = iconCss; export { Icon as limel_icon }; //# sourceMappingURL=limel-icon.entry.js.map