vite-awesome-svg-loader
Version:
A universal Vite SVG loader. Imports SVGs as source code, base64 and data URI. Preserves stroke width. Replaces colors with currentColor or custom colors. Creates SVG sprites. Optimizes SVGs.
1 lines • 35.7 kB
Source Map (JSON)
{"version":3,"file":"index-DSZOdBhc.cjs","sources":["../../../web-components-integration/src/WebComponent.ts","../../../web-components-integration/src/SvgImage.ts","../../../web-components-integration/src/SvgIcon.ts"],"sourcesContent":["import { camelCaseToKebabCase } from \"common-utils\";\nimport type { CustomElement } from \"typed-custom-elements\";\n\n/** Describes {@link WebComponent} property */\nexport interface WebComponentProp {\n /** Property name */\n name: string;\n\n /** Default value */\n default?: string;\n}\n\n/** Basic custom element's definition options that should be passed to {@link WebComponent.define} */\nexport interface BasicWebComponentDefinitionOptions {\n /** Custom element tag name */\n tag: string;\n\n /**\n * Where to define given element\n *\n * @default customElements\n */\n registry?: CustomElementRegistry;\n\n /**\n * Whether to ignore an error that is thrown when an element is defined second time under a different tag.\n *\n * This option is intended for when a web component uses another web component which may not be defined before\n * its construction.\n *\n * @default false\n */\n noRedefinitionError?: boolean;\n}\n\n/**\n * Definition options that should be used by concrete web components. Components must provide default values\n * if necessary.\n */\nexport interface WebComponentDefinitionOptions extends Partial<BasicWebComponentDefinitionOptions> {}\n\n/**\n * Current component state. Possible values:\n *\n * 1. `uninitialized` - Initialization has not yet run.\n * 1. `initialization` - Component is initializing its internal state.\n * 1. `attrs-first-change` - Component is calling {@link WebComponent.attributeChangedCallback} for the first time right\n * after initialization is completed.\n * 1. `normal` - Normal state.\n */\nexport type WebComponentState = \"uninitialized\" | \"initialization\" | \"attrs-first-change\" | \"normal\";\n\n/** Resolved and normalized property config */\nexport interface ResolvedWebComponentProp extends Omit<WebComponentProp, \"name\"> {}\n\n/** Web component metadata */\ninterface WebComponentMeta {\n /** Maps property name in `camelCase` to the resolved property config */\n props: Record<string, ResolvedWebComponentProp | undefined>;\n\n /** Maps attribute name in `kebab-case` to the resolved property config */\n attrs: Record<string, ResolvedWebComponentProp | undefined>;\n}\n\n// Not a WeakMap because custom element constructors won't be garbage-collected.\n// So let's squeeze a bit of performance by using a regular Map.\nconst componentsMeta = new Map<typeof WebComponent, WebComponentMeta>();\n\n/** Tracks which registry contains which web components */\nconst registryToComponents = new Map<CustomElementRegistry, Set<typeof WebComponent>>();\n\n/**\n * ### Introduction\n *\n * This is the base web components class and the whole web components implementation.\n *\n * This is just a\n * [custom element](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements)\n * with a number of necessary features missing from the standard custom elements.\n *\n * ### Implementation goals\n *\n * This web components implementation was designed with the following goals in mind:\n *\n * 1. Improve upon custom elements:\n * 1. Implement necessary features that are missing from the standard custom elements.\n * 1. Maintain compliance with the custom elements specification.\n * 1. Maintain compatibility with other libraries and frameworks without additional setup.\n * 1. Keep implementation minimal and size small:\n * 1. Don't pollute application's bundle with the code that most likely won't be used.\n * 1. Don't implement features for the sake of having features.\n * 1. Achieve maximum performance.\n *\n * As you can see, this is **not** a framework. There are no quality-of-life abstractions and features found in major\n * frameworks like [Lit](https://lit.dev/). Ultimately, this is a bare minimum to ship off web components integration.\n *\n * ### When to use this\n *\n * When you are:\n *\n * - Occasionally using web components (or just `vite-awesome-svg-loader` alone).\n * - Building a wrapper around `vite-awesome-svg-loader`.\n * - Having other reasons to use a **minimal** web components implementation like this one.\n *\n * ### When to NOT use this\n *\n * When you are:\n *\n * - Planning or already using a dedicated library for managing web components.\n *\n * Just use that library.\n *\n * - Planning to build more web components.\n *\n * Consider using a dedicated library. It will pay off in the long run.\n *\n * ### Behavioral differences from custom elements\n *\n * 1. All attributes are observed automatically. No need for {@link WebComponent.observedAttributes}.\n *\n * 1. {@link WebComponent.attributeChangedCallback} is called when component has initialized and when any attribute's\n * value has **actually** changed. Setting same value doesn't count as a change.\n *\n * 1. Properties can be synchronized with attributes by defining them in {@link WebComponent.props}.\n *\n * ### Core principles\n *\n * 1. Use constructors to initialize state. But do **not** use properties defined in {@link WebComponent.props}\n * in a constructor because that will trigger an attribute setter which renders constructor invalid\n * (per custom elements specification).\n *\n * 1. Use {@link WebComponent.connectedCallback} to initialize markup.\n *\n * 1. Use {@link WebComponent.attributeChangedCallback} to track property/attribute changes. Do **not** define your own\n * getters and setters, they will be overridden.\n *\n * 1. Prefer inheritance over composition. Yes, this is an anti-pattern. Web components are actual elements.\n * The more components you nest, the larger and slower to process DOM becomes. If you want composition, either sacrifice\n * performance or use a specialized library/framework.\n *\n * 1. When using a web component inside another web component, call `define({ noRedefinitionError: true })` and\n * use a constructor instead of `document.createElement()`.\n *\n * Suppress a redefinition error because in most cases user will not specify different tag and would not expect\n * an error if they haven't defined a dependency component.\n *\n * Use a constructor because user still might decide to use a custom tag.\n *\n * Ultimately, user will get an error, if the definition is invalid.\n *\n * 1. If you've encountered a problem that must be resolved immediately by modifying the internals,\n * everything's here for you. Just use `// @ts-ignore` to suppress the errors. After the hotfix, please file an issue\n * and explain your case.\n *\n * ### Creating web components\n *\n * Let's create a simple `BusinessCard` web component:\n *\n * ```ts\n * class BusinessCard extends WebComponent implements CustomElement {\n * // Define class properties that will be synced with attributes\n *\n * static readonly props = [\"personName\", { name: \"orgName\", default: \"Not affiliated\" }];\n *\n * // Declare properties for type-checking to work. You may actually define them, but they will be overridden\n * // with proper getters and setters, so don't create empty overhead.\n *\n * declare personName?: string;\n * declare orgName: string;\n *\n * // Add markup\n *\n * connectedCallback() {\n * super.connectedCallback();\n *\n * if (this.children.length) {\n * return\n * }\n *\n * const personName = document.createElement(\"div\");\n * personName.className = \"person-name\";\n * this.appendChild(personName);\n *\n * const orgName = document.createElement(\"div\");\n * orgName.className = \"org-name\";\n * this.appendChild(orgName);\n * }\n *\n * // Track changes\n *\n * attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null) {\n * switch (name) {\n * // props are tracked:\n * case \"personName\":\n * case \"orgName\":\n * this.getElementsByClassName(name)[0]!.innerText = newValue || \"-\";\n * break;\n *\n * // Every other attribute is also tracked:\n * case \"data-some-attr\":\n * console.log(oldValue, newValue);\n * break;\n * }\n * }\n *\n * // Provide default tag for definition (optional, but recommended)\n *\n * define(options?: WebComponentDefinitionOptions) {\n * super.define({ ...options, tag: options.tag || \"business-card\" });\n * }\n * }\n *\n * // Define a custom element\n *\n * BusinessCard.define();\n * ```\n *\n * ### Using web components\n *\n * Let's instantiate and mount a `BusinessCard` web component that we've created:\n *\n * ```ts\n * // Create a web component instance:\n *\n * const card = new BusinessCard();\n * // or:\n * const card = document.createElement(\"business-card\");\n *\n * // Add component to the DOM:\n *\n * document.getElementById(\"card\")!.appendChild(card);\n *\n * // Change properties:\n *\n * card.firstName = \"John\";\n * // or:\n * card.setAttribute(\"first-name\", \"John\"); // Notice that attribute is in snake-case while property is in camelCase\n * ```\n *\n * ### Extending web components\n *\n * Let's create a `CoolBusinessCard` component by extending `BusinessCard` component:\n *\n * ```ts\n * class CoolBusinessCard extends BusinessCard implements CustomElement {\n * // Define new properties. Inherited properties will be defined and copied to \"props\" automatically.\n * // Note: it is impossible to redefine inherited properties because parent relies on their behavior.\n *\n * static readonly props = [\n * { name: \"coolness\", default: \"120%\" },\n * ];\n *\n * declare coolness: string;\n *\n * // Provide default tag for definition\n *\n * define(options: WebComponentDefinitionOptions = {}) {\n * super.define({ ...options, tag: options.tag || \"cool-business-card\" });\n * }\n * }\n * ```\n */\nexport class WebComponent extends HTMLElement implements CustomElement {\n /**\n * Doesn't do anything. All attributes are already observed. This property will be deleted when custom element\n * will be defined.\n *\n * This property is recognized for compatibility reasons only.\n */\n declare static observedAttributes?: string[];\n\n /**\n * Properties that will be synced with attributes.\n *\n * Properties must be in `camelCase`. Synchronized attributes will be in `kebab-case`.\n *\n * To not confuse cases, prefer single-word names.\n */\n static props: (string | WebComponentProp)[] = [];\n\n /**\n * Current component state. See {@link WebComponentState} for the details.\n */\n protected _state: WebComponentState = \"uninitialized\";\n\n /**\n * Initial property values.\n *\n * If element is created before it is defined, and user will set properties, these properties will be own properties\n * of the element. When element is upgraded, these properties are kept as own.\n * Children's constructors may override the base class's properties.`\n *\n * The initialization logic must re-apply user's values. To do so, we save them here in the constructor before they're\n * overridden.\n *\n * This property is deleted after initialization is complete.\n */\n private _initialValues?: Record<string, string> = {};\n\n /**\n * Called when:\n *\n * 1. Component has just finished initialization. Then:\n *\n * 1. {@link _state} property will be `attrs-first-change`.\n * 1. `oldValue` argument will be `null`.\n * 1. `newValue` will have a default value or `null`, if there's no default.\n * 1. Thus, following may be true: `oldValue === newValue && newValue === null`.\n *\n * 1. **Any** of the element's attributes has **actually** changed (unlike default custom elements' behavior where\n * this method is called even if the same value has been set). Then:\n *\n * 1. {@link _state} property will be `normal`.\n * 1. `oldValue` and `newValue` will be always different.\n */\n attributeChangedCallback?(...args: Parameters<NonNullable<CustomElement[\"attributeChangedCallback\"]>>): void;\n\n // Initialization logic\n\n constructor() {\n super();\n let meta = this._getMeta();\n\n if (!meta) {\n this._ctor()._initClass();\n meta = this._getMeta();\n }\n\n for (const prop in meta.props) {\n if (!Object.hasOwn(this, prop)) {\n continue;\n }\n\n const value = this[prop as keyof this];\n\n if (typeof value === \"string\") {\n this._initialValues![prop] = value;\n }\n }\n\n queueMicrotask(this._init.bind(this));\n }\n\n /**\n * Initializes component state.\n *\n * Custom elements may not add attributes or children in a constructor, so separate initialization is required.\n * Thus, this method is called whenever an attribute is accessed or in a microtask after component's constructor\n * has run.\n *\n * Initialization is performed only once.\n */\n protected _init() {\n if (this._state !== \"uninitialized\") {\n return;\n }\n\n this._state = \"initialization\";\n const { props, attrs } = this._getMeta();\n\n // An instance might be created and manipulated before a component has been defined, and the element\n // is upgraded.\n //\n // That instance will skip our synchronization logic because no setters would have been called.\n //\n // Will use this hack (which is ~10x more performant than Object.defineProperty()) to call setters:\n // https://nolanlawson.com/2021/08/03/handling-properties-in-custom-element-upgrades/#:~:text=It%20feels%20like%20it%20should,set%20mode%20)%20will%20be%20invoked.\n\n for (const name in props) {\n // Delete own property, so prototype's property will be used instead\n delete (this as any)[name];\n\n // This calls setter defined in prototype instead of setting own property\n (this as any)[name] =\n this._initialValues![name] ?? super.getAttribute(camelCaseToKebabCase(name)) ?? props[name]!.default;\n }\n\n delete this._initialValues; // Free memory\n\n // Track first attributes' \"change\"\n\n this._state = \"attrs-first-change\";\n\n if (this.attributeChangedCallback) {\n const call = (name: string) => this.attributeChangedCallback!(name, null, this.getAttribute(name));\n\n for (const name in attrs) {\n call(name);\n }\n\n for (const { name } of this.attributes) {\n if (!(name in attrs)) {\n call(name);\n }\n }\n }\n\n this._state = \"normal\";\n }\n\n /**\n * Called when the element is added to a document.\n *\n * If overridden, `super.connectedCallback()` must be the first statement.\n */\n connectedCallback(): void {\n this._init();\n }\n\n // Make attribute getter return default value\n\n getAttribute(name: string): string | null {\n this._init();\n return super.getAttribute(name) ?? this._getMeta().attrs[name]?.default ?? null;\n }\n\n // Make all attributes setters track changes through a common setter\n\n setAttribute(name: string, value: string): void {\n this._setAttr(name, value);\n }\n\n removeAttribute(name: string): void {\n this._setAttr(name, null);\n }\n\n toggleAttribute(name: string, force?: boolean): boolean {\n this._setAttr(name, force || typeof this.getAttribute(name) === \"string\" ? null : \"\");\n return !!this.getAttribute(name); // attributeChangedCallback() may change attribute value, so call getter\n }\n\n /**\n * A common attribute setter called by attributes manipulation methods (`setAttribute`, `removeAttribute`, etc)\n * and property setters\n *\n * @param name Attribute name\n * @param value Attribute value\n */\n private _setAttr(name: string, value: string | null): void {\n this._init();\n\n const cfg = this._getMeta().attrs[name];\n const propsInitialized = this._state !== \"initialization\";\n\n const prev = this.getAttribute(name);\n value ??= cfg?.default ?? null;\n\n // Values are equal when initializing attributes but we should still reset them\n if (\n propsInitialized &&\n // @ts-expect-error\n !(this as BaseWebComponent)._isFirstObserverCall &&\n value === prev\n ) {\n return;\n }\n\n // FIXME: Somehow switch to setAttr()\n if (typeof value === \"string\") {\n super.setAttribute.call(this, name, value);\n } else {\n super.removeAttribute.call(this, name);\n }\n\n if (propsInitialized && this.attributeChangedCallback) {\n this.attributeChangedCallback(name, prev, value);\n }\n }\n\n // Rest of the logic\n\n /**\n * Returns a constructor of this class\n *\n * If you need to refer to your own class, type it like so:\n *\n * ```ts\n * class MyClass extends WebComponent {\n * declare protected _ctor: () => typeof MyClass\n * }\n * ```\n *\n * @returns constructor of this class\n */\n protected _ctor(): typeof WebComponent {\n return Object.getPrototypeOf(this).constructor;\n }\n\n /** @returns Current web component's metadata */\n private _getMeta() {\n // Meta is always initialized when calling from an instance.\n // If someone will decide to misuse web components and do something like:\n // WebComponent.prototype.getAttribute.call(someObject, \"attr\")\n // well, that's on them.\n return componentsMeta.get(this._ctor())!;\n }\n\n /**\n * Defines a custom element for this web component.\n *\n * Won't throw an error if called multiple times with the same tag.\n *\n * Will throw an error (unless suppressed via {@link BasicWebComponentDefinitionOptions.noRedefinitionError})\n * if defined under a different tag.\n *\n * @param options Definition options\n */\n static define(options: BasicWebComponentDefinitionOptions) {\n const { tag, registry = customElements, noRedefinitionError } = options;\n\n // Don't define again, if the same element is already defined under the same tag.\n // Otherwise, let browser throw an error (unless ignored via options).\n\n if (registry.get(tag) === this) {\n return;\n }\n\n if (noRedefinitionError && registryToComponents.get(registry)?.has(this)) {\n return;\n }\n\n this._initClass();\n registry.define(tag, this);\n }\n\n /** Initializes class itself. Called by {@link define} and by the constructor. Initialization happens only once. */\n protected static _initClass() {\n if (componentsMeta.has(this)) {\n return;\n }\n\n // Copy parent props\n\n this.props = Object.getPrototypeOf(this).props.concat(this.props);\n\n // Register and synchronize properties with attributes, i.e. make properties just get and set attributes\n\n const meta: WebComponentMeta = { props: {}, attrs: {} };\n componentsMeta.set(this, meta);\n\n for (const userCfg of this.props) {\n // Resolve config\n\n const { name: nameInCamelCase, ...cfg } = typeof userCfg === \"string\" ? { name: userCfg } : userCfg;\n\n if (meta.props[nameInCamelCase]) {\n continue; // Ignore duplicate definitions to prevent potential side-effects\n }\n\n const nameInKebabCase = camelCaseToKebabCase(nameInCamelCase);\n\n // Register property\n\n meta.props[nameInCamelCase] = cfg;\n meta.attrs[nameInKebabCase] = cfg;\n\n // Define getter and setter\n\n Object.defineProperty(this.prototype, nameInCamelCase, {\n get(this: WebComponent) {\n return this.getAttribute(nameInKebabCase) ?? cfg.default;\n },\n\n set(this: WebComponent, value: string | null | undefined) {\n this._setAttr(nameInKebabCase, value ?? null);\n },\n });\n }\n }\n}\n\n// Patch properties and methods that access attributes to call initialization logic beforehand\n\nconst proto = WebComponent.prototype;\n\n// Properties\n\nconst propsToPatchWithInit = [\"innerHTML\", \"innerText\", \"outerHTML\", \"attributes\"] satisfies (keyof HTMLElement)[];\n\nfor (const prop of propsToPatchWithInit) {\n const descriptor = Object.getOwnPropertyDescriptor(Element.prototype, prop);\n\n if (!descriptor) {\n continue;\n }\n\n if (!descriptor.get && !descriptor.set) {\n continue; // Probably not a good idea to patch this because there's no way to get initial value\n }\n\n const newDescriptor: PropertyDescriptor = {};\n\n if (descriptor.get) {\n newDescriptor.get = function (this: WebComponent) {\n this._init();\n return descriptor.get!.call(this);\n };\n }\n\n if (descriptor.set) {\n newDescriptor.set = function (this: WebComponent, v) {\n this._init();\n descriptor.set!.call(this, v);\n };\n }\n\n Object.defineProperty(proto, prop, newDescriptor);\n}\n\n// Methods\n\nconst methodsToPatchWithInit = [\"hasAttribute\", \"hasAttributes\", \"getAttributeNames\"] satisfies (keyof HTMLElement)[];\n\nfor (const method of methodsToPatchWithInit) {\n const orig: (...args: any[]) => any = proto[method];\n\n proto[method] = function (this: WebComponent, ...args: any[]) {\n this._init();\n return orig.call(this, ...args);\n };\n}\n\n// Patch registry\n\nconst origDefine = CustomElementRegistry.prototype.define;\n\nCustomElementRegistry.prototype.define = function (\n this: CustomElementRegistry,\n name,\n ctor: typeof WebComponent,\n ...rest\n) {\n const orig = () => origDefine.call(this, name, ctor, ...rest);\n\n if (!(ctor.prototype instanceof WebComponent)) {\n return orig();\n }\n\n // Track registered components\n\n if (!registryToComponents.has(this)) {\n registryToComponents.set(this, new Set());\n }\n\n registryToComponents.get(this)!.add(ctor);\n\n // Silently delete observedAttributes to opt out of default observer behavior\n delete ctor.observedAttributes;\n\n return orig();\n};\n","import styles from \"@/assets/styles.scss?inline\";\n\nimport { onSrcUpdate, onUnmount } from \"integration-utils\";\nimport { createStyle, setAttr, setAttrs } from \"common-utils\";\nimport { WebComponent, WebComponentDefinitionOptions } from \"@/WebComponent\";\nimport type { CustomElement } from \"typed-custom-elements\";\n\ntype SrcUpdateSvgAttr = keyof NonNullable<ReturnType<typeof onSrcUpdate>[\"attrs\"]>;\n\n/**\n * Attributes that shouldn't be changed by the user\n */\nconst PROTECTED_SVG_ATTRS: Record<string, true | undefined> = {\n viewBox: true,\n width: true,\n height: true,\n} satisfies Record<SrcUpdateSvgAttr, true>;\n\nconst EMPTY_SVG = `<svg viewBox=\"0 0 0 0\" width=\"0\" height=\"0\"></svg>`;\n\n/**\n * Basic SVG image. Implements SVG sprites. Adds `<svg>` element with the symbols to the `<body>`.\n *\n * Pass SVG source code to the `src` property, so the image will be rendered.\n *\n * Every attribute that starts with `svg-` string will be passed down to the `<svg>` element.\n *\n * Every attribute that starts with `use-` string will be passed down to the `<use>` element.\n *\n * @example\n *\n * // Import SVG source code:\n * import imgSrc from \"@/assets/image.svg?src\";\n *\n * // Import web component:\n * import { SvgImage } from \"vite-awesome-svg-loader/web-components-integration\";\n *\n * // Define a custom element:\n * SvgImage.define();\n *\n * // Create image:\n * const img = new SvgImage();\n * // or:\n * const img = document.createElement(\"svg-image\");\n *\n * // Assign SVG source code to the image:\n * img.src = imgSrc;\n *\n * // Add image to the DOM:\n * document.body.appendChild(img);\n *\n * // Set attributes to <svg> element:\n * img.setAttribute(\"svg-preserveAspectRatio\", \"xMaxYMin\"); // Will set preserveAspectRatio=\"xMaxYMin\"\n *\n * // Set attributes to <use> element:\n * img.setAttribute(\"use-data-test\", \"use-el\"); // will set data-test=\"use-el\"\n */\nexport class SvgImage extends WebComponent implements CustomElement {\n static readonly props = [\n // Web components may be used in unpredicted contexts, so it's safer to differ from the other integrations\n // and render empty SVG when there's no source code\n { name: \"src\", default: EMPTY_SVG },\n ];\n\n /** SVG source code */\n declare src: string;\n\n /**\n * Last src update result\n */\n protected _updateSrcRes: ReturnType<typeof onSrcUpdate> = {};\n\n private readonly _svgEl: SVGElement;\n private readonly _useEl: SVGUseElement;\n\n /**\n * `<use>` element\n */\n get useEl() {\n return this._useEl;\n }\n\n /**\n * `<svg>` element\n */\n get svgEl() {\n return this._svgEl;\n }\n\n constructor() {\n super();\n this._svgEl = document.createElementNS(\"http://www.w3.org/2000/svg\", \"svg\");\n this._useEl = document.createElementNS(\"http://www.w3.org/2000/svg\", \"use\");\n this._svgEl.appendChild(this.useEl);\n }\n\n connectedCallback(): void {\n super.connectedCallback();\n createStyle(this.getStyleId(), styles.replaceAll(\"svg-image\", this.localName));\n\n if (!this.childElementCount) {\n this.appendChild(this._svgEl);\n }\n }\n\n disconnectedCallback() {\n onUnmount(this._updateSrcRes.id);\n }\n\n attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null) {\n if (PROTECTED_SVG_ATTRS[name]) {\n return;\n }\n\n if (name === \"src\") {\n this._handleSrcUpdate(oldValue, newValue);\n return;\n }\n\n if (name.startsWith(\"use-\")) {\n this._handleUseAttrUpdate(name.substring(4), newValue);\n return;\n }\n\n if (name.startsWith(\"svg-\")) {\n this._handleSvgAttrUpdate(name.substring(4), newValue);\n }\n }\n\n /** @returns ID of a `<style>` element that styles this component */\n getStyleId() {\n return \"svg-image-web-component__\" + this.localName;\n }\n\n private _handleSrcUpdate(oldSrc: string | null, src: string | null) {\n this._updateSrcRes = onSrcUpdate(oldSrc ?? undefined, src || EMPTY_SVG);\n\n if (this._updateSrcRes.id) {\n setAttr(this.useEl, \"href\", \"#\" + this._updateSrcRes.id);\n }\n\n if (this._updateSrcRes.attrs) {\n setAttrs(this.svgEl, this._updateSrcRes.attrs);\n }\n }\n\n private _handleSvgAttrUpdate(name: string, value: string | null) {\n if (!PROTECTED_SVG_ATTRS[name]) {\n setAttr(this._svgEl, name, value);\n }\n }\n\n private _handleUseAttrUpdate(name: string, value: string | null) {\n if (name !== \"href\") {\n setAttr(this.useEl, name, value);\n }\n }\n\n static define(options: WebComponentDefinitionOptions = {}) {\n const tag = options.tag || \"svg-image\";\n super.define({ ...options, tag });\n }\n}\n","import { SvgImage } from \"@/SvgImage\";\nimport { WebComponent, WebComponentDefinitionOptions } from \"@/WebComponent\";\nimport { initSvgIcons, SVG_ICON_DEFAULT_COLOR_TRANSITION } from \"integration-utils\";\n\nconst CSS_PROPS: Record<string, true | undefined> = { \"size\": true, \"color\": true, \"color-transition\": true };\n\n/**\n * Basic SVG icon.\n *\n * If you plan to define {@link SvgImage} under a non-default tag, define it before creating SVG icons. Otherwise,\n * an error will be thrown.\n *\n * @example\n *\n * // Import SVG source code:\n * import imgSrc from \"@/assets/image.svg?src\";\n *\n * // Import web component:\n * import { SvgIcon } from \"vite-awesome-svg-loader/web-components-integration\";\n *\n * // Define a custom element:\n * SvgIcon.define();\n *\n * // Create icon:\n * const icon = new SvgIcon();\n * // or:\n * const icon = document.createElement(\"svg-icon\");\n *\n * // Assign SVG source code to the image:\n * icon.src = imgSrc;\n *\n * // Stylize icon:\n * icon.color = \"red\";\n * icon.size = \"24px\";\n * icon.colorTransition = \"0.2s ease-out\";\n *\n * // Add image to the DOM:\n * document.body.appendChild(icon);\n */\nexport class SvgIcon extends WebComponent {\n static DEFAULT_COLOR_TRANSITION = SVG_ICON_DEFAULT_COLOR_TRANSITION;\n\n static readonly props = [\"src\", \"size\", \"color\", { name: \"colorTransition\", default: this.DEFAULT_COLOR_TRANSITION }];\n\n /**\n * Image source code\n */\n declare src?: string;\n\n /**\n * Icon size. Empty string unsets size.\n */\n declare size?: string;\n\n /**\n * Icon color. Empty string unsets color.\n */\n declare color?: string;\n\n /**\n * Icon color transition. Empty string unsets transition.\n *\n * To set default value, use {@link DEFAULT_COLOR_TRANSITION}.\n */\n declare colorTransition: string;\n\n /**\n * Wrapped `SvgImage` element\n */\n private _svgImage: InstanceType<typeof SvgImage>;\n\n constructor() {\n super();\n initSvgIcons();\n SvgImage.define({ noRedefinitionError: true });\n this._svgImage = new SvgImage();\n this._svgImage.setAttribute(\"svg-aria-hidden\", \"true\");\n }\n\n connectedCallback(): void {\n super.connectedCallback();\n\n if (!this.childElementCount) {\n this.classList.add(\"vite-awesome-svg-loader-icon\");\n this.appendChild(this._svgImage);\n }\n }\n\n attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null) {\n if (name === \"src\") {\n this._svgImage.src = newValue || \"\";\n } else if (CSS_PROPS[name]) {\n this.style.setProperty(\"--\" + name, newValue || \"\");\n }\n }\n\n static define(options: WebComponentDefinitionOptions = {}) {\n super.define({ ...options, tag: options.tag || \"svg-icon\" });\n }\n}\n"],"names":["componentsMeta","registryToComponents","_WebComponent","meta","prop","value","props","attrs","name","camelCaseToKebabCase","call","force","cfg","propsInitialized","prev","options","tag","registry","noRedefinitionError","userCfg","nameInCamelCase","nameInKebabCase","WebComponent","proto","propsToPatchWithInit","descriptor","newDescriptor","v","methodsToPatchWithInit","method","orig","args","origDefine","ctor","rest","PROTECTED_SVG_ATTRS","EMPTY_SVG","_SvgImage","createStyle","styles","onUnmount","oldValue","newValue","oldSrc","src","onSrcUpdate","setAttr","setAttrs","SvgImage","CSS_PROPS","_SvgIcon","initSvgIcons","SVG_ICON_DEFAULT_COLOR_TRANSITION","SvgIcon"],"mappings":"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"}