UNPKG

@joist/element

Version:

Intelligently apply styles to WebComponents

114 lines 4.76 kB
import { metadataStore } from "./metadata.js"; export function element(opts) { return function elementDecorator(Base, ctx) { const meta = metadataStore.read(ctx.metadata); ctx.addInitializer(function () { if (opts?.tagName) { if (!customElements.get(opts.tagName)) { customElements.define(opts.tagName, this); } } }); const def = { [Base.name]: class extends Base { static observedAttributes = Array.from(meta.attrs.keys()); #abortController = null; constructor(...args) { super(...args); if (opts?.shadowDom) { if (!this.shadowRoot) { this.attachShadow(opts.shadowDomOpts ?? { mode: "open" }); } for (const res of opts.shadowDom) { res.apply(this); } } for (const cb of meta.onReady) { cb.call(this); } } attributeChangedCallback(name, oldValue, newValue) { const attr = meta.attrs.get(name); const cbs = meta.attrChanges.get(name); if (attr) { if (oldValue !== newValue) { const ogValue = attr.getPropValue.call(this); if (newValue === "") { attr.setPropValue.call(this, true); } else if (typeof ogValue === "number") { attr.setPropValue.call(this, Number(newValue)); } else { attr.setPropValue.call(this, newValue); } } if (cbs) { for (const cb of cbs) { cb.call(this, name, oldValue, newValue); } } if (attr.observe) { if (super.attributeChangedCallback) { super.attributeChangedCallback(name, oldValue, newValue); } } } } connectedCallback() { if (this.isConnected) { for (const { event, cb, selector } of meta.listeners) { const root = selector(this); if (root) { this.#abortController = new AbortController(); root.addEventListener(event, cb.bind(this), { signal: this.#abortController.signal, }); } else { throw new Error(`could not add listener to ${root}`); } } reflectAttributeValues(this, meta.attrs); if (super.connectedCallback) { super.connectedCallback(); } } } disconnectedCallback() { if (this.#abortController) { this.#abortController.abort(); this.#abortController = null; } if (super.disconnectedCallback) { super.disconnectedCallback(); } } }, }; return def[Base.name]; }; } function reflectAttributeValues(el, attrs) { for (const [attrName, { getPropValue, reflect }] of attrs) { if (reflect) { const value = getPropValue.call(el); if (value !== null && value !== undefined && value !== "") { if (typeof value === "boolean") { if (value === true) { if (!el.hasAttribute(attrName)) { el.setAttribute(attrName, ""); } } } else { const strValue = String(value); if (el.getAttribute(attrName) !== strValue) { el.setAttribute(attrName, strValue); } } } } } } //# sourceMappingURL=element.js.map