wj-elements 0.1.167 → 0.1.168
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/wje-icon-picker.js
CHANGED
|
@@ -147,7 +147,7 @@ class IconPicker extends WJElement {
|
|
|
147
147
|
* @returns {string} The URL of the tags path.
|
|
148
148
|
*/
|
|
149
149
|
__publicField(this, "getTagsUrl", (path) => {
|
|
150
|
-
return new URL(
|
|
150
|
+
return new URL(process.env.VITE_ICON_ASSETS_URL + path).href;
|
|
151
151
|
});
|
|
152
152
|
}
|
|
153
153
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wje-icon-picker.js","sources":["../packages/wje-icon-picker/icon-picker.element.js","../packages/wje-icon-picker/icon-picker.js"],"sourcesContent":["import { default as WJElement, event } from '../wje-element/element.js';\nimport InfiniteScroll from '../wje-infinite-scroll/infinite-scroll.js';\nimport Input from '../wje-input/input.js';\nimport Popup from '../wje-popup/popup.js';\nimport Tooltip from '../wje-tooltip/tooltip.js';\nimport styles from './styles/styles.css?inline';\n\n/**\n * @summary This element allows users to pick an icon from a set of available options.\n * `IconPicker` is a custom web component that represents an interactive icon picker. It features\n * search functionality, infinite scrolling, and popup-based selection. The component is highly customizable\n * and integrates seamlessly with other `WJElement` components.\n * @documentation https://elements.webjet.sk/components/icon-picker\n * @status stable\n * @augments {WJElement}\n * @attribute {string} icon - The selected icon's name.\n * @attribute {number} size - The number of icons displayed per page in infinite scroll. Default is 60.\n * @csspart native - The native part of the component.\n * @csspart anchor - The part representing the anchor button displaying the selected icon.\n * @csspart picker - The picker part containing the search and icon selection interface.\n * @csspart input - The input part for searching icons.\n * @cssproperty [--wje-color-picker-value=#ff0000] - The default color value.\n * @cssproperty [--wje-color-picker-area=transparent] - The background color of the color picker area.\n * @cssproperty [--wje-color-picker-swatch=transparent] - The background color of the swatch picker.\n * @cssproperty [--wje-color-picker-size=1rem] - The size of the icons in the picker.\n * @cssproperty [--wje-color-picker-radius=4px] - The border radius of the picker.\n * @tag wje-icon-picker\n */\n\nexport default class IconPicker extends WJElement {\n /**\n * Creates an instance of IconPicker.\n * @class\n */\n constructor() {\n super();\n }\n\n /**\n * Dependencies of the IconPicker component.\n * @property {object} dependencies\n */\n dependencies = {\n 'wje-input': Input,\n 'wje-infinite-scroll': InfiniteScroll,\n 'wje-tooltip': Tooltip,\n 'wje-popup': Popup,\n };\n\n /**\n * Setter for the markerPosition property.\n * @param {any} value The value to set.\n */\n set size(value) {\n this.setAttribute('size', value);\n }\n\n /**\n * Getter for the markerPosition property.\n * @returns {any} size The value of the markerPosition property.\n */\n get size() {\n return this.getAttribute('size') || 60;\n }\n\n /**\n * Setter for the value property.\n * @param value\n */\n set icon(value) {\n this.setAttribute('icon', value);\n }\n\n /**\n * Getter for the value property.\n * @returns {string}\n */\n get icon() {\n return this.getAttribute('icon');\n }\n\n className = 'IconPicker';\n\n /**\n * Returns the CSS styles for the component.\n * @static\n * @returns {CSSStyleSheet}\n */\n static get cssStyleSheet() {\n return styles;\n }\n\n /**\n * Returns the list of attributes to observe for changes.\n * @static\n * @returns {Array<string>}\n */\n static get observedAttributes() {\n return [];\n }\n\n /**\n * Sets up the attributes for the component.\n */\n setupAttributes() {\n this.isShadowRoot = 'open';\n }\n\n /**\n * Prepares the component before drawing.\n */\n async beforeDraw() {\n this.tags = Object.values(await this.getTags());\n\n this.transformedObjects = this.convertObject(this.tags);\n\n this.index = this.transformedObjects.map((item) => ({\n ...item,\n searchText: `${item.name.toLowerCase()} ${item.tags.join(' ').toLowerCase()}`,\n }));\n }\n\n /**\n * Draws the component.\n * @returns {DocumentFragment}\n */\n draw() {\n let fragment = document.createDocumentFragment();\n\n let native = document.createElement('div');\n native.classList.add('native-color-picker');\n\n // ANCHOR\n let anchor = document.createElement('div');\n anchor.setAttribute('slot', 'anchor');\n anchor.classList.add('anchor');\n\n if (this.hasAttribute('icon') && this.icon) {\n let icon = document.createElement('wje-icon');\n icon.setAttribute('name', this.icon);\n\n anchor.appendChild(icon);\n }\n\n // PICKER\n let picker = document.createElement('div');\n picker.classList.add('picker');\n\n let input = document.createElement('wje-input');\n input.classList.add('input');\n input.setAttribute('variant', 'standard');\n input.setAttribute('placeholder', 'type to filter...');\n input.setAttribute('clearable', '');\n input.addEventListener('wje-input:input', this.searchIcon);\n\n let infiniteScroll = new InfiniteScroll();\n\n infiniteScroll.setAttribute('url', this.getTagsUrl('../../tags.json'));\n infiniteScroll.setAttribute('placement', '.icon-items');\n infiniteScroll.setAttribute('size', this.size);\n infiniteScroll.setAttribute('height', '223px');\n infiniteScroll.innerHTML = '<div class=\"icon-items\"></div>';\n\n // APPEND\n picker.appendChild(input);\n\n picker.appendChild(infiniteScroll);\n\n // POPUP\n let popup = document.createElement('wje-popup');\n popup.setAttribute('placement', this.placement || 'bottom-start');\n popup.setAttribute('offset', this.offset);\n popup.setAttribute('manual', '');\n\n popup.appendChild(anchor);\n popup.appendChild(picker);\n\n native.appendChild(popup);\n\n fragment.appendChild(native);\n\n this.popup = popup;\n this.input = input;\n this.anchor = anchor;\n this.picker = picker;\n this.infiniteScroll = infiniteScroll;\n\n this.infiniteScroll.dataToHtml = this.dataToHtml;\n this.infiniteScroll.compareFunction = (i, item) => i.name === item.name;\n this.infiniteScroll.setCustomData = (page = 0) => {\n return {\n data: this.transformedObjects.slice(page * this.size, page * this.size + this.size),\n page: page,\n size: this.size,\n totalPages: Math.round(this.transformedObjects.length / this.size),\n };\n };\n\n return fragment;\n }\n\n /**\n * Called after the component has been drawn.\n */\n afterDraw() {\n this.addEventListener('wje-popup:show', () => {\n this.initial();\n });\n\n // udalost po vymazani inputu\n this.addEventListener('wje-input:clear', () => {\n this.clearIconsContainer(); // clear icons container\n this.infiniteScroll.scrollEvent(); // bind scroll event\n this.infiniteScroll.loadPages(0); // load first page\n });\n\n this.addEventListener('wje-infinite-scroll:click-item', (e) => {\n let icon = e.detail.context.querySelector('wje-icon');\n let name = icon.getAttribute('name');\n let stylesType = icon.hasAttribute('filled') ? 'filled' : 'outline';\n let uniqueObject = this.transformedObjects.find(\n (i) => i.name === name && Object.keys(i.styles)[0] === stylesType\n );\n\n const iconElement = document.createElement('wje-icon');\n iconElement.setAttribute('name', name);\n if (uniqueObject.styles.hasOwnProperty('filled')) iconElement.setAttribute('filled', '');\n\n uniqueObject.icon = iconElement;\n\n this.value = uniqueObject;\n this.icon = uniqueObject.name;\n\n this.anchor.innerHTML = '';\n this.anchor.appendChild(iconElement);\n\n event.dispatchCustomEvent(this, 'wje-icon-picker:select', uniqueObject); // odpalenie custom eventu\n });\n\n this.init = false;\n }\n\n /**\n * Initializes the component.\n */\n initial() {\n this.infiniteScroll.scrollEvent();\n }\n\n /**\n * Converts an object of tags into a transformed array of objects, separating `filled` and `outline` styles.\n * The function processes an input object containing tags, extracts its values,\n * and for each tag that has both `filled` and `outline` styles, splits them into\n * two separate objects. Tags without `filled` styles remain unchanged.\n * @param {object} tags The input object containing tags as properties. Each property is an object with a `styles` key.\n * @param {object} tags[].styles The styles object containing `filled` and/or `outline` styles.\n * @param {object} [tags[].styles.outline] The outline style object, if present.\n * @param {object} [tags[].styles.filled] The filled style object, if present.\n * @returns {Array<object>} An array of transformed objects. Objects with both `filled` and `outline` styles are split into separate objects, each containing only one style.\n * @example\n * const tags = {\n * hourglass: {\n * styles: {\n * outline: { ... },\n * filled: { ... },\n * }\n * },\n * clock: {\n * styles: {\n * outline: { ... },\n * }\n * }\n * };\n * const result = convertObject(tags);\n * console.log(result);\n * // [\n * // { styles: { outline: { ... } } },\n * // { styles: { filled: { ... } } },\n * // { styles: { outline: { ... } } }\n * // ]\n */\n convertObject = (tags = {}) => {\n let originalObjects = Object.values(tags);\n let transformedObjects = [];\n for (let i = 0; i < originalObjects.length; i++) {\n const obj = originalObjects[i];\n if (obj.styles.filled) {\n transformedObjects.push(\n { ...obj, styles: { outline: obj.styles.outline } },\n { ...obj, styles: { filled: obj.styles.filled } }\n );\n } else {\n transformedObjects.push(obj);\n }\n }\n\n return transformedObjects;\n };\n\n /**\n * Converts an icon data object into an HTML element structure.\n * This function creates a styled HTML element that represents an icon with a tooltip.\n * The tooltip displays the name of the icon, and the icon itself is styled based on\n * whether it uses the `filled` style.\n * @param {object} data The icon data object.\n * @returns {HTMLElement} A `div` element containing the icon wrapped in a `wje-tooltip`. The tooltip displays the icon name, and the `wje-icon` element represents the icon with attributes set according to the data.\n * @example\n * const iconData = {\n * name: \"hourglass\",\n * styles: {\n * filled: { ... }\n * }\n * };\n * const htmlElement = dataToHtml(iconData);\n * document.body.appendChild(htmlElement);\n *\n * // The resulting structure:\n * // <div class=\"icon-item\">\n * // <wje-tooltip content=\"hourglass\">\n * // <wje-icon name=\"hourglass\" size=\"large\" filled></wje-icon>\n * // </wje-tooltip>\n * // </div>\n */\n dataToHtml = (data) => {\n let iconItem = document.createElement('div');\n iconItem.classList.add('icon-item');\n\n let tooltip = document.createElement('wje-tooltip');\n tooltip.setAttribute('content', data.name);\n\n let icon = document.createElement('wje-icon');\n icon.setAttribute('name', data.name);\n icon.setAttribute('size', 'large');\n if (data.styles.hasOwnProperty('filled')) icon.setAttribute('filled', '');\n\n tooltip.appendChild(icon);\n iconItem.appendChild(tooltip);\n\n return iconItem;\n };\n\n /**\n * Gets the category of the tags.\n * @param {Array} tags The tags to get the category of.\n * @returns {Array} The category of the tags.\n */\n getCategory(tags) {\n return [...new Set(tags.map((obj) => obj.category))];\n }\n\n /**\n * Gets the tags.\n * @returns {Promise<Array>} The tags of the component.\n */\n async getTags() {\n const response = await fetch(this.getTagsUrl('../../tags.json'));\n return response.json();\n }\n\n /**\n * Called when the component is disconnected.\n */\n beforeDisconnect() {\n this.init = false;\n }\n\n /**\n * Searches icons based on user input.\n * This method handles the input event and filters the available icons based on the provided search string.\n * The filtering is performed on an index that combines icon names and their tags.\n * The results are then adjusted for infinite scrolling.\n * @param {Event} e The input event (e.g., `wje-input:input`) containing the search query details.\n */\n searchIcon = (e) => {\n const query = e.detail.value.toLowerCase();\n\n const results = this.index.filter((item) => item.searchText.includes(query));\n\n this.infiniteScroll.unScrollEvent();\n this.infiniteScroll.setCustomData = (page = 0) => {\n const data = results.slice(page * this.size, page * this.size + this.size);\n return {\n data: data,\n page: page,\n size: this.size,\n totalPages: Math.ceil(results.length / this.size),\n };\n };\n\n this.clearIconsContainer();\n this.infiniteScroll.loadPages(0);\n };\n\n /**\n * Clears the icons container.\n */\n clearIconsContainer() {\n this.context.querySelector('.icon-items').innerHTML = '';\n }\n\n /**\n * Closes the component.\n */\n onClose = () => {\n this.popup.handleHide();\n };\n\n /**\n * Gets the URL of the tags.\n * @param {string} path The path to get the URL of.\n * @returns {string} The URL of the tags path.\n */\n getTagsUrl = (path) => {\n return new URL(process.env.VITE_ICON_ASSETS_URL + path).href;\n };\n}\n","import IconPicker from './icon-picker.element.js';\n\nexport default IconPicker;\n\nIconPicker.define('wje-icon-picker', IconPicker);\n"],"names":[],"mappings":";;;;;;;;;;;AA6BA,MAAqB,mBAAmB,UAAU;AAAA;AAAA;AAAA;AAAA;AAAA,EAK9C,cAAc;AACJ,UAAA;AAOV;AAAA;AAAA;AAAA;AAAA,wCAAe;AAAA,MACX,aAAa;AAAA,MACb,uBAAuB;AAAA,MACvB,eAAe;AAAA,MACf,aAAa;AAAA,IACjB;AAkCA,qCAAY;AAwMZ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,yCAAgB,CAAC,OAAO,OAAO;AACvB,UAAA,kBAAkB,OAAO,OAAO,IAAI;AACxC,UAAI,qBAAqB,CAAC;AAC1B,eAAS,IAAI,GAAG,IAAI,gBAAgB,QAAQ,KAAK;AACvC,cAAA,MAAM,gBAAgB,CAAC;AACzB,YAAA,IAAI,OAAO,QAAQ;AACA,6BAAA;AAAA,YACf,EAAE,GAAG,KAAK,QAAQ,EAAE,SAAS,IAAI,OAAO,UAAU;AAAA,YAClD,EAAE,GAAG,KAAK,QAAQ,EAAE,QAAQ,IAAI,OAAO,OAAS,EAAA;AAAA,UACpD;AAAA,QAAA,OACG;AACH,6BAAmB,KAAK,GAAG;AAAA,QAAA;AAAA,MAC/B;AAGG,aAAA;AAAA,IACX;AA0BA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,sCAAa,CAAC,SAAS;AACf,UAAA,WAAW,SAAS,cAAc,KAAK;AAClC,eAAA,UAAU,IAAI,WAAW;AAE9B,UAAA,UAAU,SAAS,cAAc,aAAa;AAC1C,cAAA,aAAa,WAAW,KAAK,IAAI;AAErC,UAAA,OAAO,SAAS,cAAc,UAAU;AACvC,WAAA,aAAa,QAAQ,KAAK,IAAI;AAC9B,WAAA,aAAa,QAAQ,OAAO;AAC7B,UAAA,KAAK,OAAO,eAAe,QAAQ,EAAQ,MAAA,aAAa,UAAU,EAAE;AAExE,cAAQ,YAAY,IAAI;AACxB,eAAS,YAAY,OAAO;AAErB,aAAA;AAAA,IACX;AAkCA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,sCAAa,CAAC,MAAM;AAChB,YAAM,QAAQ,EAAE,OAAO,MAAM,YAAY;AAEnC,YAAA,UAAU,KAAK,MAAM,OAAO,CAAC,SAAS,KAAK,WAAW,SAAS,KAAK,CAAC;AAE3E,WAAK,eAAe,cAAc;AAClC,WAAK,eAAe,gBAAgB,CAAC,OAAO,MAAM;AACxC,cAAA,OAAO,QAAQ,MAAM,OAAO,KAAK,MAAM,OAAO,KAAK,OAAO,KAAK,IAAI;AAClE,eAAA;AAAA,UACH;AAAA,UACA;AAAA,UACA,MAAM,KAAK;AAAA,UACX,YAAY,KAAK,KAAK,QAAQ,SAAS,KAAK,IAAI;AAAA,QACpD;AAAA,MACJ;AAEA,WAAK,oBAAoB;AACpB,WAAA,eAAe,UAAU,CAAC;AAAA,IACnC;AAYA;AAAA;AAAA;AAAA,mCAAU,MAAM;AACZ,WAAK,MAAM,WAAW;AAAA,IAC1B;AAOA;AAAA;AAAA;AAAA;AAAA;AAAA,sCAAa,CAAC,SAAS;AACnB,aAAO,IAAI,IAAI,iDAAmC,IAAI,EAAE;AAAA,IAC5D;AAAA,EA3XU;AAAA;AAAA;AAAA;AAAA;AAAA,EAkBV,IAAI,KAAK,OAAO;AACP,SAAA,aAAa,QAAQ,KAAK;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOnC,IAAI,OAAO;AACA,WAAA,KAAK,aAAa,MAAM,KAAK;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOxC,IAAI,KAAK,OAAO;AACP,SAAA,aAAa,QAAQ,KAAK;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOnC,IAAI,OAAO;AACA,WAAA,KAAK,aAAa,MAAM;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUnC,WAAW,gBAAgB;AAChB,WAAA;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQX,WAAW,qBAAqB;AAC5B,WAAO,CAAC;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA,EAMZ,kBAAkB;AACd,SAAK,eAAe;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA,EAMxB,MAAM,aAAa;AACf,SAAK,OAAO,OAAO,OAAO,MAAM,KAAK,SAAS;AAE9C,SAAK,qBAAqB,KAAK,cAAc,KAAK,IAAI;AAEtD,SAAK,QAAQ,KAAK,mBAAmB,IAAI,CAAC,UAAU;AAAA,MAChD,GAAG;AAAA,MACH,YAAY,GAAG,KAAK,KAAK,YAAY,CAAC,IAAI,KAAK,KAAK,KAAK,GAAG,EAAE,aAAa;AAAA,IAAA,EAC7E;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAON,OAAO;AACC,QAAA,WAAW,SAAS,uBAAuB;AAE3C,QAAA,SAAS,SAAS,cAAc,KAAK;AAClC,WAAA,UAAU,IAAI,qBAAqB;AAGtC,QAAA,SAAS,SAAS,cAAc,KAAK;AAClC,WAAA,aAAa,QAAQ,QAAQ;AAC7B,WAAA,UAAU,IAAI,QAAQ;AAE7B,QAAI,KAAK,aAAa,MAAM,KAAK,KAAK,MAAM;AACpC,UAAA,OAAO,SAAS,cAAc,UAAU;AACvC,WAAA,aAAa,QAAQ,KAAK,IAAI;AAEnC,aAAO,YAAY,IAAI;AAAA,IAAA;AAIvB,QAAA,SAAS,SAAS,cAAc,KAAK;AAClC,WAAA,UAAU,IAAI,QAAQ;AAEzB,QAAA,QAAQ,SAAS,cAAc,WAAW;AACxC,UAAA,UAAU,IAAI,OAAO;AACrB,UAAA,aAAa,WAAW,UAAU;AAClC,UAAA,aAAa,eAAe,mBAAmB;AAC/C,UAAA,aAAa,aAAa,EAAE;AAC5B,UAAA,iBAAiB,mBAAmB,KAAK,UAAU;AAErD,QAAA,iBAAiB,IAAI,eAAe;AAExC,mBAAe,aAAa,OAAO,KAAK,WAAW,iBAAiB,CAAC;AACtD,mBAAA,aAAa,aAAa,aAAa;AACvC,mBAAA,aAAa,QAAQ,KAAK,IAAI;AAC9B,mBAAA,aAAa,UAAU,OAAO;AAC7C,mBAAe,YAAY;AAG3B,WAAO,YAAY,KAAK;AAExB,WAAO,YAAY,cAAc;AAG7B,QAAA,QAAQ,SAAS,cAAc,WAAW;AAC9C,UAAM,aAAa,aAAa,KAAK,aAAa,cAAc;AAC1D,UAAA,aAAa,UAAU,KAAK,MAAM;AAClC,UAAA,aAAa,UAAU,EAAE;AAE/B,UAAM,YAAY,MAAM;AACxB,UAAM,YAAY,MAAM;AAExB,WAAO,YAAY,KAAK;AAExB,aAAS,YAAY,MAAM;AAE3B,SAAK,QAAQ;AACb,SAAK,QAAQ;AACb,SAAK,SAAS;AACd,SAAK,SAAS;AACd,SAAK,iBAAiB;AAEjB,SAAA,eAAe,aAAa,KAAK;AACtC,SAAK,eAAe,kBAAkB,CAAC,GAAG,SAAS,EAAE,SAAS,KAAK;AACnE,SAAK,eAAe,gBAAgB,CAAC,OAAO,MAAM;AACvC,aAAA;AAAA,QACH,MAAM,KAAK,mBAAmB,MAAM,OAAO,KAAK,MAAM,OAAO,KAAK,OAAO,KAAK,IAAI;AAAA,QAClF;AAAA,QACA,MAAM,KAAK;AAAA,QACX,YAAY,KAAK,MAAM,KAAK,mBAAmB,SAAS,KAAK,IAAI;AAAA,MACrE;AAAA,IACJ;AAEO,WAAA;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA,EAMX,YAAY;AACH,SAAA,iBAAiB,kBAAkB,MAAM;AAC1C,WAAK,QAAQ;AAAA,IAAA,CAChB;AAGI,SAAA,iBAAiB,mBAAmB,MAAM;AAC3C,WAAK,oBAAoB;AACzB,WAAK,eAAe,YAAY;AAC3B,WAAA,eAAe,UAAU,CAAC;AAAA,IAAA,CAClC;AAEI,SAAA,iBAAiB,kCAAkC,CAAC,MAAM;AAC3D,UAAI,OAAO,EAAE,OAAO,QAAQ,cAAc,UAAU;AAChD,UAAA,OAAO,KAAK,aAAa,MAAM;AACnC,UAAI,aAAa,KAAK,aAAa,QAAQ,IAAI,WAAW;AACtD,UAAA,eAAe,KAAK,mBAAmB;AAAA,QACvC,CAAC,MAAM,EAAE,SAAS,QAAQ,OAAO,KAAK,EAAE,MAAM,EAAE,CAAC,MAAM;AAAA,MAC3D;AAEM,YAAA,cAAc,SAAS,cAAc,UAAU;AACzC,kBAAA,aAAa,QAAQ,IAAI;AACjC,UAAA,aAAa,OAAO,eAAe,QAAQ,EAAe,aAAA,aAAa,UAAU,EAAE;AAEvF,mBAAa,OAAO;AAEpB,WAAK,QAAQ;AACb,WAAK,OAAO,aAAa;AAEzB,WAAK,OAAO,YAAY;AACnB,WAAA,OAAO,YAAY,WAAW;AAE7B,YAAA,oBAAoB,MAAM,0BAA0B,YAAY;AAAA,IAAA,CACzE;AAED,SAAK,OAAO;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA,EAMhB,UAAU;AACN,SAAK,eAAe,YAAY;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAoGpC,YAAY,MAAM;AACP,WAAA,CAAC,GAAG,IAAI,IAAI,KAAK,IAAI,CAAC,QAAQ,IAAI,QAAQ,CAAC,CAAC;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOvD,MAAM,UAAU;AACZ,UAAM,WAAW,MAAM,MAAM,KAAK,WAAW,iBAAiB,CAAC;AAC/D,WAAO,SAAS,KAAK;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA,EAMzB,mBAAmB;AACf,SAAK,OAAO;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA,EAiChB,sBAAsB;AAClB,SAAK,QAAQ,cAAc,aAAa,EAAE,YAAY;AAAA,EAAA;AAkB9D;AC3ZA,WAAW,OAAO,mBAAmB,UAAU;"}
|
|
1
|
+
{"version":3,"file":"wje-icon-picker.js","sources":["../packages/wje-icon-picker/icon-picker.element.js","../packages/wje-icon-picker/icon-picker.js"],"sourcesContent":["import { default as WJElement, event } from '../wje-element/element.js';\nimport InfiniteScroll from '../wje-infinite-scroll/infinite-scroll.js';\nimport Input from '../wje-input/input.js';\nimport Popup from '../wje-popup/popup.js';\nimport Tooltip from '../wje-tooltip/tooltip.js';\nimport styles from './styles/styles.css?inline';\n\n/**\n * @summary This element allows users to pick an icon from a set of available options.\n * `IconPicker` is a custom web component that represents an interactive icon picker. It features\n * search functionality, infinite scrolling, and popup-based selection. The component is highly customizable\n * and integrates seamlessly with other `WJElement` components.\n * @documentation https://elements.webjet.sk/components/icon-picker\n * @status stable\n * @augments {WJElement}\n * @attribute {string} icon - The selected icon's name.\n * @attribute {number} size - The number of icons displayed per page in infinite scroll. Default is 60.\n * @csspart native - The native part of the component.\n * @csspart anchor - The part representing the anchor button displaying the selected icon.\n * @csspart picker - The picker part containing the search and icon selection interface.\n * @csspart input - The input part for searching icons.\n * @cssproperty [--wje-color-picker-value=#ff0000] - The default color value.\n * @cssproperty [--wje-color-picker-area=transparent] - The background color of the color picker area.\n * @cssproperty [--wje-color-picker-swatch=transparent] - The background color of the swatch picker.\n * @cssproperty [--wje-color-picker-size=1rem] - The size of the icons in the picker.\n * @cssproperty [--wje-color-picker-radius=4px] - The border radius of the picker.\n * @tag wje-icon-picker\n */\n\nexport default class IconPicker extends WJElement {\n /**\n * Creates an instance of IconPicker.\n * @class\n */\n constructor() {\n super();\n }\n\n /**\n * Dependencies of the IconPicker component.\n * @property {object} dependencies\n */\n dependencies = {\n 'wje-input': Input,\n 'wje-infinite-scroll': InfiniteScroll,\n 'wje-tooltip': Tooltip,\n 'wje-popup': Popup,\n };\n\n /**\n * Setter for the markerPosition property.\n * @param {any} value The value to set.\n */\n set size(value) {\n this.setAttribute('size', value);\n }\n\n /**\n * Getter for the markerPosition property.\n * @returns {any} size The value of the markerPosition property.\n */\n get size() {\n return this.getAttribute('size') || 60;\n }\n\n /**\n * Setter for the value property.\n * @param value\n */\n set icon(value) {\n this.setAttribute('icon', value);\n }\n\n /**\n * Getter for the value property.\n * @returns {string}\n */\n get icon() {\n return this.getAttribute('icon');\n }\n\n className = 'IconPicker';\n\n /**\n * Returns the CSS styles for the component.\n * @static\n * @returns {CSSStyleSheet}\n */\n static get cssStyleSheet() {\n return styles;\n }\n\n /**\n * Returns the list of attributes to observe for changes.\n * @static\n * @returns {Array<string>}\n */\n static get observedAttributes() {\n return [];\n }\n\n /**\n * Sets up the attributes for the component.\n */\n setupAttributes() {\n this.isShadowRoot = 'open';\n }\n\n /**\n * Prepares the component before drawing.\n */\n async beforeDraw() {\n this.tags = Object.values(await this.getTags());\n\n this.transformedObjects = this.convertObject(this.tags);\n\n this.index = this.transformedObjects.map((item) => ({\n ...item,\n searchText: `${item.name.toLowerCase()} ${item.tags.join(' ').toLowerCase()}`,\n }));\n }\n\n /**\n * Draws the component.\n * @returns {DocumentFragment}\n */\n draw() {\n let fragment = document.createDocumentFragment();\n\n let native = document.createElement('div');\n native.classList.add('native-color-picker');\n\n // ANCHOR\n let anchor = document.createElement('div');\n anchor.setAttribute('slot', 'anchor');\n anchor.classList.add('anchor');\n\n if (this.hasAttribute('icon') && this.icon) {\n let icon = document.createElement('wje-icon');\n icon.setAttribute('name', this.icon);\n\n anchor.appendChild(icon);\n }\n\n // PICKER\n let picker = document.createElement('div');\n picker.classList.add('picker');\n\n let input = document.createElement('wje-input');\n input.classList.add('input');\n input.setAttribute('variant', 'standard');\n input.setAttribute('placeholder', 'type to filter...');\n input.setAttribute('clearable', '');\n input.addEventListener('wje-input:input', this.searchIcon);\n\n let infiniteScroll = new InfiniteScroll();\n\n infiniteScroll.setAttribute('url', this.getTagsUrl('../../tags.json'));\n infiniteScroll.setAttribute('placement', '.icon-items');\n infiniteScroll.setAttribute('size', this.size);\n infiniteScroll.setAttribute('height', '223px');\n infiniteScroll.innerHTML = '<div class=\"icon-items\"></div>';\n\n // APPEND\n picker.appendChild(input);\n\n picker.appendChild(infiniteScroll);\n\n // POPUP\n let popup = document.createElement('wje-popup');\n popup.setAttribute('placement', this.placement || 'bottom-start');\n popup.setAttribute('offset', this.offset);\n popup.setAttribute('manual', '');\n\n popup.appendChild(anchor);\n popup.appendChild(picker);\n\n native.appendChild(popup);\n\n fragment.appendChild(native);\n\n this.popup = popup;\n this.input = input;\n this.anchor = anchor;\n this.picker = picker;\n this.infiniteScroll = infiniteScroll;\n\n this.infiniteScroll.dataToHtml = this.dataToHtml;\n this.infiniteScroll.compareFunction = (i, item) => i.name === item.name;\n this.infiniteScroll.setCustomData = (page = 0) => {\n return {\n data: this.transformedObjects.slice(page * this.size, page * this.size + this.size),\n page: page,\n size: this.size,\n totalPages: Math.round(this.transformedObjects.length / this.size),\n };\n };\n\n return fragment;\n }\n\n /**\n * Called after the component has been drawn.\n */\n afterDraw() {\n this.addEventListener('wje-popup:show', () => {\n this.initial();\n });\n\n // udalost po vymazani inputu\n this.addEventListener('wje-input:clear', () => {\n this.clearIconsContainer(); // clear icons container\n this.infiniteScroll.scrollEvent(); // bind scroll event\n this.infiniteScroll.loadPages(0); // load first page\n });\n\n this.addEventListener('wje-infinite-scroll:click-item', (e) => {\n let icon = e.detail.context.querySelector('wje-icon');\n let name = icon.getAttribute('name');\n let stylesType = icon.hasAttribute('filled') ? 'filled' : 'outline';\n let uniqueObject = this.transformedObjects.find(\n (i) => i.name === name && Object.keys(i.styles)[0] === stylesType\n );\n\n const iconElement = document.createElement('wje-icon');\n iconElement.setAttribute('name', name);\n if (uniqueObject.styles.hasOwnProperty('filled')) iconElement.setAttribute('filled', '');\n\n uniqueObject.icon = iconElement;\n\n this.value = uniqueObject;\n this.icon = uniqueObject.name;\n\n this.anchor.innerHTML = '';\n this.anchor.appendChild(iconElement);\n\n event.dispatchCustomEvent(this, 'wje-icon-picker:select', uniqueObject); // odpalenie custom eventu\n });\n\n this.init = false;\n }\n\n /**\n * Initializes the component.\n */\n initial() {\n this.infiniteScroll.scrollEvent();\n }\n\n /**\n * Converts an object of tags into a transformed array of objects, separating `filled` and `outline` styles.\n * The function processes an input object containing tags, extracts its values,\n * and for each tag that has both `filled` and `outline` styles, splits them into\n * two separate objects. Tags without `filled` styles remain unchanged.\n * @param {object} tags The input object containing tags as properties. Each property is an object with a `styles` key.\n * @param {object} tags[].styles The styles object containing `filled` and/or `outline` styles.\n * @param {object} [tags[].styles.outline] The outline style object, if present.\n * @param {object} [tags[].styles.filled] The filled style object, if present.\n * @returns {Array<object>} An array of transformed objects. Objects with both `filled` and `outline` styles are split into separate objects, each containing only one style.\n * @example\n * const tags = {\n * hourglass: {\n * styles: {\n * outline: { ... },\n * filled: { ... },\n * }\n * },\n * clock: {\n * styles: {\n * outline: { ... },\n * }\n * }\n * };\n * const result = convertObject(tags);\n * console.log(result);\n * // [\n * // { styles: { outline: { ... } } },\n * // { styles: { filled: { ... } } },\n * // { styles: { outline: { ... } } }\n * // ]\n */\n convertObject = (tags = {}) => {\n let originalObjects = Object.values(tags);\n let transformedObjects = [];\n for (let i = 0; i < originalObjects.length; i++) {\n const obj = originalObjects[i];\n if (obj.styles.filled) {\n transformedObjects.push(\n { ...obj, styles: { outline: obj.styles.outline } },\n { ...obj, styles: { filled: obj.styles.filled } }\n );\n } else {\n transformedObjects.push(obj);\n }\n }\n\n return transformedObjects;\n };\n\n /**\n * Converts an icon data object into an HTML element structure.\n * This function creates a styled HTML element that represents an icon with a tooltip.\n * The tooltip displays the name of the icon, and the icon itself is styled based on\n * whether it uses the `filled` style.\n * @param {object} data The icon data object.\n * @returns {HTMLElement} A `div` element containing the icon wrapped in a `wje-tooltip`. The tooltip displays the icon name, and the `wje-icon` element represents the icon with attributes set according to the data.\n * @example\n * const iconData = {\n * name: \"hourglass\",\n * styles: {\n * filled: { ... }\n * }\n * };\n * const htmlElement = dataToHtml(iconData);\n * document.body.appendChild(htmlElement);\n *\n * // The resulting structure:\n * // <div class=\"icon-item\">\n * // <wje-tooltip content=\"hourglass\">\n * // <wje-icon name=\"hourglass\" size=\"large\" filled></wje-icon>\n * // </wje-tooltip>\n * // </div>\n */\n dataToHtml = (data) => {\n let iconItem = document.createElement('div');\n iconItem.classList.add('icon-item');\n\n let tooltip = document.createElement('wje-tooltip');\n tooltip.setAttribute('content', data.name);\n\n let icon = document.createElement('wje-icon');\n icon.setAttribute('name', data.name);\n icon.setAttribute('size', 'large');\n if (data.styles.hasOwnProperty('filled')) icon.setAttribute('filled', '');\n\n tooltip.appendChild(icon);\n iconItem.appendChild(tooltip);\n\n return iconItem;\n };\n\n /**\n * Gets the category of the tags.\n * @param {Array} tags The tags to get the category of.\n * @returns {Array} The category of the tags.\n */\n getCategory(tags) {\n return [...new Set(tags.map((obj) => obj.category))];\n }\n\n /**\n * Gets the tags.\n * @returns {Promise<Array>} The tags of the component.\n */\n async getTags() {\n const response = await fetch(this.getTagsUrl('../../tags.json'));\n return response.json();\n }\n\n /**\n * Called when the component is disconnected.\n */\n beforeDisconnect() {\n this.init = false;\n }\n\n /**\n * Searches icons based on user input.\n * This method handles the input event and filters the available icons based on the provided search string.\n * The filtering is performed on an index that combines icon names and their tags.\n * The results are then adjusted for infinite scrolling.\n * @param {Event} e The input event (e.g., `wje-input:input`) containing the search query details.\n */\n searchIcon = (e) => {\n const query = e.detail.value.toLowerCase();\n\n const results = this.index.filter((item) => item.searchText.includes(query));\n\n this.infiniteScroll.unScrollEvent();\n this.infiniteScroll.setCustomData = (page = 0) => {\n const data = results.slice(page * this.size, page * this.size + this.size);\n return {\n data: data,\n page: page,\n size: this.size,\n totalPages: Math.ceil(results.length / this.size),\n };\n };\n\n this.clearIconsContainer();\n this.infiniteScroll.loadPages(0);\n };\n\n /**\n * Clears the icons container.\n */\n clearIconsContainer() {\n this.context.querySelector('.icon-items').innerHTML = '';\n }\n\n /**\n * Closes the component.\n */\n onClose = () => {\n this.popup.handleHide();\n };\n\n /**\n * Gets the URL of the tags.\n * @param {string} path The path to get the URL of.\n * @returns {string} The URL of the tags path.\n */\n getTagsUrl = (path) => {\n return new URL(process.env.VITE_ICON_ASSETS_URL + path).href;\n };\n}\n","import IconPicker from './icon-picker.element.js';\n\nexport default IconPicker;\n\nIconPicker.define('wje-icon-picker', IconPicker);\n"],"names":[],"mappings":";;;;;;;;;;;AA6Be,MAAM,mBAAmB,UAAU;AAAA;AAAA;AAAA;AAAA;AAAA,EAK9C,cAAc;AACV,UAAO;AAOX;AAAA;AAAA;AAAA;AAAA,wCAAe;AAAA,MACX,aAAa;AAAA,MACb,uBAAuB;AAAA,MACvB,eAAe;AAAA,MACf,aAAa;AAAA,IAChB;AAkCD,qCAAY;AAwMZ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,yCAAgB,CAAC,OAAO,OAAO;AAC3B,UAAI,kBAAkB,OAAO,OAAO,IAAI;AACxC,UAAI,qBAAqB,CAAE;AAC3B,eAAS,IAAI,GAAG,IAAI,gBAAgB,QAAQ,KAAK;AAC7C,cAAM,MAAM,gBAAgB,CAAC;AAC7B,YAAI,IAAI,OAAO,QAAQ;AACnB,6BAAmB;AAAA,YACf,EAAE,GAAG,KAAK,QAAQ,EAAE,SAAS,IAAI,OAAO,UAAW;AAAA,YACnD,EAAE,GAAG,KAAK,QAAQ,EAAE,QAAQ,IAAI,OAAO,OAAQ,EAAA;AAAA,UAClD;AAAA,QACjB,OAAmB;AACH,6BAAmB,KAAK,GAAG;AAAA,QAC3C;AAAA,MACA;AAEQ,aAAO;AAAA,IACV;AA0BD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,sCAAa,CAAC,SAAS;AACnB,UAAI,WAAW,SAAS,cAAc,KAAK;AAC3C,eAAS,UAAU,IAAI,WAAW;AAElC,UAAI,UAAU,SAAS,cAAc,aAAa;AAClD,cAAQ,aAAa,WAAW,KAAK,IAAI;AAEzC,UAAI,OAAO,SAAS,cAAc,UAAU;AAC5C,WAAK,aAAa,QAAQ,KAAK,IAAI;AACnC,WAAK,aAAa,QAAQ,OAAO;AACjC,UAAI,KAAK,OAAO,eAAe,QAAQ,EAAG,MAAK,aAAa,UAAU,EAAE;AAExE,cAAQ,YAAY,IAAI;AACxB,eAAS,YAAY,OAAO;AAE5B,aAAO;AAAA,IACV;AAkCD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,sCAAa,CAAC,MAAM;AAChB,YAAM,QAAQ,EAAE,OAAO,MAAM,YAAa;AAE1C,YAAM,UAAU,KAAK,MAAM,OAAO,CAAC,SAAS,KAAK,WAAW,SAAS,KAAK,CAAC;AAE3E,WAAK,eAAe,cAAe;AACnC,WAAK,eAAe,gBAAgB,CAAC,OAAO,MAAM;AAC9C,cAAM,OAAO,QAAQ,MAAM,OAAO,KAAK,MAAM,OAAO,KAAK,OAAO,KAAK,IAAI;AACzE,eAAO;AAAA,UACH;AAAA,UACA;AAAA,UACA,MAAM,KAAK;AAAA,UACX,YAAY,KAAK,KAAK,QAAQ,SAAS,KAAK,IAAI;AAAA,QACnD;AAAA,MACJ;AAED,WAAK,oBAAqB;AAC1B,WAAK,eAAe,UAAU,CAAC;AAAA,IAClC;AAYD;AAAA;AAAA;AAAA,mCAAU,MAAM;AACZ,WAAK,MAAM,WAAY;AAAA,IAC1B;AAOD;AAAA;AAAA;AAAA;AAAA;AAAA,sCAAa,CAAC,SAAS;AACnB,aAAO,IAAI,IAAI,QAAQ,IAAI,uBAAuB,IAAI,EAAE;AAAA,IAC3D;AAAA,EA1XL;AAAA;AAAA;AAAA;AAAA;AAAA,EAiBI,IAAI,KAAK,OAAO;AACZ,SAAK,aAAa,QAAQ,KAAK;AAAA,EACvC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMI,IAAI,OAAO;AACP,WAAO,KAAK,aAAa,MAAM,KAAK;AAAA,EAC5C;AAAA;AAAA;AAAA;AAAA;AAAA,EAMI,IAAI,KAAK,OAAO;AACZ,SAAK,aAAa,QAAQ,KAAK;AAAA,EACvC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMI,IAAI,OAAO;AACP,WAAO,KAAK,aAAa,MAAM;AAAA,EACvC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASI,WAAW,gBAAgB;AACvB,WAAO;AAAA,EACf;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOI,WAAW,qBAAqB;AAC5B,WAAO,CAAE;AAAA,EACjB;AAAA;AAAA;AAAA;AAAA,EAKI,kBAAkB;AACd,SAAK,eAAe;AAAA,EAC5B;AAAA;AAAA;AAAA;AAAA,EAKI,MAAM,aAAa;AACf,SAAK,OAAO,OAAO,OAAO,MAAM,KAAK,SAAS;AAE9C,SAAK,qBAAqB,KAAK,cAAc,KAAK,IAAI;AAEtD,SAAK,QAAQ,KAAK,mBAAmB,IAAI,CAAC,UAAU;AAAA,MAChD,GAAG;AAAA,MACH,YAAY,GAAG,KAAK,KAAK,YAAW,CAAE,IAAI,KAAK,KAAK,KAAK,GAAG,EAAE,YAAa,CAAA;AAAA,IACvF,EAAU;AAAA,EACV;AAAA;AAAA;AAAA;AAAA;AAAA,EAMI,OAAO;AACH,QAAI,WAAW,SAAS,uBAAwB;AAEhD,QAAI,SAAS,SAAS,cAAc,KAAK;AACzC,WAAO,UAAU,IAAI,qBAAqB;AAG1C,QAAI,SAAS,SAAS,cAAc,KAAK;AACzC,WAAO,aAAa,QAAQ,QAAQ;AACpC,WAAO,UAAU,IAAI,QAAQ;AAE7B,QAAI,KAAK,aAAa,MAAM,KAAK,KAAK,MAAM;AACxC,UAAI,OAAO,SAAS,cAAc,UAAU;AAC5C,WAAK,aAAa,QAAQ,KAAK,IAAI;AAEnC,aAAO,YAAY,IAAI;AAAA,IACnC;AAGQ,QAAI,SAAS,SAAS,cAAc,KAAK;AACzC,WAAO,UAAU,IAAI,QAAQ;AAE7B,QAAI,QAAQ,SAAS,cAAc,WAAW;AAC9C,UAAM,UAAU,IAAI,OAAO;AAC3B,UAAM,aAAa,WAAW,UAAU;AACxC,UAAM,aAAa,eAAe,mBAAmB;AACrD,UAAM,aAAa,aAAa,EAAE;AAClC,UAAM,iBAAiB,mBAAmB,KAAK,UAAU;AAEzD,QAAI,iBAAiB,IAAI,eAAgB;AAEzC,mBAAe,aAAa,OAAO,KAAK,WAAW,iBAAiB,CAAC;AACrE,mBAAe,aAAa,aAAa,aAAa;AACtD,mBAAe,aAAa,QAAQ,KAAK,IAAI;AAC7C,mBAAe,aAAa,UAAU,OAAO;AAC7C,mBAAe,YAAY;AAG3B,WAAO,YAAY,KAAK;AAExB,WAAO,YAAY,cAAc;AAGjC,QAAI,QAAQ,SAAS,cAAc,WAAW;AAC9C,UAAM,aAAa,aAAa,KAAK,aAAa,cAAc;AAChE,UAAM,aAAa,UAAU,KAAK,MAAM;AACxC,UAAM,aAAa,UAAU,EAAE;AAE/B,UAAM,YAAY,MAAM;AACxB,UAAM,YAAY,MAAM;AAExB,WAAO,YAAY,KAAK;AAExB,aAAS,YAAY,MAAM;AAE3B,SAAK,QAAQ;AACb,SAAK,QAAQ;AACb,SAAK,SAAS;AACd,SAAK,SAAS;AACd,SAAK,iBAAiB;AAEtB,SAAK,eAAe,aAAa,KAAK;AACtC,SAAK,eAAe,kBAAkB,CAAC,GAAG,SAAS,EAAE,SAAS,KAAK;AACnE,SAAK,eAAe,gBAAgB,CAAC,OAAO,MAAM;AAC9C,aAAO;AAAA,QACH,MAAM,KAAK,mBAAmB,MAAM,OAAO,KAAK,MAAM,OAAO,KAAK,OAAO,KAAK,IAAI;AAAA,QAClF;AAAA,QACA,MAAM,KAAK;AAAA,QACX,YAAY,KAAK,MAAM,KAAK,mBAAmB,SAAS,KAAK,IAAI;AAAA,MACpE;AAAA,IACJ;AAED,WAAO;AAAA,EACf;AAAA;AAAA;AAAA;AAAA,EAKI,YAAY;AACR,SAAK,iBAAiB,kBAAkB,MAAM;AAC1C,WAAK,QAAS;AAAA,IAC1B,CAAS;AAGD,SAAK,iBAAiB,mBAAmB,MAAM;AAC3C,WAAK,oBAAmB;AACxB,WAAK,eAAe;AACpB,WAAK,eAAe,UAAU,CAAC;AAAA,IAC3C,CAAS;AAED,SAAK,iBAAiB,kCAAkC,CAAC,MAAM;AAC3D,UAAI,OAAO,EAAE,OAAO,QAAQ,cAAc,UAAU;AACpD,UAAI,OAAO,KAAK,aAAa,MAAM;AACnC,UAAI,aAAa,KAAK,aAAa,QAAQ,IAAI,WAAW;AAC1D,UAAI,eAAe,KAAK,mBAAmB;AAAA,QACvC,CAAC,MAAM,EAAE,SAAS,QAAQ,OAAO,KAAK,EAAE,MAAM,EAAE,CAAC,MAAM;AAAA,MAC1D;AAED,YAAM,cAAc,SAAS,cAAc,UAAU;AACrD,kBAAY,aAAa,QAAQ,IAAI;AACrC,UAAI,aAAa,OAAO,eAAe,QAAQ,EAAG,aAAY,aAAa,UAAU,EAAE;AAEvF,mBAAa,OAAO;AAEpB,WAAK,QAAQ;AACb,WAAK,OAAO,aAAa;AAEzB,WAAK,OAAO,YAAY;AACxB,WAAK,OAAO,YAAY,WAAW;AAEnC,YAAM,oBAAoB,MAAM,0BAA0B,YAAY;AAAA,IAClF,CAAS;AAED,SAAK,OAAO;AAAA,EACpB;AAAA;AAAA;AAAA;AAAA,EAKI,UAAU;AACN,SAAK,eAAe,YAAa;AAAA,EACzC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAmGI,YAAY,MAAM;AACd,WAAO,CAAC,GAAG,IAAI,IAAI,KAAK,IAAI,CAAC,QAAQ,IAAI,QAAQ,CAAC,CAAC;AAAA,EAC3D;AAAA;AAAA;AAAA;AAAA;AAAA,EAMI,MAAM,UAAU;AACZ,UAAM,WAAW,MAAM,MAAM,KAAK,WAAW,iBAAiB,CAAC;AAC/D,WAAO,SAAS,KAAM;AAAA,EAC9B;AAAA;AAAA;AAAA;AAAA,EAKI,mBAAmB;AACf,SAAK,OAAO;AAAA,EACpB;AAAA;AAAA;AAAA;AAAA,EAgCI,sBAAsB;AAClB,SAAK,QAAQ,cAAc,aAAa,EAAE,YAAY;AAAA,EAC9D;AAiBA;AC3ZA,WAAW,OAAO,mBAAmB,UAAU;"}
|
package/dist/wje-icon.js
CHANGED
|
@@ -107,7 +107,7 @@ const getName = (iconName) => {
|
|
|
107
107
|
};
|
|
108
108
|
const getNamedUrl = (iconName, filled = false) => {
|
|
109
109
|
const path = `${filled ? "filled" : "outline"}/${iconName}.svg`;
|
|
110
|
-
let url = new URL(
|
|
110
|
+
let url = new URL(process.env.VITE_ICON_ASSETS_URL + path);
|
|
111
111
|
return url.href;
|
|
112
112
|
};
|
|
113
113
|
const styles = "/*\n[ WJ Icon ]\n*/\n\n:host {\n width: var(--wje-icon-size);\n height: var(--wje-icon-size);\n display: block;\n}\n\n.native-icon {\n display: flex;\n align-items: center;\n}\n\nsvg {\n width: 100%;\n height: 100%;\n stroke-width: var(--wje-icon-stroke);\n color: var(--wje-icon-color);\n}\n\n/*STROKE*/\n:host([stroke='1']) {\n --wje-icon-stroke: 1;\n}\n\n:host([stroke='1.25']) {\n --wje-icon-stroke: 1.25;\n}\n\n:host([stroke='1.5']) {\n --wje-icon-stroke: 1.5;\n}\n\n:host([stroke='1.75']) {\n --wje-icon-stroke: 1.75;\n}\n\n:host([stroke='2']) {\n --wje-icon-stroke: 2;\n}\n\n/*SIZE*/\n:host([size='2x-small']) {\n --wje-icon-size: var(--wje-size-2x-small);\n}\n\n:host([size='x-small']) {\n --wje-icon-size: var(--wje-size-x-small);\n}\n\n:host([size='small']) {\n --wje-icon-size: var(--wje-size-small);\n}\n\n:host([size='medium']) {\n --wje-icon-size: var(--wje-size-medium);\n}\n\n:host([size='large']) {\n --wje-icon-size: var(--wje-size-large);\n}\n\n:host([size='x-large']) {\n --wje-icon-size: var(--wje-size-x-large);\n}\n\n:host([size='2x-large']) {\n --wje-icon-size: var(--wje-size-2x-large);\n}\n\n:host([size='3x-large']) {\n --wje-icon-size: var(--wje-size-3x-large);\n}\n\n:host([size='4x-large']) {\n --wje-icon-size: var(--wje-size-4x-large);\n}\n\n/*COLOR*/\n:host([color='primary']) .native-icon {\n color: var(--wje-color-primary-9);\n}\n\n:host([color='complete']) .native-icon {\n color: var(--wje-color-complete-9);\n}\n\n:host([color='success']) .native-icon {\n color: var(--wje-color-success-9);\n}\n\n:host([color='warning']) .native-icon {\n color: var(--wje-color-warning-9);\n}\n\n:host([color='danger']) .native-icon {\n color: var(--wje-color-danger-9);\n}\n\n:host([color='info']) .native-icon {\n color: var(--wje-color-info-9);\n}\n\n:host([color='menu']) .native-icon {\n color: var(--wje-color-contrast-9);\n}\n";
|
package/dist/wje-icon.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wje-icon.js","sources":["../packages/wje-icon/service/service.js","../packages/wje-icon/icon.element.js","../packages/wje-icon/icon.js"],"sourcesContent":["export const iconContent = new Map();\nconst requests = new Map();\n\nlet parser;\n\n/**\n * Validates and returns a trimmed source string if it meets the required criteria.\n * @param {string} src The source string to validate and trim.\n * @returns {string|null} The validated and trimmed source string, or `null` if invalid.\n * @example\n * getSrc(' https://example.com/image.jpg '); // Returns 'https://example.com/image.jpg'\n * getSrc('invalid-src'); // Returns null\n */\nexport const getSrc = (src) => {\n if (isStr(src)) {\n src = src.trim();\n if (isSrc(src)) {\n return src;\n }\n }\n return null;\n};\n\n/**\n * Checks if a given string is a valid source based on specific criteria.\n * @param {string} str The string to validate as a source.\n * @returns {boolean} `true` if the string is considered a valid source, `false` otherwise.\n * @example\n * isSrc('https://example.com/image.jpg'); // Returns true\n * isSrc('image.jpg'); // Returns true\n * isSrc('invalid-src'); // Returns false\n */\nexport const isSrc = (str) => str.length > 0 && /(\\/|\\.)/.test(str);\n\n/**\n * Checks if the provided URL is an SVG data URL.\n * @param {string} url The URL to check.\n * @returns {boolean} - Returns `true` if the URL starts with 'data:image/svg+xml', otherwise `false`.\n * @example\n * isSvgDataUrl('data:image/svg+xml;base64,...'); // Returns true\n * isSvgDataUrl('https://example.com/image.svg'); // Returns false\n */\nexport const isSvgDataUrl = (url) => url.startsWith('data:image/svg+xml');\n\n/**\n * Checks if the provided URL is an encoded data URL.\n * @param {string} url The URL to check.\n * @returns {boolean} - Returns `true` if the URL contains ';utf8,', otherwise `false`.\n * @example\n * isEncodedDataUrl('data:text/plain;charset=utf8,...'); // Returns true\n * isEncodedDataUrl('https://example.com/file.txt'); // Returns false\n */\nexport const isEncodedDataUrl = (url) => url.indexOf(';utf8,') !== -1;\n\n/**\n * Checks if the provided value is of string type.\n * @param {*} val The value to check.\n * @returns {boolean} - Returns `true` if the value is a string, otherwise `false`.\n * @example\n * isStr('Hello, World!'); // Returns true\n * isStr(12345); // Returns false\n */\nexport const isStr = (val) => typeof val === 'string';\n\n/**\n * Validates the provided SVG content and ensures it contains a valid SVG element.\n * @param {string} svgContent The SVG content to validate.\n * @returns {string} Returns the validated SVG content as a string if valid, otherwise an empty string.\n * @example\n * const validSvg = '<svg class=\"icon\" xmlns=\"http://www.w3.org/2000/svg\"></svg>';\n * validateContent(validSvg); // Returns '<svg class=\"icon\" xmlns=\"http://www.w3.org/2000/svg\"></svg>'\n * const invalidSvg = '<div></div>';\n * validateContent(invalidSvg); // Returns ''\n */\nexport const validateContent = (svgContent) => {\n const div = document.createElement('div');\n div.innerHTML = svgContent;\n\n const svgElm = div.firstElementChild;\n if (svgElm && svgElm.nodeName.toLowerCase() === 'svg') {\n const svgClass = svgElm.getAttribute('class') || '';\n\n if (isValid(svgElm)) {\n return div.innerHTML;\n }\n }\n return '';\n};\n\n/**\n * Validates an element to ensure it does not contain potentially unsafe content.\n * @param {Element|Node} elm The element or node to validate.\n * @returns {boolean} - Returns `true` if the element is valid, otherwise `false`.\n * @description\n * This function checks the following:\n * 1. The element is an element node (nodeType 1).\n * 2. The element is not a `<script>` tag.\n * 3. The element does not contain any `on*` event handler attributes (e.g., `onclick`).\n * 4. All child nodes recursively pass the same validation.\n * @example\n * const validElement = document.createElement('div');\n * isValid(validElement); // Returns true\n *\n * const scriptElement = document.createElement('script');\n * isValid(scriptElement); // Returns false\n *\n * const divWithOnClick = document.createElement('div');\n * divWithOnClick.setAttribute('onclick', 'alert(\"hi\")');\n * isValid(divWithOnClick); // Returns false\n */\nexport const isValid = (elm) => {\n // Only element nodes\n if (elm.nodeType === 1) {\n // Check for script elements\n if (elm.nodeName.toLowerCase() === 'script') {\n return false;\n }\n\n // Check for on* attributes\n for (let i = 0; i < elm.attributes.length; i++) {\n const name = elm.attributes[i].name;\n if (isStr(name) && name.toLowerCase().indexOf('on') === 0) {\n return false;\n }\n }\n\n // Check for child nodes\n for (let i = 0; i < elm.childNodes.length; i++) {\n if (!isValid(elm.childNodes[i])) {\n return false;\n }\n }\n }\n return true;\n};\n\n/**\n * Fetches and optionally sanitizes SVG content from a given URL.\n * @param {string} url The URL of the SVG resource or data URL.\n * @param {boolean} [sanitize] Whether to sanitize the SVG content. Defaults to `true`.\n * @returns {Promise<void>} A promise that resolves when the SVG content is fetched and stored.\n * @description\n * This function performs the following:\n * - If the URL is an SVG data URL and encoded, it parses the content to extract the SVG.\n * - If the URL is a standard HTTP/HTTPS URL, it fetches the content.\n * - Optionally sanitizes the fetched SVG content.\n * - Caches the content for future use.\n * @example\n * getSvgContent('https://example.com/icon.svg').then(() => {\n * console.log('SVG content fetched and stored.');\n * });\n * @example\n * getSvgContent('data:image/svg+xml;base64,...', false).then(() => {\n * console.log('SVG data URL processed without sanitization.');\n * });\n */\nexport const getSvgContent = (url, sanitize) => {\n let req = requests.get(url);\n if (!req) {\n if (typeof fetch !== 'undefined' && typeof document !== 'undefined') {\n if (isSvgDataUrl(url) && isEncodedDataUrl(url)) {\n if (!parser) {\n parser = new DOMParser();\n }\n const doc = parser.parseFromString(url, 'text/html');\n const svg = doc.querySelector('svg');\n if (svg) {\n iconContent.set(url, svg.outerHTML);\n }\n return Promise.resolve();\n } else {\n req = fetch(url).then((rsp) => {\n if (rsp.ok) {\n return rsp.text().then((svgContent) => {\n if (svgContent && sanitize !== false) {\n svgContent = validateContent(svgContent);\n }\n iconContent.set(url, svgContent || '');\n });\n }\n return iconContent.set(url, '');\n });\n requests.set(url, req);\n }\n } else {\n iconContent.set(url, '');\n return Promise.resolve();\n }\n }\n return req;\n};\n\n/**\n * Retrieves the URL for an icon based on its `src` or `name` attributes.\n * @param {HTMLElement} i The icon element from which to extract the URL.\n * @returns {string|null} The URL of the icon if found, or `null` if no valid URL can be determined.\n * @description\n * This function performs the following:\n * 1. Attempts to retrieve the URL from the `src` attribute using `getSrc`.\n * 2. If no `src` is provided, it falls back to the `name` attribute using `getName`.\n * 3. If a name is found, it uses `getNamedUrl` to construct the URL, considering the `filled` attribute.\n * @example\n * const iconElement = document.querySelector('wje-icon');\n * const url = getUrl(iconElement);\n * console.log(url); // Outputs the resolved URL or `null`.\n */\nexport const getUrl = (i) => {\n let url = getSrc(i.src);\n if (url) {\n return url;\n }\n\n url = getName(i.name);\n\n if (url) {\n return getNamedUrl(url, i.hasAttribute('filled'));\n }\n\n return null;\n};\n\n/**\n * Validates and returns a sanitized icon name.\n * @param {string} iconName The icon name to validate.\n * @returns {string|null} The sanitized icon name, or `null` if the input is invalid.\n * @description\n * This function checks if the provided `iconName` is a valid string:\n * - It must not be empty or contain invalid characters.\n * - Only alphanumeric characters, hyphens, and digits are allowed.\n * @example\n * const validName = getName('user-icon');\n * console.log(validName); // 'user-icon'\n * const invalidName = getName('user@icon!');\n * console.log(invalidName); // null\n */\nexport const getName = (iconName) => {\n if (!isStr(iconName) || iconName.trim() === '') {\n return null;\n }\n\n const invalidChars = iconName.replace(/[a-z]|-|\\d/gi, '');\n if (invalidChars !== '') {\n return null;\n }\n\n return iconName;\n};\n\n/**\n * Constructs the URL for a named SVG icon.\n * @param {string} iconName The name of the icon to retrieve.\n * @param {boolean} [filled] Whether to use the \"filled\" variant of the icon. Defaults to \"outline\" if `false`.\n * @returns {string} - The complete URL to the SVG icon.\n * @description\n * This function generates a URL for an icon based on its name and style (filled or outline).\n * It uses the base URL from the environment variable `VITE_ICON_ASSETS_URL`.\n * @example\n * const url = getNamedUrl('user-icon', true);\n * console.log(url); // 'https://example.com/filled/user-icon.svg'\n *\n * const outlineUrl = getNamedUrl('settings');\n * console.log(outlineUrl); // 'https://example.com/outline/settings.svg'\n */\nconst getNamedUrl = (iconName, filled = false) => {\n const path = `${filled ? 'filled' : 'outline'}/${iconName}.svg`;\n\n let url = new URL(process.env.VITE_ICON_ASSETS_URL + path);\n\n return url.href;\n};\n","import { default as WJElement } from '../wje-element/element.js';\nimport { getSvgContent, getUrl, iconContent } from './service/service.js';\nimport styles from './styles/styles.css?inline';\n\n/**\n * @summary This element represents an icon. `IconElement` is a custom web component that represents an icon.\n * @documentation https://elements.webjet.sk/components/icon\n * @status stable\n * @augments WJElement\n * @csspart svg - The SVG part of the icon\n * @cssproperty [--wje-icon-size=1rem] - The size of the icon element\n * @cssproperty [--wje-icon-width=var(--wje-icon-size, 100%)] - The width of the icon element\n * @cssproperty [--wje-icon-height=var(--wje-icon-size, 100%)] - The height of the icon element\n * @tag wje-icon\n */\nexport default class Icon extends WJElement {\n /**\n * Creates an instance of IconElement.\n * @class\n */\n constructor() {\n super();\n }\n\n /**\n * Sets the name of the icon.\n * @type {string}\n */\n className = 'Icon';\n\n /**\n * Returns the CSS styles for the component.\n * @static\n * @returns {CSSStyleSheet}\n */\n static get cssStyleSheet() {\n return styles;\n }\n\n /**\n * Returns the list of attributes to observe for changes.\n * @static\n * @returns {Array<string>}\n */\n static get observedAttributes() {\n return ['name', 'filled'];\n }\n\n /**\n * Sets up the attributes for the component.\n */\n setupAttributes() {\n this.isShadowRoot = 'open';\n }\n\n /**\n * Draws the component.\n * @param {object} context The context for drawing.\n * @param {object} store The store for drawing.\n * @param {object} params The parameters for drawing.\n * @returns {DocumentFragment}\n */\n draw(context, store, params) {\n let fragment = document.createDocumentFragment();\n\n this.classList.add('lazy-loaded-image', 'lazy');\n\n let native = document.createElement('div');\n native.setAttribute('part', 'native');\n native.classList.add('native-icon');\n\n this.url = getUrl(this);\n\n fragment.appendChild(native);\n\n this.native = native;\n\n return fragment;\n }\n\n /**\n * Called after the component has been drawn.\n */\n afterDraw() {\n let lazyImageObserver = new IntersectionObserver((entries, observer) => {\n entries.forEach((entry) => {\n if (entry.isIntersecting) {\n getSvgContent(this.url).then((svgContent) => {\n this.native.innerHTML = iconContent?.get(this.url);\n this.native.querySelector('svg')?.setAttribute('part', 'svg');\n });\n\n this.classList.remove('lazy');\n lazyImageObserver.unobserve(entry.target);\n }\n });\n });\n\n lazyImageObserver.observe(this.native);\n }\n}\n","import Icon from './icon.element.js';\n\nexport default Icon;\n\nIcon.define('wje-icon', Icon);\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"wje-icon.js","sources":["../packages/wje-icon/service/service.js","../packages/wje-icon/icon.element.js","../packages/wje-icon/icon.js"],"sourcesContent":["export const iconContent = new Map();\nconst requests = new Map();\n\nlet parser;\n\n/**\n * Validates and returns a trimmed source string if it meets the required criteria.\n * @param {string} src The source string to validate and trim.\n * @returns {string|null} The validated and trimmed source string, or `null` if invalid.\n * @example\n * getSrc(' https://example.com/image.jpg '); // Returns 'https://example.com/image.jpg'\n * getSrc('invalid-src'); // Returns null\n */\nexport const getSrc = (src) => {\n if (isStr(src)) {\n src = src.trim();\n if (isSrc(src)) {\n return src;\n }\n }\n return null;\n};\n\n/**\n * Checks if a given string is a valid source based on specific criteria.\n * @param {string} str The string to validate as a source.\n * @returns {boolean} `true` if the string is considered a valid source, `false` otherwise.\n * @example\n * isSrc('https://example.com/image.jpg'); // Returns true\n * isSrc('image.jpg'); // Returns true\n * isSrc('invalid-src'); // Returns false\n */\nexport const isSrc = (str) => str.length > 0 && /(\\/|\\.)/.test(str);\n\n/**\n * Checks if the provided URL is an SVG data URL.\n * @param {string} url The URL to check.\n * @returns {boolean} - Returns `true` if the URL starts with 'data:image/svg+xml', otherwise `false`.\n * @example\n * isSvgDataUrl('data:image/svg+xml;base64,...'); // Returns true\n * isSvgDataUrl('https://example.com/image.svg'); // Returns false\n */\nexport const isSvgDataUrl = (url) => url.startsWith('data:image/svg+xml');\n\n/**\n * Checks if the provided URL is an encoded data URL.\n * @param {string} url The URL to check.\n * @returns {boolean} - Returns `true` if the URL contains ';utf8,', otherwise `false`.\n * @example\n * isEncodedDataUrl('data:text/plain;charset=utf8,...'); // Returns true\n * isEncodedDataUrl('https://example.com/file.txt'); // Returns false\n */\nexport const isEncodedDataUrl = (url) => url.indexOf(';utf8,') !== -1;\n\n/**\n * Checks if the provided value is of string type.\n * @param {*} val The value to check.\n * @returns {boolean} - Returns `true` if the value is a string, otherwise `false`.\n * @example\n * isStr('Hello, World!'); // Returns true\n * isStr(12345); // Returns false\n */\nexport const isStr = (val) => typeof val === 'string';\n\n/**\n * Validates the provided SVG content and ensures it contains a valid SVG element.\n * @param {string} svgContent The SVG content to validate.\n * @returns {string} Returns the validated SVG content as a string if valid, otherwise an empty string.\n * @example\n * const validSvg = '<svg class=\"icon\" xmlns=\"http://www.w3.org/2000/svg\"></svg>';\n * validateContent(validSvg); // Returns '<svg class=\"icon\" xmlns=\"http://www.w3.org/2000/svg\"></svg>'\n * const invalidSvg = '<div></div>';\n * validateContent(invalidSvg); // Returns ''\n */\nexport const validateContent = (svgContent) => {\n const div = document.createElement('div');\n div.innerHTML = svgContent;\n\n const svgElm = div.firstElementChild;\n if (svgElm && svgElm.nodeName.toLowerCase() === 'svg') {\n const svgClass = svgElm.getAttribute('class') || '';\n\n if (isValid(svgElm)) {\n return div.innerHTML;\n }\n }\n return '';\n};\n\n/**\n * Validates an element to ensure it does not contain potentially unsafe content.\n * @param {Element|Node} elm The element or node to validate.\n * @returns {boolean} - Returns `true` if the element is valid, otherwise `false`.\n * @description\n * This function checks the following:\n * 1. The element is an element node (nodeType 1).\n * 2. The element is not a `<script>` tag.\n * 3. The element does not contain any `on*` event handler attributes (e.g., `onclick`).\n * 4. All child nodes recursively pass the same validation.\n * @example\n * const validElement = document.createElement('div');\n * isValid(validElement); // Returns true\n *\n * const scriptElement = document.createElement('script');\n * isValid(scriptElement); // Returns false\n *\n * const divWithOnClick = document.createElement('div');\n * divWithOnClick.setAttribute('onclick', 'alert(\"hi\")');\n * isValid(divWithOnClick); // Returns false\n */\nexport const isValid = (elm) => {\n // Only element nodes\n if (elm.nodeType === 1) {\n // Check for script elements\n if (elm.nodeName.toLowerCase() === 'script') {\n return false;\n }\n\n // Check for on* attributes\n for (let i = 0; i < elm.attributes.length; i++) {\n const name = elm.attributes[i].name;\n if (isStr(name) && name.toLowerCase().indexOf('on') === 0) {\n return false;\n }\n }\n\n // Check for child nodes\n for (let i = 0; i < elm.childNodes.length; i++) {\n if (!isValid(elm.childNodes[i])) {\n return false;\n }\n }\n }\n return true;\n};\n\n/**\n * Fetches and optionally sanitizes SVG content from a given URL.\n * @param {string} url The URL of the SVG resource or data URL.\n * @param {boolean} [sanitize] Whether to sanitize the SVG content. Defaults to `true`.\n * @returns {Promise<void>} A promise that resolves when the SVG content is fetched and stored.\n * @description\n * This function performs the following:\n * - If the URL is an SVG data URL and encoded, it parses the content to extract the SVG.\n * - If the URL is a standard HTTP/HTTPS URL, it fetches the content.\n * - Optionally sanitizes the fetched SVG content.\n * - Caches the content for future use.\n * @example\n * getSvgContent('https://example.com/icon.svg').then(() => {\n * console.log('SVG content fetched and stored.');\n * });\n * @example\n * getSvgContent('data:image/svg+xml;base64,...', false).then(() => {\n * console.log('SVG data URL processed without sanitization.');\n * });\n */\nexport const getSvgContent = (url, sanitize) => {\n let req = requests.get(url);\n if (!req) {\n if (typeof fetch !== 'undefined' && typeof document !== 'undefined') {\n if (isSvgDataUrl(url) && isEncodedDataUrl(url)) {\n if (!parser) {\n parser = new DOMParser();\n }\n const doc = parser.parseFromString(url, 'text/html');\n const svg = doc.querySelector('svg');\n if (svg) {\n iconContent.set(url, svg.outerHTML);\n }\n return Promise.resolve();\n } else {\n req = fetch(url).then((rsp) => {\n if (rsp.ok) {\n return rsp.text().then((svgContent) => {\n if (svgContent && sanitize !== false) {\n svgContent = validateContent(svgContent);\n }\n iconContent.set(url, svgContent || '');\n });\n }\n return iconContent.set(url, '');\n });\n requests.set(url, req);\n }\n } else {\n iconContent.set(url, '');\n return Promise.resolve();\n }\n }\n return req;\n};\n\n/**\n * Retrieves the URL for an icon based on its `src` or `name` attributes.\n * @param {HTMLElement} i The icon element from which to extract the URL.\n * @returns {string|null} The URL of the icon if found, or `null` if no valid URL can be determined.\n * @description\n * This function performs the following:\n * 1. Attempts to retrieve the URL from the `src` attribute using `getSrc`.\n * 2. If no `src` is provided, it falls back to the `name` attribute using `getName`.\n * 3. If a name is found, it uses `getNamedUrl` to construct the URL, considering the `filled` attribute.\n * @example\n * const iconElement = document.querySelector('wje-icon');\n * const url = getUrl(iconElement);\n * console.log(url); // Outputs the resolved URL or `null`.\n */\nexport const getUrl = (i) => {\n let url = getSrc(i.src);\n if (url) {\n return url;\n }\n\n url = getName(i.name);\n\n if (url) {\n return getNamedUrl(url, i.hasAttribute('filled'));\n }\n\n return null;\n};\n\n/**\n * Validates and returns a sanitized icon name.\n * @param {string} iconName The icon name to validate.\n * @returns {string|null} The sanitized icon name, or `null` if the input is invalid.\n * @description\n * This function checks if the provided `iconName` is a valid string:\n * - It must not be empty or contain invalid characters.\n * - Only alphanumeric characters, hyphens, and digits are allowed.\n * @example\n * const validName = getName('user-icon');\n * console.log(validName); // 'user-icon'\n * const invalidName = getName('user@icon!');\n * console.log(invalidName); // null\n */\nexport const getName = (iconName) => {\n if (!isStr(iconName) || iconName.trim() === '') {\n return null;\n }\n\n const invalidChars = iconName.replace(/[a-z]|-|\\d/gi, '');\n if (invalidChars !== '') {\n return null;\n }\n\n return iconName;\n};\n\n/**\n * Constructs the URL for a named SVG icon.\n * @param {string} iconName The name of the icon to retrieve.\n * @param {boolean} [filled] Whether to use the \"filled\" variant of the icon. Defaults to \"outline\" if `false`.\n * @returns {string} - The complete URL to the SVG icon.\n * @description\n * This function generates a URL for an icon based on its name and style (filled or outline).\n * It uses the base URL from the environment variable `VITE_ICON_ASSETS_URL`.\n * @example\n * const url = getNamedUrl('user-icon', true);\n * console.log(url); // 'https://example.com/filled/user-icon.svg'\n *\n * const outlineUrl = getNamedUrl('settings');\n * console.log(outlineUrl); // 'https://example.com/outline/settings.svg'\n */\nconst getNamedUrl = (iconName, filled = false) => {\n const path = `${filled ? 'filled' : 'outline'}/${iconName}.svg`;\n\n let url = new URL(process.env.VITE_ICON_ASSETS_URL + path);\n\n return url.href;\n};\n","import { default as WJElement } from '../wje-element/element.js';\nimport { getSvgContent, getUrl, iconContent } from './service/service.js';\nimport styles from './styles/styles.css?inline';\n\n/**\n * @summary This element represents an icon. `IconElement` is a custom web component that represents an icon.\n * @documentation https://elements.webjet.sk/components/icon\n * @status stable\n * @augments WJElement\n * @csspart svg - The SVG part of the icon\n * @cssproperty [--wje-icon-size=1rem] - The size of the icon element\n * @cssproperty [--wje-icon-width=var(--wje-icon-size, 100%)] - The width of the icon element\n * @cssproperty [--wje-icon-height=var(--wje-icon-size, 100%)] - The height of the icon element\n * @tag wje-icon\n */\nexport default class Icon extends WJElement {\n /**\n * Creates an instance of IconElement.\n * @class\n */\n constructor() {\n super();\n }\n\n /**\n * Sets the name of the icon.\n * @type {string}\n */\n className = 'Icon';\n\n /**\n * Returns the CSS styles for the component.\n * @static\n * @returns {CSSStyleSheet}\n */\n static get cssStyleSheet() {\n return styles;\n }\n\n /**\n * Returns the list of attributes to observe for changes.\n * @static\n * @returns {Array<string>}\n */\n static get observedAttributes() {\n return ['name', 'filled'];\n }\n\n /**\n * Sets up the attributes for the component.\n */\n setupAttributes() {\n this.isShadowRoot = 'open';\n }\n\n /**\n * Draws the component.\n * @param {object} context The context for drawing.\n * @param {object} store The store for drawing.\n * @param {object} params The parameters for drawing.\n * @returns {DocumentFragment}\n */\n draw(context, store, params) {\n let fragment = document.createDocumentFragment();\n\n this.classList.add('lazy-loaded-image', 'lazy');\n\n let native = document.createElement('div');\n native.setAttribute('part', 'native');\n native.classList.add('native-icon');\n\n this.url = getUrl(this);\n\n fragment.appendChild(native);\n\n this.native = native;\n\n return fragment;\n }\n\n /**\n * Called after the component has been drawn.\n */\n afterDraw() {\n let lazyImageObserver = new IntersectionObserver((entries, observer) => {\n entries.forEach((entry) => {\n if (entry.isIntersecting) {\n getSvgContent(this.url).then((svgContent) => {\n this.native.innerHTML = iconContent?.get(this.url);\n this.native.querySelector('svg')?.setAttribute('part', 'svg');\n });\n\n this.classList.remove('lazy');\n lazyImageObserver.unobserve(entry.target);\n }\n });\n });\n\n lazyImageObserver.observe(this.native);\n }\n}\n","import Icon from './icon.element.js';\n\nexport default Icon;\n\nIcon.define('wje-icon', Icon);\n"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wj-elements",
|
|
3
3
|
"description": "WebJET Elements is a modern set of user interface tools harnessing the power of web components designed to simplify web application development.",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.168",
|
|
5
5
|
"homepage": "https://github.com/lencys/wj-elements",
|
|
6
6
|
"author": "Lukáš Ondrejček <lukas.ondrejcek@gmail.com>",
|
|
7
7
|
"license": "MIT",
|