@pyreon/runtime-dom 0.14.0 → 0.15.0
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/lib/analysis/index.js.html +1 -1
- package/lib/analysis/keep-alive-entry.js.html +1 -1
- package/lib/analysis/transition-entry.js.html +1 -1
- package/lib/index.js +62 -14
- package/lib/keep-alive-entry.js +5 -4
- package/lib/transition-entry.js +3 -2
- package/lib/types/index.d.ts +54 -5
- package/package.json +6 -5
- package/src/delegate.ts +16 -0
- package/src/hydrate.ts +9 -2
- package/src/hydration-debug.ts +99 -14
- package/src/index.ts +11 -3
- package/src/keep-alive.ts +5 -1
- package/src/mount.ts +1 -2
- package/src/nodes.ts +1 -2
- package/src/props.ts +1 -2
- package/src/template.ts +46 -2
- package/src/tests/dev-gate-pattern.test.ts +17 -11
- package/src/tests/dev-gate-treeshake.test.ts +20 -26
- package/src/tests/hydration-integration.test.tsx +166 -1
- package/src/tests/mount.test.ts +91 -0
- package/src/tests/native-markers.test.ts +19 -0
- package/src/tests/runtime-dom.browser.test.ts +58 -6
- package/src/tests/show-context.test.ts +93 -0
- package/src/tests/template.test.ts +71 -1
- package/src/transition-group.ts +6 -1
- package/src/transition.ts +11 -3
- package/lib/index.js.map +0 -1
- package/lib/keep-alive-entry.js.map +0 -1
- package/lib/transition-entry.js.map +0 -1
- package/lib/types/index.d.ts.map +0 -1
- package/lib/types/keep-alive-entry.d.ts.map +0 -1
- package/lib/types/transition-entry.d.ts.map +0 -1
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"keep-alive-entry.js","names":["__DEV__","_countSink","__DEV__"],"sources":["../src/devtools.ts","../src/nodes.ts","../src/delegate.ts","../src/props.ts","../src/mount.ts","../src/keep-alive.ts"],"sourcesContent":["/**\n * Pyreon DevTools — exposes a `__PYREON_DEVTOOLS__` global hook for browser devtools extensions\n * and in-app debugging utilities.\n *\n * Installed automatically on first `mount()` call in the browser.\n * No-op on the server (typeof window === \"undefined\").\n *\n * Usage:\n * window.__PYREON_DEVTOOLS__.getComponentTree() // root component entries\n * window.__PYREON_DEVTOOLS__.getAllComponents() // flat list of all live components\n * window.__PYREON_DEVTOOLS__.highlight(\"comp-id\") // outline a component's DOM node\n * window.__PYREON_DEVTOOLS__.onComponentMount(cb) // subscribe to mount events\n * window.__PYREON_DEVTOOLS__.onComponentUnmount(cb)// subscribe to unmount events\n * window.__PYREON_DEVTOOLS__.enableOverlay() // Ctrl+Shift+P: hover to inspect components\n */\n\nexport interface DevtoolsComponentEntry {\n id: string\n name: string\n /** First DOM element produced by this component, if any */\n el: Element | null\n parentId: string | null\n childIds: string[]\n}\n\nexport interface PyreonDevtools {\n readonly version: string\n getComponentTree(): DevtoolsComponentEntry[]\n getAllComponents(): DevtoolsComponentEntry[]\n highlight(id: string): void\n onComponentMount(cb: (entry: DevtoolsComponentEntry) => void): () => void\n onComponentUnmount(cb: (id: string) => void): () => void\n /** Toggle the component inspector overlay (also: Ctrl+Shift+P) */\n enableOverlay(): void\n disableOverlay(): void\n}\n\n// ─── Internal registry ────────────────────────────────────────────────────────\n\nconst _components = new Map<string, DevtoolsComponentEntry>()\nconst _mountListeners: ((entry: DevtoolsComponentEntry) => void)[] = []\nconst _unmountListeners: ((id: string) => void)[] = []\n\nexport function registerComponent(\n id: string,\n name: string,\n el: Element | null,\n parentId: string | null,\n): void {\n const entry: DevtoolsComponentEntry = { id, name, el, parentId, childIds: [] }\n _components.set(id, entry)\n if (parentId) {\n const parent = _components.get(parentId)\n if (parent) parent.childIds.push(id)\n }\n for (const cb of _mountListeners) cb(entry)\n}\n\nexport function unregisterComponent(id: string): void {\n const entry = _components.get(id)\n if (!entry) return\n if (entry.parentId) {\n const parent = _components.get(entry.parentId)\n if (parent) parent.childIds = parent.childIds.filter((c) => c !== id)\n }\n _components.delete(id)\n for (const cb of _unmountListeners) cb(id)\n}\n\n// ─── Component Inspector Overlay ─────────────────────────────────────────────\n\nlet _overlayActive = false\nlet _overlayEl: HTMLDivElement | null = null\nlet _tooltipEl: HTMLDivElement | null = null\nlet _currentHighlight: Element | null = null\n\nfunction findComponentForElement(el: Element): DevtoolsComponentEntry | null {\n // Walk up from the hovered element to find the nearest registered component\n let node: Element | null = el\n while (node) {\n for (const entry of _components.values()) {\n if (entry.el === node) return entry\n }\n node = node.parentElement\n }\n return null\n}\n\nfunction createOverlayElements(): void {\n if (_overlayEl) return\n\n _overlayEl = document.createElement('div')\n _overlayEl.id = '__pyreon-overlay'\n _overlayEl.style.cssText =\n 'position:fixed;pointer-events:none;border:2px solid #00b4d8;border-radius:3px;z-index:999999;display:none;transition:all 0.08s ease-out;'\n\n _tooltipEl = document.createElement('div')\n _tooltipEl.style.cssText =\n 'position:fixed;pointer-events:none;background:#1a1a2e;color:#e0e0e0;font:12px/1.4 ui-monospace,monospace;padding:6px 10px;border-radius:4px;z-index:999999;display:none;box-shadow:0 2px 8px rgba(0,0,0,0.3);max-width:400px;white-space:pre-wrap;'\n\n document.body.appendChild(_overlayEl)\n document.body.appendChild(_tooltipEl)\n}\n\nfunction positionOverlay(rect: DOMRect): void {\n if (!_overlayEl) return\n _overlayEl.style.display = 'block'\n _overlayEl.style.top = `${rect.top}px`\n _overlayEl.style.left = `${rect.left}px`\n _overlayEl.style.width = `${rect.width}px`\n _overlayEl.style.height = `${rect.height}px`\n}\n\nfunction positionTooltip(entry: DevtoolsComponentEntry, rect: DOMRect): void {\n if (!_tooltipEl) return\n const childCount = entry.childIds.length\n let info = `<${entry.name}>`\n if (childCount > 0) info += `\\n ${childCount} child component${childCount === 1 ? '' : 's'}`\n _tooltipEl.textContent = info\n _tooltipEl.style.display = 'block'\n _tooltipEl.style.top = `${rect.top - 30}px`\n _tooltipEl.style.left = `${rect.left}px`\n if (rect.top < 35) {\n _tooltipEl.style.top = `${rect.bottom + 4}px`\n }\n}\n\nfunction hideOverlayElements(): void {\n if (_overlayEl) _overlayEl.style.display = 'none'\n if (_tooltipEl) _tooltipEl.style.display = 'none'\n _currentHighlight = null\n}\n\n/** @internal — exported for testing only */\nexport function onOverlayMouseMove(e: MouseEvent): void {\n const target = document.elementFromPoint(e.clientX, e.clientY)\n if (!target || target === _overlayEl || target === _tooltipEl) return\n\n const entry = findComponentForElement(target)\n if (!entry?.el) {\n hideOverlayElements()\n return\n }\n\n if (entry.el === _currentHighlight) return\n _currentHighlight = entry.el\n\n const rect = entry.el.getBoundingClientRect()\n positionOverlay(rect)\n positionTooltip(entry, rect)\n}\n\n/** @internal — exported for testing only */\nexport function onOverlayClick(e: MouseEvent): void {\n e.preventDefault()\n e.stopPropagation()\n const target = document.elementFromPoint(e.clientX, e.clientY)\n if (!target) return\n const entry = findComponentForElement(target)\n if (entry) {\n console.group(`[Pyreon] <${entry.name}>`)\n console.log('element:', entry.el)\n console.log('children:', entry.childIds.length)\n if (entry.parentId) {\n const parent = _components.get(entry.parentId)\n if (parent) {\n console.log('parent:', `<${parent.name}>`)\n }\n }\n console.groupEnd()\n }\n disableOverlay()\n}\n\nfunction onOverlayKeydown(e: KeyboardEvent): void {\n if (e.key === 'Escape') {\n disableOverlay()\n }\n}\n\nfunction enableOverlay(): void {\n if (_overlayActive) return\n _overlayActive = true\n createOverlayElements()\n document.addEventListener('mousemove', onOverlayMouseMove, true)\n document.addEventListener('click', onOverlayClick, true)\n document.addEventListener('keydown', onOverlayKeydown, true)\n document.body.style.cursor = 'crosshair'\n}\n\nfunction disableOverlay(): void {\n if (!_overlayActive) return\n _overlayActive = false\n document.removeEventListener('mousemove', onOverlayMouseMove, true)\n document.removeEventListener('click', onOverlayClick, true)\n document.removeEventListener('keydown', onOverlayKeydown, true)\n document.body.style.cursor = ''\n if (_overlayEl) _overlayEl.style.display = 'none'\n if (_tooltipEl) _tooltipEl.style.display = 'none'\n _currentHighlight = null\n}\n\n// ─── Installation ─────────────────────────────────────────────────────────────\n\nlet _installed = false\n// Resolved once at module load — avoids per-call typeof branch in coverage\nconst _hasWindow = typeof window !== 'undefined'\n\nexport function installDevTools(): void {\n if (!_hasWindow || _installed) return\n _installed = true\n\n const devtools: PyreonDevtools = {\n version: '0.1.0',\n\n getComponentTree() {\n return Array.from(_components.values()).filter((e) => e.parentId === null)\n },\n\n getAllComponents() {\n return Array.from(_components.values())\n },\n\n highlight(id: string) {\n const entry = _components.get(id)\n if (!entry?.el) return\n const el = entry.el as HTMLElement\n const prev = el.style.outline\n el.style.outline = '2px solid #00b4d8'\n setTimeout(() => {\n el.style.outline = prev\n }, 1500)\n },\n\n onComponentMount(cb: (entry: DevtoolsComponentEntry) => void): () => void {\n _mountListeners.push(cb)\n return () => {\n const i = _mountListeners.indexOf(cb)\n if (i >= 0) _mountListeners.splice(i, 1)\n }\n },\n\n onComponentUnmount(cb: (id: string) => void): () => void {\n _unmountListeners.push(cb)\n return () => {\n const i = _unmountListeners.indexOf(cb)\n if (i >= 0) _unmountListeners.splice(i, 1)\n }\n },\n\n enableOverlay,\n disableOverlay,\n }\n\n // Attach to window — compatible with browser devtools extensions\n ;(window as unknown as Record<string, unknown>).__PYREON_DEVTOOLS__ = devtools\n\n // Ctrl+Shift+P toggles the component inspector overlay\n window.addEventListener('keydown', (e) => {\n if (e.ctrlKey && e.shiftKey && e.key === 'P') {\n e.preventDefault()\n if (_overlayActive) disableOverlay()\n else enableOverlay()\n }\n })\n\n // ── $p console helper ────────────────────────────────────────────────────\n // Type `$p` in the browser console for quick access to Pyreon debug tools.\n const win = window as unknown as Record<string, unknown>\n win.$p = {\n /** List all mounted components */\n components: () => devtools.getAllComponents(),\n /** Component tree (roots only) */\n tree: () => devtools.getComponentTree(),\n /** Highlight a component by id */\n highlight: (id: string) => devtools.highlight(id),\n /** Toggle component inspector overlay */\n inspect: () => {\n if (_overlayActive) disableOverlay()\n else enableOverlay()\n },\n /** Print component count */\n stats: () => {\n const all = devtools.getAllComponents()\n const roots = devtools.getComponentTree()\n console.log(\n `[Pyreon] ${all.length} component${all.length === 1 ? '' : 's'}, ${roots.length} root${roots.length === 1 ? '' : 's'}`,\n )\n return { total: all.length, roots: roots.length }\n },\n /** Quick help */\n help: () => {\n console.log(\n '[Pyreon] $p commands:\\n' +\n ' $p.components() — list all mounted components\\n' +\n ' $p.tree() — component tree (roots only)\\n' +\n ' $p.highlight(id)— outline a component\\n' +\n ' $p.inspect() — toggle component inspector\\n' +\n ' $p.stats() — print component count\\n' +\n ' $p.help() — this message',\n )\n },\n }\n}\n","import type { VNode, VNodeChild } from '@pyreon/core'\nimport { captureContextStack, restoreContextStack } from '@pyreon/core'\n\ntype MountFn = (child: VNodeChild, parent: Node, anchor: Node | null) => Cleanup\n\nimport { effect, runUntracked } from '@pyreon/reactivity'\n\n// Dev-mode gate: see `pyreon/no-process-dev-gate` lint rule for why this\n// uses `import.meta.env.DEV` instead of `typeof process !== 'undefined'`.\n// @ts-ignore — `import.meta.env.DEV` is provided by Vite/Rolldown at build time\nconst __DEV__ = import.meta.env?.DEV === true\n\n// Dev-time counter sink — see packages/internals/perf-harness for contract.\nconst _countSink = globalThis as { __pyreon_count__?: (name: string, n?: number) => void }\n\ntype Cleanup = () => void\n\n/**\n * Move all nodes strictly between `start` and `end` into a throwaway\n * DocumentFragment, detaching them from the live DOM in O(n) top-level moves.\n *\n * This is dramatically faster than Range.deleteContents() in JS-based DOMs\n * (happy-dom, jsdom) where deleting connected nodes with deep subtrees is O(n²).\n * In real browsers both approaches are similar, but the fragment approach is\n * never slower and avoids the pathological case.\n *\n * After this call every moved node has isConnected=false, so cleanup functions\n * that guard removeChild with `isConnected !== false` become no-ops.\n */\nfunction clearBetween(start: Node, end: Node): void {\n const frag = document.createDocumentFragment()\n let cur: Node | null = start.nextSibling\n while (cur && cur !== end) {\n const next: Node | null = cur.nextSibling\n frag.appendChild(cur)\n cur = next\n }\n // frag goes out of scope → nodes are GC-eligible\n}\n\n/**\n * Mount a reactive node whose content changes over time.\n *\n * A comment node is used as a stable anchor point in the DOM.\n * On each change: old nodes are removed, new ones inserted before the anchor.\n */\nexport function mountReactive(\n accessor: () => VNodeChild,\n parent: Node,\n anchor: Node | null,\n mount: (child: VNodeChild, p: Node, a: Node | null) => Cleanup,\n): Cleanup {\n const marker = document.createComment('pyreon')\n parent.insertBefore(marker, anchor)\n\n // Capture the context stack at creation time — ancestor provide() calls\n // have already run, so this snapshot contains all parent contexts.\n // When the effect re-mounts children later (e.g. Show toggling on),\n // we restore this snapshot so children see ancestor providers.\n const contextSnapshot = captureContextStack()\n\n let currentCleanup: Cleanup = () => {\n /* noop */\n }\n let generation = 0\n\n const e = effect(() => {\n const myGen = ++generation\n // Run cleanup outside tracking context — cleanup may write to signals\n // (e.g. onUnmount hooks), and those writes must not accidentally register\n // as dependencies of this effect, which would cause infinite recursion.\n runUntracked(() => currentCleanup())\n currentCleanup = () => {\n /* noop */\n }\n const value = accessor()\n // Note: typeof value === 'function' is a VALID return from a reactive\n // accessor — it represents a nested `() => VNodeChild` accessor (the\n // conditional rendering pattern: `{() => show() ? <A /> : null}`).\n // mountChild handles function children by calling them reactively.\n // Do NOT warn on function returns — they are handled correctly at\n // runtime by mountChild's function branch (line 58 above).\n if (value != null && value !== false) {\n // Mount children UNTRACKED — signal reads during child component\n // setup (useContext, useTheme, etc.) must NOT subscribe this\n // mountReactive effect. Otherwise, any signal read during the\n // entire child tree's setup becomes a dependency, causing full\n // DOM teardown + remount on that signal's change.\n //\n // Child components set up their OWN effects for reactivity\n // (e.g. DynamicStyled's class swap effect). Those effects track\n // their own dependencies independently.\n const cleanup = runUntracked(() =>\n restoreContextStack(contextSnapshot, () => mount(value, parent, marker)),\n )\n // Guard: a re-entrant signal update (e.g. ErrorBoundary catching a child\n // throw) may have already re-run this effect and updated currentCleanup.\n // In that case, discard our stale cleanup rather than overwriting the one\n // set by the re-entrant run.\n if (myGen === generation) {\n currentCleanup = cleanup\n } else {\n cleanup()\n }\n }\n })\n\n return () => {\n e.dispose()\n currentCleanup()\n marker.parentNode?.removeChild(marker)\n }\n}\n\n// ─── Keyed list reconciler ────────────────────────────────────────────────────\n\n/**\n * Efficient keyed list reconciler.\n *\n * When a reactive accessor returns VNode[] where every vnode carries a key,\n * this reconciler reuses, moves, and creates DOM nodes surgically instead of\n * tearing down and rebuilding the full list on every signal update.\n */\n\ninterface KeyedEntry {\n /** Comment node placed immediately before this entry's DOM content. */\n anchor: Comment\n cleanup: Cleanup\n}\n\n// WeakSets to identify anchor nodes belonging to list entries.\n// Entries use their first DOM node as anchor (element for simple vnodes, comment fallback for empty).\nconst _keyedAnchors = new WeakSet<Node>()\n\n/** LIS-based reorder state — shared across keyed list instances, grown as needed */\ninterface LisState {\n tails: Int32Array\n tailIdx: Int32Array\n pred: Int32Array\n stay: Uint8Array\n}\n\nfunction growLisArrays(lis: LisState, n: number): LisState {\n if (n <= lis.pred.length) return lis\n return {\n tails: new Int32Array(n + 16),\n tailIdx: new Int32Array(n + 16),\n pred: new Int32Array(n + 16),\n stay: new Uint8Array(n + 16),\n }\n}\n\nfunction computeKeyedLis(\n lis: LisState,\n n: number,\n newKeyOrder: (string | number)[],\n curPos: Map<string | number, number>,\n): number {\n const { tails, tailIdx, pred } = lis\n let lisLen = 0\n let ops = 0\n for (let i = 0; i < n; i++) {\n const key = newKeyOrder[i]\n if (key === undefined) continue\n const v = curPos.get(key) ?? -1\n if (v < 0) continue\n\n let lo = 0\n let hi = lisLen\n while (lo < hi) {\n const mid = (lo + hi) >> 1\n ops++\n if ((tails[mid] as number) < v) lo = mid + 1\n else hi = mid\n }\n tails[lo] = v\n tailIdx[lo] = i\n if (lo > 0) pred[i] = tailIdx[lo - 1] as number\n if (lo === lisLen) lisLen++\n }\n if (__DEV__ && ops > 0) _countSink.__pyreon_count__?.('runtime.mountFor.lisOps', ops)\n return lisLen\n}\n\nfunction markStayingEntries(lis: LisState, lisLen: number): void {\n const { tailIdx, pred, stay } = lis\n let cur: number = lisLen > 0 ? (tailIdx[lisLen - 1] as number) : -1\n while (cur !== -1) {\n stay[cur] = 1\n cur = pred[cur] as number\n }\n}\n\nfunction applyKeyedMoves(\n n: number,\n newKeyOrder: (string | number)[],\n stay: Uint8Array,\n cache: Map<string | number, KeyedEntry>,\n parent: Node,\n tailMarker: Comment,\n): void {\n let cursor: Node = tailMarker\n for (let i = n - 1; i >= 0; i--) {\n const key = newKeyOrder[i]\n if (key === undefined) continue\n const entry = cache.get(key)\n if (!entry) continue\n if (!stay[i]) moveEntryBefore(parent, entry.anchor, cursor)\n cursor = entry.anchor\n }\n}\n\n/** Grow LIS typed arrays if needed, then compute and apply reorder. */\nfunction keyedListReorder(\n lis: LisState,\n n: number,\n newKeyOrder: (string | number)[],\n curPos: Map<string | number, number>,\n cache: Map<string | number, KeyedEntry>,\n parent: Node,\n tailMarker: Comment,\n): LisState {\n const grown = growLisArrays(lis, n)\n grown.pred.fill(-1, 0, n)\n grown.stay.fill(0, 0, n)\n\n const lisLen = computeKeyedLis(grown, n, newKeyOrder, curPos)\n markStayingEntries(grown, lisLen)\n applyKeyedMoves(n, newKeyOrder, grown.stay, cache, parent, tailMarker)\n\n return grown\n}\n\nexport function mountKeyedList(\n accessor: () => VNode[],\n parent: Node,\n listAnchor: Node | null,\n mountVNode: (vnode: VNode, p: Node, a: Node | null) => Cleanup,\n): Cleanup {\n const startMarker = document.createComment('')\n const tailMarker = document.createComment('')\n parent.insertBefore(startMarker, listAnchor)\n parent.insertBefore(tailMarker, listAnchor)\n\n const cache = new Map<string | number, KeyedEntry>()\n const curPos = new Map<string | number, number>()\n let currentKeyOrder: (string | number)[] = []\n\n let lis: LisState = {\n tails: new Int32Array(16),\n tailIdx: new Int32Array(16),\n pred: new Int32Array(16),\n stay: new Uint8Array(16),\n }\n\n const collectKeyOrder = (\n newList: VNode[],\n ): { newKeyOrder: (string | number)[]; newKeySet: Set<string | number> } => {\n const newKeyOrder: (string | number)[] = []\n const newKeySet = new Set<string | number>()\n for (const vnode of newList) {\n const key = vnode.key\n if (key !== null && key !== undefined) {\n newKeyOrder.push(key)\n newKeySet.add(key)\n }\n }\n return { newKeyOrder, newKeySet }\n }\n\n const removeStaleEntries = (newKeySet: Set<string | number>) => {\n for (const [key, entry] of cache) {\n if (newKeySet.has(key)) continue\n entry.cleanup()\n entry.anchor.parentNode?.removeChild(entry.anchor)\n cache.delete(key)\n curPos.delete(key)\n }\n }\n\n const mountNewEntries = (newList: VNode[]) => {\n for (const vnode of newList) {\n const key = vnode.key\n if (key === null || key === undefined) continue\n if (cache.has(key)) continue\n const anchor = document.createComment('')\n _keyedAnchors.add(anchor)\n parent.insertBefore(anchor, tailMarker)\n const cleanup = mountVNode(vnode, parent, tailMarker)\n cache.set(key, { anchor, cleanup })\n }\n }\n\n const e = effect(() => {\n const newList = accessor()\n const n = newList.length\n\n if (n === 0 && cache.size > 0) {\n for (const entry of cache.values()) entry.cleanup()\n cache.clear()\n curPos.clear()\n currentKeyOrder = []\n clearBetween(startMarker, tailMarker)\n return\n }\n\n const { newKeyOrder, newKeySet } = collectKeyOrder(newList)\n removeStaleEntries(newKeySet)\n mountNewEntries(newList)\n\n if (currentKeyOrder.length > 0 && n > 0) {\n lis = keyedListReorder(lis, n, newKeyOrder, curPos, cache, parent, tailMarker)\n }\n\n curPos.clear()\n for (let i = 0; i < newKeyOrder.length; i++) {\n const k = newKeyOrder[i]\n if (k !== undefined) curPos.set(k, i)\n }\n currentKeyOrder = newKeyOrder\n })\n\n return () => {\n e.dispose()\n for (const entry of cache.values()) {\n entry.cleanup()\n entry.anchor.parentNode?.removeChild(entry.anchor)\n }\n cache.clear()\n startMarker.parentNode?.removeChild(startMarker)\n tailMarker.parentNode?.removeChild(tailMarker)\n }\n}\n\n// ─── For — source-aware keyed reconciler ─────────────────────────────────────\n\n/** Maximum number of displaced positions before falling back to full LIS. */\nconst SMALL_K = 8\n\n// WeakSet to identify anchor nodes belonging to mountFor entries.\nconst _forAnchors = new WeakSet<Node>()\n\n// anchor is the first DOM node of the entry (element for normal vnodes, comment fallback for empty).\n// Using the element itself saves 1 createComment + 1 DOM node per entry.\n// pos is merged here (instead of a separate Map) to halve Map operations.\n// cleanup is null when the entry has no teardown work (saves function call overhead on clear).\ninterface ForEntry {\n anchor: Node\n cleanup: Cleanup | null\n pos: number\n}\n\n/** Try small-k reorder; returns true if handled, false if LIS fallback needed. */\nfunction trySmallKReorder(\n n: number,\n newKeys: (string | number)[],\n currentKeys: (string | number)[],\n cache: Map<string | number, ForEntry>,\n liveParent: Node,\n tailMarker: Comment,\n): boolean {\n if (n !== currentKeys.length) return false\n const diffs: number[] = []\n for (let i = 0; i < n; i++) {\n if (newKeys[i] !== currentKeys[i]) {\n diffs.push(i)\n if (diffs.length > SMALL_K) return false\n }\n }\n if (diffs.length > 0) smallKPlace(liveParent, diffs, newKeys, cache, tailMarker)\n for (const i of diffs) {\n const cached = cache.get(newKeys[i] as string | number)\n if (cached) cached.pos = i\n }\n return true\n}\n\nfunction computeForLis(\n lis: LisState,\n n: number,\n newKeys: (string | number)[],\n cache: Map<string | number, ForEntry>,\n): number {\n const { tails, tailIdx, pred } = lis\n let lisLen = 0\n let ops = 0\n // Two-tier fast path.\n //\n // Tier 1 — \"extend LIS\": if v > the current tail-of-tails, v becomes the\n // new tail. O(1). Covers APPEND: positions [0..N-1] are strictly\n // increasing → the whole sequence is the LIS, 0 probes.\n //\n // Tier 2 — \"known slot\": if v ≤ lastV but tails[v] === v already, the\n // binary-search answer is provably lo = v (strict-increase invariant\n // guarantees tails[v-1] < v, so v slots exactly at index v). O(1) too.\n // Covers PREPEND: [new N rows, old M rows] produces positions [0..N-1,\n // 0..M-1] — the second monotonic run replaces tails[0..M-1] at indices\n // N..N+M-1 with zero probes each. Before this tier, 1k prepend was ~10k\n // probes; with it, 0.\n //\n // Tier 3 — binary search fallback. Random shuffles and other mixed\n // reorders pay the standard log₂(lisLen) per index.\n //\n // Safety: the `v < lisLen && tails[v] === v` check is a strict subset of\n // \"binary-search would return v\", so it never produces a wrong answer on\n // shufles — it just opportunistically avoids probing when the answer\n // happens to be the index itself. No behaviour change, only fewer probes.\n let lastV = -1\n for (let i = 0; i < n; i++) {\n const key = newKeys[i] as string | number\n const v = cache.get(key)?.pos ?? 0\n // Tier 1: extend LIS.\n if (v > lastV) {\n tails[lisLen] = v\n tailIdx[lisLen] = i\n if (lisLen > 0) pred[i] = tailIdx[lisLen - 1] as number\n lisLen++\n lastV = v\n continue\n }\n // Tier 2: known slot for piecewise-monotonic patterns (prepend, etc.).\n let lo: number\n if (v < lisLen && (tails[v] as number) === v) {\n lo = v\n } else {\n // Tier 3: binary search.\n lo = 0\n let hi = lisLen\n while (lo < hi) {\n const mid = (lo + hi) >> 1\n ops++\n if ((tails[mid] as number) < v) lo = mid + 1\n else hi = mid\n }\n }\n tails[lo] = v\n tailIdx[lo] = i\n if (lo > 0) pred[i] = tailIdx[lo - 1] as number\n // v ≤ lastV here, so tails can't be extended: lo < lisLen always.\n }\n if (__DEV__ && ops > 0) _countSink.__pyreon_count__?.('runtime.mountFor.lisOps', ops)\n return lisLen\n}\n\nfunction applyForMoves(\n n: number,\n newKeys: (string | number)[],\n stay: Uint8Array,\n cache: Map<string | number, ForEntry>,\n liveParent: Node,\n tailMarker: Comment,\n): void {\n let cursor: Node = tailMarker\n for (let i = n - 1; i >= 0; i--) {\n const entry = cache.get(newKeys[i] as string | number)\n if (!entry) continue\n if (!stay[i]) moveEntryBefore(liveParent, entry.anchor, cursor)\n cursor = entry.anchor\n }\n}\n\n/** LIS-based reorder for mountFor. */\nfunction forLisReorder(\n lis: LisState,\n n: number,\n newKeys: (string | number)[],\n cache: Map<string | number, ForEntry>,\n liveParent: Node,\n tailMarker: Comment,\n): LisState {\n const grown = growLisArrays(lis, n)\n grown.pred.fill(-1, 0, n)\n grown.stay.fill(0, 0, n)\n\n const lisLen = computeForLis(grown, n, newKeys, cache)\n markStayingEntries(grown, lisLen)\n applyForMoves(n, newKeys, grown.stay, cache, liveParent, tailMarker)\n\n for (let i = 0; i < n; i++) {\n const cached = cache.get(newKeys[i] as string | number)\n if (cached) cached.pos = i\n }\n\n return grown\n}\n\n/**\n * Keyed reconciler that works directly on the source item array.\n *\n * Optimizations:\n * - Calls renderItem() only for NEW keys — 0 VNode allocations for reorders\n * - Small-k fast path: if <= SMALL_K positions changed, skips LIS\n * - Fast clear path: moves nodes to DocumentFragment for O(n) bulk detach\n * - Fresh render fast path: skips stale-check and reorder on first render\n */\nexport function mountFor<T>(\n source: () => T[],\n getKey: (item: T) => string | number,\n renderItem: (item: T) => import('@pyreon/core').VNode | import('@pyreon/core').NativeItem,\n parent: Node,\n anchor: Node | null,\n mountChild: MountFn,\n): Cleanup {\n const startMarker = document.createComment('')\n const tailMarker = document.createComment('')\n parent.insertBefore(startMarker, anchor)\n parent.insertBefore(tailMarker, anchor)\n\n let cache = new Map<string | number, ForEntry>()\n let currentKeys: (string | number)[] = []\n const _reusableKeySet = new Set<string | number>()\n let cleanupCount = 0\n let anchorsRegistered = false\n\n let lis: LisState = {\n tails: new Int32Array(16),\n tailIdx: new Int32Array(16),\n pred: new Int32Array(16),\n stay: new Uint8Array(16),\n }\n\n const warnForKey = (seen: Set<string | number> | null, key: string | number) => {\n if (!seen) return\n if (__DEV__ && key == null) {\n console.warn(\n '[Pyreon] <For> `by` function returned null/undefined. ' +\n 'Keys must be strings or numbers. Check your `by` prop.',\n )\n }\n if (seen.has(key)) {\n if (__DEV__) {\n console.warn(`[Pyreon] Duplicate key \"${String(key)}\" in <For> list. Keys must be unique.`)\n }\n // In production: skip duplicate — use first occurrence only.\n // Prevents silent DOM corruption from cache key collision.\n return true\n }\n seen.add(key)\n return false\n }\n\n /** Render item into container, update cache+cleanupCount. No anchor registration. */\n const renderInto = (\n item: T,\n key: string | number,\n pos: number,\n container: Node,\n before: Node | null,\n ) => {\n const result = renderItem(item)\n if ((result as import('@pyreon/core').NativeItem).__isNative) {\n const native = result as import('@pyreon/core').NativeItem\n container.insertBefore(native.el, before)\n cache.set(key, { anchor: native.el, cleanup: native.cleanup, pos })\n if (native.cleanup) cleanupCount++\n return\n }\n const priorLast = before ? before.previousSibling : container.lastChild\n const cl = mountChild(result as import('@pyreon/core').VNode, container, before)\n const firstMounted = priorLast ? priorLast.nextSibling : container.firstChild\n if (!firstMounted || firstMounted === before) {\n const ph = document.createComment('')\n container.insertBefore(ph, before)\n cache.set(key, { anchor: ph, cleanup: cl, pos })\n } else {\n cache.set(key, { anchor: firstMounted, cleanup: cl, pos })\n }\n cleanupCount++\n }\n\n const handleFreshRender = (items: T[], n: number, liveParent: Node) => {\n const frag = document.createDocumentFragment()\n const keys = new Array<string | number>(n)\n const _seenKeys = new Set<string | number>()\n for (let i = 0; i < n; i++) {\n const item = items[i] as T\n const key = getKey(item)\n if (warnForKey(_seenKeys, key)) continue // skip duplicate\n keys[i] = key\n renderInto(item, key, i, frag, null)\n }\n liveParent.insertBefore(frag, tailMarker)\n anchorsRegistered = false\n currentKeys = keys\n }\n\n const collectNewKeys = (items: T[], n: number): (string | number)[] => {\n const newKeys = new Array<string | number>(n)\n const _seenUpdate = new Set<string | number>()\n for (let i = 0; i < n; i++) {\n newKeys[i] = getKey(items[i] as T)\n warnForKey(_seenUpdate, newKeys[i] as string | number)\n // Note: we don't skip here — keys array must match items array length.\n // Duplicate keys in update will just cause cache collisions (first wins).\n }\n return newKeys\n }\n\n const handleReplaceAll = (\n items: T[],\n n: number,\n newKeys: (string | number)[],\n liveParent: Node,\n ) => {\n if (cleanupCount > 0) {\n for (const entry of cache.values()) if (entry.cleanup) entry.cleanup()\n }\n cache = new Map()\n cleanupCount = 0\n\n const parentParent = liveParent.parentNode\n const canSwap =\n parentParent && liveParent.firstChild === startMarker && liveParent.lastChild === tailMarker\n\n const frag = document.createDocumentFragment()\n for (let i = 0; i < n; i++) {\n renderInto(items[i] as T, newKeys[i] as string | number, i, frag, null)\n }\n anchorsRegistered = false\n\n if (canSwap) {\n const fresh = liveParent.cloneNode(false)\n fresh.appendChild(startMarker)\n fresh.appendChild(frag)\n fresh.appendChild(tailMarker)\n parentParent.replaceChild(fresh, liveParent)\n } else {\n clearBetween(startMarker, tailMarker)\n liveParent.insertBefore(frag, tailMarker)\n }\n currentKeys = newKeys\n }\n\n const removeStaleForEntries = (newKeySet: Set<string | number>) => {\n for (const [key, entry] of cache) {\n if (newKeySet.has(key)) continue\n if (entry.cleanup) {\n entry.cleanup()\n cleanupCount--\n }\n entry.anchor.parentNode?.removeChild(entry.anchor)\n cache.delete(key)\n }\n }\n\n const mountNewForEntries = (\n items: T[],\n n: number,\n newKeys: (string | number)[],\n liveParent: Node,\n ) => {\n for (let i = 0; i < n; i++) {\n const key = newKeys[i] as string | number\n if (cache.has(key)) continue\n renderInto(items[i] as T, key, i, liveParent, tailMarker)\n const entry = cache.get(key)\n if (entry) _forAnchors.add(entry.anchor)\n }\n }\n\n const handleFastClear = (liveParent: Node) => {\n if (cache.size === 0) return\n if (cleanupCount > 0) {\n for (const entry of cache.values()) if (entry.cleanup) entry.cleanup()\n }\n const pp = liveParent.parentNode\n if (pp && liveParent.firstChild === startMarker && liveParent.lastChild === tailMarker) {\n const fresh = liveParent.cloneNode(false)\n fresh.appendChild(startMarker)\n fresh.appendChild(tailMarker)\n pp.replaceChild(fresh, liveParent)\n } else {\n clearBetween(startMarker, tailMarker)\n }\n cache = new Map()\n cleanupCount = 0\n currentKeys = []\n }\n\n const hasAnyKeptKey = (n: number, newKeys: (string | number)[]): boolean => {\n for (let i = 0; i < n; i++) {\n if (cache.has(newKeys[i] as string | number)) return true\n }\n return false\n }\n\n const handleIncrementalUpdate = (\n items: T[],\n n: number,\n newKeys: (string | number)[],\n liveParent: Node,\n ) => {\n // Reuse a persistent Set to avoid allocating a new one per update.\n // Cleared + repopulated instead of constructing new Set(newKeys).\n _reusableKeySet.clear()\n for (let i = 0; i < newKeys.length; i++) _reusableKeySet.add(newKeys[i] as string | number)\n removeStaleForEntries(_reusableKeySet)\n mountNewForEntries(items, n, newKeys, liveParent)\n\n if (!anchorsRegistered) {\n for (const entry of cache.values()) _forAnchors.add(entry.anchor)\n anchorsRegistered = true\n }\n\n if (trySmallKReorder(n, newKeys, currentKeys, cache, liveParent, tailMarker)) {\n currentKeys = newKeys\n return\n }\n\n lis = forLisReorder(lis, n, newKeys, cache, liveParent, tailMarker)\n currentKeys = newKeys\n }\n\n const e = effect(() => {\n const liveParent = startMarker.parentNode\n if (!liveParent) return\n const items = source()\n const n = items.length\n\n if (n === 0) {\n handleFastClear(liveParent)\n return\n }\n\n if (currentKeys.length === 0) {\n handleFreshRender(items, n, liveParent)\n return\n }\n\n const newKeys = collectNewKeys(items, n)\n\n if (!hasAnyKeptKey(n, newKeys)) {\n handleReplaceAll(items, n, newKeys, liveParent)\n return\n }\n\n handleIncrementalUpdate(items, n, newKeys, liveParent)\n })\n\n return () => {\n e.dispose()\n for (const entry of cache.values()) {\n if (cleanupCount > 0 && entry.cleanup) entry.cleanup()\n entry.anchor.parentNode?.removeChild(entry.anchor)\n }\n cache = new Map()\n cleanupCount = 0\n startMarker.parentNode?.removeChild(startMarker)\n tailMarker.parentNode?.removeChild(tailMarker)\n }\n}\n\n/**\n * Small-k reorder: directly place the k displaced entries without LIS.\n */\nfunction smallKPlace(\n parent: Node,\n diffs: number[],\n newKeys: (string | number)[],\n cache: Map<string | number, { anchor: Node; cleanup: Cleanup | null }>,\n tailMarker: Comment,\n): void {\n const diffSet = new Set(diffs)\n let cursor: Node = tailMarker\n let prevDiffIdx = newKeys.length\n\n for (let d = diffs.length - 1; d >= 0; d--) {\n const i = diffs[d] as number\n\n let nextNonDiff = -1\n for (let j = i + 1; j < prevDiffIdx; j++) {\n if (!diffSet.has(j)) {\n nextNonDiff = j\n break\n }\n }\n\n if (nextNonDiff >= 0) {\n const nc = cache.get(newKeys[nextNonDiff] as string | number)?.anchor\n if (nc) cursor = nc\n }\n\n const entry = cache.get(newKeys[i] as string | number)\n if (!entry) {\n prevDiffIdx = i\n continue\n }\n moveEntryBefore(parent, entry.anchor, cursor)\n cursor = entry.anchor\n prevDiffIdx = i\n }\n}\n\n/**\n * Move startNode and all siblings belonging to this entry to just before `before`.\n * Stops at the next entry anchor (identified via WeakSet) or the tail marker.\n *\n * Fast path: if the next sibling is already a boundary (another entry or tail),\n * this entry is a single node — skip the toMove array entirely.\n */\nfunction moveEntryBefore(parent: Node, startNode: Node, before: Node): void {\n const next = startNode.nextSibling\n // Single-node fast path (covers all createTemplate rows — the common case)\n if (\n !next ||\n next === before ||\n (next.parentNode === parent && (_forAnchors.has(next) || _keyedAnchors.has(next)))\n ) {\n parent.insertBefore(startNode, before)\n return\n }\n // Multi-node slow path (fragments, components with multiple root nodes)\n const toMove: Node[] = [startNode]\n let cur: Node | null = next\n while (cur && cur !== before) {\n const nextNode: Node | null = cur.nextSibling\n toMove.push(cur)\n cur = nextNode\n if (\n cur &&\n cur.parentNode === parent &&\n (cur === before || _forAnchors.has(cur) || _keyedAnchors.has(cur))\n )\n break\n }\n for (const node of toMove) {\n parent.insertBefore(node, before)\n }\n}\n","/**\n * Event delegation — single listener per event type on the mount container.\n *\n * Instead of calling addEventListener on every element, the compiler emits\n * `el.__click = handler` (expando property). A single delegated listener on the\n * container walks event.target up the DOM tree, checking for expandos.\n *\n * Benefits:\n * - Saves ~2000 addEventListener calls for 1000 rows with 2 handlers each\n * - Reduces memory per row (no per-element listener closure)\n * - Faster initial mount (~0.4-0.8ms savings on 1000-row benchmarks)\n */\n\nimport { batch } from '@pyreon/reactivity'\n\n/**\n * Events that are delegated (common bubbling events).\n * Non-bubbling events (focus, blur, mouseenter, mouseleave, load, error, scroll)\n * are NOT delegated — they must use addEventListener.\n */\nexport const DELEGATED_EVENTS = new Set([\n 'click',\n 'dblclick',\n 'contextmenu',\n 'focusin',\n 'focusout',\n 'input',\n 'change',\n 'keydown',\n 'keyup',\n 'mousedown',\n 'mouseup',\n 'mousemove',\n 'mouseover',\n 'mouseout',\n 'pointerdown',\n 'pointerup',\n 'pointermove',\n 'pointerover',\n 'pointerout',\n 'touchstart',\n 'touchend',\n 'touchmove',\n 'submit',\n])\n\n/**\n * Property name used on DOM elements to store delegated event handlers.\n * Format: `__ev_{eventName}` e.g. `__ev_click`, `__ev_input`\n */\nexport function delegatedPropName(eventName: string): string {\n return `__ev_${eventName}`\n}\n\n// Track which containers already have delegation installed\nconst _delegated = new WeakSet<Element>()\n\n/**\n * Install delegation listeners on a container element.\n * Called once from mount(). Idempotent — safe to call multiple times.\n */\nexport function setupDelegation(container: Element): void {\n if (_delegated.has(container)) return\n _delegated.add(container)\n\n for (const eventName of DELEGATED_EVENTS) {\n const prop = delegatedPropName(eventName)\n container.addEventListener(eventName, (e: Event) => {\n let el = e.target as (HTMLElement & Record<string, unknown>) | null\n while (el && el !== container) {\n const handler = el[prop]\n if (typeof handler === 'function') {\n batch(() => handler(e))\n // Don't break — allow ancestor handlers too (consistent with addEventListener)\n // But if stopPropagation was called, stop walking\n if (e.cancelBubble) break\n }\n el = el.parentElement as (HTMLElement & Record<string, unknown>) | null\n }\n })\n }\n}\n","import type { ClassValue, Props } from '@pyreon/core'\nimport { cx, normalizeStyleValue, toKebabCase } from '@pyreon/core'\n\nimport { batch, renderEffect } from '@pyreon/reactivity'\nimport { DELEGATED_EVENTS, delegatedPropName } from './delegate'\n\ntype Cleanup = () => void\n\n// Dev-mode gate: see `pyreon/no-process-dev-gate` lint rule for why this\n// uses `import.meta.env.DEV` instead of `typeof process !== 'undefined'`.\n// @ts-ignore — `import.meta.env.DEV` is provided by Vite/Rolldown at build time\nconst __DEV__ = import.meta.env?.DEV === true\n\n// ─── Configurable sanitizer ──────────────────────────────────────────────────\n\nexport type SanitizeFn = (html: string) => string\n\nlet _customSanitizer: SanitizeFn | null = null\n\n/**\n * Set a custom HTML sanitizer used by `innerHTML` and `sanitizeHtml()`.\n * Overrides both the Sanitizer API and the built-in fallback.\n *\n * @example\n * // With DOMPurify:\n * import DOMPurify from \"dompurify\"\n * setSanitizer((html) => DOMPurify.sanitize(html))\n *\n * // With sanitize-html:\n * import sanitize from \"sanitize-html\"\n * setSanitizer((html) => sanitize(html))\n *\n * // Reset to built-in:\n * setSanitizer(null)\n */\nexport function setSanitizer(fn: SanitizeFn | null): void {\n _customSanitizer = fn\n}\n\n// Safe HTML tags allowed by the fallback sanitizer (block + inline, no scripts/embeds/forms)\nconst SAFE_TAGS = new Set([\n 'a',\n 'abbr',\n 'address',\n 'article',\n 'aside',\n 'b',\n 'bdi',\n 'bdo',\n 'blockquote',\n 'br',\n 'caption',\n 'cite',\n 'code',\n 'col',\n 'colgroup',\n 'dd',\n 'del',\n 'details',\n 'dfn',\n 'div',\n 'dl',\n 'dt',\n 'em',\n 'figcaption',\n 'figure',\n 'footer',\n 'h1',\n 'h2',\n 'h3',\n 'h4',\n 'h5',\n 'h6',\n 'header',\n 'hr',\n 'i',\n 'ins',\n 'kbd',\n 'li',\n 'main',\n 'mark',\n 'nav',\n 'ol',\n 'p',\n 'pre',\n 'q',\n 'rp',\n 'rt',\n 'ruby',\n 's',\n 'samp',\n 'section',\n 'small',\n 'span',\n 'strong',\n 'sub',\n 'summary',\n 'sup',\n 'table',\n 'tbody',\n 'td',\n 'tfoot',\n 'th',\n 'thead',\n 'time',\n 'tr',\n 'u',\n 'ul',\n 'var',\n 'wbr',\n])\n\n// Attributes that can carry executable code\nconst UNSAFE_ATTR_RE = /^on/i\n\n/**\n * Fallback tag-stripping sanitizer for environments without the Sanitizer API.\n * Removes all tags not in SAFE_TAGS, strips event handler attributes,\n * and blocks javascript:/data: URLs in href/src/action attributes.\n */\nfunction fallbackSanitize(html: string): string {\n const doc = new DOMParser().parseFromString(html, 'text/html')\n sanitizeNode(doc.body)\n return doc.body.innerHTML\n}\n\n/** Strip unsafe attributes from a single element. */\nfunction stripUnsafeAttrs(el: Element): void {\n const attrs = Array.from(el.attributes)\n for (const attr of attrs) {\n if (UNSAFE_ATTR_RE.test(attr.name)) {\n el.removeAttribute(attr.name)\n } else if (URL_ATTRS.has(attr.name) && UNSAFE_URL_RE.test(attr.value)) {\n el.removeAttribute(attr.name)\n }\n }\n}\n\nfunction sanitizeNode(node: Node): void {\n const children = Array.from(node.childNodes)\n for (const child of children) {\n if (child.nodeType !== 1) continue\n const el = child as Element\n const tag = el.tagName.toLowerCase()\n if (!SAFE_TAGS.has(tag)) {\n const text = document.createTextNode(el.textContent as string)\n node.replaceChild(text, el)\n continue\n }\n stripUnsafeAttrs(el)\n sanitizeNode(el)\n }\n}\n\n/**\n * Sanitize an HTML string using the browser Sanitizer API (Chrome 105+).\n * Falls back to a tag-allowlist sanitizer that strips unsafe elements and attributes.\n */\nexport function sanitizeHtml(html: string): string {\n // User-provided sanitizer takes priority (e.g. DOMPurify)\n if (_customSanitizer) return _customSanitizer(html)\n // DOM-based allowlist sanitizer — DOMParser is available in all browser targets.\n // sanitizeHtml is only called for innerHTML (DOM-only), so SSR fallback is not needed.\n return fallbackSanitize(html)\n}\n\n// Matches onClick, onInput, onMouseEnter, etc.\nconst EVENT_RE = /^on[A-Z]/\n\n/**\n * Apply all props to a DOM element.\n * Returns a single chained cleanup (or null if no props need teardown).\n * Uses for-in instead of Object.keys() to avoid allocating a keys array.\n */\nexport function applyProps(el: Element, props: Props): Cleanup | null {\n let first: Cleanup | null = null\n let cleanups: Cleanup[] | null = null\n for (const key in props) {\n if (key === 'key' || key === 'ref' || key === 'children') continue\n const c = applyProp(el, key, props[key])\n if (c) {\n if (!first) {\n first = c\n } else if (!cleanups) {\n cleanups = [first, c]\n } else {\n cleanups.push(c)\n }\n }\n }\n if (cleanups)\n return () => {\n for (const c of cleanups) c()\n }\n return first\n}\n\n/**\n * Apply a single prop.\n *\n * - `onXxx` → addEventListener\n * - `() => value` (non-event function) → reactive via effect\n * - anything else → static attribute / DOM property\n */\n/**\n * Bind an event handler (onClick → \"click\") with batching + delegation support.\n */\nfunction applyEventProp(el: Element, key: string, value: unknown): Cleanup | null {\n if (typeof value !== 'function') {\n // `undefined` and `null` are legitimate — conditional handler pattern:\n // <button onClick={condition ? handler : undefined}>\n // The runtime silently bails on nullish values. Only warn for\n // actually-wrong types (strings, numbers, objects) that indicate\n // a real bug in the caller (e.g. `onClick={someSignal()}` where\n // the signal returns a value instead of a handler function).\n if (__DEV__ && value != null) {\n console.warn(\n `[Pyreon] Event handler \"${key}\" received a non-function value (${typeof value}). ` +\n `Expected a function. Did you mean ${key}={() => ...}?`,\n )\n }\n return null\n }\n // `onPointerDown` -> `pointerdown`. Multi-word DOM event names are\n // all-lowercase (`pointerdown`, `dblclick`, `mouseover`), so we\n // lowercase the WHOLE name — not just the first letter, as a previous\n // version did. That bug silently dropped delegation for every\n // multi-word event (pointerdown/up/move, mousedown/up/move, dblclick,\n // touchstart/end/move, etc.) — the handler was attached via\n // `addEventListener('pointerDown', ...)` which never fires because\n // real events use the lowercase name.\n const eventName = (key[2]?.toLowerCase() + key.slice(3)).toLowerCase()\n const handler = value as EventListener\n\n if (DELEGATED_EVENTS.has(eventName)) {\n const prop = delegatedPropName(eventName)\n ;(el as unknown as Record<string, unknown>)[prop] = (e: Event) => batch(() => handler(e))\n return () => {\n ;(el as unknown as Record<string, unknown>)[prop] = undefined\n }\n }\n\n const batched: EventListener = (e) => batch(() => handler(e))\n el.addEventListener(eventName, batched)\n return () => el.removeEventListener(eventName, batched)\n}\n\n/**\n * Sink for a single prop's CALLED value (always a primitive / object /\n * `null` — never a function). Called both directly for static values and\n * from the reactive `renderEffect` for accessor-bound values.\n *\n * NOTE on architecture: extracting the special-cased sinks\n * (`innerHTML` / `dangerouslySetInnerHTML`) into this single dispatch\n * function ensures every prop kind goes through the same reactive\n * wrapping at `applyProp`'s entry. Previously each special case had its\n * own early-return branch that needed to remember to handle function\n * values; missing the dance once meant the closure was stringified and\n * set as literal text. The structural fix (one reactive-wrap, then\n * dispatch) eliminates the entire bug class.\n */\nfunction applyStaticProp(el: Element, key: string, value: unknown): void {\n if (__DEV__ && typeof value === 'function') {\n // Defensive: function values must be unwrapped via `renderEffect`\n // before reaching here. If we see one, a NEW special-case branch\n // somewhere upstream skipped the reactive-wrapping dance — exactly\n // the bug class the structural refactor was meant to eliminate.\n console.warn(\n `[Pyreon] applyStaticProp received a function for \"${key}\". ` +\n `This likely means a new special-cased prop sink in applyProp() ` +\n `bypassed the reactive-wrap path. The closure would be stringified ` +\n `and set as a literal value. Verify the dispatch in applyProp().`,\n )\n }\n\n // innerHTML — sanitized via Sanitizer API or fallback allowlist sanitizer.\n if (key === 'innerHTML') {\n const html = String(value ?? '')\n if (typeof (el as HTMLElement & { setHTML?: (h: string) => void }).setHTML === 'function') {\n ;(el as HTMLElement & { setHTML: (h: string) => void }).setHTML(html)\n } else {\n ;(el as HTMLElement).innerHTML = sanitizeHtml(html)\n }\n return\n }\n\n // dangerouslySetInnerHTML — intentionally raw, developer owns sanitization\n // (same as React). The name itself is the warning — React doesn't log,\n // neither should we.\n if (key === 'dangerouslySetInnerHTML') {\n const v = value as { __html: string } | null | undefined\n ;(el as HTMLElement).innerHTML = v?.__html ?? ''\n return\n }\n\n setStaticProp(el, key, value)\n}\n\nexport function applyProp(el: Element, key: string, value: unknown): Cleanup | null {\n // Event listener: onClick → \"click\"\n if (EVENT_RE.test(key)) return applyEventProp(el, key, value)\n\n // Reactive prop — function value is an accessor closure. The JSX compiler\n // emits `prop={someExpr(signal())}` as a `() => someExpr(signal())` thunk\n // so the prop tracks the signal automatically. We wrap in `renderEffect`\n // ONCE here, before any prop-kind dispatch, so EVERY sink gets the same\n // reactive treatment. Previously special-cased sinks (innerHTML etc.) had\n // early-return branches that bypassed this wrap and stringified the\n // closure — the bug fixed by this restructure.\n //\n // Uses renderEffect (lighter than effect — no scope registration, no\n // WeakMap) since lifecycle is managed by mountElement's cleanup array.\n if (typeof value === 'function') {\n return renderEffect(() => applyStaticProp(el, key, (value as () => unknown)()))\n }\n\n applyStaticProp(el, key, value)\n return null\n}\n\n// Attributes that carry URLs and must be guarded against javascript:/data: injection.\nconst URL_ATTRS = new Set(['href', 'src', 'action', 'formaction', 'poster', 'cite', 'data'])\nconst UNSAFE_URL_RE = /^\\s*(?:javascript|data):/i\n\n// Track the CSS property names an element's last-applied style object set,\n// so a reactive style going from `{ color, fontSize }` to `{ color }` removes\n// the stale `fontSize`. React/Vue/Solid all do this diff; previously Pyreon\n// only applied new keys, leaking the removed ones onto the DOM.\nconst _prevStyleKeys: WeakMap<HTMLElement, Set<string>> = new WeakMap()\n\n/** Apply a style prop (string or object). */\nfunction applyStyleProp(el: HTMLElement, value: unknown): void {\n if (typeof value === 'string') {\n // cssText replaces everything — drop any tracked object-mode keys.\n el.style.cssText = value\n _prevStyleKeys.delete(el)\n return\n }\n\n const prev = _prevStyleKeys.get(el)\n\n if (value == null) {\n // Explicit null/undefined: clear whatever object-mode keys we set.\n if (prev) {\n for (const propName of prev) el.style.removeProperty(propName)\n _prevStyleKeys.delete(el)\n }\n return\n }\n\n if (typeof value === 'object') {\n const obj = value as Record<string, unknown>\n const next = new Set<string>()\n for (const k in obj) {\n const propName = k.startsWith('--') ? k : toKebabCase(k)\n next.add(propName)\n const css = normalizeStyleValue(k, obj[k])\n el.style.setProperty(propName, css)\n }\n if (prev) {\n for (const propName of prev) {\n if (!next.has(propName)) el.style.removeProperty(propName)\n }\n }\n if (next.size === 0) _prevStyleKeys.delete(el)\n else _prevStyleKeys.set(el, next)\n }\n}\n\nfunction applyClassProp(el: Element, value: unknown): void {\n const resolved = typeof value === 'string' ? value : cx(value as ClassValue)\n el.setAttribute('class', resolved || '')\n}\n\nfunction setStaticProp(el: Element, key: string, value: unknown): void {\n // Block javascript:/data: URI injection in URL-bearing attributes.\n if (URL_ATTRS.has(key) && typeof value === 'string' && UNSAFE_URL_RE.test(value)) {\n if (__DEV__) {\n console.warn(`[Pyreon] Blocked unsafe URL in \"${key}\" attribute: ${value}`)\n }\n return\n }\n\n if (key === 'class' || key === 'className') {\n applyClassProp(el, value)\n return\n }\n\n if (key === 'style') {\n applyStyleProp(el as HTMLElement, value)\n return\n }\n\n if (value == null) {\n el.removeAttribute(key)\n return\n }\n\n if (typeof value === 'boolean') {\n if (value) el.setAttribute(key, '')\n else el.removeAttribute(key)\n return\n }\n\n // SVG and MathML elements: ALWAYS use setAttribute. Many of their\n // properties are read-only `SVGAnimated*` getters (e.g.\n // `SVGMarkerElement.refX`, `SVGMarkerElement.markerWidth`,\n // `SVGRectElement.x`, etc.). Trying `el[key] = value` on those\n // crashes with \"Cannot set property X of [object Object] which has\n // only a getter\". The standard React/Vue/Solid behavior is to\n // skip the property assignment optimization for non-HTML elements\n // and always go through setAttribute.\n if (el.namespaceURI && el.namespaceURI !== 'http://www.w3.org/1999/xhtml') {\n el.setAttribute(key, String(value))\n return\n }\n\n if (key in el) {\n ;(el as unknown as Record<string, unknown>)[key] = value\n return\n }\n\n // Custom elements: set as property (element may not be upgraded yet,\n // so `key in el` missed it). Properties set before upgrade are picked\n // up when the element's constructor runs.\n const tag = el.tagName\n if (tag.includes('-')) {\n ;(el as unknown as Record<string, unknown>)[key] = value\n return\n }\n\n el.setAttribute(key, String(value))\n}\n","import type {\n ComponentFn,\n ForProps,\n NativeItem,\n PortalProps,\n RefProp,\n VNode,\n VNodeChild,\n} from '@pyreon/core'\nimport {\n dispatchToErrorBoundary,\n EMPTY_PROPS,\n ForSymbol,\n Fragment,\n makeReactiveProps,\n PortalSymbol,\n propagateError,\n reportError,\n runWithHooks,\n} from '@pyreon/core'\nimport { effectScope, renderEffect, runUntracked, setCurrentScope } from '@pyreon/reactivity'\nimport { registerComponent, unregisterComponent } from './devtools'\nimport { mountFor, mountKeyedList, mountReactive } from './nodes'\nimport { applyProps } from './props'\n\n// Dev-mode gate: see `pyreon/no-process-dev-gate` lint rule for why this\n// uses `import.meta.env.DEV` instead of `typeof process !== 'undefined'`.\n// @ts-ignore — `import.meta.env.DEV` is provided by Vite/Rolldown at build time\nconst __DEV__ = import.meta.env?.DEV === true\n\n// Dev-time counter sink — see packages/internals/perf-harness for contract.\nconst _countSink = globalThis as { __pyreon_count__?: (name: string, n?: number) => void }\n\ntype Cleanup = () => void\nconst noop: Cleanup = () => {\n /* noop */\n}\n\n// When > 0, we're mounting children inside an element — child cleanups can skip\n// DOM removal (parent element removal handles it). This avoids allocating a\n// removeChild closure for every nested element that has no reactive work.\nlet _elementDepth = 0\n\n// Stack tracking which component is currently being mounted (depth-first order).\n// Used to infer parent/child relationships for DevTools.\n// Only allocated in dev — production mounts skip devtools entirely.\nlet _mountingStack: string[] | undefined\nif (__DEV__) _mountingStack = []\n\n/**\n * Mount a single child into `parent`, inserting before `anchor` (null = append).\n * Returns a cleanup that removes the node(s) and disposes all reactive effects.\n *\n * This function is the hot path — all child types are handled inline to avoid\n * function call overhead in tight render loops (1000+ calls per list render).\n */\nexport function mountChild(\n child: VNodeChild | VNodeChild[] | (() => VNodeChild | VNodeChild[]),\n parent: Node,\n anchor: Node | null = null,\n): Cleanup {\n if (__DEV__) _countSink.__pyreon_count__?.('runtime.mountChild')\n // Reactive accessor — function that reads signals\n if (typeof child === 'function') {\n const sample = runUntracked(() => (child as () => VNodeChild | VNodeChild[])())\n if (isKeyedArray(sample)) {\n const prevDepth = _elementDepth\n _elementDepth = 0\n const cleanup = mountKeyedList(child as () => VNode[], parent, anchor, (v, p, a) =>\n mountChild(v, p, a),\n )\n _elementDepth = prevDepth\n return cleanup\n }\n // Text fast path: reactive string/number/boolean — update text.data in-place\n if (typeof sample === 'string' || typeof sample === 'number' || typeof sample === 'boolean') {\n const text = document.createTextNode(sample === false ? '' : String(sample))\n parent.insertBefore(text, anchor)\n const dispose = renderEffect(() => {\n const v = (child as () => unknown)()\n const next = v == null || v === false ? '' : String(v as string | number)\n if (next !== text.data) text.data = next\n })\n if (_elementDepth > 0) return dispose\n return () => {\n dispose()\n const p = text.parentNode\n if (p && (p as Element).isConnected !== false) p.removeChild(text)\n }\n }\n const prevDepth = _elementDepth\n _elementDepth = 0\n const cleanup = mountReactive(child as () => VNodeChild, parent, anchor, mountChild)\n _elementDepth = prevDepth\n return cleanup\n }\n\n // Array of children (e.g. from .map())\n if (Array.isArray(child)) return mountChildren(child, parent, anchor)\n\n // Nothing to render\n if (child == null || child === false) return noop\n\n // Primitive — text node (static, no reactive effects to tear down).\n if (typeof child !== 'object') {\n parent.insertBefore(document.createTextNode(String(child)), anchor)\n return noop\n }\n\n // NativeItem — pre-built DOM element from _tpl() or createTemplate().\n if ((child as unknown as NativeItem).__isNative) {\n const native = child as unknown as NativeItem\n parent.insertBefore(native.el, anchor)\n if (!native.cleanup) {\n if (_elementDepth > 0) return noop\n return () => {\n const p = native.el.parentNode\n if (p && (p as Element).isConnected !== false) p.removeChild(native.el)\n }\n }\n if (_elementDepth > 0) return native.cleanup\n return () => {\n native.cleanup?.()\n const p = native.el.parentNode\n if (p && (p as Element).isConnected !== false) p.removeChild(native.el)\n }\n }\n\n // VNode — element, component, fragment, For, Portal\n const vnode = child as VNode\n\n if (vnode.type === Fragment) return mountChildren(vnode.children ?? [], parent, anchor)\n\n if (vnode.type === (ForSymbol as unknown as string)) {\n // Compiler wraps `<For each={signal}>` in `_rp(() => signal())` →\n // `props.each` is a getter that returns the resolved array, not the\n // function. Destructuring eagerly captures the array and breaks\n // reactivity + crashes mountFor (which calls `source()`). Read each\n // lazily so the _rp getter fires inside mountFor's effect, preserving\n // signal tracking. User-written `each={() => fn()}` (already a\n // function, not _rp-wrapped) still works because props.each is the\n // function itself.\n const props = vnode.props as unknown as ForProps<unknown>\n const initialEach = props.each as unknown\n const source: () => unknown[] =\n typeof initialEach === 'function'\n ? (initialEach as () => unknown[])\n : (() => props.each as unknown as unknown[])\n const prevDepth = _elementDepth\n _elementDepth = 0\n const cleanup = mountFor(\n source as () => unknown[],\n props.by,\n props.children,\n parent,\n anchor,\n mountChild,\n )\n _elementDepth = prevDepth\n return cleanup\n }\n\n if (vnode.type === (PortalSymbol as unknown as string)) {\n const { target, children } = vnode.props as unknown as PortalProps\n if (__DEV__ && !target) {\n console.warn('[Pyreon] <Portal> received a falsy `target`. Provide a valid DOM element.')\n return noop\n }\n if (__DEV__ && !(target instanceof Node)) {\n console.warn(\n `[Pyreon] <Portal> target must be a DOM node. Received ${typeof target}. ` +\n 'Use document.getElementById() or a ref to get the target element.',\n )\n }\n return mountChild(children, target, null)\n }\n\n if (typeof vnode.type === 'function') {\n return mountComponent(vnode as VNode & { type: ComponentFn }, parent, anchor)\n }\n\n if (__DEV__ && typeof vnode.type !== 'string') {\n console.warn(\n `[Pyreon] Invalid VNode type: expected a string tag or component function, ` +\n `received ${typeof vnode.type} (${String(vnode.type)}). ` +\n `This usually means you passed an object or class instead of a component function.`,\n )\n return noop\n }\n\n return mountElement(vnode, parent, anchor)\n}\n\n// ─── Element ─────────────────────────────────────────────────────────────────\n\n// Void elements that cannot have children\nconst VOID_ELEMENTS = new Set([\n 'area',\n 'base',\n 'br',\n 'col',\n 'embed',\n 'hr',\n 'img',\n 'input',\n 'link',\n 'meta',\n 'param',\n 'source',\n 'track',\n 'wbr',\n])\n\nconst SVG_NS = 'http://www.w3.org/2000/svg'\nconst MATHML_NS = 'http://www.w3.org/1998/Math/MathML'\n\n// Tags that require namespace-aware creation\nconst SVG_TAGS = new Set([\n 'svg',\n 'circle',\n 'ellipse',\n 'line',\n 'path',\n 'polygon',\n 'polyline',\n 'rect',\n 'g',\n 'defs',\n 'symbol',\n 'use',\n 'text',\n 'tspan',\n 'textPath',\n 'image',\n 'clipPath',\n 'mask',\n 'pattern',\n 'marker',\n 'linearGradient',\n 'radialGradient',\n 'stop',\n 'filter',\n 'feBlend',\n 'feColorMatrix',\n 'feComponentTransfer',\n 'feComposite',\n 'feConvolveMatrix',\n 'feDiffuseLighting',\n 'feDisplacementMap',\n 'feFlood',\n 'feGaussianBlur',\n 'feImage',\n 'feMerge',\n 'feMergeNode',\n 'feMorphology',\n 'feOffset',\n 'feSpecularLighting',\n 'feTile',\n 'feTurbulence',\n 'animate',\n 'animateMotion',\n 'animateTransform',\n 'set',\n 'desc',\n 'title',\n 'metadata',\n 'foreignObject',\n])\n\nconst MATHML_TAGS = new Set([\n 'math',\n 'mi',\n 'mo',\n 'mn',\n 'ms',\n 'mtext',\n 'mspace',\n 'mrow',\n 'mfrac',\n 'msqrt',\n 'mroot',\n 'msub',\n 'msup',\n 'msubsup',\n 'munder',\n 'mover',\n 'munderover',\n 'mtable',\n 'mtr',\n 'mtd',\n 'mpadded',\n 'mphantom',\n 'menclose',\n])\n\n/** Track SVG context depth — children of <svg> inherit the SVG namespace. */\nlet _svgDepth = 0\nlet _mathmlDepth = 0\n\nfunction createElementWithNS(tag: string): Element {\n if (_svgDepth > 0 || SVG_TAGS.has(tag)) return document.createElementNS(SVG_NS, tag)\n if (_mathmlDepth > 0 || MATHML_TAGS.has(tag)) return document.createElementNS(MATHML_NS, tag)\n return document.createElement(tag)\n}\n\nfunction mountElement(vnode: VNode, parent: Node, anchor: Node | null): Cleanup {\n const tag = vnode.type as string\n const el = createElementWithNS(tag)\n const isSvg = tag === 'svg'\n const isMathml = tag === 'math'\n if (isSvg) _svgDepth++\n if (isMathml) _mathmlDepth++\n\n if (__DEV__ && (vnode.children?.length ?? 0) > 0 && VOID_ELEMENTS.has(vnode.type as string)) {\n console.warn(\n `[Pyreon] <${vnode.type as string}> is a void element and cannot have children. ` +\n 'Children passed to void elements will be ignored by the browser.',\n )\n }\n\n // Skip applyProps entirely when props is the shared empty sentinel (identity check — no allocation)\n const props = vnode.props\n const propCleanup: Cleanup | null = props !== EMPTY_PROPS ? applyProps(el, props) : null\n\n // Mount children inside element context — nested elements can skip DOM removal closures\n _elementDepth++\n const childCleanup = mountChildren(vnode.children ?? [], el, null)\n _elementDepth--\n if (isSvg) _svgDepth--\n if (isMathml) _mathmlDepth--\n\n parent.insertBefore(el, anchor)\n\n // Populate ref after the element is in the DOM\n const ref = props.ref as RefProp<Element> | null | undefined\n if (ref) {\n if (typeof ref === 'function') ref(el)\n else ref.current = el\n }\n\n if (!propCleanup && childCleanup === noop && !ref) {\n if (_elementDepth > 0) return noop\n return () => {\n const p = el.parentNode\n if (p && (p as Element).isConnected !== false) p.removeChild(el)\n }\n }\n\n if (_elementDepth > 0) {\n if (!ref && !propCleanup) return childCleanup\n if (!ref && propCleanup)\n return () => {\n propCleanup()\n childCleanup()\n }\n const refToClean = ref\n return () => {\n if (refToClean) {\n if (typeof refToClean === 'function') refToClean(null)\n else refToClean.current = null\n }\n if (propCleanup) propCleanup()\n childCleanup()\n }\n }\n\n return () => {\n if (ref) {\n if (typeof ref === 'function') ref(null)\n else ref.current = null\n }\n if (propCleanup) propCleanup()\n childCleanup()\n const p = el.parentNode\n if (p && (p as Element).isConnected !== false) p.removeChild(el)\n }\n}\n\n// ─── Component ───────────────────────────────────────────────────────────────\n\nfunction mountComponent(\n vnode: VNode & { type: ComponentFn },\n parent: Node,\n anchor: Node | null,\n): Cleanup {\n const scope = effectScope()\n setCurrentScope(scope)\n\n let hooks: ReturnType<typeof runWithHooks>['hooks']\n let output: VNodeChild\n\n const componentName = (vnode.type.name || 'Anonymous') as string\n\n // Devtools: generate ID + track parent/child hierarchy (dev only).\n // In production, compId/devParentId are never assigned — Vite tree-shakes\n // all __DEV__ blocks + the devtools module import to zero bytes.\n let compId: string | undefined\n let devParentId: string | null | undefined\n if (__DEV__) {\n compId = `${componentName}-${Math.random().toString(36).slice(2, 9)}`\n devParentId = _mountingStack![_mountingStack!.length - 1] ?? null\n _mountingStack!.push(compId)\n }\n\n // Merge vnode.children into props.children if not already set\n const children = vnode.children ?? []\n const rawProps =\n children.length > 0 && (vnode.props as Record<string, unknown>).children === undefined\n ? {\n ...vnode.props,\n children: children.length === 1 ? children[0] : children,\n }\n : vnode.props\n\n // Convert compiler-emitted () => expr wrappers into getter properties.\n // This makes component props reactive — reading props.state inside an\n // effect/computed tracks the underlying signals.\n const mergedProps =\n rawProps === EMPTY_PROPS ? rawProps : makeReactiveProps(rawProps as Record<string, unknown>)\n\n try {\n const result = runWithHooks(vnode.type, mergedProps)\n hooks = result.hooks\n output = result.vnode\n } catch (err) {\n if (__DEV__) _mountingStack!.pop()\n setCurrentScope(null)\n scope.stop()\n reportError({\n component: componentName,\n phase: 'setup',\n error: err,\n timestamp: Date.now(),\n props: vnode.props as Record<string, unknown>,\n })\n const handled = dispatchToErrorBoundary(err)\n if (!handled) {\n console.error(`[Pyreon] <${componentName}> threw during setup:`, err)\n }\n if (__DEV__ && !handled) {\n const overlay = document.createElement('pre')\n overlay.style.cssText =\n 'color:#e53e3e;background:#fff5f5;padding:12px;border:2px solid #e53e3e;border-radius:6px;font-size:12px;margin:4px;font-family:monospace;white-space:pre-wrap;word-break:break-word'\n const e = err as Error\n overlay.textContent = `[${componentName}] ${e.message ?? err}\\n${e.stack ?? ''}`\n parent.insertBefore(overlay, anchor)\n return () => overlay.remove()\n }\n return noop\n } finally {\n setCurrentScope(null)\n }\n\n if (__DEV__ && output != null && typeof output === 'object') {\n if (output instanceof Promise) {\n console.warn(\n `[Pyreon] Component <${componentName}> returned a Promise. ` +\n 'Components must be synchronous — use lazy() + Suspense for async loading, ' +\n 'or fetch data in onMount and store it in a signal.',\n )\n } else if (!('type' in output) && !Array.isArray(output) && !(output as any).__isNative) {\n // Objects without `type` that are NOT arrays (valid VNodeChild[])\n // and NOT NativeItems (from _tpl()) are invalid. Arrays come from\n // Fragment returns, NativeItems come from compiled templates.\n console.warn(\n `[Pyreon] Component <${componentName}> returned an invalid value. Components must return a VNode, string, null, function, or array.`,\n )\n }\n }\n\n if (hooks.update) {\n for (const fn of hooks.update) scope.addUpdateHook(fn)\n }\n\n let subtreeCleanup: Cleanup = noop\n try {\n subtreeCleanup = output != null ? mountChild(output, parent, anchor) : noop\n } catch (err) {\n if (__DEV__) _mountingStack!.pop()\n scope.stop()\n const handled = propagateError(err, hooks) || dispatchToErrorBoundary(err)\n if (!handled) {\n reportError({\n component: componentName,\n phase: 'render',\n error: err,\n timestamp: Date.now(),\n props: vnode.props as Record<string, unknown>,\n })\n console.error(`[Pyreon] <${componentName}> threw during render:`, err)\n }\n return noop\n }\n\n if (__DEV__) {\n _mountingStack!.pop()\n const firstEl = parent instanceof Element ? parent.firstElementChild : null\n registerComponent(compId!, componentName, firstEl, devParentId!)\n }\n\n // Fire onMount hooks inline — effects created inside are tracked by the scope.\n // Lazy-allocate mountCleanups only when an onMount callback returns a cleanup fn.\n let mountCleanups: Cleanup[] | null = null\n if (hooks.mount) {\n for (const fn of hooks.mount) {\n try {\n let cleanup: (() => void) | undefined\n scope.runInScope(() => {\n cleanup = fn() as (() => void) | undefined\n })\n if (cleanup) {\n if (mountCleanups === null) mountCleanups = []\n mountCleanups.push(cleanup)\n }\n } catch (err) {\n console.error(`[Pyreon] Error in onMount hook of <${componentName}>:`, err)\n reportError({ component: componentName, phase: 'mount', error: err, timestamp: Date.now() })\n }\n }\n }\n\n return () => {\n if (__DEV__) unregisterComponent(compId!)\n scope.stop()\n subtreeCleanup()\n if (hooks.unmount) {\n for (const fn of hooks.unmount) {\n try {\n fn()\n } catch (err) {\n console.error(`[Pyreon] Error in onUnmount hook of <${componentName}>:`, err)\n reportError({\n component: componentName,\n phase: 'unmount',\n error: err,\n timestamp: Date.now(),\n })\n }\n }\n }\n if (mountCleanups) for (const fn of mountCleanups) fn()\n }\n}\n\n// ─── Children ────────────────────────────────────────────────────────────────\n\nfunction mountChildren(children: VNodeChild[], parent: Node, anchor: Node | null): Cleanup {\n if (children.length === 0) return noop\n\n // 1-child fast path\n if (children.length === 1) {\n const c = children[0] as VNodeChild\n if (c !== undefined) {\n if (anchor === null && (typeof c === 'string' || typeof c === 'number')) {\n ;(parent as HTMLElement).textContent = String(c)\n return noop\n }\n return mountChild(c, parent, anchor)\n }\n }\n\n // 2-child fast path — avoids .map() allocation (covers <tr><td/><td/></tr>)\n if (children.length === 2) {\n const c0 = children[0] as VNodeChild\n const c1 = children[1] as VNodeChild\n if (c0 !== undefined && c1 !== undefined) {\n const d0 = mountChild(c0, parent, anchor)\n const d1 = mountChild(c1, parent, anchor)\n if (d0 === noop && d1 === noop) return noop\n if (d0 === noop) return d1\n if (d1 === noop) return d0\n return () => {\n d0()\n d1()\n }\n }\n }\n\n const cleanups = children.map((c) => mountChild(c, parent, anchor))\n return () => {\n for (const fn of cleanups) fn()\n }\n}\n\n// ─── Keyed array detection ────────────────────────────────────────────────────\n\n/** Returns true if value is a non-empty array of VNodes that all carry keys. */\nfunction isKeyedArray(value: unknown): value is VNode[] {\n if (!Array.isArray(value) || value.length === 0) return false\n return value.every(\n (v) =>\n v !== null &&\n typeof v === 'object' &&\n !Array.isArray(v) &&\n (v as VNode).key !== null &&\n (v as VNode).key !== undefined,\n )\n}\n","import type { Props, VNodeChild } from '@pyreon/core'\nimport { createRef, h, onMount } from '@pyreon/core'\nimport { effect } from '@pyreon/reactivity'\nimport { mountChild } from './mount'\n\nexport interface KeepAliveProps extends Props {\n /**\n * Accessor that returns true when this slot's children should be visible.\n * When false, children are CSS-hidden but remain mounted — effects and\n * signals stay alive.\n * Defaults to true (always visible / always mounted).\n */\n active?: () => boolean\n children?: VNodeChild\n}\n\n/**\n * KeepAlive — mounts its children once and keeps them alive even when hidden.\n *\n * Unlike conditional rendering (which destroys and recreates component state),\n * KeepAlive CSS-hides the children while preserving all reactive state,\n * scroll position, form values, and in-flight async operations.\n *\n * Children are mounted imperatively on first activation and are never unmounted\n * while the KeepAlive itself is mounted.\n *\n * Multi-slot pattern (one KeepAlive per route):\n * @example\n * h(Fragment, null, [\n * h(KeepAlive, { active: () => route() === \"/a\" }, h(RouteA, null)),\n * h(KeepAlive, { active: () => route() === \"/b\" }, h(RouteB, null)),\n * ])\n *\n * With JSX:\n * @example\n * <>\n * <KeepAlive active={() => route() === \"/a\"}><RouteA /></KeepAlive>\n * <KeepAlive active={() => route() === \"/b\"}><RouteB /></KeepAlive>\n * </>\n */\nexport function KeepAlive(props: KeepAliveProps): VNodeChild {\n const containerRef = createRef<HTMLElement>()\n let childCleanup: (() => void) | null = null\n let childMounted = false\n\n onMount(() => {\n const container = containerRef.current\n if (!container) return\n\n const e = effect(() => {\n const isActive = props.active?.() ?? true\n\n if (!childMounted) {\n // Mount children into the container div exactly once\n childCleanup = mountChild(props.children ?? null, container, null)\n childMounted = true\n }\n\n // Show/hide without unmounting — state is fully preserved\n container.style.display = isActive ? '' : 'none'\n })\n\n return () => {\n e.dispose()\n childCleanup?.()\n }\n })\n\n // `display: contents` makes the wrapper transparent to layout\n // (children appear as if directly in the parent flow)\n return h('div', { ref: containerRef, style: 'display: contents' })\n}\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"transition-entry.js","names":[],"sources":["../src/transition.ts"],"sourcesContent":["import type { Props, VNode, VNodeChild } from '@pyreon/core'\nimport { createRef, Fragment, h, onUnmount } from '@pyreon/core'\nimport { effect, runUntracked, signal } from '@pyreon/reactivity'\n\n// Dev-mode gate: `import.meta.env.DEV` is the Vite/Rolldown standard,\n// literal-replaced at build time. The previous `typeof process !== 'undefined'`\n// pattern was dead code in real Vite browser bundles because Vite does not\n// polyfill `process` for the client — every wrapped warning silently never\n// fired in dev. Enforced by the `pyreon/no-process-dev-gate` lint rule.\n// @ts-ignore — `import.meta.env.DEV` is provided by Vite/Rolldown at build time\nconst __DEV__ = import.meta.env?.DEV === true\n\nexport interface TransitionProps {\n /**\n * CSS class name prefix.\n * \"fade\" → fade-enter-from, fade-enter-active, fade-enter-to, fade-leave-from, …\n * Default: \"pyreon\"\n */\n name?: string\n /** Reactive boolean controlling whether the child is shown. */\n show: () => boolean\n /**\n * If true, runs the enter transition on the initial mount (instead of\n * appearing immediately). Default: false.\n */\n appear?: boolean\n // Individual class name overrides (override the prefix-based defaults)\n enterFrom?: string\n enterActive?: string\n enterTo?: string\n leaveFrom?: string\n leaveActive?: string\n leaveTo?: string\n // Lifecycle callbacks\n onBeforeEnter?: (el: HTMLElement) => void\n onAfterEnter?: (el: HTMLElement) => void\n onBeforeLeave?: (el: HTMLElement) => void\n onAfterLeave?: (el: HTMLElement) => void\n /**\n * The single child element to animate.\n * Must be a direct DOM element VNode (not a component) for class injection to work.\n */\n children?: VNodeChild\n}\n\n/**\n * Transition — adds CSS enter/leave animation classes to a single child element,\n * controlled by the reactive `show` prop.\n *\n * Class lifecycle:\n * Enter: {name}-enter-from → (next frame) → {name}-enter-active + {name}-enter-to → cleanup\n * Leave: {name}-leave-from → (next frame) → {name}-leave-active + {name}-leave-to → unmount\n *\n * The child element stays in the DOM during the leave animation and is removed only\n * after the CSS transition / animation completes.\n *\n * @example\n * const visible = signal(false)\n *\n * h(Transition, { name: \"fade\", show: () => visible() },\n * h(\"div\", { class: \"modal\" }, \"content\")\n * )\n *\n * // CSS:\n * // .fade-enter-from, .fade-leave-to { opacity: 0; }\n * // .fade-enter-active, .fade-leave-active { transition: opacity 300ms ease; }\n */\nexport function Transition(props: TransitionProps): VNodeChild {\n const n = props.name ?? 'pyreon'\n const cls = {\n ef: props.enterFrom ?? `${n}-enter-from`,\n ea: props.enterActive ?? `${n}-enter-active`,\n et: props.enterTo ?? `${n}-enter-to`,\n lf: props.leaveFrom ?? `${n}-leave-from`,\n la: props.leaveActive ?? `${n}-leave-active`,\n lt: props.leaveTo ?? `${n}-leave-to`,\n }\n\n // Ref injected into the child element so we can apply/remove classes\n const ref = createRef<HTMLElement>()\n const isMounted = signal(runUntracked<boolean>(props.show))\n\n // Cancel in-progress enter / leave when the component unmounts or when a\n // new transition supersedes the current one. Both are set inside their\n // respective applyX(). Calling the cancel removes event listeners, clears\n // the safety timer, and strips active-state classes — WITHOUT firing the\n // onAfterX callback (which would run on a detached element after unmount).\n let pendingEnterCancel: (() => void) | null = null\n let pendingLeaveCancel: (() => void) | null = null\n let initialized = false\n\n const applyEnter = (el: HTMLElement) => {\n pendingLeaveCancel?.()\n pendingLeaveCancel = null\n pendingEnterCancel?.()\n pendingEnterCancel = null\n props.onBeforeEnter?.(el)\n el.classList.remove(cls.lf, cls.la, cls.lt)\n el.classList.add(cls.ef, cls.ea)\n requestAnimationFrame(() => {\n el.classList.remove(cls.ef)\n el.classList.add(cls.et)\n let safetyTimer: ReturnType<typeof setTimeout> | null = null\n const done = () => {\n // Remove both listeners — only one fires, so clean up the other\n el.removeEventListener('transitionend', done)\n el.removeEventListener('animationend', done)\n // Clear the safety timeout — without this, when transitionend fires\n // normally the 5s timer would still fire later and re-invoke done(),\n // leaking timer refs and re-firing onAfterEnter.\n if (safetyTimer !== null) {\n clearTimeout(safetyTimer)\n safetyTimer = null\n }\n pendingEnterCancel = null\n el.classList.remove(cls.ea, cls.et)\n props.onAfterEnter?.(el)\n }\n // Cancel path (called from onUnmount or a superseding transition): tears\n // down without firing onAfterEnter on a detached element.\n pendingEnterCancel = () => {\n el.removeEventListener('transitionend', done)\n el.removeEventListener('animationend', done)\n if (safetyTimer !== null) {\n clearTimeout(safetyTimer)\n safetyTimer = null\n }\n el.classList.remove(cls.ef, cls.ea, cls.et)\n }\n el.addEventListener('transitionend', done, { once: true })\n el.addEventListener('animationend', done, { once: true })\n // Safety timeout: if CSS animation never fires (bad CSS, off-screen), force cleanup\n safetyTimer = setTimeout(done, 5000)\n })\n }\n\n const applyLeave = (el: HTMLElement) => {\n pendingEnterCancel?.()\n pendingEnterCancel = null\n props.onBeforeLeave?.(el)\n el.classList.remove(cls.ef, cls.ea, cls.et)\n el.classList.add(cls.lf, cls.la)\n requestAnimationFrame(() => {\n el.classList.remove(cls.lf)\n el.classList.add(cls.lt)\n let safetyTimer: ReturnType<typeof setTimeout> | null = null\n const done = () => {\n // Remove both listeners — only one fires, so clean up the other\n el.removeEventListener('transitionend', done)\n el.removeEventListener('animationend', done)\n // Clear the safety timeout (see applyEnter for rationale).\n if (safetyTimer !== null) {\n clearTimeout(safetyTimer)\n safetyTimer = null\n }\n el.classList.remove(cls.la, cls.lt)\n pendingLeaveCancel = null\n isMounted.set(false)\n props.onAfterLeave?.(el)\n }\n pendingLeaveCancel = () => {\n el.removeEventListener('transitionend', done)\n el.removeEventListener('animationend', done)\n if (safetyTimer !== null) {\n clearTimeout(safetyTimer)\n safetyTimer = null\n }\n el.classList.remove(cls.lf, cls.la, cls.lt)\n }\n el.addEventListener('transitionend', done, { once: true })\n el.addEventListener('animationend', done, { once: true })\n // Safety timeout: if CSS animation never fires, force cleanup\n safetyTimer = setTimeout(done, 5000)\n })\n }\n\n const handleVisibilityChange = (visible: boolean) => {\n if (visible) {\n if (!isMounted.peek()) isMounted.set(true)\n queueMicrotask(() => applyEnter(ref.current as HTMLElement))\n return\n }\n if (!isMounted.peek()) return\n const el = ref.current\n if (!el) {\n isMounted.set(false)\n return\n }\n applyLeave(el)\n }\n\n effect(() => {\n const visible = props.show()\n if (!initialized) {\n initialized = true\n if (visible && props.appear) {\n queueMicrotask(() => applyEnter(ref.current as HTMLElement))\n }\n return\n }\n handleVisibilityChange(visible)\n })\n\n onUnmount(() => {\n // Cancel both pending transitions so neither fires its onAfterX\n // callback on a now-detached element after the 5s safety window.\n pendingEnterCancel?.()\n pendingEnterCancel = null\n pendingLeaveCancel?.()\n pendingLeaveCancel = null\n })\n\n // Return a reactive getter. Each call clones the child VNode with our injected ref\n // so we can read / write classes on the underlying DOM element.\n const rawChild = props.children\n // Return an empty Fragment (not null) when unmounted so mountChild uses\n // mountReactive instead of the null/primitive text-node fast-path, which\n // cannot later be swapped for a VNode when the element enters.\n const emptyFragment = h(Fragment, null)\n return (() => {\n if (!isMounted()) return emptyFragment\n if (!rawChild || typeof rawChild !== 'object' || Array.isArray(rawChild)) {\n return rawChild ?? null\n }\n const vnode = rawChild as VNode\n // Only inject ref into DOM element children — component children need ref forwarding\n if (typeof vnode.type !== 'string') {\n if (__DEV__) {\n console.warn(\n '[Pyreon] Transition child is a component. Wrap it in a DOM element for enter/leave animations to work.',\n )\n }\n return vnode\n }\n return { ...vnode, props: { ...vnode.props, ref } as Props }\n }) as unknown as VNode\n}\n"],"mappings":"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"}
|
package/lib/types/index.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index2.d.ts","names":[],"sources":["../../../src/delegate.ts","../../../src/devtools.ts","../../../src/hydrate.ts","../../../src/hydration-debug.ts","../../../src/keep-alive.ts","../../../src/mount.ts","../../../src/props.ts","../../../src/template.ts","../../../src/transition.ts","../../../src/transition-group.ts","../../../src/index.ts"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"keep-alive-entry2.d.ts","names":[],"sources":["../../../src/keep-alive.ts"],"mappings":";;;UAKiB,cAAA,SAAuB,KAAA;;AAAxC;;;;;EAOE,MAAA;EACA,QAAA,GAAW,UAAA;AAAA;;;AA2Bb;;;;;;;;;;;;;;;;;;;;;;iBAAgB,SAAA,CAAU,KAAA,EAAO,cAAA,GAAiB,UAAA"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"transition-entry2.d.ts","names":[],"sources":["../../../src/transition.ts"],"mappings":";;;UAYiB,eAAA;;AAAjB;;;;EAME,IAAA;EAkBqB;EAhBrB,IAAA;EAsBW;;;;EAjBX,MAAA;EAEA,SAAA;EACA,WAAA;EACA,OAAA;EACA,SAAA;EACA,WAAA;EACA,OAAA;EAEA,aAAA,IAAiB,EAAA,EAAI,WAAA;EACrB,YAAA,IAAgB,EAAA,EAAI,WAAA;EACpB,aAAA,IAAiB,EAAA,EAAI,WAAA;EACrB,YAAA,IAAgB,EAAA,EAAI,WAAA;EAFpB;;;;EAOA,QAAA,GAAW,UAAA;AAAA;;;;;;;;AAyBb;;;;;;;;;;;;;;;iBAAgB,UAAA,CAAW,KAAA,EAAO,eAAA,GAAkB,UAAA"}
|