UNPKG

@larva.io/webcomponents

Version:

Fentrica SmartUnits WebComponents package

235 lines (234 loc) 8.09 kB
/*! * (C) Fentrica http://fentrica.com - Seee LICENSE.md */ import { Host, h } from "@stencil/core"; import { createColorClasses } from "../../../utils/theme"; import isEmpty from "lodash-es/isEmpty"; import { getIconMap } from "./utils"; export class Icon { loadIcon() { // Check if it's a named icon (from built-in icons) if (!isEmpty(this.icon)) { const svgContent = getIconMap().get(this.icon); if (svgContent) { // It's a built-in icon with inlined SVG this.svgContent = validateContent(document, svgContent, this.el['s-sc']); return; } } // Handle src attribute (custom URL) const url = getSrc(this.src); if (!isEmpty(url)) { getSvgContent(url).then(svgContent => { this.svgContent = validateContent(document, svgContent, this.el['s-sc']); }); } } componentWillLoad() { this.loadIcon(); } render() { let ret; if (!isEmpty(this.svgContent)) { // we've already loaded up this svg at one point // and the svg content we've loaded and assigned checks out // render this svg!! ret = h("div", { key: '525d0b09cd5a3dad9719ec9590598b3ac139c81a', class: "lar-icon-inner" }, h("div", { key: 'b27996d14010b096f467c3e205a56d85ecfa3f62', innerHTML: this.svgContent })); } else { // actively requesting the svg // or it's an SSR render // so let's just render an empty div for now ret = h("div", { key: '7b954444ae93d046aaa002e90d148325f7ee6f59', class: "lar-icon-inner" }); } return (h(Host, { key: 'bc2ba9cd78548ef518300cf2d201897330862770', role: "img", class: Object.assign(Object.assign({}, createColorClasses(this.color)), { [`lar-icon-${this.size}`]: (this.size === 'large' || this.size === 'small' || this.size === 'medium') }) }, ret)); } static get is() { return "lar-icon"; } static get encapsulation() { return "shadow"; } static get originalStyleUrls() { return { "$": ["icon.scss"] }; } static get styleUrls() { return { "$": ["icon.css"] }; } static get assetsDirs() { return ["assets"]; } static get properties() { return { "color": { "type": "string", "mutable": false, "complexType": { "original": "Color", "resolved": "string", "references": { "Color": { "location": "import", "path": "../../../interface", "id": "src/interface.d.ts::Color" } } }, "required": false, "optional": true, "docs": { "tags": [], "text": "The color to use from your application's color palette.\nDefault options are: `\"primary\"`, `\"secondary\"`, `\"tertiary\"`, `\"success\"`, `\"warning\"`, `\"danger\"`, `\"light\"`, `\"medium\"`, and `\"dark\"`." }, "getter": false, "setter": false, "reflect": false, "attribute": "color" }, "icon": { "type": "string", "mutable": false, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": true, "optional": false, "docs": { "tags": [], "text": "Use 'named' incon param icon or\nsrc for svg url" }, "getter": false, "setter": false, "reflect": false, "attribute": "icon" }, "src": { "type": "string", "mutable": false, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": false, "optional": true, "docs": { "tags": [], "text": "" }, "getter": false, "setter": false, "reflect": false, "attribute": "src" }, "size": { "type": "string", "mutable": false, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": false, "optional": true, "docs": { "tags": [], "text": "The size of the icon.\nAvailable options are: `\"small\"`, `\"medium\"` `\"large\"`." }, "getter": false, "setter": false, "reflect": false, "attribute": "size" } }; } static get states() { return { "svgContent": {} }; } static get elementRef() { return "el"; } static get watchers() { return [{ "propName": "icon", "methodName": "loadIcon" }, { "propName": "src", "methodName": "loadIcon" }]; } } function getSrc(src) { if (typeof src === 'string') { src = src.trim(); if (src.length > 0 && /(\/|\.)/.test(src)) { return src; } } return null; } const requests = new Map(); function getSvgContent(url) { // see if we already have a request for this url let req = requests.get(url); if (req === undefined) { // we don't already have a request req = fetch(url, { cache: 'force-cache' }).then(rsp => { if (rsp.ok) { return rsp.text(); } return Promise.resolve(null); }); // cache for the same requests requests.set(url, req); } return req; } function validateContent(document, svgContent, scopeId) { if (!isEmpty(svgContent)) { const frag = document.createDocumentFragment(); const div = document.createElement('div'); div.innerHTML = svgContent; frag.appendChild(div); // setup this way to ensure it works on our buddy IE for (let i = div.childNodes.length - 1; i >= 0; i--) { if (div.childNodes[i].nodeName.toLowerCase() !== 'svg') { div.removeChild(div.childNodes[i]); } } // must only have 1 root element const svgElm = div.firstElementChild; if (svgElm && svgElm.nodeName.toLowerCase() === 'svg') { if (!isEmpty(scopeId)) { svgElm.setAttribute('class', scopeId); } // root element must be an svg // lets double check we've got valid elements // do not allow scripts if (isValid(svgElm)) { return div.innerHTML; } } } return ''; } function isValid(elm) { if (elm.nodeType === 1) { if (elm.nodeName.toLowerCase() === 'script') { return false; } for (let i = 0; i < elm.attributes.length; i++) { const val = elm.attributes[i].value; if (typeof val === 'string' && val.toLowerCase().indexOf('on') === 0) { return false; } } for (let i = 0; i < elm.childNodes.length; i++) { if (!isValid(elm.childNodes[i])) { return false; } } } return true; } //# sourceMappingURL=icon.js.map