UNPKG

@tempots/dom

Version:

Fully-typed frontend framework alternative to React and Angular

1,634 lines 62.3 kB
import { createRenderable as Me, DisposalScope as Oe, withScope as Le, Value as $, makeProviderMark as ie, prop as B, easeOutQuad as Ie, guessInterpolate as He, Signal as j, createSelector as De } from "@tempots/core"; import { Computed as tr, DisposalScope as nr, ElementPosition as rr, KeyedPosition as sr, MemoryStore as ir, Prop as or, Signal as lr, Value as cr, accumulateSignal as ar, and as ur, animateSignal as dr, animateSignals as hr, bind as fr, chainEasing as pr, coalesce as mr, computed as gr, computedOf as yr, computedOfAsync as Tr, computedOfAsyncGenerator as vr, computedRecord as br, createRenderable as Sr, createSelector as xr, delaySignal as wr, distinctUntilChanged as Er, easeInBack as kr, easeInBounce as Ar, easeInCubic as Cr, easeInElastic as Pr, easeInExpo as Mr, easeInOutBack as Or, easeInOutBounce as Lr, easeInOutCubic as Ir, easeInOutElastic as Hr, easeInOutExpo as Dr, easeInOutQuad as Nr, easeInOutQuart as Rr, easeInOutSine as _r, easeInQuad as $r, easeInQuart as Br, easeInSine as Vr, easeOutBack as jr, easeOutBounce as Yr, easeOutCubic as Xr, easeOutElastic as Fr, easeOutExpo as Wr, easeOutQuad as Kr, easeOutQuart as Ur, easeOutSine as qr, effect as Gr, effectOf as Qr, endInterpolate as Jr, getCurrentScope as Zr, getParentScope as zr, getScopeStack as es, guessInterpolate as ts, interpolateDate as ns, interpolateNumber as rs, interpolateString as ss, joinSignals as is, linear as os, localStorageProp as ls, makeProviderMark as cs, merge as as, mirrorEasing as us, not as ds, notNil as hs, or as fs, popScope as ps, previousSignal as ms, prop as gs, propHistory as ys, pushScope as Ts, reverseEasing as vs, scopeStack as bs, scoped as Ss, sessionStorageProp as xs, signal as ws, slidingWindowSignal as Es, storedProp as ks, strictEquals as As, syncProp as Cs, throttleSignal as Ps, untracked as Ms, withScope as Os } from "@tempots/core"; import { ProviderNotFoundError as oe, createRenderKit as Ne } from "@tempots/render"; import { ProviderNotFoundError as Is, createRenderKit as Hs } from "@tempots/render"; const le = /* @__PURE__ */ Symbol("DOM_RENDERABLE"), y = (n) => Me(le, n), ce = /* @__PURE__ */ new Set([ "checked", "disabled", "hidden", "multiple", "readonly", "required", "autofocus" ]), ae = /* @__PURE__ */ new Set(["selected"]), ue = /* @__PURE__ */ new Set([ "rowSpan", "colSpan", "tabIndex", "valueAsNumber" ]), de = /* @__PURE__ */ new Set(["valueAsDate"]), he = { readonly: "readOnly" }, fe = /* @__PURE__ */ new Set([ "value", "textContent", "innerText", // ⚠️ XSS Warning: innerHTML and outerHTML can execute arbitrary scripts if set with untrusted input "innerHTML", "outerHTML", "className", "classList" ]), Re = (n, e) => { if (ae.has(n)) return (t) => { t == null || t !== !0 ? e.removeAttribute(n) : e.setAttribute(n, ""); }; if (ce.has(n)) { const t = he[n] || n; return (r) => { r == null ? e[t] = null : e[t] = !!r; }; } else return ue.has(n) ? (t) => { t == null ? e[n] = null : e[n] = Number(t); } : de.has(n) ? (t) => { t == null ? e[n] = null : e[n] = t; } : fe.has(n) ? (t) => { t == null ? e[n] = null : e[n] = String(t); } : (t) => { t == null ? e.removeAttribute(n) : e.setAttribute(n, t); }; }, _e = (n, e) => ae.has(n) ? () => e.hasAttribute(n) : ce.has(n) ? () => ( // eslint-disable-next-line @typescript-eslint/no-explicit-any !!e[he[n] || n] ) : ue.has(n) ? () => Number(e[n]) : de.has(n) ? () => e[n] : fe.has(n) ? () => String(e[n]) : () => e.getAttribute(n), V = (n) => { const e = n; e && e.onblur && (e.onblur = null), !(!n || n.ownerDocument === void 0) && n.parentNode && n.parentNode.removeChild(n); }, $e = (n) => pe(n) || me(n) ? n : n.parentElement, pe = (n) => n.nodeType === 1, me = (n) => n.nodeType === 11; class b { /** * Constructs a new `DOMContext` instance. * * @param document - The `Document` instance associated with this context. * @param element - The `Element` instance associated with this context. * @param reference - An optional `Node` instance that serves as a reference for this context. * @param providers - The `Providers` instance associated with this context. * @param isFirstLevel - A boolean value indicating whether this context is at the first level, meaning the outermost node in the generated DOM. */ constructor(e, t, r, s) { this.document = e, this.element = t, this.reference = r, this.providers = s; } /** * Creates a new `DOMContext` instance for the given `Element` and optional reference `Node`. * * @param element - The `HTMLElement` to create the `DOMContext` for. * @param ref - A reference `Node` to associate with the `DOMContext` or undefined . * @param providers - The providers to associate with the `DOMContext`. * @returns A new `DOMContext` instance. */ static of(e, t, r) { return new b(e.ownerDocument, e, t, r); } /** * Creates a new DOM element (eg: HTML or SVG) with the specified tag name and namespace. * * @param tagName - The tag name of the element to create. * @param namespace - The namespace URI to create the element in, or `undefined` to create a standard HTML element. * @returns The newly created element. */ createElement(e, t) { return t !== void 0 ? this.document.createElementNS(t, e) : this.document.createElement(e); } /** * Creates a new child element and appends it to the current element, returning a new context. * * This method creates a new DOM element with the specified tag name and namespace, * appends it to the current element, and returns a new DOMContext focused on the * newly created child element. This is the primary method for building DOM trees. * * @example * ```typescript * // Create HTML elements * const divCtx = ctx.makeChildElement('div', undefined) * const spanCtx = divCtx.makeChildElement('span', undefined) * * // Create SVG elements * const svgCtx = ctx.makeChildElement('svg', 'http://www.w3.org/2000/svg') * const circleCtx = svgCtx.makeChildElement('circle', 'http://www.w3.org/2000/svg') * ``` * * @param tagName - The tag name of the element to create (e.g., 'div', 'span', 'svg') * @param namespace - The namespace URI for the element, or undefined for HTML elements * @returns A new DOMContext focused on the newly created child element */ makeChildElement(e, t) { const r = this.createElement(e, t); return this.appendOrInsert(r), this.withElement(r); } /** * Creates a new text node with the specified text content. * @param text - The text content for the new text node. * @returns A new `Text` node with the specified text content. */ createText(e) { return this.document.createTextNode(e); } /** * Creates a new text node with the specified text content and appends it to the current element. * @param text - The text content for the new text node. Primitives are coerced to strings by the DOM. * @returns A new `DOMContext` with a reference to the new text node. */ makeChildText(e) { const t = this.createText(e); return this.appendOrInsert(t), this.withReference(t); } /** * Sets the text content of the current element. * @param text - The text content to set. Primitives are coerced to strings by the DOM. */ setText(e) { this.reference.nodeValue = e; } /** * Gets the text content of the current element or text node. * @returns The text content of the current element or text node. */ getText() { return this.reference?.nodeValue ?? this.element.textContent ?? ""; } /** * Creates a new `DOMContext` with a reference to a newly created Comment node. * The Comment node is appended or inserted to the current `DOMContext`. * The new `DOMContext` with the reference is returned. */ makeRef() { const e = this.document.createComment(""); return this.appendOrInsert(e), this.withReference(e); } /** * Creates a lightweight Comment marker node and appends/inserts it. * Used as boundary references for keyed list items and conditional renderables. */ makeMarker() { return this.makeRef(); } /** * Appends or inserts a child node to the element, depending on whether a reference node is provided. * * @param child - The child node to append or insert. */ appendOrInsert(e) { this.reference === void 0 ? this.element.appendChild(e) : this.element.insertBefore(e, this.reference); } /** * Creates a new `DOMContext` instance with the provided `element`. * @param element - The DOM element to use in the new `DOMContext` instance. * @returns A new `DOMContext` instance with the provided `element`. */ withElement(e) { return new b( e.ownerDocument ?? this.document, e, void 0, this.providers ); } /** * Creates a portal to render content in a different part of the DOM tree. * * Portals allow you to render child components into a DOM node that exists outside * the parent component's DOM hierarchy. This is useful for modals, tooltips, * dropdowns, and other UI elements that need to break out of their container's * styling or z-index context. * * @example * ```typescript * // Portal to a modal container * const modalCtx = ctx.makePortal('#modal-root') * const modal = modalCtx.makeChildElement('div', undefined) * * // Add modal content * modal.makeChildText('This renders in #modal-root') * ``` * * @example * ```typescript * // Portal to an existing element reference * const tooltipContainer = document.getElementById('tooltip-container')! * const tooltipCtx = ctx.makePortal(tooltipContainer) * * // Render tooltip content * const tooltip = tooltipCtx.makeChildElement('div', undefined) * tooltip.addClasses(['tooltip', 'tooltip-top']) * ``` * * @example * ```typescript * // Portal for dropdown menu * const dropdownCtx = ctx.makePortal('body') // Render at body level * const dropdown = dropdownCtx.makeChildElement('div', undefined) * dropdown.addClasses(['dropdown-menu']) * dropdown.setStyle('position', 'absolute') * dropdown.setStyle('top', '100px') * dropdown.setStyle('left', '50px') * ``` * * @param selector - CSS selector string or HTMLElement reference for the portal target * @returns A new DOMContext focused on the portal target element * @throws {Error} When the selector doesn't match any element in the document */ makePortal(e) { const t = typeof e == "string" ? this.document.querySelector(e) : e; if (t == null) throw new Error(`Cannot find element by selector for portal: ${e}`); return this.withElement(t); } /** * Creates a new `DOMContext` instance with the specified reference. * * @param reference - The optional `Node` to use as the reference for the new `DOMContext`. * @returns A new `DOMContext` instance with the specified reference. */ withReference(e) { return new b( this.document, this.element, e, this.providers ); } /** * Sets a provider for the given provider mark. * * @param mark - The provider mark to set the provider for. * @param value - The provider to set for the given mark. * @returns A new `DOMContext` instance with the specified provider. */ setProvider(e, t, r) { return new b(this.document, this.element, this.reference, { ...this.providers, [e]: [t, r] }); } /** * Retrieves a provider for the given provider mark. * * @param mark - The provider mark to retrieve the provider for. * @returns The provider for the given mark. * @throws Throws `ProviderNotFoundError` if the provider for the given mark is not found. */ getProvider(e) { if (this.providers[e] === void 0) throw new oe(e); const [t, r] = this.providers[e]; return { value: t, onUse: r }; } tryGetProvider(e) { if (this.providers[e] === void 0) return; const [t, r] = this.providers[e]; return { value: t, onUse: r }; } clear(e) { e && (this.reference !== void 0 ? V(this.reference) : V(this.element)); } /** * Adds classes to the element. * @param tokens - The class names to add. */ addClasses(e) { this.element.classList.add(...e); } /** * Removes classes from the element. * @param tokens - The class names to remove. */ removeClasses(e) { this.element.classList.remove(...e); } /** * Gets the classes of the element. * @returns The classes of the element. */ getClasses() { return Array.from(this.element.classList); } /** * Adds an event listener to the element. * @param event - The event to listen for. * @param listener - The listener to call when the event occurs. * @param options - The options for the event listener. * @returns A function to remove the event listener. */ on(e, t, r) { const s = (i) => t(i, this); return this.element.addEventListener(e, s, r), (i) => { i && this.element.removeEventListener(e, s, r); }; } /** * Returns `true` if the context is a browser DOM context. * @returns `true` if the context is a browser DOM context. * @deprecated Use `isBrowser()` instead. */ isBrowserDOM() { return !0; } /** * Returns `true` if the context is a browser context. * @returns `true` if the context is a browser context. */ isBrowser() { return !0; } /** * Returns `true` if the context is a headless DOM context. * @returns `true` if the context is a headless DOM context. */ isHeadlessDOM() { return !1; } /** * Returns `true` if the context is a headless context. * @returns `true` if the context is a headless context. */ isHeadless() { return !1; } /** * Sets the style of the element. * @param name - The name of the style to set. * @param value - The value of the style to set. */ setStyle(e, t) { e.startsWith("--") ? this.element.style.setProperty(e, t) : this.element.style[e] = t; } /** * Gets the style of the element. * @param name - The name of the style to get. * @returns The value of the style. */ getStyle(e) { return e.startsWith("--") ? this.element.style.getPropertyValue(e) : this.element.style[e]; } makeAccessors(e) { return { get: _e(e, this.element), set: Re(e, this.element) }; } getWindow() { return this.document.defaultView; } moveRangeBefore(e, t, r) { const s = e.reference, i = t.reference, o = r.reference, l = this.element; let c = s; for (; c !== null; ) { const d = c.nextSibling; if (l.insertBefore(c, o), c === i) break; c = d; } } removeRange(e, t) { const r = e.reference, s = t.reference, i = this.element; let o = r; for (; o !== null; ) { const l = o.nextSibling; if (i.removeChild(o), o === s) break; o = l; } } removeAllBefore(e) { const t = e.reference, r = this.element; if (!r.firstChild || r.firstChild === t) return; const s = this.document.createRange(); s.setStartBefore(r.firstChild), s.setEndBefore(t), s.deleteContents(); } _detachedParent = null; _detachedNext = null; detach() { const e = this.element; e.parentNode && (this._detachedParent = e.parentNode, this._detachedNext = e.nextSibling, e.remove()); } reattach() { this._detachedParent && (this._detachedParent.insertBefore(this.element, this._detachedNext), this._detachedParent = null, this._detachedNext = null); } } const I = (n, e, t) => { const r = new Oe(); t?.(r); const s = Le(r, () => n.render(e)); return (i = !0) => { r.dispose(), s(i); }; }, Vt = (n, e, { doc: t, clear: r, disposeWithParent: s = !0, providers: i = {}, onScope: o } = {}) => { const l = typeof e == "string" ? (t ?? document).querySelector(e) : e; if (l === null) throw new Be( `Cannot find element by selector for render: ${e}` ); r !== !1 && (t ?? l.ownerDocument) != null && (l.nodeType === 1 || l.nodeType === 11) && (l.innerHTML = ""); const c = $e(l), d = pe(l) || me(l) ? void 0 : l, f = b.of(c, d, i), h = I(n, f, o); let a; return s && l.parentElement != null && (a = new MutationObserver((u) => { u[0]?.removedNodes.forEach((p) => { p === l && (a?.disconnect(), h(l.nodeType !== 1)); }); }), a.observe(l.parentElement, { childList: !0, subtree: !1, attributes: !1 })), () => { a?.disconnect(), h(!0); }; }, jt = (n, { startUrl: e = "https://example.com", selector: t, providers: r = {} } = { selector: "body" }) => { const s = $.toSignal(e).deriveProp(), i = new ve(t, void 0), o = new k(i, void 0, { currentURL: s }, r); return { clear: I(n(), o), root: i, currentURL: s }; }; class Be extends Error { constructor(e) { super(e); } } const W = "data-tts-node", C = "data-tts-class", P = "data-tts-style", M = "data-tts-html", O = "data-tts-text", L = "data-tts-attrs"; class Yt { /** * Selects elements from the headless environment. * @param selector - The selector to select elements from. The supported selectors are CSS selectors whose complexity depends on the adapter implementation. * @returns An array of elements. */ select; /** * Gets the value of an attribute from an element. * @param el - The element to get the attribute from. * @param attr - The attribute to get the value from. * @returns The value of the attribute or null if the attribute is not set. */ getAttribute; /** * Sets the value of an attribute on an element. * @param el - The element to set the attribute on. * @param attr - The attribute to set the value of. * @param value - The value to set the attribute to. */ setAttribute; /** * Gets the class of an element. * @param el - The element to get the class from. * @returns The class of the element or an empty string if the class is not set. */ getClass; /** * Sets the class of an element. * @param el - The element to set the class on. * @param cls - The class to set. */ setClass; /** * Gets the styles of an element. * @param el - The element to get the styles from. * @returns The styles of the element. */ getStyles; /** * Sets the styles of an element. * @param el - The element to set the styles on. */ setStyles; /** * Appends HTML to an element. * @param el - The element to append the HTML to. * @param html - The HTML to append. */ appendHTML; /** * Gets the inner HTML of an element. * @param el - The element to get the inner HTML from. * @returns The inner HTML of the element or an empty string if the inner HTML is not set. */ getInnerHTML; /** * Sets the inner HTML of an element. * @param el - The element to set the inner HTML on. * @param html - The inner HTML to set. */ setInnerHTML; /** * Gets the inner text of an element. * @param el - The element to get the inner text from. * @returns The inner text of the element or an empty string if the inner text is not set. */ getInnerText; /** * Sets the inner text of an element. * @param el - The element to set the inner text on. * @param text - The inner text to set. */ setInnerText; constructor({ select: e, getAttribute: t, setAttribute: r, getClass: s, setClass: i, getStyles: o, setStyles: l, appendHTML: c, getInnerHTML: d, setInnerHTML: f, getInnerText: h, setInnerText: a }) { this.select = e, this.getAttribute = t, this.setAttribute = r, this.getClass = s, this.setClass = i, this.getStyles = o, this.setStyles = l, this.appendHTML = c, this.getInnerHTML = d, this.setInnerHTML = f, this.getInnerText = h, this.setInnerText = a; } /** * Sets the content of the root element from a HeadlessPortal. Generally this will be the same instance that is * returned by `runHeadless`. * * @param root - The HeadlessPortal containing the content to set. * @param setPlaceholders - Whether to set placeholders for the content. This allows you to restore the original content * when you render on the server and then hydrate on the client. */ setFromRoot = (e, t) => { e.getPortals().forEach((s) => { const i = typeof s.selector == "string" ? this.select(s.selector) : [s.selector]; for (const o of i) { if (o == null) throw new Error( `Cannot find element by selector for render: ${s.selector}` ); if (s.hasChildren() && this.appendHTML(o, s.contentToHTML(t)), s.hasInnerHTML()) { if (t) { const l = this.getInnerHTML(o); l != null && this.setAttribute(o, M, l); } this.setInnerHTML(o, s.getInnerHTML()); } if (s.hasInnerText()) { if (t) { const l = this.getInnerText(o); l != null && this.setAttribute(o, O, l); } this.setInnerText(o, s.getInnerText()); } if (s.hasClasses()) { if (t) { const l = this.getClass(o); l != null && this.setAttribute(o, C, l); } this.setClass(o, s.getClasses().join(" ")); } if (s.hasStyles()) { if (t) { const l = this.getStyles(o); Object.keys(l).length > 0 && this.setAttribute( o, P, JSON.stringify(l) ); } this.setStyles(o, s.getStyles()); } if (s.hasAttributes()) { const l = s.getAttributes(); if (t) { const c = []; l.forEach(([d]) => { const f = this.getAttribute(o, d); f != null && c.push([d, f]); }), c.length > 0 && this.setAttribute( o, L, JSON.stringify(Object.fromEntries(c)) ); } l.forEach(([c, d]) => { this.setAttribute(o, c, d); }); } } }); }; } const ge = (n) => JSON.parse(n.replace(/&quot;/g, '"')), Ve = (n) => { const e = n.getAttribute(C); n.removeAttribute(C), e != null && n.setAttribute("class", e); }, je = (n) => { const e = n.getAttribute(M); n.removeAttribute(M), e != null && (n.innerHTML = e); }, Ye = (n) => { const e = n.getAttribute(O); n.removeAttribute(O), e != null && (n.innerText = e); }, Xe = (n) => { const e = n.getAttribute(P); if (n.removeAttribute(P), e != null) { const t = ge(e), r = Object.entries(t); r.length > 0 && (n.style.cssText = r.map(([s, i]) => `${s}: ${i}`).join("; ")); } }, Fe = (n) => { const e = n.getAttribute(L); if (n.removeAttribute(L), e != null) { const t = ge(e); Object.entries(t).forEach(([r, s]) => { s == null ? n.removeAttribute(r) : n.setAttribute(r, s); }); } }, Xt = () => { const e = [ W, C, M, O, P, L ].map((r) => `[${r}]`).join(","); document.querySelectorAll(e).forEach((r) => { const s = r; if (s.hasAttribute(W)) { V(s); return; } s.hasAttribute(C) && Ve(s), s.hasAttribute(O) && Ye(s), s.hasAttribute(M) && je(s), s.hasAttribute(P) && Xe(s), s.hasAttribute(L) && Fe(s); }); }, We = "data-tempo-id", w = /* @__PURE__ */ Symbol("class"), E = /* @__PURE__ */ Symbol("style"), R = /* @__PURE__ */ Symbol("handler"), ye = () => Math.random().toString(36).substring(2, 15), Ke = (n) => n.replace(/<[^>]*>?/g, ""); class Te { constructor(e) { this.parent = e; } id = ye(); properties = {}; children = []; isElement() { return !0; } isText() { return !1; } getText() { return this.properties.innerText != null ? this.properties.innerText : this.properties.innerHTML != null ? Ke(this.properties.innerHTML) : this.children.map((e) => e.getText()).join(""); } removeChild(e) { const t = this.children.indexOf(e); t !== -1 && this.children.splice(t, 1); } remove() { if (this.parent != null) this.parent.removeChild(this); else throw new Error("Parent is undefined"); } getPortals() { const e = this.elements().flatMap((t) => t.isPortal() ? [t, ...t.getPortals()] : t.getPortals()); return this.isPortal() && e.unshift(this), e; } elements() { return this.children.filter((e) => e.isElement()); } hasInnerHTML() { return this.properties.innerHTML != null; } getInnerHTML() { return this.properties.innerHTML ?? ""; } getInnerText() { return this.properties.innerText ?? ""; } hasInnerText() { return this.properties.innerText != null; } hasChildren() { return this.children.length > 0; } hasClasses() { return this.properties[w] != null; } hasStyles() { return this.properties[E] != null; } hasAttributes() { return Object.keys(this.properties).length > 0; } hasHandlers() { return this.properties[R] != null; } hasRenderableProperties() { return this.hasClasses() || this.hasAttributes() || this.hasStyles(); } getById(e) { if (this.properties.id === e) return this; for (const t of this.elements()) { const r = t.getById(e); if (r != null) return r; } } trigger(e, t) { ((this.properties[R] ?? {})[e] ?? []).forEach((s) => s(t)); } click() { this.trigger("click", {}); } on(e, t, r, s) { const i = this.properties[R] ??= {}, o = s?.once ? (c) => { l(), t(c, r); } : (c) => t(c, r); i[e] = [...i[e] ?? [], o]; const l = () => { const c = i[e] ?? [], d = c.indexOf(o); d !== -1 && (c.splice(d, 1), c.length === 0 ? (delete i[e], Object.keys(i).length === 0 && delete this.properties[R]) : i[e] = c, s?.signal != null && s.signal.removeEventListener("abort", l)); }; return s?.signal != null && s.signal.addEventListener("abort", l), l; } addClasses(e) { if (e.length === 0) return; const t = this.properties[w] ??= [], r = new Set(t); for (const s of e) r.has(s) || (t.push(s), r.add(s)); } removeClasses(e) { if (e.length === 0) return; const t = this.properties[w] ??= [], r = new Set(e); let s = 0; for (let i = 0; i < t.length; i++) r.has(t[i]) || (t[s] = t[i], s++); t.length = s, t.length === 0 && delete this.properties[w]; } getClasses() { return this.properties[w] ?? []; } getAttributes() { return Object.entries(this.properties).filter( ([e]) => !["innerText", "innerHTML"].includes(e) ); } getVisibleAttributes() { return Reflect.ownKeys(this.properties).flatMap( (e) => e === w ? [["class", this.getClasses()]] : e === E ? [["style", this.getStyles()]] : typeof e == "string" ? [[e, String(this.properties[e])]] : [] ); } setStyle(e, t) { const r = this.properties[E] ??= {}; r[e] = t, t === "" && (delete r[e], Object.keys(r).length === 0 && delete this.properties[E]); } getStyle(e) { return this.properties[E]?.[e] ?? ""; } getStyles() { return this.properties[E] ?? {}; } makeAccessors(e) { const t = this.properties; return { get: () => t[e], set: (r) => t[e] = r }; } } const Ue = (n) => n.replace(/"/g, "&quot;"), qe = (n) => n.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;"); class Ge extends Te { constructor(e, t, r) { super(r), this.tagName = e, this.namespace = t; } isPortal() { return !1; } /** * Builds the attributes string for this element. * Returns an object containing the attributes string and any innerHTML value. */ buildAttributesString(e) { let t = null; const r = this.namespace ? ` xmlns="${this.namespace}"` : "", s = this.getVisibleAttributes().map(([o, l]) => o === "class" ? ` class="${l.join(" ")}"` : o === "style" ? typeof l == "string" ? ` style="${l}"` : ` style="${Object.entries(l).map(([c, d]) => `${c}: ${d};`).join(" ")}"` : Je.has(o) ? ` ${o}` : o === "innerHTML" ? (t = l, "") : o === "innerText" ? (t = qe(l), "") : ` ${o}="${Ue(l)}"`).join(""), i = e ? ` ${W} ${We}="${this.id}"` : ""; return { attrs: `${r}${s}${i}`, innerHTML: t }; } toHTML(e = !1) { const t = this.children.map((i) => i.toHTML()).join(""), { attrs: r, innerHTML: s } = this.buildAttributesString(e); return Z.has(this.tagName) && t === "" ? `<${this.tagName}${r} />` : `<${this.tagName}${r}>${s ?? t}</${this.tagName}>`; } /** * Generates HTML output as an async stream of string chunks. * Yields the opening tag, then each child's content, then the closing tag. * * @param options - Options for streaming output. * @yields String chunks of HTML content. */ async *toHTMLStream(e) { const t = e?.generatePlaceholders ?? !1, { attrs: r, innerHTML: s } = this.buildAttributesString(t); if (Z.has(this.tagName) && this.children.length === 0) { yield `<${this.tagName}${r} />`; return; } if (yield `<${this.tagName}${r}>`, s !== null) yield s; else for (const i of this.children) yield* i.toHTMLStream(e); yield `</${this.tagName}>`; } } class ve extends Te { constructor(e, t) { super(t), this.selector = e; } isPortal() { return !0; } toHTML() { return ""; } /** * Portals don't render inline - they render at their target selector. * This method yields nothing for the inline position. */ // eslint-disable-next-line require-yield async *toHTMLStream(e) { } contentToHTML(e = !1) { return this.children.map((t) => t.toHTML(e)).join(""); } /** * Streams the portal's content HTML. * Unlike toHTMLStream, this yields the actual content for rendering at the target location. * * @param options - Options for streaming output. * @yields String chunks of the portal's content. */ async *contentToHTMLStream(e) { for (const t of this.children) yield* t.toHTMLStream(e); } } class Qe { constructor(e) { this.text = e; } id = ye(); isElement() { return !1; } isText() { return !0; } getText() { return this.text; } toHTML() { return this.text; } /** * Streams the text content as a single chunk. * * @param options - Options (unused for text nodes, kept for API consistency). * @yields The text content. */ async *toHTMLStream(e) { yield this.text; } } class k { constructor(e, t, r, s) { this.element = e, this.reference = t, this.container = r, this.providers = s; } appendOrInsert(e) { if (this.reference != null) { const t = this.element.children.indexOf(this.reference); t >= 0 && this.element.children.splice(t, 0, e); } else this.element.children.push(e); } makeChildElement(e, t) { const r = new Ge(e, t, this.element); return this.appendOrInsert(r), new k( r, void 0, this.container, this.providers ); } makeChildText(e) { const t = new Qe(String(e)); return this.appendOrInsert(t), new k( this.element, t, this.container, this.providers ); } setText(e) { this.reference && this.reference.isText() && (this.reference.text = String(e)); } getText() { return this.reference?.getText() ?? this.element.getText(); } makeRef() { return this.makeChildText(""); } makeMarker() { return this.makeChildText(""); } makePortal(e) { const t = new ve(e, this.element); return this.appendOrInsert(t), new k( t, void 0, this.container, this.providers ); } /** * Sets a provider for the given provider mark. * * @param mark - The provider mark to set the provider for. * @param value - The provider to set for the given mark. * @returns A new `DOMContext` instance with the specified provider. */ setProvider(e, t, r) { return new k(this.element, this.reference, this.container, { ...this.providers, [e]: [t, r] }); } getProvider(e) { if (this.providers[e] === void 0) throw new oe(e); const [t, r] = this.providers[e]; return { value: t, onUse: r }; } tryGetProvider(e) { if (this.providers[e] === void 0) return; const [t, r] = this.providers[e]; return { value: t, onUse: r }; } clear(e) { e && (this.reference !== void 0 ? this.element.removeChild(this.reference) : this.element.remove()); } on(e, t) { return this.element.on(e, t, this); } addClasses(e) { this.element.addClasses(e); } removeClasses(e) { this.element.removeClasses(e); } getClasses() { return this.element.getClasses(); } isBrowserDOM() { return !1; } isBrowser() { return !1; } isHeadlessDOM() { return !0; } isHeadless() { return !0; } setStyle(e, t) { this.element.setStyle(e, t); } getStyle(e) { return this.element.getStyle(e); } makeAccessors(e) { return this.element.makeAccessors(e); } moveRangeBefore(e, t, r) { const s = e.reference, i = t.reference, o = r.reference, l = this.element.children, c = l.indexOf(s), f = l.indexOf(i) - c + 1, h = l.splice(c, f), a = l.indexOf(o); l.splice(a, 0, ...h); } removeRange(e, t) { const r = e.reference, s = t.reference, i = this.element.children, o = i.indexOf(r), c = i.indexOf(s) - o + 1; i.splice(o, c); } removeAllBefore(e) { const t = e.reference, r = this.element.children, s = r.indexOf(t); s > 0 && r.splice(0, s); } detach() { } reattach() { } } const Je = /* @__PURE__ */ new Set([ "checked", "disabled", "multiple", "readonly", "required", "selected" ]), Z = /* @__PURE__ */ new Set(["img", "br", "hr", "input", "link", "meta"]), Ze = () => ( /* c8 ignore next */ typeof window < "u" ? window : void 0 ); function ze() { const n = Ze(), e = n?.matchMedia("(prefers-reduced-motion: reduce)"), t = B(e?.matches ?? !1); if (e != null) { const r = (s) => t.set(s.matches); e.addEventListener("change", r), t.onDispose(() => e.removeEventListener("change", r)); } return t; } const Ft = { mark: ie("ReducedMotion"), create: () => { const n = ze(); return { value: n, dispose: () => n.dispose() }; } }; function U(n) { let e = null, t = null, r = !1; const s = (i) => { if (r) return; const o = e === null ? 0 : i - e; e = i, n(o), t = requestAnimationFrame(s); }; return t = requestAnimationFrame(s), { dispose: () => { r = !0, t !== null && cancelAnimationFrame(t); } }; } const Wt = (n) => y((e) => { const t = U(n); return (r) => { t.dispose(), e.clear(r); }; }); function Kt(n) { const e = n ?? (typeof document < "u" ? document : void 0); if (e == null) return !1; const t = e.activeElement; if (t == null) return !1; const r = t.tagName; return r === "INPUT" || r === "TEXTAREA" || r === "SELECT" || t.isContentEditable === !0; } function Ut(n, e) { const t = e?.duration ?? 300, r = e?.easing ?? Ie, s = e?.reducedMotion; let i = e?.interpolate; const o = B(n); let l = null, c = n, d = n, f = 0; const h = () => { l !== null && (l.dispose(), l = null); }; return { value: o, tweenTo: (p) => { if (h(), t <= 0 || s != null && s.get() === !0) { o.set(p); return; } c = o.get(), d = p, f = 0, i == null && (i = He(c)), l = U((m) => { f += m; const g = Math.min(f / t, 1), v = r(g); o.set(i(c, d, v)), g >= 1 && h(); }); }, cancel: h, dispose: () => { h(), o.dispose(); } }; } function z(n, e) { const t = n.clientX - e.clientX, r = n.clientY - e.clientY; return Math.hypot(t, r); } function ee(n, e) { return { x: (n.clientX + e.clientX) / 2, y: (n.clientY + e.clientY) / 2 }; } function et(n, e, t) { const r = t?.minScale ?? 0.1, s = t?.maxScale ?? 5; let i = 0, o = { x: 0, y: 0 }, l = { scale: 1, panX: 0, panY: 0 }; const c = (a) => Math.min(s, Math.max(r, a)); return { onTouchStart: (a) => { if (a.touches.length !== 2) return; a.preventDefault(); const u = a.touches[0], p = a.touches[1]; i = z(u, p), o = ee(u, p), l = n.get(); }, onTouchMove: (a) => { if (a.touches.length !== 2) return; a.preventDefault(); const u = a.touches[0], p = a.touches[1], m = z(u, p), g = ee(u, p), v = e(), F = m / i, q = c(l.scale * F), G = o.x - v.left, Q = o.y - v.top, ke = g.x - o.x, Ae = g.y - o.y, J = q / l.scale, Ce = G - (G - l.panX) * J + ke, Pe = Q - (Q - l.panY) * J + Ae; n.set({ scale: q, panX: Ce, panY: Pe }); }, onTouchEnd: () => { } }; } function tt(n, e) { const t = e?.friction ?? 0.95, r = e?.minVelocity ?? 0.5; let s = 0, i = 0, o = null, l = 0, c = 0; return { track: (h, a) => { const u = performance.now(); if (o !== null) { const p = (u - o) / 1e3; p > 0 && (l = (h - s) / p, c = (a - i) / p); } s = h, i = a, o = u; }, release: () => { let h = l, a = c; o = null, l = 0, c = 0; const u = U((p) => { const m = p / 1e3; if (h *= t, a *= t, Math.hypot(h, a) < r) { u.dispose(); return; } n(h * m, a * m); }); return u; } }; } function nt(n, e) { const t = [], r = e.createDocumentFragment(); return K(n, r, [], { count: 0 }, t, e) ? { fragment: r, slots: t, topNodeCount: r.childNodes.length } : null; } function K(n, e, t, r, s, i) { switch (n.kind) { case "element": { const { tag: o, ns: l, children: c } = n, d = l != null ? i.createElementNS(l, o) : i.createElement(o), f = [...t, r.count++]; let h = ""; for (let u = 0; u < c.length; u++) { const p = c[u]; p.kind === "static-attr" && (p.name === "class" ? h += (h ? " " : "") + p.value : d.setAttribute(p.name, p.value)); } h && d.setAttribute("class", h), e.appendChild(d); for (let u = 0; u < c.length; u++) c[u].kind === "dynamic-attr" && s.push({ path: f, kind: "dynamic-attr" }); const a = { count: 0 }; for (let u = 0; u < c.length; u++) { const p = c[u]; if (!(p.kind === "static-attr" || p.kind === "dynamic-attr") && !K(p, d, f, a, s, i)) return !1; } return !0; } case "static-text": return e.appendChild(i.createTextNode(n.text)), r.count++, !0; case "dynamic-text": return e.appendChild(i.createTextNode("")), s.push({ path: [...t, r.count++], kind: "dynamic-text" }), !0; case "fragment": { const { children: o } = n; for (let l = 0; l < o.length; l++) if (!K(o[l], e, t, r, s, i)) return !1; return !0; } case "empty": return !0; default: return n.kind === void 0 ? (e.appendChild(i.createComment("")), s.push({ path: [...t, r.count++], kind: "slot" }), !0) : !1; } } function rt(n, e) { let t = n; for (let r = 0; r < e.length; r++) t = t.childNodes[e[r]]; return t; } function st(n, e, t) { const r = e, s = n.fragment.cloneNode(!0), i = n.topNodeCount, o = new Array(i); let l = s.firstChild; for (let a = 0; a < i; a++) o[a] = l, l = l.nextSibling; const c = n.slots.length, d = new Array(c); for (let a = 0; a < c; a++) d[a] = rt(s, n.slots[a].path); r.appendOrInsert(s); const f = new Array(c); for (let a = 0; a < c; a++) { const u = n.slots[a], p = d[a]; if (u.kind === "dynamic-text") { const m = t[a], g = p; g.textContent = m.transform(m.source.value), f[a] = m.source.onChange((v) => { g.textContent = m.transform(v); }); } else if (u.kind === "dynamic-attr") { const m = t[a], g = new b( r.document, p, void 0, r.providers ); f[a] = m.render(g); } else { const m = t[a], g = p, v = new b( r.document, g.parentNode, g, r.providers ); f[a] = m.render(v), g.remove(); } } const h = new b( r.document, r.element, o[0], r.providers ); return { clear: (a) => { for (let u = 0; u < c; u++) f[u](a); if (a) for (let u = 0; u < i; u++) { const p = o[u]; p.parentNode && p.parentNode.removeChild(p); } }, startCtx: h }; } function it(n) { const e = []; function t(r) { switch (r.kind) { case "element": { const { tag: s, children: i } = r; e.push(`E:${s}`); for (const o of i) if (!t(o)) return !1; e.push("/E"); break; } case "static-attr": e.push(`SA:${r.name}=${r.value}`); break; case "dynamic-attr": e.push("DA"); break; case "static-text": e.push(`ST:${r.text}`); break; case "dynamic-text": e.push("DT"); break; case "fragment": { const { children: s } = r; for (const i of s) if (!t(i)) return !1; break; } case "empty": break; default: if (r.kind === void 0) { e.push("S"); break; } return !1; } return !0; } return t(n) ? e.join("|") : null; } function ot(n) { const e = []; function t(r) { switch (r.kind) { case "element": { const { children: s } = r; for (const i of s) if (i.kind !== "static-attr") { if (i.kind === "dynamic-attr") { e.push(i); continue; } t(i); } break; } case "fragment": { const { children: s } = r; for (const i of s) t(i); break; } case "static-text": case "empty": break; case "dynamic-text": e.push(r); break; default: r.kind === void 0 && e.push(r); break; } } return t(n), e; } const lt = { build(n, e) { if (!e.isBrowser()) return null; const t = n; if (t.kind === void 0) return null; const r = e.document; return nt(t, r); }, cloneAndHydrate(n, e, t) { return st(n, e, t); }, fingerprint(n) { return it(n); }, extractSlots(n) { return ot(n); } }, ct = Ne({ type: le, create: y, templateEngine: lt }), { Empty: at, Fragment: S, When: qt, Unless: Gt, ForEach: Qt, KeyedForEach: ut, Repeat: Jt, OneOf: Zt, OneOfField: zt, OneOfKind: en, OneOfType: tn, OneOfValue: nn, OneOfTuple: rn, MapSignal: sn, MapText: on, Ensure: ln, EnsureAll: cn, NotEmpty: an, Task: un, Async: dn, OnDispose: Y, Conjunction: hn, WithScope: dt, WithProvider: fn, Provide: pn, Use: mn, UseMany: gn, UseOptional: yn, Catch: Tn, handleValueOrSignal: vn, createReactiveRenderable: bn, renderableOfTNode: A } = ct, te = /* @__PURE__ */ new Map(); function ht(n) { let e = te.get(n); return e === void 0 && (e = n.split(" ").filter((t) => t.length > 0), te.set(n, e)), e; } const ft = (n) => { const e = y((t) => (t.addClasses(n), (r) => { r && t.removeClasses(n); })); return e.kind = "static-attr", e.name = "class", e.value = n.join(" "), e; }, pt = (n) => { const e = y((t) => { let r = []; const s = n.on( (i) => { const o = (i ?? "").split(" ").filter((l) => l.length > 0); r.length > 0 && t.removeClasses(r), o.length > 0 && t.addClasses(o), r = o; }, { noAutoDispose: !0 } ); return (i) => { s(), i && t.removeClasses(r), r = []; }; }); return e.kind = "dynamic-attr", e; }, mt = (n, e) => { const t = y((r) => { const { get: s, set: i } = r.makeAccessors(n), o = s(); return i(e), (l) => { l && i(o); }; }); return t.kind = "static-attr", t.name = n, t.value = String(e), t; }, gt = (n, e) => { const t = y((r) => { const { get: s, set: i } = r.makeAccessors(n), o = s(), l = e.on(i, { noAutoDispose: !0 }); return (c) => { l(), c && i(o); }; }); return t.kind = "dynamic-attr", t; }, H = (n, e) => j.is(e) ? gt(n, e) : mt(n, e), yt = (n, e) => n === "class" ? j.is(e) ? pt(e) : ft( /* c8 ignore next */ (e ?? "").split(" ").filter((t) => t.length > 0) ) : H(n, e), T = new Proxy( {}, { /** * Creates a renderable component for the specified attribute. * * Generally using multiple attributes with the same name is not recommended. * `class` is the exception and can be used multiple times. * * @param _ - The target object. * @param name - The name of the attribute. * @returns The renderable component for the specified attribute. * */ get: (n, e) => (t) => yt(e, t) } ), Tt = (n, e) => H(`data-${n}`, e), Sn = (n, e) => Tt(n, e), vt = (n, e) => H(`aria-${n}`, e), xn = new Proxy( {}, { /** * Creates a renderable component for the specified `aria-?` attribute. * * @param _ - The target object. * @param name - The name of the aria attribute. * @returns The renderable component for the specified attribute. * */ get: (n, e) => (t) => vt(e, t) } ), bt = (n, e) => H(n, e), wn = new Proxy( {}, { /** * Creates a renderable component for the specified `svg` attribute. * * @param _ - The target object. * @param name - The name of the SVG attribute. * @returns The renderable component for the specified attribute. * */ get: (n, e) => (t) => bt(e, t) } ), St = (n, e) => H(n, e), En = new Proxy( {}, { /** * Creates a renderable component for the specified `math` attribute. * * @param name - The name of the Math attribute. * @returns The renderable component for the specified attribute. * */ get: (n, e) => (t) => St(e, t) } ), ne = /* @__PURE__ */ new WeakMap(); function xt(n, e) { let t = ne.get(n); return t || (t = De(n, e), ne.set( n, t )), t; } const kn = (n, e, t = "danger", r) => { const s = ht(t), i = y((o) => { const d = xt(n, r)(e).on( (f) => { f ? o.addClasses(s) : o.removeClasses(s); }, { noAutoDispose: !0 } ); return (f) => { d(), f && o.removeClasses(s); }; }); return i.kind = "dynamic-attr", i; }, be = (n, e, t) => { const r = y( (s) => s.on(n, e, t) ); return r.kind = "dynamic-attr", r; }, Se = (n) => (e, t, r) => { const s = y((i) => { if (!i.isBrowser()) return () => { }; const o = i, l = o.element, c = n === "document" ? o.document : o.getWindow(); let d = !1; const f = (h) => { d || !l.isConnected || t(h, i); }; return c.addEventListener(e, f, r), () => { d = !0, c.removeEventListener(e, f, r); }; }); return s.kind = "dynamic-attr", s; }, wt = Se("document"), Et = Se("window"), kt = (n) => be("click", (e, t) => { e.preventDefault(); const r = e.target; setTimeout(() => { const s = r.ownerDocument != null ? r?.checked : void 0; s != null && n(!s, t); }, 0); }), re = (n) => new Proxy({}, { get: (e, t) => (r, s) => n(t, r, s) }), D = new Proxy( {}, { get: (n, e) => e === "document" ? re(wt) : e === "window" ? re(Et) : (t, r) => be(e, t, r) } ), At = (n, e) => (t) => { e?.preventDefault === !0 && t.preventDefault(), e?.stopPropagation === !0 && t.stopPropagation(), e?.stopImmediatePropagation === !0 && t.stopImmediatePropagation(), n(t); }, x = (n, e) => At((t) => { const r = t.target; n(r, t); }, e), Ct = (n, e) => x( (t, r) => n(t.value, r), e ), Pt = (n, e) => x( (t, r) => n(t.valueAsNumber, r), e ), Mt = (n, e) => x((t, r) => { if (t.value === "") return; const s = t.value.split("-"), i = new Date( Number(s[0]), Number(s[1]) - 1, Number(s[2].substring(0, 2)) ); n(i, r); }, e), An = (n, e) => x((t, r) => { if (t.value === "") { n(null, r); return; } const s = t.value.split("-"), i = new Date( Number(s[0]), Number(s[1]) - 1, Number(s[2].substring(0, 2)) ); n(i, r); }, e), Ot = (n, e) => x((t, r) => { if (t.value === "") return; const s = t.value.split("T"), i = s[0].split("-"), o = new Date( Number(i[0]), Number(i[1]) - 1, Number(i[2]) ), l = s[1].split(":"); o.setHours(Number(l[0])), o.setMinutes(Number(l[1])), o.setSeconds(Number(l[2])), n(o, r); }, e), Cn = (n, e) => x((t, r) => { if (t.value === "") { n(null, r); return; } const s = t.value.split("T"); if (s.length !== 2) { n(null, r); return; } const i = s[0].split("-"), o = new Date( Number(i[0]), Number(i[1]) - 1, Number(i[2]) ), l = s[1].split(":"); o.setHours(Number(l[0] ?? 0)), o.setMinutes(Number(l[1] ?? 0)), o.setSeconds(Number(l[2] ?? 0)), n(o, r); }, e), Pn = (n, e) => x((t, r) => { n(t.checked, r); }, e), Mn = (n, e = "input") => S( T.valueAsDate(n), D[e](Mt((t) => n.set(t))) ), On = (n, e = "input") => S( T.valueAsDate(n), D[e](Ot((t) => n.set(t))) ), Ln = (n, e = "input") => S( T.valueAsNumber(n), D[e](Pt((t) => n.set(t))) ), In = (n, e = "input") => S(T.value(n), D[e](Ct((t) => n.set(t)))), Hn = (n) => S( T.checked(n), kt((e) => n.set(e)) ), Lt = (n, e, t, r) => { const s = y((i) => { if (!i.isBrowser()) return () => { }; const o = i.element, l = (c) => { const d = c.target?.closest(e); d != null && o.contains(d) && t(c, i); }; return o.addEventListener(n, l, r), (c) => { c && o.removeEventListener(n, l, r); }; }); return s.kind = "dynamic-attr", s; }, Dn = new Proxy( {}, { get: (n, e) => (t, r, s) => Lt(e, t, r, s) } ), Nn = (n) => y((e) => (e.appendOrInsert(n), (t) => { t && V(n); })), xe = (n, ...e) => { const t = e.map(A), r = y((s) => { const i = s.makeChildElement(n, void 0), o = t.map((l) => l.render(i)); return (l) => {