UNPKG

kk-web-components

Version:

A collection of reusable web components, including ui-icon and others.

122 lines (101 loc) 3.09 kB
const defaultConfig = { version: Date.now(), filePath: '/assets/iconset.svg', defaultSize: 24, }; class UiIcon extends HTMLElement { constructor() { super(); this.attachShadow({ mode: 'open' }); if (this.shadowRoot.adoptedStyleSheets) { this.shadowRoot.adoptedStyleSheets = [sharedStyles]; } else { const style = document.createElement('style'); style.textContent = sharedStylesText; this.shadowRoot.appendChild(style); } } connectedCallback() { setTimeout(() => { this.render(); }, 20); } render() { const config = { ...defaultConfig, ...(window.UiIcon || {}), }; const options = this.getOptions({ name: null, icon: null, size: config.defaultSize, rotation: 0, viewbox: null, }); const iconName = options.icon || options.name; if (options.name && !options.icon && !window.UiIconDeprecationWarningAttrNameSent) { console.warn(`[ui-icon] Attribute "name" is deprecated. Use "icon" instead.`); window.UiIconDeprecationWarningAttrNameSent = true; } const { size, rotation, viewbox } = options; const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); svg.setAttribute('aria-hidden', 'true'); svg.setAttribute('part', 'icon'); const isValidSize = Number.isFinite(size) && size > 0; const isValidViewbox = viewbox && /^(\d+(\.\d+)?\s){3}\d+(\.\d+)?$/.test(viewbox); const isValidRotation = !isNaN(parseFloat(rotation)); if (isValidViewbox) { svg.setAttribute('viewBox', viewbox); } if (isValidSize) { svg.setAttribute('width', size); svg.setAttribute('height', size); } if (isValidRotation) { svg.style.transform = `rotate(${rotation}deg)`; } const use = document.createElementNS('http://www.w3.org/2000/svg', 'use'); const encodedIconName = encodeURIComponent(iconName || ''); const version = encodeURIComponent(config.version); const urlParams = `?v=${version}`; use.setAttribute('href', `${config.filePath}${urlParams}#${encodedIconName}`); svg.appendChild(use); this.shadowRoot.innerHTML = ''; this.shadowRoot.appendChild(svg); } getOptions(defaults) { return Object.keys(defaults).reduce((acc, key) => { const value = this.getAttribute(key); acc[key] = value !== null ? typeof defaults[key] === 'number' ? parseFloat(value) : value : defaults[key]; return acc; }, {}); } static get observedAttributes() { return ['name', 'icon', 'size', 'rotation', 'viewbox']; } attributeChangedCallback(name, oldValue, newValue) { if (oldValue !== newValue) { this.render(); } } } const sharedStylesText = ` :host { flex-shrink: 0; display: block; } svg { display: block; pointer-events: none; } `; const sharedStyles = new CSSStyleSheet(); sharedStyles.replaceSync(sharedStylesText); if (!customElements.get('ui-icon')) { customElements.define('ui-icon', UiIcon); }