@elurjs/core 3.5.0 → 3.5.1

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/README.md CHANGED
@@ -19,7 +19,7 @@ A lightweight, fully reactive framework for building modern web UIs — no virtu
19
19
  ## Installation
20
20
 
21
21
  ```bash
22
- npm install elur
22
+ npm install @elurjs/core
23
23
  ```
24
24
 
25
25
  ## Subpath Imports (Tree-Shaking)
@@ -39,12 +39,12 @@ import { provide, inject, createInjectionKey } from "elur/context";
39
39
  import { enableDevTools } from "elur/devtools";
40
40
  ```
41
41
 
42
- This is optional: `import { ... } from "elur"` remains fully supported.
42
+ This is optional: `import { ... } from "@elurjs/core"` remains fully supported.
43
43
 
44
44
  ## Quick Start
45
45
 
46
46
  ```typescript
47
- import { signal, html, ElurTemplate, ElurComponent, mount, createRouter, RouterView, Link, elurRouter } from "elur";
47
+ import { signal, html, ElurTemplate, ElurComponent, mount, createRouter, RouterView, Link, elurRouter } from "@elurjs/core";
48
48
 
49
49
  // --- Pages as function components (ElurTemplate) ---
50
50
  // Plain functions returning html`` are recommended for pages and
@@ -121,13 +121,13 @@ Everything ships in a single zero-dependency import:
121
121
  ## Server-side rendering & hydration (v3)
122
122
 
123
123
  ```bash
124
- npm install elur
124
+ npm install @elurjs/core
125
125
  ```
126
126
 
127
127
  ```typescript
128
128
  import { renderToString, renderToChunks, createServerRenderScope } from "elur/server";
129
129
  import { hydrate } from "elur/hydrate";
130
- import { raw } from "elur";
130
+ import { raw } from "@elurjs/core";
131
131
  ```
132
132
 
133
133
  - DOM-free SSR (`renderToString`), incremental streaming (`renderToChunks`) and
@@ -42,7 +42,7 @@ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=requi
42
42
  </div>
43
43
  `}function M(e){let t=n._debugGetRouterInternal(),i=t?`${t.mode}|${t.base}|${t.currentPath}|${JSON.stringify(t.params)}|${JSON.stringify(t.query)}|${t.matchedPath}|${t.activeGuards.names.join(`,`)}`:`none`;if(r.renderedTab===`router`&&r.renderKeys.router===i)return;if(r.renderKeys.router=i,r.renderedTab=`router`,!t){e.innerHTML=`
44
44
  <strong>Router State</strong>
45
- <div style="margin-top:8px;opacity:.75">No active Elur router instance. Ensure your app uses createRouter()/RouterView from elur/router.</div>
45
+ <div style="margin-top:8px;opacity:.75">No active Elur router instance. Ensure your app uses createRouter()/RouterView from @elurjs/core/router.</div>
46
46
  `;return}let a=b(t.matchedPath);e.innerHTML=`
47
47
  <strong>Router State</strong>
48
48
  <div data-elur-devtools-scroll="router" style="margin-top:8px;font-size:12px;line-height:1.55;max-height:280px;overflow:auto;overscroll-behavior:contain;border:1px solid #2f2f35;border-radius:8px;padding:8px;">
@@ -248,7 +248,7 @@ function M(e) {
248
248
  let t = n(), i = t ? `${t.mode}|${t.base}|${t.currentPath}|${JSON.stringify(t.params)}|${JSON.stringify(t.query)}|${t.matchedPath}|${t.activeGuards.names.join(",")}` : "none";
249
249
  if (r.renderedTab === "router" && r.renderKeys.router === i) return;
250
250
  if (r.renderKeys.router = i, r.renderedTab = "router", !t) {
251
- e.innerHTML = "\n <strong>Router State</strong>\n <div style=\"margin-top:8px;opacity:.75\">No active Elur router instance. Ensure your app uses createRouter()/RouterView from elur/router.</div>\n ";
251
+ e.innerHTML = "\n <strong>Router State</strong>\n <div style=\"margin-top:8px;opacity:.75\">No active Elur router instance. Ensure your app uses createRouter()/RouterView from @elurjs/core/router.</div>\n ";
252
252
  return;
253
253
  }
254
254
  let a = b(t.matchedPath);
@@ -42,7 +42,7 @@ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=requi
42
42
  </div>
43
43
  `}function M(e){let t=n._debugGetRouterInternal(),i=t?`${t.mode}|${t.base}|${t.currentPath}|${JSON.stringify(t.params)}|${JSON.stringify(t.query)}|${t.matchedPath}|${t.activeGuards.names.join(`,`)}`:`none`;if(r.renderedTab===`router`&&r.renderKeys.router===i)return;if(r.renderKeys.router=i,r.renderedTab=`router`,!t){e.innerHTML=`
44
44
  <strong>Router State</strong>
45
- <div style="margin-top:8px;opacity:.75">No active Elur router instance. Ensure your app uses createRouter()/RouterView from elur/router.</div>
45
+ <div style="margin-top:8px;opacity:.75">No active Elur router instance. Ensure your app uses createRouter()/RouterView from @elurjs/core/router.</div>
46
46
  `;return}let a=b(t.matchedPath);e.innerHTML=`
47
47
  <strong>Router State</strong>
48
48
  <div data-elur-devtools-scroll="router" style="margin-top:8px;font-size:12px;line-height:1.55;max-height:280px;overflow:auto;overscroll-behavior:contain;border:1px solid #2f2f35;border-radius:8px;padding:8px;">
@@ -1 +1 @@
1
- {"version":3,"file":"devtools.cjs","names":[],"sources":["../../src/elur/devtools.ts"],"sourcesContent":["import { _debugGetRouterInternal } from \"./router.js\";\nimport {\n _setComponentDebugHooks,\n type ElurComponent,\n} from \"./lifecycle.js\";\nimport {\n _setSignalDebugHooks,\n type Signal,\n} from \"./reactivity.js\";\n\nexport interface DevToolsOptions {\n refreshMs?: number;\n historyLimit?: number;\n initiallyOpen?: boolean;\n position?: \"bottom-right\" | \"bottom-left\";\n}\n\ntype _DevToolsTab = \"signals\" | \"components\" | \"router\";\n\ninterface _DevToolsState {\n enabled: boolean;\n activeTab: _DevToolsTab;\n renderedTab: _DevToolsTab | null;\n refreshId: ReturnType<typeof setInterval> | null;\n root: HTMLDivElement | null;\n panel: HTMLDivElement | null;\n content: HTMLDivElement | null;\n dispose: (() => void) | null;\n renderKeys: Record<_DevToolsTab, string>;\n scrollMemo: Record<_DevToolsTab, { top: number; left: number }>;\n}\n\nconst _state: _DevToolsState = {\n enabled: false,\n activeTab: \"signals\",\n renderedTab: null,\n refreshId: null,\n root: null,\n panel: null,\n content: null,\n dispose: null,\n renderKeys: { signals: \"\", components: \"\", router: \"\" },\n scrollMemo: {\n signals: { top: 0, left: 0 },\n components: { top: 0, left: 0 },\n router: { top: 0, left: 0 },\n },\n};\n\ntype _SignalRef = { deref(): Signal<any> | undefined };\n\ninterface _SignalMeta {\n id: number;\n createdAt: number;\n lastUpdated: number;\n history: Array<{ at: number; value: unknown }>;\n}\n\ninterface _SignalSnapshot {\n id: number;\n value: unknown;\n subscriberCount: number;\n createdAt: number;\n lastUpdated: number;\n history: Array<{ at: number; value: unknown }>;\n}\n\ninterface _ComponentSnapshot {\n id: number;\n parentId: number | null;\n debugName: string;\n mountedAt: number;\n hasDefaultSlot: boolean;\n slotNames: string[];\n props: Record<string, unknown>;\n}\n\ninterface _ComponentRecord extends _ComponentSnapshot {\n ref: _ComponentRef;\n}\n\ntype _ComponentRef = { deref(): ElurComponent | undefined };\n\nconst _signalRefs = new Set<_SignalRef>();\nlet _signalMeta = new WeakMap<Signal<any>, _SignalMeta>();\nlet _signalSeq = 1;\nlet _signalHistoryLimit = 50;\n\nlet _componentIds = new WeakMap<ElurComponent, number>();\nconst _componentMounted = new Map<number, _ComponentRecord>();\nconst _componentMountStack: number[] = [];\nlet _componentSeq = 1;\n\nfunction _makeSignalRef<T>(s: Signal<T>): _SignalRef {\n if (typeof WeakRef !== \"undefined\") return new WeakRef(s) as _SignalRef;\n return { deref: () => s };\n}\n\nfunction _makeComponentRef(inst: ElurComponent): _ComponentRef {\n if (typeof WeakRef !== \"undefined\") return new WeakRef(inst) as _ComponentRef;\n return { deref: () => inst };\n}\n\nfunction _trimSignalHistory(meta: _SignalMeta): void {\n if (meta.history.length > _signalHistoryLimit) {\n meta.history.splice(0, meta.history.length - _signalHistoryLimit);\n }\n}\n\nfunction _ensureSignalMeta<T>(s: Signal<T>, initialValue: T): _SignalMeta {\n const existing = _signalMeta.get(s);\n if (existing) {\n _trimSignalHistory(existing);\n return existing;\n }\n\n const now = Date.now();\n const meta: _SignalMeta = {\n id: _signalSeq++,\n createdAt: now,\n lastUpdated: now,\n history: [{ at: now, value: initialValue }],\n };\n _signalMeta.set(s, meta);\n _signalRefs.add(_makeSignalRef(s));\n return meta;\n}\n\n/** @internal Exported for testing. */\nexport function _listSignals(): _SignalSnapshot[] {\n const out: _SignalSnapshot[] = [];\n\n for (const ref of Array.from(_signalRefs)) {\n const s = ref.deref();\n if (!s) {\n _signalRefs.delete(ref);\n continue;\n }\n\n const meta = _signalMeta.get(s);\n if (!meta) continue;\n\n const subCount = (s as unknown as { _subs?: Set<() => void> })._subs?.size ?? 0;\n\n out.push({\n id: meta.id,\n value: s.peek(),\n subscriberCount: subCount,\n createdAt: meta.createdAt,\n lastUpdated: meta.lastUpdated,\n history: meta.history.slice(),\n });\n }\n\n out.sort((a, b) => b.lastUpdated - a.lastUpdated);\n return out;\n}\n\nfunction _componentName(inst: ElurComponent): string {\n const maybeDebugName = (inst as { _debugName?: string })._debugName;\n if (maybeDebugName && maybeDebugName.trim()) return maybeDebugName;\n const ctor = (inst as { constructor?: { name?: string } }).constructor;\n return ctor?.name && ctor.name.trim() ? ctor.name : \"AnonymousComponent\";\n}\n\nfunction _componentSlotNames(inst: ElurComponent): string[] {\n const slots = (inst as unknown as { _slots?: unknown })._slots;\n if (!(slots instanceof Map)) return [];\n return Array.from(slots.keys()).map((k) => String(k));\n}\n\nfunction _componentProps(inst: ElurComponent): Record<string, unknown> {\n const out: Record<string, unknown> = {};\n for (const key of Object.keys(inst as unknown as Record<string, unknown>)) {\n if (\n key === \"__isElurComponent\" ||\n key === \"children\" ||\n key === \"_debugName\" ||\n key.startsWith(\"_\")\n ) {\n continue;\n }\n const value = (inst as unknown as Record<string, unknown>)[key];\n if (typeof value === \"function\") continue;\n out[key] = value;\n }\n return out;\n}\n\nfunction _mountPathChain(fullPath: string | null): string[] {\n if (!fullPath) return [];\n if (fullPath === \"*\") return [\"*\"];\n\n const parts = fullPath.split(\"/\").filter(Boolean);\n const out: string[] = [];\n let cur = \"\";\n for (const part of parts) {\n cur += \"/\" + part;\n out.push(cur);\n }\n return out.length > 0 ? out : [\"/\"];\n}\n\nfunction _listMountedComponents(): _ComponentSnapshot[] {\n const out: _ComponentSnapshot[] = [];\n\n for (const [id, item] of _componentMounted) {\n const inst = item.ref.deref();\n if (!inst) {\n _componentMounted.delete(id);\n continue;\n }\n\n // Keep rows fresh while panel is open (debug name/props can change after mount).\n item.debugName = _componentName(inst);\n item.hasDefaultSlot = inst.children != null;\n item.slotNames = _componentSlotNames(inst);\n item.props = _componentProps(inst);\n\n out.push({\n id: item.id,\n parentId: item.parentId,\n debugName: item.debugName,\n mountedAt: item.mountedAt,\n hasDefaultSlot: item.hasDefaultSlot,\n slotNames: [...item.slotNames],\n props: { ...item.props },\n });\n }\n\n out.sort((a, b) => a.id - b.id);\n return out;\n}\n\nfunction _removeMountedComponentSubtree(rootId: number): void {\n const pending = [rootId];\n while (pending.length > 0) {\n const current = pending.pop()!;\n for (const [id, record] of _componentMounted) {\n if (record.parentId === current) pending.push(id);\n }\n _componentMounted.delete(current);\n }\n}\n\nfunction _resetDevtoolsStores(): void {\n _signalRefs.clear();\n _signalMeta = new WeakMap<Signal<any>, _SignalMeta>();\n _signalSeq = 1;\n\n _componentIds = new WeakMap<ElurComponent, number>();\n _componentMounted.clear();\n _componentMountStack.length = 0;\n _componentSeq = 1;\n}\n\nfunction _safeStringify(value: unknown): string {\n if (typeof value === \"string\") return value;\n if (typeof value === \"number\" || typeof value === \"boolean\" || value == null) {\n return String(value);\n }\n try {\n return JSON.stringify(value);\n } catch {\n return Object.prototype.toString.call(value);\n }\n}\n\nfunction _escapeHtml(value: string): string {\n return value\n .replace(/&/g, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\")\n .replace(/\\\"/g, \"&quot;\")\n .replace(/'/g, \"&#39;\");\n}\n\nfunction _valuePreview(value: unknown, max = 90): string {\n const raw = _safeStringify(value);\n if (raw.length <= max) return raw;\n return raw.slice(0, max - 1) + \"…\";\n}\n\nfunction _relativeTime(ts: number): string {\n if (!ts) return \"-\";\n const diff = Date.now() - ts;\n if (diff < 1000) return `${diff}ms ago`;\n if (diff < 60_000) return `${Math.floor(diff / 1000)}s ago`;\n return `${Math.floor(diff / 60_000)}m ago`;\n}\n\nfunction _renderSignals(target: HTMLDivElement): void {\n const signals = _listSignals();\n const key = `${signals.length}:${signals.map((s) => `${s.id}-${s.lastUpdated}-${s.subscriberCount}`).join(\"|\")}`;\n if (_state.renderedTab === \"signals\" && _state.renderKeys.signals === key) return;\n _state.renderKeys.signals = key;\n _state.renderedTab = \"signals\";\n\n const rows = signals\n .map((s) => {\n const fullValue = _safeStringify(s.value);\n const preview = _valuePreview(s.value, 120);\n return `<tr data-elur-devtools-signal-id=\"${s.id}\">\n <td style=\"padding:6px 8px;white-space:nowrap;\">${s.id}</td>\n <td style=\"padding:6px 8px;max-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-family:ui-monospace, SFMono-Regular, Menlo, monospace;\" title=\"${_escapeHtml(fullValue)}\">${_escapeHtml(preview)}</td>\n <td>${s.subscriberCount}</td>\n <td data-elur-devtools-history-count=\"${s.history.length}\">${s.history.length}</td>\n <td>${_relativeTime(s.lastUpdated)}</td>\n </tr>`;\n })\n .join(\"\");\n\n target.innerHTML = `\n <div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:8px;\">\n <strong>Signals</strong>\n <span style=\"opacity:.8\">${signals.length} active</span>\n </div>\n <div data-elur-devtools-scroll=\"signals\" style=\"max-height:260px;overflow:auto;overscroll-behavior:contain;border:1px solid #2f2f35;border-radius:8px;\">\n <table style=\"width:100%;border-collapse:collapse;font-size:12px;table-layout:fixed;\">\n <thead>\n <tr style=\"background:#1f1f24;\">\n <th style=\"text-align:left;padding:6px 8px;width:42px;\">ID</th>\n <th style=\"text-align:left;padding:6px 8px;\">Value</th>\n <th style=\"text-align:left;padding:6px 8px;width:50px;\">Subs</th>\n <th style=\"text-align:left;padding:6px 8px;width:50px;\">History</th>\n <th style=\"text-align:left;padding:6px 8px;width:84px;\">Updated</th>\n </tr>\n </thead>\n <tbody>${rows}</tbody>\n </table>\n </div>\n <p style=\"margin:8px 0 0 0;font-size:11px;opacity:.75;\">Click a row to log full history in console.</p>\n `;\n\n for (const row of target.querySelectorAll<HTMLTableRowElement>(\"tr[data-elur-devtools-signal-id]\")) {\n row.style.cursor = \"pointer\";\n row.addEventListener(\"click\", () => {\n const id = Number(row.dataset.elurDevtoolsSignalId);\n const signal = signals.find((s) => s.id === id);\n if (!signal) return;\n console.group(`[Elur DevTools] Signal #${signal.id}`);\n console.log(\"Current value:\", signal.value);\n console.log(\"Subscribers:\", signal.subscriberCount);\n console.table(signal.history.map((h) => ({ at: new Date(h.at).toISOString(), value: h.value })));\n console.groupEnd();\n });\n }\n}\n\ninterface _TreeNode extends _ComponentSnapshot {\n children: _TreeNode[];\n}\n\nfunction _buildComponentTree(rows: _ComponentSnapshot[]): _TreeNode[] {\n const byId = new Map<number, _TreeNode>();\n const roots: _TreeNode[] = [];\n\n for (const row of rows) {\n byId.set(row.id, { ...row, children: [] });\n }\n\n for (const node of byId.values()) {\n if (node.parentId == null) {\n roots.push(node);\n continue;\n }\n const parent = byId.get(node.parentId);\n if (!parent) {\n roots.push(node);\n continue;\n }\n parent.children.push(node);\n }\n\n return roots;\n}\n\nfunction _renderTreeNode(node: _TreeNode, depth: number): string {\n const pad = 10 + depth * 14;\n const props = Object.keys(node.props).length > 0 ? _safeStringify(node.props) : \"{}\";\n const slots = node.slotNames.length > 0 ? node.slotNames.join(\", \") : \"none\";\n\n const header = `<div style=\"padding:6px 8px 6px ${pad}px;border-bottom:1px solid #24242b;\">\n <div><strong>${_escapeHtml(node.debugName)}</strong> <span style=\"opacity:.7\">#${node.id}</span></div>\n <div style=\"font-size:11px;opacity:.8;\">slots: ${slots} | default-slot: ${node.hasDefaultSlot ? \"yes\" : \"no\"}</div>\n <div style=\"font-size:11px;opacity:.8;\">props: ${_escapeHtml(_valuePreview(props, 180))}</div>\n </div>`;\n\n return header + node.children.map((c) => _renderTreeNode(c, depth + 1)).join(\"\");\n}\n\nfunction _renderComponents(target: HTMLDivElement): void {\n const rows = _listMountedComponents();\n const router = _debugGetRouterInternal();\n const routeKey = router ? `${router.currentPath}|${router.matchedPath ?? \"\"}` : \"no-router\";\n const key = `${routeKey}:${rows.length}:${rows.map((r) => `${r.id}-${r.parentId}-${r.debugName}-${r.hasDefaultSlot}-${r.slotNames.join(\",\")}-${_safeStringify(r.props)}`).join(\"|\")}`;\n if (_state.renderedTab === \"components\" && _state.renderKeys.components === key) return;\n _state.renderKeys.components = key;\n _state.renderedTab = \"components\";\n\n const roots = _buildComponentTree(rows);\n\n target.innerHTML = `\n <div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:8px;\">\n <strong>Component Tree</strong>\n <span style=\"opacity:.8\">${rows.length} mounted</span>\n </div>\n <div style=\"font-size:11px;opacity:.82;margin-bottom:8px;display:flex;gap:8px;flex-wrap:wrap;\">\n <span><b>current:</b> ${_escapeHtml(router?.currentPath ?? \"-\")}</span>\n <span><b>matched:</b> ${_escapeHtml(router?.matchedPath ?? \"none\")}</span>\n </div>\n <div data-elur-devtools-scroll=\"components\" style=\"max-height:280px;overflow:auto;overscroll-behavior:contain;border:1px solid #2f2f35;border-radius:8px;\">\n ${roots.length > 0\n ? roots.map((r) => _renderTreeNode(r, 0)).join(\"\")\n : \"<div style='padding:10px;opacity:.75'>No mounted components tracked. Enable devtools before your first mount() to capture initial tree.</div>\"}\n </div>\n `;\n}\n\nfunction _renderRouter(target: HTMLDivElement): void {\n const router = _debugGetRouterInternal();\n const key = router\n ? `${router.mode}|${router.base}|${router.currentPath}|${JSON.stringify(router.params)}|${JSON.stringify(router.query)}|${router.matchedPath}|${router.activeGuards.names.join(\",\")}`\n : \"none\";\n if (_state.renderedTab === \"router\" && _state.renderKeys.router === key) return;\n _state.renderKeys.router = key;\n _state.renderedTab = \"router\";\n\n if (!router) {\n target.innerHTML = `\n <strong>Router State</strong>\n <div style=\"margin-top:8px;opacity:.75\">No active Elur router instance. Ensure your app uses createRouter()/RouterView from elur/router.</div>\n `;\n return;\n }\n\n const chain = _mountPathChain(router.matchedPath);\n target.innerHTML = `\n <strong>Router State</strong>\n <div data-elur-devtools-scroll=\"router\" style=\"margin-top:8px;font-size:12px;line-height:1.55;max-height:280px;overflow:auto;overscroll-behavior:contain;border:1px solid #2f2f35;border-radius:8px;padding:8px;\">\n <div><b>mode</b>: ${router.mode}</div>\n <div><b>base</b>: ${router.base}</div>\n <div><b>current</b>: ${_escapeHtml(router.currentPath)}</div>\n <div><b>params</b>: ${_escapeHtml(_safeStringify(router.params))}</div>\n <div><b>query</b>: ${_escapeHtml(_safeStringify(router.query))}</div>\n <div><b>matched</b>: ${_escapeHtml(router.matchedPath ?? \"none\")}</div>\n <div><b>matched chain</b>: ${chain.length > 0 ? _escapeHtml(chain.join(\" -> \")) : \"none\"}</div>\n <div><b>guards</b>: ${router.activeGuards.names.length > 0 ? _escapeHtml(router.activeGuards.names.join(\", \")) : \"none\"}</div>\n </div>\n `;\n}\n\nfunction _rememberScroll(tab: _DevToolsTab): void {\n if (!_state.content) return;\n const box = _state.content.querySelector<HTMLElement>(`[data-elur-devtools-scroll='${tab}']`);\n if (!box) return;\n _state.scrollMemo[tab] = { top: box.scrollTop, left: box.scrollLeft };\n}\n\nfunction _restoreScroll(tab: _DevToolsTab): void {\n if (!_state.content) return;\n const box = _state.content.querySelector<HTMLElement>(`[data-elur-devtools-scroll='${tab}']`);\n if (!box) return;\n const memo = _state.scrollMemo[tab];\n box.scrollTop = memo.top;\n box.scrollLeft = memo.left;\n if (box.dataset.elurDevtoolsScrollBound !== \"1\") {\n box.addEventListener(\"scroll\", () => {\n _state.scrollMemo[tab] = { top: box.scrollTop, left: box.scrollLeft };\n }, { passive: true });\n box.dataset.elurDevtoolsScrollBound = \"1\";\n }\n}\n\nfunction _refreshPanel(force = false): void {\n if (!_state.content) return;\n\n const tab = _state.activeTab;\n if (!force) _rememberScroll(tab);\n\n if (_state.activeTab === \"signals\") {\n _renderSignals(_state.content);\n _restoreScroll(\"signals\");\n return;\n }\n if (_state.activeTab === \"components\") {\n _renderComponents(_state.content);\n _restoreScroll(\"components\");\n return;\n }\n _renderRouter(_state.content);\n _restoreScroll(\"router\");\n}\n\nfunction _syncTabButtons(): void {\n if (!_state.panel) return;\n for (const btn of _state.panel.querySelectorAll<HTMLButtonElement>(\"button[data-elur-devtools-tab]\")) {\n const isActive = btn.dataset.elurDevtoolsTab === _state.activeTab;\n btn.style.background = isActive ? \"#2d4c7a\" : \"#1f1f24\";\n }\n}\n\nfunction _createOverlay(options: Required<Pick<DevToolsOptions, \"position\">>): void {\n const root = document.createElement(\"div\");\n root.setAttribute(\"data-elur-devtools-root\", \"\");\n root.style.position = \"fixed\";\n root.style.zIndex = \"2147483647\";\n root.style.bottom = \"16px\";\n root.style.right = options.position === \"bottom-right\" ? \"16px\" : \"auto\";\n root.style.left = options.position === \"bottom-left\" ? \"16px\" : \"auto\";\n root.style.fontFamily = \"ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, sans-serif\";\n\n const button = document.createElement(\"button\");\n button.type = \"button\";\n button.textContent = \"Elur DevTools\";\n button.setAttribute(\"data-elur-devtools-button\", \"\");\n button.style.background = \"#111827\";\n button.style.color = \"#f9fafb\";\n button.style.border = \"1px solid #374151\";\n button.style.borderRadius = \"999px\";\n button.style.padding = \"8px 12px\";\n button.style.cursor = \"pointer\";\n button.style.boxShadow = \"0 6px 18px rgba(0,0,0,.3)\";\n\n const panel = document.createElement(\"div\");\n panel.setAttribute(\"data-elur-devtools-panel\", \"\");\n panel.style.marginTop = \"8px\";\n panel.style.width = \"460px\";\n panel.style.maxWidth = \"min(92vw, 460px)\";\n panel.style.background = \"#15151b\";\n panel.style.color = \"#e5e7eb\";\n panel.style.border = \"1px solid #2f2f35\";\n panel.style.borderRadius = \"12px\";\n panel.style.padding = \"10px\";\n panel.style.display = \"none\";\n panel.style.boxShadow = \"0 14px 28px rgba(0,0,0,.35)\";\n\n const tabs = document.createElement(\"div\");\n tabs.style.display = \"flex\";\n tabs.style.gap = \"6px\";\n tabs.style.marginBottom = \"10px\";\n\n const content = document.createElement(\"div\");\n content.setAttribute(\"data-elur-devtools-content\", \"\");\n\n const makeTab = (name: _DevToolsTab, label: string): HTMLButtonElement => {\n const t = document.createElement(\"button\");\n t.type = \"button\";\n t.textContent = label;\n t.setAttribute(\"data-elur-devtools-tab\", name);\n t.style.border = \"1px solid #353543\";\n t.style.borderRadius = \"8px\";\n t.style.padding = \"6px 9px\";\n t.style.background = \"#1f1f24\";\n t.style.color = \"#d1d5db\";\n t.style.cursor = \"pointer\";\n t.addEventListener(\"click\", () => {\n _state.activeTab = name;\n _syncTabButtons();\n _refreshPanel(true);\n });\n return t;\n };\n\n tabs.appendChild(makeTab(\"signals\", \"Signals\"));\n tabs.appendChild(makeTab(\"components\", \"Components\"));\n tabs.appendChild(makeTab(\"router\", \"Router\"));\n\n button.addEventListener(\"click\", () => {\n panel.style.display = panel.style.display === \"none\" ? \"block\" : \"none\";\n if (panel.style.display === \"block\") {\n _syncTabButtons();\n _refreshPanel(true);\n }\n });\n\n panel.appendChild(tabs);\n panel.appendChild(content);\n root.appendChild(button);\n root.appendChild(panel);\n document.body.appendChild(root);\n\n _state.root = root;\n _state.panel = panel;\n _state.content = content;\n}\n\nexport function disableDevTools(): void {\n if (!_state.enabled) return;\n _state.enabled = false;\n\n if (_state.refreshId != null) {\n clearInterval(_state.refreshId);\n _state.refreshId = null;\n }\n\n _setSignalDebugHooks(null);\n _setComponentDebugHooks(null);\n _resetDevtoolsStores();\n\n if (_state.root?.parentNode) {\n _state.root.parentNode.removeChild(_state.root);\n }\n\n _state.root = null;\n _state.panel = null;\n _state.content = null;\n _state.dispose = null;\n _state.renderedTab = null;\n _state.renderKeys = { signals: \"\", components: \"\", router: \"\" };\n _state.scrollMemo = {\n signals: { top: 0, left: 0 },\n components: { top: 0, left: 0 },\n router: { top: 0, left: 0 },\n };\n}\n\nexport function enableDevTools(options: DevToolsOptions = {}): { disable: () => void } {\n if (typeof document === \"undefined\") {\n return { disable: () => undefined };\n }\n\n if (_state.enabled && _state.dispose) {\n return { disable: _state.dispose };\n }\n\n const refreshMs = Math.max(100, options.refreshMs ?? 350);\n _signalHistoryLimit = Math.max(1, options.historyLimit ?? 50);\n const position = options.position ?? \"bottom-right\";\n\n _state.enabled = true;\n _state.activeTab = \"signals\";\n\n // Apply the new limit to histories that were already created before enableDevTools.\n for (const ref of Array.from(_signalRefs)) {\n const s = ref.deref();\n if (!s) {\n _signalRefs.delete(ref);\n continue;\n }\n const meta = _signalMeta.get(s);\n if (meta) _trimSignalHistory(meta);\n }\n\n _setSignalDebugHooks({\n onCreate(signal, initialValue) {\n _ensureSignalMeta(signal, initialValue);\n },\n onWrite(signal, value) {\n const meta = _ensureSignalMeta(signal, value);\n const now = Date.now();\n meta.lastUpdated = now;\n meta.history.push({ at: now, value });\n _trimSignalHistory(meta);\n },\n });\n\n _setComponentDebugHooks({\n onMountStart(inst) {\n let id = _componentIds.get(inst);\n if (id == null) {\n id = _componentSeq++;\n _componentIds.set(inst, id);\n }\n\n const parentId = _componentMountStack.length > 0\n ? _componentMountStack[_componentMountStack.length - 1]\n : null;\n\n _componentMounted.set(id, {\n id,\n parentId,\n debugName: _componentName(inst),\n mountedAt: Date.now(),\n hasDefaultSlot: inst.children != null,\n slotNames: _componentSlotNames(inst),\n props: _componentProps(inst),\n ref: _makeComponentRef(inst),\n });\n\n _componentMountStack.push(id);\n },\n onMountEnd(inst) {\n const id = _componentIds.get(inst);\n if (id == null) return;\n\n const entry = _componentMounted.get(id);\n if (entry) {\n entry.debugName = _componentName(inst);\n entry.hasDefaultSlot = inst.children != null;\n entry.slotNames = _componentSlotNames(inst);\n entry.props = _componentProps(inst);\n }\n\n if (_componentMountStack[_componentMountStack.length - 1] === id) {\n _componentMountStack.pop();\n return;\n }\n\n const idx = _componentMountStack.lastIndexOf(id);\n if (idx >= 0) _componentMountStack.splice(idx, 1);\n },\n onUnmount(inst) {\n const id = _componentIds.get(inst);\n if (id == null) return;\n\n _removeMountedComponentSubtree(id);\n\n const idx = _componentMountStack.lastIndexOf(id);\n if (idx >= 0) _componentMountStack.splice(idx, 1);\n },\n });\n\n _createOverlay({ position });\n\n _state.refreshId = setInterval(() => {\n if (_state.panel?.style.display === \"block\") {\n _refreshPanel();\n }\n }, refreshMs);\n\n if (options.initiallyOpen && _state.panel) {\n _state.panel.style.display = \"block\";\n _syncTabButtons();\n _refreshPanel(true);\n }\n\n const dispose = () => disableDevTools();\n _state.dispose = dispose;\n return { disable: dispose };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"devtools.cjs","names":[],"sources":["../../src/elur/devtools.ts"],"sourcesContent":["import { _debugGetRouterInternal } from \"./router.js\";\nimport {\n _setComponentDebugHooks,\n type ElurComponent,\n} from \"./lifecycle.js\";\nimport {\n _setSignalDebugHooks,\n type Signal,\n} from \"./reactivity.js\";\n\nexport interface DevToolsOptions {\n refreshMs?: number;\n historyLimit?: number;\n initiallyOpen?: boolean;\n position?: \"bottom-right\" | \"bottom-left\";\n}\n\ntype _DevToolsTab = \"signals\" | \"components\" | \"router\";\n\ninterface _DevToolsState {\n enabled: boolean;\n activeTab: _DevToolsTab;\n renderedTab: _DevToolsTab | null;\n refreshId: ReturnType<typeof setInterval> | null;\n root: HTMLDivElement | null;\n panel: HTMLDivElement | null;\n content: HTMLDivElement | null;\n dispose: (() => void) | null;\n renderKeys: Record<_DevToolsTab, string>;\n scrollMemo: Record<_DevToolsTab, { top: number; left: number }>;\n}\n\nconst _state: _DevToolsState = {\n enabled: false,\n activeTab: \"signals\",\n renderedTab: null,\n refreshId: null,\n root: null,\n panel: null,\n content: null,\n dispose: null,\n renderKeys: { signals: \"\", components: \"\", router: \"\" },\n scrollMemo: {\n signals: { top: 0, left: 0 },\n components: { top: 0, left: 0 },\n router: { top: 0, left: 0 },\n },\n};\n\ntype _SignalRef = { deref(): Signal<any> | undefined };\n\ninterface _SignalMeta {\n id: number;\n createdAt: number;\n lastUpdated: number;\n history: Array<{ at: number; value: unknown }>;\n}\n\ninterface _SignalSnapshot {\n id: number;\n value: unknown;\n subscriberCount: number;\n createdAt: number;\n lastUpdated: number;\n history: Array<{ at: number; value: unknown }>;\n}\n\ninterface _ComponentSnapshot {\n id: number;\n parentId: number | null;\n debugName: string;\n mountedAt: number;\n hasDefaultSlot: boolean;\n slotNames: string[];\n props: Record<string, unknown>;\n}\n\ninterface _ComponentRecord extends _ComponentSnapshot {\n ref: _ComponentRef;\n}\n\ntype _ComponentRef = { deref(): ElurComponent | undefined };\n\nconst _signalRefs = new Set<_SignalRef>();\nlet _signalMeta = new WeakMap<Signal<any>, _SignalMeta>();\nlet _signalSeq = 1;\nlet _signalHistoryLimit = 50;\n\nlet _componentIds = new WeakMap<ElurComponent, number>();\nconst _componentMounted = new Map<number, _ComponentRecord>();\nconst _componentMountStack: number[] = [];\nlet _componentSeq = 1;\n\nfunction _makeSignalRef<T>(s: Signal<T>): _SignalRef {\n if (typeof WeakRef !== \"undefined\") return new WeakRef(s) as _SignalRef;\n return { deref: () => s };\n}\n\nfunction _makeComponentRef(inst: ElurComponent): _ComponentRef {\n if (typeof WeakRef !== \"undefined\") return new WeakRef(inst) as _ComponentRef;\n return { deref: () => inst };\n}\n\nfunction _trimSignalHistory(meta: _SignalMeta): void {\n if (meta.history.length > _signalHistoryLimit) {\n meta.history.splice(0, meta.history.length - _signalHistoryLimit);\n }\n}\n\nfunction _ensureSignalMeta<T>(s: Signal<T>, initialValue: T): _SignalMeta {\n const existing = _signalMeta.get(s);\n if (existing) {\n _trimSignalHistory(existing);\n return existing;\n }\n\n const now = Date.now();\n const meta: _SignalMeta = {\n id: _signalSeq++,\n createdAt: now,\n lastUpdated: now,\n history: [{ at: now, value: initialValue }],\n };\n _signalMeta.set(s, meta);\n _signalRefs.add(_makeSignalRef(s));\n return meta;\n}\n\n/** @internal Exported for testing. */\nexport function _listSignals(): _SignalSnapshot[] {\n const out: _SignalSnapshot[] = [];\n\n for (const ref of Array.from(_signalRefs)) {\n const s = ref.deref();\n if (!s) {\n _signalRefs.delete(ref);\n continue;\n }\n\n const meta = _signalMeta.get(s);\n if (!meta) continue;\n\n const subCount = (s as unknown as { _subs?: Set<() => void> })._subs?.size ?? 0;\n\n out.push({\n id: meta.id,\n value: s.peek(),\n subscriberCount: subCount,\n createdAt: meta.createdAt,\n lastUpdated: meta.lastUpdated,\n history: meta.history.slice(),\n });\n }\n\n out.sort((a, b) => b.lastUpdated - a.lastUpdated);\n return out;\n}\n\nfunction _componentName(inst: ElurComponent): string {\n const maybeDebugName = (inst as { _debugName?: string })._debugName;\n if (maybeDebugName && maybeDebugName.trim()) return maybeDebugName;\n const ctor = (inst as { constructor?: { name?: string } }).constructor;\n return ctor?.name && ctor.name.trim() ? ctor.name : \"AnonymousComponent\";\n}\n\nfunction _componentSlotNames(inst: ElurComponent): string[] {\n const slots = (inst as unknown as { _slots?: unknown })._slots;\n if (!(slots instanceof Map)) return [];\n return Array.from(slots.keys()).map((k) => String(k));\n}\n\nfunction _componentProps(inst: ElurComponent): Record<string, unknown> {\n const out: Record<string, unknown> = {};\n for (const key of Object.keys(inst as unknown as Record<string, unknown>)) {\n if (\n key === \"__isElurComponent\" ||\n key === \"children\" ||\n key === \"_debugName\" ||\n key.startsWith(\"_\")\n ) {\n continue;\n }\n const value = (inst as unknown as Record<string, unknown>)[key];\n if (typeof value === \"function\") continue;\n out[key] = value;\n }\n return out;\n}\n\nfunction _mountPathChain(fullPath: string | null): string[] {\n if (!fullPath) return [];\n if (fullPath === \"*\") return [\"*\"];\n\n const parts = fullPath.split(\"/\").filter(Boolean);\n const out: string[] = [];\n let cur = \"\";\n for (const part of parts) {\n cur += \"/\" + part;\n out.push(cur);\n }\n return out.length > 0 ? out : [\"/\"];\n}\n\nfunction _listMountedComponents(): _ComponentSnapshot[] {\n const out: _ComponentSnapshot[] = [];\n\n for (const [id, item] of _componentMounted) {\n const inst = item.ref.deref();\n if (!inst) {\n _componentMounted.delete(id);\n continue;\n }\n\n // Keep rows fresh while panel is open (debug name/props can change after mount).\n item.debugName = _componentName(inst);\n item.hasDefaultSlot = inst.children != null;\n item.slotNames = _componentSlotNames(inst);\n item.props = _componentProps(inst);\n\n out.push({\n id: item.id,\n parentId: item.parentId,\n debugName: item.debugName,\n mountedAt: item.mountedAt,\n hasDefaultSlot: item.hasDefaultSlot,\n slotNames: [...item.slotNames],\n props: { ...item.props },\n });\n }\n\n out.sort((a, b) => a.id - b.id);\n return out;\n}\n\nfunction _removeMountedComponentSubtree(rootId: number): void {\n const pending = [rootId];\n while (pending.length > 0) {\n const current = pending.pop()!;\n for (const [id, record] of _componentMounted) {\n if (record.parentId === current) pending.push(id);\n }\n _componentMounted.delete(current);\n }\n}\n\nfunction _resetDevtoolsStores(): void {\n _signalRefs.clear();\n _signalMeta = new WeakMap<Signal<any>, _SignalMeta>();\n _signalSeq = 1;\n\n _componentIds = new WeakMap<ElurComponent, number>();\n _componentMounted.clear();\n _componentMountStack.length = 0;\n _componentSeq = 1;\n}\n\nfunction _safeStringify(value: unknown): string {\n if (typeof value === \"string\") return value;\n if (typeof value === \"number\" || typeof value === \"boolean\" || value == null) {\n return String(value);\n }\n try {\n return JSON.stringify(value);\n } catch {\n return Object.prototype.toString.call(value);\n }\n}\n\nfunction _escapeHtml(value: string): string {\n return value\n .replace(/&/g, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\")\n .replace(/\\\"/g, \"&quot;\")\n .replace(/'/g, \"&#39;\");\n}\n\nfunction _valuePreview(value: unknown, max = 90): string {\n const raw = _safeStringify(value);\n if (raw.length <= max) return raw;\n return raw.slice(0, max - 1) + \"…\";\n}\n\nfunction _relativeTime(ts: number): string {\n if (!ts) return \"-\";\n const diff = Date.now() - ts;\n if (diff < 1000) return `${diff}ms ago`;\n if (diff < 60_000) return `${Math.floor(diff / 1000)}s ago`;\n return `${Math.floor(diff / 60_000)}m ago`;\n}\n\nfunction _renderSignals(target: HTMLDivElement): void {\n const signals = _listSignals();\n const key = `${signals.length}:${signals.map((s) => `${s.id}-${s.lastUpdated}-${s.subscriberCount}`).join(\"|\")}`;\n if (_state.renderedTab === \"signals\" && _state.renderKeys.signals === key) return;\n _state.renderKeys.signals = key;\n _state.renderedTab = \"signals\";\n\n const rows = signals\n .map((s) => {\n const fullValue = _safeStringify(s.value);\n const preview = _valuePreview(s.value, 120);\n return `<tr data-elur-devtools-signal-id=\"${s.id}\">\n <td style=\"padding:6px 8px;white-space:nowrap;\">${s.id}</td>\n <td style=\"padding:6px 8px;max-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-family:ui-monospace, SFMono-Regular, Menlo, monospace;\" title=\"${_escapeHtml(fullValue)}\">${_escapeHtml(preview)}</td>\n <td>${s.subscriberCount}</td>\n <td data-elur-devtools-history-count=\"${s.history.length}\">${s.history.length}</td>\n <td>${_relativeTime(s.lastUpdated)}</td>\n </tr>`;\n })\n .join(\"\");\n\n target.innerHTML = `\n <div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:8px;\">\n <strong>Signals</strong>\n <span style=\"opacity:.8\">${signals.length} active</span>\n </div>\n <div data-elur-devtools-scroll=\"signals\" style=\"max-height:260px;overflow:auto;overscroll-behavior:contain;border:1px solid #2f2f35;border-radius:8px;\">\n <table style=\"width:100%;border-collapse:collapse;font-size:12px;table-layout:fixed;\">\n <thead>\n <tr style=\"background:#1f1f24;\">\n <th style=\"text-align:left;padding:6px 8px;width:42px;\">ID</th>\n <th style=\"text-align:left;padding:6px 8px;\">Value</th>\n <th style=\"text-align:left;padding:6px 8px;width:50px;\">Subs</th>\n <th style=\"text-align:left;padding:6px 8px;width:50px;\">History</th>\n <th style=\"text-align:left;padding:6px 8px;width:84px;\">Updated</th>\n </tr>\n </thead>\n <tbody>${rows}</tbody>\n </table>\n </div>\n <p style=\"margin:8px 0 0 0;font-size:11px;opacity:.75;\">Click a row to log full history in console.</p>\n `;\n\n for (const row of target.querySelectorAll<HTMLTableRowElement>(\"tr[data-elur-devtools-signal-id]\")) {\n row.style.cursor = \"pointer\";\n row.addEventListener(\"click\", () => {\n const id = Number(row.dataset.elurDevtoolsSignalId);\n const signal = signals.find((s) => s.id === id);\n if (!signal) return;\n console.group(`[Elur DevTools] Signal #${signal.id}`);\n console.log(\"Current value:\", signal.value);\n console.log(\"Subscribers:\", signal.subscriberCount);\n console.table(signal.history.map((h) => ({ at: new Date(h.at).toISOString(), value: h.value })));\n console.groupEnd();\n });\n }\n}\n\ninterface _TreeNode extends _ComponentSnapshot {\n children: _TreeNode[];\n}\n\nfunction _buildComponentTree(rows: _ComponentSnapshot[]): _TreeNode[] {\n const byId = new Map<number, _TreeNode>();\n const roots: _TreeNode[] = [];\n\n for (const row of rows) {\n byId.set(row.id, { ...row, children: [] });\n }\n\n for (const node of byId.values()) {\n if (node.parentId == null) {\n roots.push(node);\n continue;\n }\n const parent = byId.get(node.parentId);\n if (!parent) {\n roots.push(node);\n continue;\n }\n parent.children.push(node);\n }\n\n return roots;\n}\n\nfunction _renderTreeNode(node: _TreeNode, depth: number): string {\n const pad = 10 + depth * 14;\n const props = Object.keys(node.props).length > 0 ? _safeStringify(node.props) : \"{}\";\n const slots = node.slotNames.length > 0 ? node.slotNames.join(\", \") : \"none\";\n\n const header = `<div style=\"padding:6px 8px 6px ${pad}px;border-bottom:1px solid #24242b;\">\n <div><strong>${_escapeHtml(node.debugName)}</strong> <span style=\"opacity:.7\">#${node.id}</span></div>\n <div style=\"font-size:11px;opacity:.8;\">slots: ${slots} | default-slot: ${node.hasDefaultSlot ? \"yes\" : \"no\"}</div>\n <div style=\"font-size:11px;opacity:.8;\">props: ${_escapeHtml(_valuePreview(props, 180))}</div>\n </div>`;\n\n return header + node.children.map((c) => _renderTreeNode(c, depth + 1)).join(\"\");\n}\n\nfunction _renderComponents(target: HTMLDivElement): void {\n const rows = _listMountedComponents();\n const router = _debugGetRouterInternal();\n const routeKey = router ? `${router.currentPath}|${router.matchedPath ?? \"\"}` : \"no-router\";\n const key = `${routeKey}:${rows.length}:${rows.map((r) => `${r.id}-${r.parentId}-${r.debugName}-${r.hasDefaultSlot}-${r.slotNames.join(\",\")}-${_safeStringify(r.props)}`).join(\"|\")}`;\n if (_state.renderedTab === \"components\" && _state.renderKeys.components === key) return;\n _state.renderKeys.components = key;\n _state.renderedTab = \"components\";\n\n const roots = _buildComponentTree(rows);\n\n target.innerHTML = `\n <div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:8px;\">\n <strong>Component Tree</strong>\n <span style=\"opacity:.8\">${rows.length} mounted</span>\n </div>\n <div style=\"font-size:11px;opacity:.82;margin-bottom:8px;display:flex;gap:8px;flex-wrap:wrap;\">\n <span><b>current:</b> ${_escapeHtml(router?.currentPath ?? \"-\")}</span>\n <span><b>matched:</b> ${_escapeHtml(router?.matchedPath ?? \"none\")}</span>\n </div>\n <div data-elur-devtools-scroll=\"components\" style=\"max-height:280px;overflow:auto;overscroll-behavior:contain;border:1px solid #2f2f35;border-radius:8px;\">\n ${roots.length > 0\n ? roots.map((r) => _renderTreeNode(r, 0)).join(\"\")\n : \"<div style='padding:10px;opacity:.75'>No mounted components tracked. Enable devtools before your first mount() to capture initial tree.</div>\"}\n </div>\n `;\n}\n\nfunction _renderRouter(target: HTMLDivElement): void {\n const router = _debugGetRouterInternal();\n const key = router\n ? `${router.mode}|${router.base}|${router.currentPath}|${JSON.stringify(router.params)}|${JSON.stringify(router.query)}|${router.matchedPath}|${router.activeGuards.names.join(\",\")}`\n : \"none\";\n if (_state.renderedTab === \"router\" && _state.renderKeys.router === key) return;\n _state.renderKeys.router = key;\n _state.renderedTab = \"router\";\n\n if (!router) {\n target.innerHTML = `\n <strong>Router State</strong>\n <div style=\"margin-top:8px;opacity:.75\">No active Elur router instance. Ensure your app uses createRouter()/RouterView from @elurjs/core/router.</div>\n `;\n return;\n }\n\n const chain = _mountPathChain(router.matchedPath);\n target.innerHTML = `\n <strong>Router State</strong>\n <div data-elur-devtools-scroll=\"router\" style=\"margin-top:8px;font-size:12px;line-height:1.55;max-height:280px;overflow:auto;overscroll-behavior:contain;border:1px solid #2f2f35;border-radius:8px;padding:8px;\">\n <div><b>mode</b>: ${router.mode}</div>\n <div><b>base</b>: ${router.base}</div>\n <div><b>current</b>: ${_escapeHtml(router.currentPath)}</div>\n <div><b>params</b>: ${_escapeHtml(_safeStringify(router.params))}</div>\n <div><b>query</b>: ${_escapeHtml(_safeStringify(router.query))}</div>\n <div><b>matched</b>: ${_escapeHtml(router.matchedPath ?? \"none\")}</div>\n <div><b>matched chain</b>: ${chain.length > 0 ? _escapeHtml(chain.join(\" -> \")) : \"none\"}</div>\n <div><b>guards</b>: ${router.activeGuards.names.length > 0 ? _escapeHtml(router.activeGuards.names.join(\", \")) : \"none\"}</div>\n </div>\n `;\n}\n\nfunction _rememberScroll(tab: _DevToolsTab): void {\n if (!_state.content) return;\n const box = _state.content.querySelector<HTMLElement>(`[data-elur-devtools-scroll='${tab}']`);\n if (!box) return;\n _state.scrollMemo[tab] = { top: box.scrollTop, left: box.scrollLeft };\n}\n\nfunction _restoreScroll(tab: _DevToolsTab): void {\n if (!_state.content) return;\n const box = _state.content.querySelector<HTMLElement>(`[data-elur-devtools-scroll='${tab}']`);\n if (!box) return;\n const memo = _state.scrollMemo[tab];\n box.scrollTop = memo.top;\n box.scrollLeft = memo.left;\n if (box.dataset.elurDevtoolsScrollBound !== \"1\") {\n box.addEventListener(\"scroll\", () => {\n _state.scrollMemo[tab] = { top: box.scrollTop, left: box.scrollLeft };\n }, { passive: true });\n box.dataset.elurDevtoolsScrollBound = \"1\";\n }\n}\n\nfunction _refreshPanel(force = false): void {\n if (!_state.content) return;\n\n const tab = _state.activeTab;\n if (!force) _rememberScroll(tab);\n\n if (_state.activeTab === \"signals\") {\n _renderSignals(_state.content);\n _restoreScroll(\"signals\");\n return;\n }\n if (_state.activeTab === \"components\") {\n _renderComponents(_state.content);\n _restoreScroll(\"components\");\n return;\n }\n _renderRouter(_state.content);\n _restoreScroll(\"router\");\n}\n\nfunction _syncTabButtons(): void {\n if (!_state.panel) return;\n for (const btn of _state.panel.querySelectorAll<HTMLButtonElement>(\"button[data-elur-devtools-tab]\")) {\n const isActive = btn.dataset.elurDevtoolsTab === _state.activeTab;\n btn.style.background = isActive ? \"#2d4c7a\" : \"#1f1f24\";\n }\n}\n\nfunction _createOverlay(options: Required<Pick<DevToolsOptions, \"position\">>): void {\n const root = document.createElement(\"div\");\n root.setAttribute(\"data-elur-devtools-root\", \"\");\n root.style.position = \"fixed\";\n root.style.zIndex = \"2147483647\";\n root.style.bottom = \"16px\";\n root.style.right = options.position === \"bottom-right\" ? \"16px\" : \"auto\";\n root.style.left = options.position === \"bottom-left\" ? \"16px\" : \"auto\";\n root.style.fontFamily = \"ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, sans-serif\";\n\n const button = document.createElement(\"button\");\n button.type = \"button\";\n button.textContent = \"Elur DevTools\";\n button.setAttribute(\"data-elur-devtools-button\", \"\");\n button.style.background = \"#111827\";\n button.style.color = \"#f9fafb\";\n button.style.border = \"1px solid #374151\";\n button.style.borderRadius = \"999px\";\n button.style.padding = \"8px 12px\";\n button.style.cursor = \"pointer\";\n button.style.boxShadow = \"0 6px 18px rgba(0,0,0,.3)\";\n\n const panel = document.createElement(\"div\");\n panel.setAttribute(\"data-elur-devtools-panel\", \"\");\n panel.style.marginTop = \"8px\";\n panel.style.width = \"460px\";\n panel.style.maxWidth = \"min(92vw, 460px)\";\n panel.style.background = \"#15151b\";\n panel.style.color = \"#e5e7eb\";\n panel.style.border = \"1px solid #2f2f35\";\n panel.style.borderRadius = \"12px\";\n panel.style.padding = \"10px\";\n panel.style.display = \"none\";\n panel.style.boxShadow = \"0 14px 28px rgba(0,0,0,.35)\";\n\n const tabs = document.createElement(\"div\");\n tabs.style.display = \"flex\";\n tabs.style.gap = \"6px\";\n tabs.style.marginBottom = \"10px\";\n\n const content = document.createElement(\"div\");\n content.setAttribute(\"data-elur-devtools-content\", \"\");\n\n const makeTab = (name: _DevToolsTab, label: string): HTMLButtonElement => {\n const t = document.createElement(\"button\");\n t.type = \"button\";\n t.textContent = label;\n t.setAttribute(\"data-elur-devtools-tab\", name);\n t.style.border = \"1px solid #353543\";\n t.style.borderRadius = \"8px\";\n t.style.padding = \"6px 9px\";\n t.style.background = \"#1f1f24\";\n t.style.color = \"#d1d5db\";\n t.style.cursor = \"pointer\";\n t.addEventListener(\"click\", () => {\n _state.activeTab = name;\n _syncTabButtons();\n _refreshPanel(true);\n });\n return t;\n };\n\n tabs.appendChild(makeTab(\"signals\", \"Signals\"));\n tabs.appendChild(makeTab(\"components\", \"Components\"));\n tabs.appendChild(makeTab(\"router\", \"Router\"));\n\n button.addEventListener(\"click\", () => {\n panel.style.display = panel.style.display === \"none\" ? \"block\" : \"none\";\n if (panel.style.display === \"block\") {\n _syncTabButtons();\n _refreshPanel(true);\n }\n });\n\n panel.appendChild(tabs);\n panel.appendChild(content);\n root.appendChild(button);\n root.appendChild(panel);\n document.body.appendChild(root);\n\n _state.root = root;\n _state.panel = panel;\n _state.content = content;\n}\n\nexport function disableDevTools(): void {\n if (!_state.enabled) return;\n _state.enabled = false;\n\n if (_state.refreshId != null) {\n clearInterval(_state.refreshId);\n _state.refreshId = null;\n }\n\n _setSignalDebugHooks(null);\n _setComponentDebugHooks(null);\n _resetDevtoolsStores();\n\n if (_state.root?.parentNode) {\n _state.root.parentNode.removeChild(_state.root);\n }\n\n _state.root = null;\n _state.panel = null;\n _state.content = null;\n _state.dispose = null;\n _state.renderedTab = null;\n _state.renderKeys = { signals: \"\", components: \"\", router: \"\" };\n _state.scrollMemo = {\n signals: { top: 0, left: 0 },\n components: { top: 0, left: 0 },\n router: { top: 0, left: 0 },\n };\n}\n\nexport function enableDevTools(options: DevToolsOptions = {}): { disable: () => void } {\n if (typeof document === \"undefined\") {\n return { disable: () => undefined };\n }\n\n if (_state.enabled && _state.dispose) {\n return { disable: _state.dispose };\n }\n\n const refreshMs = Math.max(100, options.refreshMs ?? 350);\n _signalHistoryLimit = Math.max(1, options.historyLimit ?? 50);\n const position = options.position ?? \"bottom-right\";\n\n _state.enabled = true;\n _state.activeTab = \"signals\";\n\n // Apply the new limit to histories that were already created before enableDevTools.\n for (const ref of Array.from(_signalRefs)) {\n const s = ref.deref();\n if (!s) {\n _signalRefs.delete(ref);\n continue;\n }\n const meta = _signalMeta.get(s);\n if (meta) _trimSignalHistory(meta);\n }\n\n _setSignalDebugHooks({\n onCreate(signal, initialValue) {\n _ensureSignalMeta(signal, initialValue);\n },\n onWrite(signal, value) {\n const meta = _ensureSignalMeta(signal, value);\n const now = Date.now();\n meta.lastUpdated = now;\n meta.history.push({ at: now, value });\n _trimSignalHistory(meta);\n },\n });\n\n _setComponentDebugHooks({\n onMountStart(inst) {\n let id = _componentIds.get(inst);\n if (id == null) {\n id = _componentSeq++;\n _componentIds.set(inst, id);\n }\n\n const parentId = _componentMountStack.length > 0\n ? _componentMountStack[_componentMountStack.length - 1]\n : null;\n\n _componentMounted.set(id, {\n id,\n parentId,\n debugName: _componentName(inst),\n mountedAt: Date.now(),\n hasDefaultSlot: inst.children != null,\n slotNames: _componentSlotNames(inst),\n props: _componentProps(inst),\n ref: _makeComponentRef(inst),\n });\n\n _componentMountStack.push(id);\n },\n onMountEnd(inst) {\n const id = _componentIds.get(inst);\n if (id == null) return;\n\n const entry = _componentMounted.get(id);\n if (entry) {\n entry.debugName = _componentName(inst);\n entry.hasDefaultSlot = inst.children != null;\n entry.slotNames = _componentSlotNames(inst);\n entry.props = _componentProps(inst);\n }\n\n if (_componentMountStack[_componentMountStack.length - 1] === id) {\n _componentMountStack.pop();\n return;\n }\n\n const idx = _componentMountStack.lastIndexOf(id);\n if (idx >= 0) _componentMountStack.splice(idx, 1);\n },\n onUnmount(inst) {\n const id = _componentIds.get(inst);\n if (id == null) return;\n\n _removeMountedComponentSubtree(id);\n\n const idx = _componentMountStack.lastIndexOf(id);\n if (idx >= 0) _componentMountStack.splice(idx, 1);\n },\n });\n\n _createOverlay({ position });\n\n _state.refreshId = setInterval(() => {\n if (_state.panel?.style.display === \"block\") {\n _refreshPanel();\n }\n }, refreshMs);\n\n if (options.initiallyOpen && _state.panel) {\n _state.panel.style.display = \"block\";\n _syncTabButtons();\n _refreshPanel(true);\n }\n\n const dispose = () => disableDevTools();\n _state.dispose = dispose;\n return { disable: dispose };\n}\n"],"mappings":"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"}
@@ -248,7 +248,7 @@ function M(e) {
248
248
  let t = n(), i = t ? `${t.mode}|${t.base}|${t.currentPath}|${JSON.stringify(t.params)}|${JSON.stringify(t.query)}|${t.matchedPath}|${t.activeGuards.names.join(",")}` : "none";
249
249
  if (r.renderedTab === "router" && r.renderKeys.router === i) return;
250
250
  if (r.renderKeys.router = i, r.renderedTab = "router", !t) {
251
- e.innerHTML = "\n <strong>Router State</strong>\n <div style=\"margin-top:8px;opacity:.75\">No active Elur router instance. Ensure your app uses createRouter()/RouterView from elur/router.</div>\n ";
251
+ e.innerHTML = "\n <strong>Router State</strong>\n <div style=\"margin-top:8px;opacity:.75\">No active Elur router instance. Ensure your app uses createRouter()/RouterView from @elurjs/core/router.</div>\n ";
252
252
  return;
253
253
  }
254
254
  let a = b(t.matchedPath);
@@ -1 +1 @@
1
- {"version":3,"file":"devtools.js","names":[],"sources":["../../src/elur/devtools.ts"],"sourcesContent":["import { _debugGetRouterInternal } from \"./router.js\";\nimport {\n _setComponentDebugHooks,\n type ElurComponent,\n} from \"./lifecycle.js\";\nimport {\n _setSignalDebugHooks,\n type Signal,\n} from \"./reactivity.js\";\n\nexport interface DevToolsOptions {\n refreshMs?: number;\n historyLimit?: number;\n initiallyOpen?: boolean;\n position?: \"bottom-right\" | \"bottom-left\";\n}\n\ntype _DevToolsTab = \"signals\" | \"components\" | \"router\";\n\ninterface _DevToolsState {\n enabled: boolean;\n activeTab: _DevToolsTab;\n renderedTab: _DevToolsTab | null;\n refreshId: ReturnType<typeof setInterval> | null;\n root: HTMLDivElement | null;\n panel: HTMLDivElement | null;\n content: HTMLDivElement | null;\n dispose: (() => void) | null;\n renderKeys: Record<_DevToolsTab, string>;\n scrollMemo: Record<_DevToolsTab, { top: number; left: number }>;\n}\n\nconst _state: _DevToolsState = {\n enabled: false,\n activeTab: \"signals\",\n renderedTab: null,\n refreshId: null,\n root: null,\n panel: null,\n content: null,\n dispose: null,\n renderKeys: { signals: \"\", components: \"\", router: \"\" },\n scrollMemo: {\n signals: { top: 0, left: 0 },\n components: { top: 0, left: 0 },\n router: { top: 0, left: 0 },\n },\n};\n\ntype _SignalRef = { deref(): Signal<any> | undefined };\n\ninterface _SignalMeta {\n id: number;\n createdAt: number;\n lastUpdated: number;\n history: Array<{ at: number; value: unknown }>;\n}\n\ninterface _SignalSnapshot {\n id: number;\n value: unknown;\n subscriberCount: number;\n createdAt: number;\n lastUpdated: number;\n history: Array<{ at: number; value: unknown }>;\n}\n\ninterface _ComponentSnapshot {\n id: number;\n parentId: number | null;\n debugName: string;\n mountedAt: number;\n hasDefaultSlot: boolean;\n slotNames: string[];\n props: Record<string, unknown>;\n}\n\ninterface _ComponentRecord extends _ComponentSnapshot {\n ref: _ComponentRef;\n}\n\ntype _ComponentRef = { deref(): ElurComponent | undefined };\n\nconst _signalRefs = new Set<_SignalRef>();\nlet _signalMeta = new WeakMap<Signal<any>, _SignalMeta>();\nlet _signalSeq = 1;\nlet _signalHistoryLimit = 50;\n\nlet _componentIds = new WeakMap<ElurComponent, number>();\nconst _componentMounted = new Map<number, _ComponentRecord>();\nconst _componentMountStack: number[] = [];\nlet _componentSeq = 1;\n\nfunction _makeSignalRef<T>(s: Signal<T>): _SignalRef {\n if (typeof WeakRef !== \"undefined\") return new WeakRef(s) as _SignalRef;\n return { deref: () => s };\n}\n\nfunction _makeComponentRef(inst: ElurComponent): _ComponentRef {\n if (typeof WeakRef !== \"undefined\") return new WeakRef(inst) as _ComponentRef;\n return { deref: () => inst };\n}\n\nfunction _trimSignalHistory(meta: _SignalMeta): void {\n if (meta.history.length > _signalHistoryLimit) {\n meta.history.splice(0, meta.history.length - _signalHistoryLimit);\n }\n}\n\nfunction _ensureSignalMeta<T>(s: Signal<T>, initialValue: T): _SignalMeta {\n const existing = _signalMeta.get(s);\n if (existing) {\n _trimSignalHistory(existing);\n return existing;\n }\n\n const now = Date.now();\n const meta: _SignalMeta = {\n id: _signalSeq++,\n createdAt: now,\n lastUpdated: now,\n history: [{ at: now, value: initialValue }],\n };\n _signalMeta.set(s, meta);\n _signalRefs.add(_makeSignalRef(s));\n return meta;\n}\n\n/** @internal Exported for testing. */\nexport function _listSignals(): _SignalSnapshot[] {\n const out: _SignalSnapshot[] = [];\n\n for (const ref of Array.from(_signalRefs)) {\n const s = ref.deref();\n if (!s) {\n _signalRefs.delete(ref);\n continue;\n }\n\n const meta = _signalMeta.get(s);\n if (!meta) continue;\n\n const subCount = (s as unknown as { _subs?: Set<() => void> })._subs?.size ?? 0;\n\n out.push({\n id: meta.id,\n value: s.peek(),\n subscriberCount: subCount,\n createdAt: meta.createdAt,\n lastUpdated: meta.lastUpdated,\n history: meta.history.slice(),\n });\n }\n\n out.sort((a, b) => b.lastUpdated - a.lastUpdated);\n return out;\n}\n\nfunction _componentName(inst: ElurComponent): string {\n const maybeDebugName = (inst as { _debugName?: string })._debugName;\n if (maybeDebugName && maybeDebugName.trim()) return maybeDebugName;\n const ctor = (inst as { constructor?: { name?: string } }).constructor;\n return ctor?.name && ctor.name.trim() ? ctor.name : \"AnonymousComponent\";\n}\n\nfunction _componentSlotNames(inst: ElurComponent): string[] {\n const slots = (inst as unknown as { _slots?: unknown })._slots;\n if (!(slots instanceof Map)) return [];\n return Array.from(slots.keys()).map((k) => String(k));\n}\n\nfunction _componentProps(inst: ElurComponent): Record<string, unknown> {\n const out: Record<string, unknown> = {};\n for (const key of Object.keys(inst as unknown as Record<string, unknown>)) {\n if (\n key === \"__isElurComponent\" ||\n key === \"children\" ||\n key === \"_debugName\" ||\n key.startsWith(\"_\")\n ) {\n continue;\n }\n const value = (inst as unknown as Record<string, unknown>)[key];\n if (typeof value === \"function\") continue;\n out[key] = value;\n }\n return out;\n}\n\nfunction _mountPathChain(fullPath: string | null): string[] {\n if (!fullPath) return [];\n if (fullPath === \"*\") return [\"*\"];\n\n const parts = fullPath.split(\"/\").filter(Boolean);\n const out: string[] = [];\n let cur = \"\";\n for (const part of parts) {\n cur += \"/\" + part;\n out.push(cur);\n }\n return out.length > 0 ? out : [\"/\"];\n}\n\nfunction _listMountedComponents(): _ComponentSnapshot[] {\n const out: _ComponentSnapshot[] = [];\n\n for (const [id, item] of _componentMounted) {\n const inst = item.ref.deref();\n if (!inst) {\n _componentMounted.delete(id);\n continue;\n }\n\n // Keep rows fresh while panel is open (debug name/props can change after mount).\n item.debugName = _componentName(inst);\n item.hasDefaultSlot = inst.children != null;\n item.slotNames = _componentSlotNames(inst);\n item.props = _componentProps(inst);\n\n out.push({\n id: item.id,\n parentId: item.parentId,\n debugName: item.debugName,\n mountedAt: item.mountedAt,\n hasDefaultSlot: item.hasDefaultSlot,\n slotNames: [...item.slotNames],\n props: { ...item.props },\n });\n }\n\n out.sort((a, b) => a.id - b.id);\n return out;\n}\n\nfunction _removeMountedComponentSubtree(rootId: number): void {\n const pending = [rootId];\n while (pending.length > 0) {\n const current = pending.pop()!;\n for (const [id, record] of _componentMounted) {\n if (record.parentId === current) pending.push(id);\n }\n _componentMounted.delete(current);\n }\n}\n\nfunction _resetDevtoolsStores(): void {\n _signalRefs.clear();\n _signalMeta = new WeakMap<Signal<any>, _SignalMeta>();\n _signalSeq = 1;\n\n _componentIds = new WeakMap<ElurComponent, number>();\n _componentMounted.clear();\n _componentMountStack.length = 0;\n _componentSeq = 1;\n}\n\nfunction _safeStringify(value: unknown): string {\n if (typeof value === \"string\") return value;\n if (typeof value === \"number\" || typeof value === \"boolean\" || value == null) {\n return String(value);\n }\n try {\n return JSON.stringify(value);\n } catch {\n return Object.prototype.toString.call(value);\n }\n}\n\nfunction _escapeHtml(value: string): string {\n return value\n .replace(/&/g, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\")\n .replace(/\\\"/g, \"&quot;\")\n .replace(/'/g, \"&#39;\");\n}\n\nfunction _valuePreview(value: unknown, max = 90): string {\n const raw = _safeStringify(value);\n if (raw.length <= max) return raw;\n return raw.slice(0, max - 1) + \"…\";\n}\n\nfunction _relativeTime(ts: number): string {\n if (!ts) return \"-\";\n const diff = Date.now() - ts;\n if (diff < 1000) return `${diff}ms ago`;\n if (diff < 60_000) return `${Math.floor(diff / 1000)}s ago`;\n return `${Math.floor(diff / 60_000)}m ago`;\n}\n\nfunction _renderSignals(target: HTMLDivElement): void {\n const signals = _listSignals();\n const key = `${signals.length}:${signals.map((s) => `${s.id}-${s.lastUpdated}-${s.subscriberCount}`).join(\"|\")}`;\n if (_state.renderedTab === \"signals\" && _state.renderKeys.signals === key) return;\n _state.renderKeys.signals = key;\n _state.renderedTab = \"signals\";\n\n const rows = signals\n .map((s) => {\n const fullValue = _safeStringify(s.value);\n const preview = _valuePreview(s.value, 120);\n return `<tr data-elur-devtools-signal-id=\"${s.id}\">\n <td style=\"padding:6px 8px;white-space:nowrap;\">${s.id}</td>\n <td style=\"padding:6px 8px;max-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-family:ui-monospace, SFMono-Regular, Menlo, monospace;\" title=\"${_escapeHtml(fullValue)}\">${_escapeHtml(preview)}</td>\n <td>${s.subscriberCount}</td>\n <td data-elur-devtools-history-count=\"${s.history.length}\">${s.history.length}</td>\n <td>${_relativeTime(s.lastUpdated)}</td>\n </tr>`;\n })\n .join(\"\");\n\n target.innerHTML = `\n <div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:8px;\">\n <strong>Signals</strong>\n <span style=\"opacity:.8\">${signals.length} active</span>\n </div>\n <div data-elur-devtools-scroll=\"signals\" style=\"max-height:260px;overflow:auto;overscroll-behavior:contain;border:1px solid #2f2f35;border-radius:8px;\">\n <table style=\"width:100%;border-collapse:collapse;font-size:12px;table-layout:fixed;\">\n <thead>\n <tr style=\"background:#1f1f24;\">\n <th style=\"text-align:left;padding:6px 8px;width:42px;\">ID</th>\n <th style=\"text-align:left;padding:6px 8px;\">Value</th>\n <th style=\"text-align:left;padding:6px 8px;width:50px;\">Subs</th>\n <th style=\"text-align:left;padding:6px 8px;width:50px;\">History</th>\n <th style=\"text-align:left;padding:6px 8px;width:84px;\">Updated</th>\n </tr>\n </thead>\n <tbody>${rows}</tbody>\n </table>\n </div>\n <p style=\"margin:8px 0 0 0;font-size:11px;opacity:.75;\">Click a row to log full history in console.</p>\n `;\n\n for (const row of target.querySelectorAll<HTMLTableRowElement>(\"tr[data-elur-devtools-signal-id]\")) {\n row.style.cursor = \"pointer\";\n row.addEventListener(\"click\", () => {\n const id = Number(row.dataset.elurDevtoolsSignalId);\n const signal = signals.find((s) => s.id === id);\n if (!signal) return;\n console.group(`[Elur DevTools] Signal #${signal.id}`);\n console.log(\"Current value:\", signal.value);\n console.log(\"Subscribers:\", signal.subscriberCount);\n console.table(signal.history.map((h) => ({ at: new Date(h.at).toISOString(), value: h.value })));\n console.groupEnd();\n });\n }\n}\n\ninterface _TreeNode extends _ComponentSnapshot {\n children: _TreeNode[];\n}\n\nfunction _buildComponentTree(rows: _ComponentSnapshot[]): _TreeNode[] {\n const byId = new Map<number, _TreeNode>();\n const roots: _TreeNode[] = [];\n\n for (const row of rows) {\n byId.set(row.id, { ...row, children: [] });\n }\n\n for (const node of byId.values()) {\n if (node.parentId == null) {\n roots.push(node);\n continue;\n }\n const parent = byId.get(node.parentId);\n if (!parent) {\n roots.push(node);\n continue;\n }\n parent.children.push(node);\n }\n\n return roots;\n}\n\nfunction _renderTreeNode(node: _TreeNode, depth: number): string {\n const pad = 10 + depth * 14;\n const props = Object.keys(node.props).length > 0 ? _safeStringify(node.props) : \"{}\";\n const slots = node.slotNames.length > 0 ? node.slotNames.join(\", \") : \"none\";\n\n const header = `<div style=\"padding:6px 8px 6px ${pad}px;border-bottom:1px solid #24242b;\">\n <div><strong>${_escapeHtml(node.debugName)}</strong> <span style=\"opacity:.7\">#${node.id}</span></div>\n <div style=\"font-size:11px;opacity:.8;\">slots: ${slots} | default-slot: ${node.hasDefaultSlot ? \"yes\" : \"no\"}</div>\n <div style=\"font-size:11px;opacity:.8;\">props: ${_escapeHtml(_valuePreview(props, 180))}</div>\n </div>`;\n\n return header + node.children.map((c) => _renderTreeNode(c, depth + 1)).join(\"\");\n}\n\nfunction _renderComponents(target: HTMLDivElement): void {\n const rows = _listMountedComponents();\n const router = _debugGetRouterInternal();\n const routeKey = router ? `${router.currentPath}|${router.matchedPath ?? \"\"}` : \"no-router\";\n const key = `${routeKey}:${rows.length}:${rows.map((r) => `${r.id}-${r.parentId}-${r.debugName}-${r.hasDefaultSlot}-${r.slotNames.join(\",\")}-${_safeStringify(r.props)}`).join(\"|\")}`;\n if (_state.renderedTab === \"components\" && _state.renderKeys.components === key) return;\n _state.renderKeys.components = key;\n _state.renderedTab = \"components\";\n\n const roots = _buildComponentTree(rows);\n\n target.innerHTML = `\n <div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:8px;\">\n <strong>Component Tree</strong>\n <span style=\"opacity:.8\">${rows.length} mounted</span>\n </div>\n <div style=\"font-size:11px;opacity:.82;margin-bottom:8px;display:flex;gap:8px;flex-wrap:wrap;\">\n <span><b>current:</b> ${_escapeHtml(router?.currentPath ?? \"-\")}</span>\n <span><b>matched:</b> ${_escapeHtml(router?.matchedPath ?? \"none\")}</span>\n </div>\n <div data-elur-devtools-scroll=\"components\" style=\"max-height:280px;overflow:auto;overscroll-behavior:contain;border:1px solid #2f2f35;border-radius:8px;\">\n ${roots.length > 0\n ? roots.map((r) => _renderTreeNode(r, 0)).join(\"\")\n : \"<div style='padding:10px;opacity:.75'>No mounted components tracked. Enable devtools before your first mount() to capture initial tree.</div>\"}\n </div>\n `;\n}\n\nfunction _renderRouter(target: HTMLDivElement): void {\n const router = _debugGetRouterInternal();\n const key = router\n ? `${router.mode}|${router.base}|${router.currentPath}|${JSON.stringify(router.params)}|${JSON.stringify(router.query)}|${router.matchedPath}|${router.activeGuards.names.join(\",\")}`\n : \"none\";\n if (_state.renderedTab === \"router\" && _state.renderKeys.router === key) return;\n _state.renderKeys.router = key;\n _state.renderedTab = \"router\";\n\n if (!router) {\n target.innerHTML = `\n <strong>Router State</strong>\n <div style=\"margin-top:8px;opacity:.75\">No active Elur router instance. Ensure your app uses createRouter()/RouterView from elur/router.</div>\n `;\n return;\n }\n\n const chain = _mountPathChain(router.matchedPath);\n target.innerHTML = `\n <strong>Router State</strong>\n <div data-elur-devtools-scroll=\"router\" style=\"margin-top:8px;font-size:12px;line-height:1.55;max-height:280px;overflow:auto;overscroll-behavior:contain;border:1px solid #2f2f35;border-radius:8px;padding:8px;\">\n <div><b>mode</b>: ${router.mode}</div>\n <div><b>base</b>: ${router.base}</div>\n <div><b>current</b>: ${_escapeHtml(router.currentPath)}</div>\n <div><b>params</b>: ${_escapeHtml(_safeStringify(router.params))}</div>\n <div><b>query</b>: ${_escapeHtml(_safeStringify(router.query))}</div>\n <div><b>matched</b>: ${_escapeHtml(router.matchedPath ?? \"none\")}</div>\n <div><b>matched chain</b>: ${chain.length > 0 ? _escapeHtml(chain.join(\" -> \")) : \"none\"}</div>\n <div><b>guards</b>: ${router.activeGuards.names.length > 0 ? _escapeHtml(router.activeGuards.names.join(\", \")) : \"none\"}</div>\n </div>\n `;\n}\n\nfunction _rememberScroll(tab: _DevToolsTab): void {\n if (!_state.content) return;\n const box = _state.content.querySelector<HTMLElement>(`[data-elur-devtools-scroll='${tab}']`);\n if (!box) return;\n _state.scrollMemo[tab] = { top: box.scrollTop, left: box.scrollLeft };\n}\n\nfunction _restoreScroll(tab: _DevToolsTab): void {\n if (!_state.content) return;\n const box = _state.content.querySelector<HTMLElement>(`[data-elur-devtools-scroll='${tab}']`);\n if (!box) return;\n const memo = _state.scrollMemo[tab];\n box.scrollTop = memo.top;\n box.scrollLeft = memo.left;\n if (box.dataset.elurDevtoolsScrollBound !== \"1\") {\n box.addEventListener(\"scroll\", () => {\n _state.scrollMemo[tab] = { top: box.scrollTop, left: box.scrollLeft };\n }, { passive: true });\n box.dataset.elurDevtoolsScrollBound = \"1\";\n }\n}\n\nfunction _refreshPanel(force = false): void {\n if (!_state.content) return;\n\n const tab = _state.activeTab;\n if (!force) _rememberScroll(tab);\n\n if (_state.activeTab === \"signals\") {\n _renderSignals(_state.content);\n _restoreScroll(\"signals\");\n return;\n }\n if (_state.activeTab === \"components\") {\n _renderComponents(_state.content);\n _restoreScroll(\"components\");\n return;\n }\n _renderRouter(_state.content);\n _restoreScroll(\"router\");\n}\n\nfunction _syncTabButtons(): void {\n if (!_state.panel) return;\n for (const btn of _state.panel.querySelectorAll<HTMLButtonElement>(\"button[data-elur-devtools-tab]\")) {\n const isActive = btn.dataset.elurDevtoolsTab === _state.activeTab;\n btn.style.background = isActive ? \"#2d4c7a\" : \"#1f1f24\";\n }\n}\n\nfunction _createOverlay(options: Required<Pick<DevToolsOptions, \"position\">>): void {\n const root = document.createElement(\"div\");\n root.setAttribute(\"data-elur-devtools-root\", \"\");\n root.style.position = \"fixed\";\n root.style.zIndex = \"2147483647\";\n root.style.bottom = \"16px\";\n root.style.right = options.position === \"bottom-right\" ? \"16px\" : \"auto\";\n root.style.left = options.position === \"bottom-left\" ? \"16px\" : \"auto\";\n root.style.fontFamily = \"ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, sans-serif\";\n\n const button = document.createElement(\"button\");\n button.type = \"button\";\n button.textContent = \"Elur DevTools\";\n button.setAttribute(\"data-elur-devtools-button\", \"\");\n button.style.background = \"#111827\";\n button.style.color = \"#f9fafb\";\n button.style.border = \"1px solid #374151\";\n button.style.borderRadius = \"999px\";\n button.style.padding = \"8px 12px\";\n button.style.cursor = \"pointer\";\n button.style.boxShadow = \"0 6px 18px rgba(0,0,0,.3)\";\n\n const panel = document.createElement(\"div\");\n panel.setAttribute(\"data-elur-devtools-panel\", \"\");\n panel.style.marginTop = \"8px\";\n panel.style.width = \"460px\";\n panel.style.maxWidth = \"min(92vw, 460px)\";\n panel.style.background = \"#15151b\";\n panel.style.color = \"#e5e7eb\";\n panel.style.border = \"1px solid #2f2f35\";\n panel.style.borderRadius = \"12px\";\n panel.style.padding = \"10px\";\n panel.style.display = \"none\";\n panel.style.boxShadow = \"0 14px 28px rgba(0,0,0,.35)\";\n\n const tabs = document.createElement(\"div\");\n tabs.style.display = \"flex\";\n tabs.style.gap = \"6px\";\n tabs.style.marginBottom = \"10px\";\n\n const content = document.createElement(\"div\");\n content.setAttribute(\"data-elur-devtools-content\", \"\");\n\n const makeTab = (name: _DevToolsTab, label: string): HTMLButtonElement => {\n const t = document.createElement(\"button\");\n t.type = \"button\";\n t.textContent = label;\n t.setAttribute(\"data-elur-devtools-tab\", name);\n t.style.border = \"1px solid #353543\";\n t.style.borderRadius = \"8px\";\n t.style.padding = \"6px 9px\";\n t.style.background = \"#1f1f24\";\n t.style.color = \"#d1d5db\";\n t.style.cursor = \"pointer\";\n t.addEventListener(\"click\", () => {\n _state.activeTab = name;\n _syncTabButtons();\n _refreshPanel(true);\n });\n return t;\n };\n\n tabs.appendChild(makeTab(\"signals\", \"Signals\"));\n tabs.appendChild(makeTab(\"components\", \"Components\"));\n tabs.appendChild(makeTab(\"router\", \"Router\"));\n\n button.addEventListener(\"click\", () => {\n panel.style.display = panel.style.display === \"none\" ? \"block\" : \"none\";\n if (panel.style.display === \"block\") {\n _syncTabButtons();\n _refreshPanel(true);\n }\n });\n\n panel.appendChild(tabs);\n panel.appendChild(content);\n root.appendChild(button);\n root.appendChild(panel);\n document.body.appendChild(root);\n\n _state.root = root;\n _state.panel = panel;\n _state.content = content;\n}\n\nexport function disableDevTools(): void {\n if (!_state.enabled) return;\n _state.enabled = false;\n\n if (_state.refreshId != null) {\n clearInterval(_state.refreshId);\n _state.refreshId = null;\n }\n\n _setSignalDebugHooks(null);\n _setComponentDebugHooks(null);\n _resetDevtoolsStores();\n\n if (_state.root?.parentNode) {\n _state.root.parentNode.removeChild(_state.root);\n }\n\n _state.root = null;\n _state.panel = null;\n _state.content = null;\n _state.dispose = null;\n _state.renderedTab = null;\n _state.renderKeys = { signals: \"\", components: \"\", router: \"\" };\n _state.scrollMemo = {\n signals: { top: 0, left: 0 },\n components: { top: 0, left: 0 },\n router: { top: 0, left: 0 },\n };\n}\n\nexport function enableDevTools(options: DevToolsOptions = {}): { disable: () => void } {\n if (typeof document === \"undefined\") {\n return { disable: () => undefined };\n }\n\n if (_state.enabled && _state.dispose) {\n return { disable: _state.dispose };\n }\n\n const refreshMs = Math.max(100, options.refreshMs ?? 350);\n _signalHistoryLimit = Math.max(1, options.historyLimit ?? 50);\n const position = options.position ?? \"bottom-right\";\n\n _state.enabled = true;\n _state.activeTab = \"signals\";\n\n // Apply the new limit to histories that were already created before enableDevTools.\n for (const ref of Array.from(_signalRefs)) {\n const s = ref.deref();\n if (!s) {\n _signalRefs.delete(ref);\n continue;\n }\n const meta = _signalMeta.get(s);\n if (meta) _trimSignalHistory(meta);\n }\n\n _setSignalDebugHooks({\n onCreate(signal, initialValue) {\n _ensureSignalMeta(signal, initialValue);\n },\n onWrite(signal, value) {\n const meta = _ensureSignalMeta(signal, value);\n const now = Date.now();\n meta.lastUpdated = now;\n meta.history.push({ at: now, value });\n _trimSignalHistory(meta);\n },\n });\n\n _setComponentDebugHooks({\n onMountStart(inst) {\n let id = _componentIds.get(inst);\n if (id == null) {\n id = _componentSeq++;\n _componentIds.set(inst, id);\n }\n\n const parentId = _componentMountStack.length > 0\n ? _componentMountStack[_componentMountStack.length - 1]\n : null;\n\n _componentMounted.set(id, {\n id,\n parentId,\n debugName: _componentName(inst),\n mountedAt: Date.now(),\n hasDefaultSlot: inst.children != null,\n slotNames: _componentSlotNames(inst),\n props: _componentProps(inst),\n ref: _makeComponentRef(inst),\n });\n\n _componentMountStack.push(id);\n },\n onMountEnd(inst) {\n const id = _componentIds.get(inst);\n if (id == null) return;\n\n const entry = _componentMounted.get(id);\n if (entry) {\n entry.debugName = _componentName(inst);\n entry.hasDefaultSlot = inst.children != null;\n entry.slotNames = _componentSlotNames(inst);\n entry.props = _componentProps(inst);\n }\n\n if (_componentMountStack[_componentMountStack.length - 1] === id) {\n _componentMountStack.pop();\n return;\n }\n\n const idx = _componentMountStack.lastIndexOf(id);\n if (idx >= 0) _componentMountStack.splice(idx, 1);\n },\n onUnmount(inst) {\n const id = _componentIds.get(inst);\n if (id == null) return;\n\n _removeMountedComponentSubtree(id);\n\n const idx = _componentMountStack.lastIndexOf(id);\n if (idx >= 0) _componentMountStack.splice(idx, 1);\n },\n });\n\n _createOverlay({ position });\n\n _state.refreshId = setInterval(() => {\n if (_state.panel?.style.display === \"block\") {\n _refreshPanel();\n }\n }, refreshMs);\n\n if (options.initiallyOpen && _state.panel) {\n _state.panel.style.display = \"block\";\n _syncTabButtons();\n _refreshPanel(true);\n }\n\n const dispose = () => disableDevTools();\n _state.dispose = dispose;\n return { disable: dispose };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"devtools.js","names":[],"sources":["../../src/elur/devtools.ts"],"sourcesContent":["import { _debugGetRouterInternal } from \"./router.js\";\nimport {\n _setComponentDebugHooks,\n type ElurComponent,\n} from \"./lifecycle.js\";\nimport {\n _setSignalDebugHooks,\n type Signal,\n} from \"./reactivity.js\";\n\nexport interface DevToolsOptions {\n refreshMs?: number;\n historyLimit?: number;\n initiallyOpen?: boolean;\n position?: \"bottom-right\" | \"bottom-left\";\n}\n\ntype _DevToolsTab = \"signals\" | \"components\" | \"router\";\n\ninterface _DevToolsState {\n enabled: boolean;\n activeTab: _DevToolsTab;\n renderedTab: _DevToolsTab | null;\n refreshId: ReturnType<typeof setInterval> | null;\n root: HTMLDivElement | null;\n panel: HTMLDivElement | null;\n content: HTMLDivElement | null;\n dispose: (() => void) | null;\n renderKeys: Record<_DevToolsTab, string>;\n scrollMemo: Record<_DevToolsTab, { top: number; left: number }>;\n}\n\nconst _state: _DevToolsState = {\n enabled: false,\n activeTab: \"signals\",\n renderedTab: null,\n refreshId: null,\n root: null,\n panel: null,\n content: null,\n dispose: null,\n renderKeys: { signals: \"\", components: \"\", router: \"\" },\n scrollMemo: {\n signals: { top: 0, left: 0 },\n components: { top: 0, left: 0 },\n router: { top: 0, left: 0 },\n },\n};\n\ntype _SignalRef = { deref(): Signal<any> | undefined };\n\ninterface _SignalMeta {\n id: number;\n createdAt: number;\n lastUpdated: number;\n history: Array<{ at: number; value: unknown }>;\n}\n\ninterface _SignalSnapshot {\n id: number;\n value: unknown;\n subscriberCount: number;\n createdAt: number;\n lastUpdated: number;\n history: Array<{ at: number; value: unknown }>;\n}\n\ninterface _ComponentSnapshot {\n id: number;\n parentId: number | null;\n debugName: string;\n mountedAt: number;\n hasDefaultSlot: boolean;\n slotNames: string[];\n props: Record<string, unknown>;\n}\n\ninterface _ComponentRecord extends _ComponentSnapshot {\n ref: _ComponentRef;\n}\n\ntype _ComponentRef = { deref(): ElurComponent | undefined };\n\nconst _signalRefs = new Set<_SignalRef>();\nlet _signalMeta = new WeakMap<Signal<any>, _SignalMeta>();\nlet _signalSeq = 1;\nlet _signalHistoryLimit = 50;\n\nlet _componentIds = new WeakMap<ElurComponent, number>();\nconst _componentMounted = new Map<number, _ComponentRecord>();\nconst _componentMountStack: number[] = [];\nlet _componentSeq = 1;\n\nfunction _makeSignalRef<T>(s: Signal<T>): _SignalRef {\n if (typeof WeakRef !== \"undefined\") return new WeakRef(s) as _SignalRef;\n return { deref: () => s };\n}\n\nfunction _makeComponentRef(inst: ElurComponent): _ComponentRef {\n if (typeof WeakRef !== \"undefined\") return new WeakRef(inst) as _ComponentRef;\n return { deref: () => inst };\n}\n\nfunction _trimSignalHistory(meta: _SignalMeta): void {\n if (meta.history.length > _signalHistoryLimit) {\n meta.history.splice(0, meta.history.length - _signalHistoryLimit);\n }\n}\n\nfunction _ensureSignalMeta<T>(s: Signal<T>, initialValue: T): _SignalMeta {\n const existing = _signalMeta.get(s);\n if (existing) {\n _trimSignalHistory(existing);\n return existing;\n }\n\n const now = Date.now();\n const meta: _SignalMeta = {\n id: _signalSeq++,\n createdAt: now,\n lastUpdated: now,\n history: [{ at: now, value: initialValue }],\n };\n _signalMeta.set(s, meta);\n _signalRefs.add(_makeSignalRef(s));\n return meta;\n}\n\n/** @internal Exported for testing. */\nexport function _listSignals(): _SignalSnapshot[] {\n const out: _SignalSnapshot[] = [];\n\n for (const ref of Array.from(_signalRefs)) {\n const s = ref.deref();\n if (!s) {\n _signalRefs.delete(ref);\n continue;\n }\n\n const meta = _signalMeta.get(s);\n if (!meta) continue;\n\n const subCount = (s as unknown as { _subs?: Set<() => void> })._subs?.size ?? 0;\n\n out.push({\n id: meta.id,\n value: s.peek(),\n subscriberCount: subCount,\n createdAt: meta.createdAt,\n lastUpdated: meta.lastUpdated,\n history: meta.history.slice(),\n });\n }\n\n out.sort((a, b) => b.lastUpdated - a.lastUpdated);\n return out;\n}\n\nfunction _componentName(inst: ElurComponent): string {\n const maybeDebugName = (inst as { _debugName?: string })._debugName;\n if (maybeDebugName && maybeDebugName.trim()) return maybeDebugName;\n const ctor = (inst as { constructor?: { name?: string } }).constructor;\n return ctor?.name && ctor.name.trim() ? ctor.name : \"AnonymousComponent\";\n}\n\nfunction _componentSlotNames(inst: ElurComponent): string[] {\n const slots = (inst as unknown as { _slots?: unknown })._slots;\n if (!(slots instanceof Map)) return [];\n return Array.from(slots.keys()).map((k) => String(k));\n}\n\nfunction _componentProps(inst: ElurComponent): Record<string, unknown> {\n const out: Record<string, unknown> = {};\n for (const key of Object.keys(inst as unknown as Record<string, unknown>)) {\n if (\n key === \"__isElurComponent\" ||\n key === \"children\" ||\n key === \"_debugName\" ||\n key.startsWith(\"_\")\n ) {\n continue;\n }\n const value = (inst as unknown as Record<string, unknown>)[key];\n if (typeof value === \"function\") continue;\n out[key] = value;\n }\n return out;\n}\n\nfunction _mountPathChain(fullPath: string | null): string[] {\n if (!fullPath) return [];\n if (fullPath === \"*\") return [\"*\"];\n\n const parts = fullPath.split(\"/\").filter(Boolean);\n const out: string[] = [];\n let cur = \"\";\n for (const part of parts) {\n cur += \"/\" + part;\n out.push(cur);\n }\n return out.length > 0 ? out : [\"/\"];\n}\n\nfunction _listMountedComponents(): _ComponentSnapshot[] {\n const out: _ComponentSnapshot[] = [];\n\n for (const [id, item] of _componentMounted) {\n const inst = item.ref.deref();\n if (!inst) {\n _componentMounted.delete(id);\n continue;\n }\n\n // Keep rows fresh while panel is open (debug name/props can change after mount).\n item.debugName = _componentName(inst);\n item.hasDefaultSlot = inst.children != null;\n item.slotNames = _componentSlotNames(inst);\n item.props = _componentProps(inst);\n\n out.push({\n id: item.id,\n parentId: item.parentId,\n debugName: item.debugName,\n mountedAt: item.mountedAt,\n hasDefaultSlot: item.hasDefaultSlot,\n slotNames: [...item.slotNames],\n props: { ...item.props },\n });\n }\n\n out.sort((a, b) => a.id - b.id);\n return out;\n}\n\nfunction _removeMountedComponentSubtree(rootId: number): void {\n const pending = [rootId];\n while (pending.length > 0) {\n const current = pending.pop()!;\n for (const [id, record] of _componentMounted) {\n if (record.parentId === current) pending.push(id);\n }\n _componentMounted.delete(current);\n }\n}\n\nfunction _resetDevtoolsStores(): void {\n _signalRefs.clear();\n _signalMeta = new WeakMap<Signal<any>, _SignalMeta>();\n _signalSeq = 1;\n\n _componentIds = new WeakMap<ElurComponent, number>();\n _componentMounted.clear();\n _componentMountStack.length = 0;\n _componentSeq = 1;\n}\n\nfunction _safeStringify(value: unknown): string {\n if (typeof value === \"string\") return value;\n if (typeof value === \"number\" || typeof value === \"boolean\" || value == null) {\n return String(value);\n }\n try {\n return JSON.stringify(value);\n } catch {\n return Object.prototype.toString.call(value);\n }\n}\n\nfunction _escapeHtml(value: string): string {\n return value\n .replace(/&/g, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\")\n .replace(/\\\"/g, \"&quot;\")\n .replace(/'/g, \"&#39;\");\n}\n\nfunction _valuePreview(value: unknown, max = 90): string {\n const raw = _safeStringify(value);\n if (raw.length <= max) return raw;\n return raw.slice(0, max - 1) + \"…\";\n}\n\nfunction _relativeTime(ts: number): string {\n if (!ts) return \"-\";\n const diff = Date.now() - ts;\n if (diff < 1000) return `${diff}ms ago`;\n if (diff < 60_000) return `${Math.floor(diff / 1000)}s ago`;\n return `${Math.floor(diff / 60_000)}m ago`;\n}\n\nfunction _renderSignals(target: HTMLDivElement): void {\n const signals = _listSignals();\n const key = `${signals.length}:${signals.map((s) => `${s.id}-${s.lastUpdated}-${s.subscriberCount}`).join(\"|\")}`;\n if (_state.renderedTab === \"signals\" && _state.renderKeys.signals === key) return;\n _state.renderKeys.signals = key;\n _state.renderedTab = \"signals\";\n\n const rows = signals\n .map((s) => {\n const fullValue = _safeStringify(s.value);\n const preview = _valuePreview(s.value, 120);\n return `<tr data-elur-devtools-signal-id=\"${s.id}\">\n <td style=\"padding:6px 8px;white-space:nowrap;\">${s.id}</td>\n <td style=\"padding:6px 8px;max-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-family:ui-monospace, SFMono-Regular, Menlo, monospace;\" title=\"${_escapeHtml(fullValue)}\">${_escapeHtml(preview)}</td>\n <td>${s.subscriberCount}</td>\n <td data-elur-devtools-history-count=\"${s.history.length}\">${s.history.length}</td>\n <td>${_relativeTime(s.lastUpdated)}</td>\n </tr>`;\n })\n .join(\"\");\n\n target.innerHTML = `\n <div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:8px;\">\n <strong>Signals</strong>\n <span style=\"opacity:.8\">${signals.length} active</span>\n </div>\n <div data-elur-devtools-scroll=\"signals\" style=\"max-height:260px;overflow:auto;overscroll-behavior:contain;border:1px solid #2f2f35;border-radius:8px;\">\n <table style=\"width:100%;border-collapse:collapse;font-size:12px;table-layout:fixed;\">\n <thead>\n <tr style=\"background:#1f1f24;\">\n <th style=\"text-align:left;padding:6px 8px;width:42px;\">ID</th>\n <th style=\"text-align:left;padding:6px 8px;\">Value</th>\n <th style=\"text-align:left;padding:6px 8px;width:50px;\">Subs</th>\n <th style=\"text-align:left;padding:6px 8px;width:50px;\">History</th>\n <th style=\"text-align:left;padding:6px 8px;width:84px;\">Updated</th>\n </tr>\n </thead>\n <tbody>${rows}</tbody>\n </table>\n </div>\n <p style=\"margin:8px 0 0 0;font-size:11px;opacity:.75;\">Click a row to log full history in console.</p>\n `;\n\n for (const row of target.querySelectorAll<HTMLTableRowElement>(\"tr[data-elur-devtools-signal-id]\")) {\n row.style.cursor = \"pointer\";\n row.addEventListener(\"click\", () => {\n const id = Number(row.dataset.elurDevtoolsSignalId);\n const signal = signals.find((s) => s.id === id);\n if (!signal) return;\n console.group(`[Elur DevTools] Signal #${signal.id}`);\n console.log(\"Current value:\", signal.value);\n console.log(\"Subscribers:\", signal.subscriberCount);\n console.table(signal.history.map((h) => ({ at: new Date(h.at).toISOString(), value: h.value })));\n console.groupEnd();\n });\n }\n}\n\ninterface _TreeNode extends _ComponentSnapshot {\n children: _TreeNode[];\n}\n\nfunction _buildComponentTree(rows: _ComponentSnapshot[]): _TreeNode[] {\n const byId = new Map<number, _TreeNode>();\n const roots: _TreeNode[] = [];\n\n for (const row of rows) {\n byId.set(row.id, { ...row, children: [] });\n }\n\n for (const node of byId.values()) {\n if (node.parentId == null) {\n roots.push(node);\n continue;\n }\n const parent = byId.get(node.parentId);\n if (!parent) {\n roots.push(node);\n continue;\n }\n parent.children.push(node);\n }\n\n return roots;\n}\n\nfunction _renderTreeNode(node: _TreeNode, depth: number): string {\n const pad = 10 + depth * 14;\n const props = Object.keys(node.props).length > 0 ? _safeStringify(node.props) : \"{}\";\n const slots = node.slotNames.length > 0 ? node.slotNames.join(\", \") : \"none\";\n\n const header = `<div style=\"padding:6px 8px 6px ${pad}px;border-bottom:1px solid #24242b;\">\n <div><strong>${_escapeHtml(node.debugName)}</strong> <span style=\"opacity:.7\">#${node.id}</span></div>\n <div style=\"font-size:11px;opacity:.8;\">slots: ${slots} | default-slot: ${node.hasDefaultSlot ? \"yes\" : \"no\"}</div>\n <div style=\"font-size:11px;opacity:.8;\">props: ${_escapeHtml(_valuePreview(props, 180))}</div>\n </div>`;\n\n return header + node.children.map((c) => _renderTreeNode(c, depth + 1)).join(\"\");\n}\n\nfunction _renderComponents(target: HTMLDivElement): void {\n const rows = _listMountedComponents();\n const router = _debugGetRouterInternal();\n const routeKey = router ? `${router.currentPath}|${router.matchedPath ?? \"\"}` : \"no-router\";\n const key = `${routeKey}:${rows.length}:${rows.map((r) => `${r.id}-${r.parentId}-${r.debugName}-${r.hasDefaultSlot}-${r.slotNames.join(\",\")}-${_safeStringify(r.props)}`).join(\"|\")}`;\n if (_state.renderedTab === \"components\" && _state.renderKeys.components === key) return;\n _state.renderKeys.components = key;\n _state.renderedTab = \"components\";\n\n const roots = _buildComponentTree(rows);\n\n target.innerHTML = `\n <div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:8px;\">\n <strong>Component Tree</strong>\n <span style=\"opacity:.8\">${rows.length} mounted</span>\n </div>\n <div style=\"font-size:11px;opacity:.82;margin-bottom:8px;display:flex;gap:8px;flex-wrap:wrap;\">\n <span><b>current:</b> ${_escapeHtml(router?.currentPath ?? \"-\")}</span>\n <span><b>matched:</b> ${_escapeHtml(router?.matchedPath ?? \"none\")}</span>\n </div>\n <div data-elur-devtools-scroll=\"components\" style=\"max-height:280px;overflow:auto;overscroll-behavior:contain;border:1px solid #2f2f35;border-radius:8px;\">\n ${roots.length > 0\n ? roots.map((r) => _renderTreeNode(r, 0)).join(\"\")\n : \"<div style='padding:10px;opacity:.75'>No mounted components tracked. Enable devtools before your first mount() to capture initial tree.</div>\"}\n </div>\n `;\n}\n\nfunction _renderRouter(target: HTMLDivElement): void {\n const router = _debugGetRouterInternal();\n const key = router\n ? `${router.mode}|${router.base}|${router.currentPath}|${JSON.stringify(router.params)}|${JSON.stringify(router.query)}|${router.matchedPath}|${router.activeGuards.names.join(\",\")}`\n : \"none\";\n if (_state.renderedTab === \"router\" && _state.renderKeys.router === key) return;\n _state.renderKeys.router = key;\n _state.renderedTab = \"router\";\n\n if (!router) {\n target.innerHTML = `\n <strong>Router State</strong>\n <div style=\"margin-top:8px;opacity:.75\">No active Elur router instance. Ensure your app uses createRouter()/RouterView from @elurjs/core/router.</div>\n `;\n return;\n }\n\n const chain = _mountPathChain(router.matchedPath);\n target.innerHTML = `\n <strong>Router State</strong>\n <div data-elur-devtools-scroll=\"router\" style=\"margin-top:8px;font-size:12px;line-height:1.55;max-height:280px;overflow:auto;overscroll-behavior:contain;border:1px solid #2f2f35;border-radius:8px;padding:8px;\">\n <div><b>mode</b>: ${router.mode}</div>\n <div><b>base</b>: ${router.base}</div>\n <div><b>current</b>: ${_escapeHtml(router.currentPath)}</div>\n <div><b>params</b>: ${_escapeHtml(_safeStringify(router.params))}</div>\n <div><b>query</b>: ${_escapeHtml(_safeStringify(router.query))}</div>\n <div><b>matched</b>: ${_escapeHtml(router.matchedPath ?? \"none\")}</div>\n <div><b>matched chain</b>: ${chain.length > 0 ? _escapeHtml(chain.join(\" -> \")) : \"none\"}</div>\n <div><b>guards</b>: ${router.activeGuards.names.length > 0 ? _escapeHtml(router.activeGuards.names.join(\", \")) : \"none\"}</div>\n </div>\n `;\n}\n\nfunction _rememberScroll(tab: _DevToolsTab): void {\n if (!_state.content) return;\n const box = _state.content.querySelector<HTMLElement>(`[data-elur-devtools-scroll='${tab}']`);\n if (!box) return;\n _state.scrollMemo[tab] = { top: box.scrollTop, left: box.scrollLeft };\n}\n\nfunction _restoreScroll(tab: _DevToolsTab): void {\n if (!_state.content) return;\n const box = _state.content.querySelector<HTMLElement>(`[data-elur-devtools-scroll='${tab}']`);\n if (!box) return;\n const memo = _state.scrollMemo[tab];\n box.scrollTop = memo.top;\n box.scrollLeft = memo.left;\n if (box.dataset.elurDevtoolsScrollBound !== \"1\") {\n box.addEventListener(\"scroll\", () => {\n _state.scrollMemo[tab] = { top: box.scrollTop, left: box.scrollLeft };\n }, { passive: true });\n box.dataset.elurDevtoolsScrollBound = \"1\";\n }\n}\n\nfunction _refreshPanel(force = false): void {\n if (!_state.content) return;\n\n const tab = _state.activeTab;\n if (!force) _rememberScroll(tab);\n\n if (_state.activeTab === \"signals\") {\n _renderSignals(_state.content);\n _restoreScroll(\"signals\");\n return;\n }\n if (_state.activeTab === \"components\") {\n _renderComponents(_state.content);\n _restoreScroll(\"components\");\n return;\n }\n _renderRouter(_state.content);\n _restoreScroll(\"router\");\n}\n\nfunction _syncTabButtons(): void {\n if (!_state.panel) return;\n for (const btn of _state.panel.querySelectorAll<HTMLButtonElement>(\"button[data-elur-devtools-tab]\")) {\n const isActive = btn.dataset.elurDevtoolsTab === _state.activeTab;\n btn.style.background = isActive ? \"#2d4c7a\" : \"#1f1f24\";\n }\n}\n\nfunction _createOverlay(options: Required<Pick<DevToolsOptions, \"position\">>): void {\n const root = document.createElement(\"div\");\n root.setAttribute(\"data-elur-devtools-root\", \"\");\n root.style.position = \"fixed\";\n root.style.zIndex = \"2147483647\";\n root.style.bottom = \"16px\";\n root.style.right = options.position === \"bottom-right\" ? \"16px\" : \"auto\";\n root.style.left = options.position === \"bottom-left\" ? \"16px\" : \"auto\";\n root.style.fontFamily = \"ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, sans-serif\";\n\n const button = document.createElement(\"button\");\n button.type = \"button\";\n button.textContent = \"Elur DevTools\";\n button.setAttribute(\"data-elur-devtools-button\", \"\");\n button.style.background = \"#111827\";\n button.style.color = \"#f9fafb\";\n button.style.border = \"1px solid #374151\";\n button.style.borderRadius = \"999px\";\n button.style.padding = \"8px 12px\";\n button.style.cursor = \"pointer\";\n button.style.boxShadow = \"0 6px 18px rgba(0,0,0,.3)\";\n\n const panel = document.createElement(\"div\");\n panel.setAttribute(\"data-elur-devtools-panel\", \"\");\n panel.style.marginTop = \"8px\";\n panel.style.width = \"460px\";\n panel.style.maxWidth = \"min(92vw, 460px)\";\n panel.style.background = \"#15151b\";\n panel.style.color = \"#e5e7eb\";\n panel.style.border = \"1px solid #2f2f35\";\n panel.style.borderRadius = \"12px\";\n panel.style.padding = \"10px\";\n panel.style.display = \"none\";\n panel.style.boxShadow = \"0 14px 28px rgba(0,0,0,.35)\";\n\n const tabs = document.createElement(\"div\");\n tabs.style.display = \"flex\";\n tabs.style.gap = \"6px\";\n tabs.style.marginBottom = \"10px\";\n\n const content = document.createElement(\"div\");\n content.setAttribute(\"data-elur-devtools-content\", \"\");\n\n const makeTab = (name: _DevToolsTab, label: string): HTMLButtonElement => {\n const t = document.createElement(\"button\");\n t.type = \"button\";\n t.textContent = label;\n t.setAttribute(\"data-elur-devtools-tab\", name);\n t.style.border = \"1px solid #353543\";\n t.style.borderRadius = \"8px\";\n t.style.padding = \"6px 9px\";\n t.style.background = \"#1f1f24\";\n t.style.color = \"#d1d5db\";\n t.style.cursor = \"pointer\";\n t.addEventListener(\"click\", () => {\n _state.activeTab = name;\n _syncTabButtons();\n _refreshPanel(true);\n });\n return t;\n };\n\n tabs.appendChild(makeTab(\"signals\", \"Signals\"));\n tabs.appendChild(makeTab(\"components\", \"Components\"));\n tabs.appendChild(makeTab(\"router\", \"Router\"));\n\n button.addEventListener(\"click\", () => {\n panel.style.display = panel.style.display === \"none\" ? \"block\" : \"none\";\n if (panel.style.display === \"block\") {\n _syncTabButtons();\n _refreshPanel(true);\n }\n });\n\n panel.appendChild(tabs);\n panel.appendChild(content);\n root.appendChild(button);\n root.appendChild(panel);\n document.body.appendChild(root);\n\n _state.root = root;\n _state.panel = panel;\n _state.content = content;\n}\n\nexport function disableDevTools(): void {\n if (!_state.enabled) return;\n _state.enabled = false;\n\n if (_state.refreshId != null) {\n clearInterval(_state.refreshId);\n _state.refreshId = null;\n }\n\n _setSignalDebugHooks(null);\n _setComponentDebugHooks(null);\n _resetDevtoolsStores();\n\n if (_state.root?.parentNode) {\n _state.root.parentNode.removeChild(_state.root);\n }\n\n _state.root = null;\n _state.panel = null;\n _state.content = null;\n _state.dispose = null;\n _state.renderedTab = null;\n _state.renderKeys = { signals: \"\", components: \"\", router: \"\" };\n _state.scrollMemo = {\n signals: { top: 0, left: 0 },\n components: { top: 0, left: 0 },\n router: { top: 0, left: 0 },\n };\n}\n\nexport function enableDevTools(options: DevToolsOptions = {}): { disable: () => void } {\n if (typeof document === \"undefined\") {\n return { disable: () => undefined };\n }\n\n if (_state.enabled && _state.dispose) {\n return { disable: _state.dispose };\n }\n\n const refreshMs = Math.max(100, options.refreshMs ?? 350);\n _signalHistoryLimit = Math.max(1, options.historyLimit ?? 50);\n const position = options.position ?? \"bottom-right\";\n\n _state.enabled = true;\n _state.activeTab = \"signals\";\n\n // Apply the new limit to histories that were already created before enableDevTools.\n for (const ref of Array.from(_signalRefs)) {\n const s = ref.deref();\n if (!s) {\n _signalRefs.delete(ref);\n continue;\n }\n const meta = _signalMeta.get(s);\n if (meta) _trimSignalHistory(meta);\n }\n\n _setSignalDebugHooks({\n onCreate(signal, initialValue) {\n _ensureSignalMeta(signal, initialValue);\n },\n onWrite(signal, value) {\n const meta = _ensureSignalMeta(signal, value);\n const now = Date.now();\n meta.lastUpdated = now;\n meta.history.push({ at: now, value });\n _trimSignalHistory(meta);\n },\n });\n\n _setComponentDebugHooks({\n onMountStart(inst) {\n let id = _componentIds.get(inst);\n if (id == null) {\n id = _componentSeq++;\n _componentIds.set(inst, id);\n }\n\n const parentId = _componentMountStack.length > 0\n ? _componentMountStack[_componentMountStack.length - 1]\n : null;\n\n _componentMounted.set(id, {\n id,\n parentId,\n debugName: _componentName(inst),\n mountedAt: Date.now(),\n hasDefaultSlot: inst.children != null,\n slotNames: _componentSlotNames(inst),\n props: _componentProps(inst),\n ref: _makeComponentRef(inst),\n });\n\n _componentMountStack.push(id);\n },\n onMountEnd(inst) {\n const id = _componentIds.get(inst);\n if (id == null) return;\n\n const entry = _componentMounted.get(id);\n if (entry) {\n entry.debugName = _componentName(inst);\n entry.hasDefaultSlot = inst.children != null;\n entry.slotNames = _componentSlotNames(inst);\n entry.props = _componentProps(inst);\n }\n\n if (_componentMountStack[_componentMountStack.length - 1] === id) {\n _componentMountStack.pop();\n return;\n }\n\n const idx = _componentMountStack.lastIndexOf(id);\n if (idx >= 0) _componentMountStack.splice(idx, 1);\n },\n onUnmount(inst) {\n const id = _componentIds.get(inst);\n if (id == null) return;\n\n _removeMountedComponentSubtree(id);\n\n const idx = _componentMountStack.lastIndexOf(id);\n if (idx >= 0) _componentMountStack.splice(idx, 1);\n },\n });\n\n _createOverlay({ position });\n\n _state.refreshId = setInterval(() => {\n if (_state.panel?.style.display === \"block\") {\n _refreshPanel();\n }\n }, refreshMs);\n\n if (options.initiallyOpen && _state.panel) {\n _state.panel.style.display = \"block\";\n _syncTabButtons();\n _refreshPanel(true);\n }\n\n const dispose = () => disableDevTools();\n _state.dispose = dispose;\n return { disable: dispose };\n}\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});function e(){return{ctxPool:[],ctxStack:[],activeEffect:null,activeDeps:null,activeErrorHandler:null,errorHandlerStack:[],batchLevel:0,pendingEffectsSet:new Set,pendingEffectsArr:[],effectDepth:0,notifyBuf:[],notifyBase:0,signalDebugHooks:null}}var t=Symbol.for(`elur/reactivity-state`),n=globalThis,r=(()=>{let r=n[t];if(r)return r;let i=e();return n[t]=i,i})();function i(e){r.errorHandlerStack.push(r.activeErrorHandler),r.activeErrorHandler=e}function a(){r.activeErrorHandler=r.errorHandlerStack.pop()??null}var o=100,s=64,c=16,l=32;function u(e){r.signalDebugHooks=e}function d(){return r.notifyBuf.length}var f=class{_value;_subs=new Set;constructor(e){this._value=e,r.signalDebugHooks?.onCreate?.(this,e)}get value(){return r.activeEffect&&(this._subs.add(r.activeEffect),r.activeDeps?.add(this)),this._value}set value(e){Object.is(this._value,e)||(this._value=e,r.signalDebugHooks?.onWrite?.(this,e),this._notify())}update(e){this.value=e(this._value)}peek(){return this._value}_removeSub(e){this._subs.delete(e)}_notify(){if(r.batchLevel>0){for(let e of this._subs)r.pendingEffectsSet.has(e)||(r.pendingEffectsSet.add(e),r.pendingEffectsArr.push(e));return}let e=r.notifyBase,t=0;for(let n of this._subs)r.notifyBuf[e+ t++]=n;r.notifyBase=e+t;try{for(let n=0;n<t;n++){let t=r.notifyBuf[e+n];r.notifyBuf[e+n]=null,t?.()}}finally{r.notifyBase=e,e===0&&r.notifyBuf.length>s&&t<c&&(r.notifyBuf.length=l)}}dispose(){this._subs.clear()}};function p(e){return new f(e)}function m(e){let t=!1,n,i=new Set,a=new Set,s=r.activeErrorHandler,c=()=>{if(t)return;typeof n==`function`&&n();let l=i;i=a,a=l,a.clear();let u=r.ctxPool.length>0?r.ctxPool.pop():{effect:null,deps:null};if(u.effect=r.activeEffect,u.deps=r.activeDeps,r.ctxStack.push(u),r.activeEffect=c,r.activeDeps=a,r.effectDepth++,r.effectDepth>o){r.effectDepth=0;let e=r.ctxStack.pop();throw r.activeEffect=e.effect,r.activeDeps=e.deps,e.effect=null,e.deps=null,r.ctxPool.push(e),Error(`[elur] Maximum effect re-execution depth exceeded (possible infinite loop).`)}try{n=e()}catch(e){if(s)s(e);else throw e}finally{r.effectDepth--;let e=r.ctxStack.pop();r.activeEffect=e.effect,r.activeDeps=e.deps,e.effect=null,e.deps=null,r.ctxPool.push(e);for(let e of i)a.has(e)||e._removeSub(c)}};return c(),()=>{t=!0,typeof n==`function`&&n();for(let e of a)e._removeSub(c);a.clear(),i.clear()}}var h=Symbol(`elur-computed-uninitialized`);function g(e,t=Object.is){let n=new f(h),r=null,i=!1,a=!1,o=()=>{i||a||(i=!0,v(()=>{r=m(()=>{let r=e(),i=n.peek();(i===h||!t(r,i))&&(n.value=r)})}))},s=Object.getOwnPropertyDescriptor(Object.getPrototypeOf(n),`value`);if(!s?.get||!s?.set)throw Error(`[elur] Internal error: Signal.value descriptor not found.`);Object.defineProperty(n,`value`,{get(){return o(),s.get.call(this)},set(e){s.set.call(this,e)},configurable:!0});let c=n.dispose;return n.dispose=()=>{a=!0,r?.(),r=null,c.call(n)},n}function _(e){r.batchLevel++;try{e()}finally{if(r.batchLevel--,r.batchLevel===0&&r.pendingEffectsArr.length>0){let e=r.pendingEffectsArr.length;for(let t=0;t<e;t++)r.pendingEffectsArr[t]();r.pendingEffectsArr.length=0,r.pendingEffectsSet.clear()}}}function v(e){let t=r.activeEffect,n=r.activeDeps;r.activeEffect=null,r.activeDeps=null;try{return e()}finally{r.activeEffect=t,r.activeDeps=n}}function y(e,t,n={}){let{immediate:r=!1,once:i=!1}=n,a=e instanceof f?()=>e.value:e,o,s=!0,c=!1,l=m(()=>{let e=a();if(s){if(s=!1,r&&!c){let n=e;v(()=>t(n,void 0)),i&&(c=!0,Promise.resolve().then(l))}o=e;return}if(!c){let n=e,r=o;o=e,v(()=>t(n,r)),i&&(c=!0,Promise.resolve().then(l))}});return()=>{c=!0,l()}}function b(e){return e?Promise.resolve().then(e):Promise.resolve()}exports.Signal=f,exports._getNotifyBufSize=d,exports._popErrorHandler=a,exports._pushErrorHandler=i,exports._setSignalDebugHooks=u,exports.batch=_,exports.computed=g,exports.effect=m,exports.nextTick=b,exports.signal=p,exports.untrack=v,exports.watch=y;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});function e(){return{ctxPool:[],ctxStack:[],activeEffect:null,activeDeps:null,activeErrorHandler:null,errorHandlerStack:[],batchLevel:0,pendingEffectsSet:new Set,pendingEffectsArr:[],effectDepth:0,notifyBuf:[],notifyBase:0,signalDebugHooks:null}}var t=Symbol.for(`@elurjs/core/reactivity-state`),n=globalThis,r=(()=>{let r=n[t];if(r)return r;let i=e();return n[t]=i,i})();function i(e){r.errorHandlerStack.push(r.activeErrorHandler),r.activeErrorHandler=e}function a(){r.activeErrorHandler=r.errorHandlerStack.pop()??null}var o=100,s=64,c=16,l=32;function u(e){r.signalDebugHooks=e}function d(){return r.notifyBuf.length}var f=class{_value;_subs=new Set;constructor(e){this._value=e,r.signalDebugHooks?.onCreate?.(this,e)}get value(){return r.activeEffect&&(this._subs.add(r.activeEffect),r.activeDeps?.add(this)),this._value}set value(e){Object.is(this._value,e)||(this._value=e,r.signalDebugHooks?.onWrite?.(this,e),this._notify())}update(e){this.value=e(this._value)}peek(){return this._value}_removeSub(e){this._subs.delete(e)}_notify(){if(r.batchLevel>0){for(let e of this._subs)r.pendingEffectsSet.has(e)||(r.pendingEffectsSet.add(e),r.pendingEffectsArr.push(e));return}let e=r.notifyBase,t=0;for(let n of this._subs)r.notifyBuf[e+ t++]=n;r.notifyBase=e+t;try{for(let n=0;n<t;n++){let t=r.notifyBuf[e+n];r.notifyBuf[e+n]=null,t?.()}}finally{r.notifyBase=e,e===0&&r.notifyBuf.length>s&&t<c&&(r.notifyBuf.length=l)}}dispose(){this._subs.clear()}};function p(e){return new f(e)}function m(e){let t=!1,n,i=new Set,a=new Set,s=r.activeErrorHandler,c=()=>{if(t)return;typeof n==`function`&&n();let l=i;i=a,a=l,a.clear();let u=r.ctxPool.length>0?r.ctxPool.pop():{effect:null,deps:null};if(u.effect=r.activeEffect,u.deps=r.activeDeps,r.ctxStack.push(u),r.activeEffect=c,r.activeDeps=a,r.effectDepth++,r.effectDepth>o){r.effectDepth=0;let e=r.ctxStack.pop();throw r.activeEffect=e.effect,r.activeDeps=e.deps,e.effect=null,e.deps=null,r.ctxPool.push(e),Error(`[elur] Maximum effect re-execution depth exceeded (possible infinite loop).`)}try{n=e()}catch(e){if(s)s(e);else throw e}finally{r.effectDepth--;let e=r.ctxStack.pop();r.activeEffect=e.effect,r.activeDeps=e.deps,e.effect=null,e.deps=null,r.ctxPool.push(e);for(let e of i)a.has(e)||e._removeSub(c)}};return c(),()=>{t=!0,typeof n==`function`&&n();for(let e of a)e._removeSub(c);a.clear(),i.clear()}}var h=Symbol(`elur-computed-uninitialized`);function g(e,t=Object.is){let n=new f(h),r=null,i=!1,a=!1,o=()=>{i||a||(i=!0,v(()=>{r=m(()=>{let r=e(),i=n.peek();(i===h||!t(r,i))&&(n.value=r)})}))},s=Object.getOwnPropertyDescriptor(Object.getPrototypeOf(n),`value`);if(!s?.get||!s?.set)throw Error(`[elur] Internal error: Signal.value descriptor not found.`);Object.defineProperty(n,`value`,{get(){return o(),s.get.call(this)},set(e){s.set.call(this,e)},configurable:!0});let c=n.dispose;return n.dispose=()=>{a=!0,r?.(),r=null,c.call(n)},n}function _(e){r.batchLevel++;try{e()}finally{if(r.batchLevel--,r.batchLevel===0&&r.pendingEffectsArr.length>0){let e=r.pendingEffectsArr.length;for(let t=0;t<e;t++)r.pendingEffectsArr[t]();r.pendingEffectsArr.length=0,r.pendingEffectsSet.clear()}}}function v(e){let t=r.activeEffect,n=r.activeDeps;r.activeEffect=null,r.activeDeps=null;try{return e()}finally{r.activeEffect=t,r.activeDeps=n}}function y(e,t,n={}){let{immediate:r=!1,once:i=!1}=n,a=e instanceof f?()=>e.value:e,o,s=!0,c=!1,l=m(()=>{let e=a();if(s){if(s=!1,r&&!c){let n=e;v(()=>t(n,void 0)),i&&(c=!0,Promise.resolve().then(l))}o=e;return}if(!c){let n=e,r=o;o=e,v(()=>t(n,r)),i&&(c=!0,Promise.resolve().then(l))}});return()=>{c=!0,l()}}function b(e){return e?Promise.resolve().then(e):Promise.resolve()}exports.Signal=f,exports._getNotifyBufSize=d,exports._popErrorHandler=a,exports._pushErrorHandler=i,exports._setSignalDebugHooks=u,exports.batch=_,exports.computed=g,exports.effect=m,exports.nextTick=b,exports.signal=p,exports.untrack=v,exports.watch=y;
2
2
  //# sourceMappingURL=signals.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"signals.cjs","names":[],"sources":["../../src/elur/reactivity.ts"],"sourcesContent":["// --- Dependency tracking ---\n\ninterface _EffectCtx {\n effect: (() => void) | null;\n deps: Set<Signal<any>> | null;\n}\n\ninterface _ReactivityGlobalState {\n ctxPool: _EffectCtx[];\n ctxStack: _EffectCtx[];\n activeEffect: (() => void) | null;\n activeDeps: Set<Signal<any>> | null;\n activeErrorHandler: ((err: unknown) => void) | null;\n errorHandlerStack: (((err: unknown) => void) | null)[];\n batchLevel: number;\n pendingEffectsSet: Set<() => void>;\n pendingEffectsArr: (() => void)[];\n effectDepth: number;\n notifyBuf: ((() => void) | null)[];\n notifyBase: number;\n signalDebugHooks: _SignalDebugHooks | null;\n}\n\nfunction _createReactivityState(): _ReactivityGlobalState {\n return {\n ctxPool: [],\n ctxStack: [],\n activeEffect: null,\n activeDeps: null,\n activeErrorHandler: null,\n errorHandlerStack: [],\n batchLevel: 0,\n pendingEffectsSet: new Set<() => void>(),\n pendingEffectsArr: [],\n effectDepth: 0,\n notifyBuf: [],\n notifyBase: 0,\n signalDebugHooks: null,\n };\n}\n\nconst _reactivityStateKey = Symbol.for(\"elur/reactivity-state\");\nconst _globalObj = globalThis as Record<PropertyKey, unknown>;\nconst _state = (() => {\n const existing = _globalObj[_reactivityStateKey] as _ReactivityGlobalState | undefined;\n if (existing) return existing;\n const created = _createReactivityState();\n _globalObj[_reactivityStateKey] = created;\n return created;\n})();\n\n// --- Error boundary support ---\n\n/**\n * @internal — Register an error boundary handler. All `effect()` calls made\n * synchronously while this handler is active will capture it. When those\n * effects re-run and throw, the captured handler is invoked.\n */\nexport function _pushErrorHandler(h: (err: unknown) => void): void {\n _state.errorHandlerStack.push(_state.activeErrorHandler);\n _state.activeErrorHandler = h;\n}\n\n/** @internal — Restore the previous error boundary handler. */\nexport function _popErrorHandler(): void {\n _state.activeErrorHandler = _state.errorHandlerStack.pop() ?? null;\n}\n\n// --- Batching ---\n\n/**\n * Guards against synchronous effect re-entrancy.\n *\n * Effects re-run synchronously when a signal they depend on changes. If an\n * effect writes to a signal it also reads, this creates a synchronous loop.\n * The guard below caps re-execution at MAX_EFFECT_DEPTH (100) iterations and\n * throws an error to prevent stack overflow.\n *\n * Throwing is deliberate: when the guard fires, the reactive graph is in an\n * inconsistent state — the effect partially executed, dependencies may be\n * stale, and continuing could produce incorrect UI. Throwing surfaces the\n * bug immediately instead of silently degrading.\n *\n * To avoid re-entrancy:\n * 1. Use `computed()` for derived state — computed signals cache their result\n * and only recompute when dependencies change. They never write to other\n * signals, so they can't loop.\n * 2. Use `watch()` for side effects — watch callbacks receive the new value;\n * if you need to update other signals, do it inside `batch()` to coalesce\n * notifications.\n * 3. Never write to a signal you read in the same effect — this is the direct\n * cause of re-entrancy. If you need to transform a value, use `computed()`\n * instead.\n * 4. Use `batch()` to group writes — batched writes flush once at the end,\n * preventing intermediate re-runs.\n */\n\nconst MAX_EFFECT_DEPTH = 100;\nconst _NOTIFY_SHRINK_TRIGGER = 64;\nconst _NOTIFY_LOW_USAGE = 16;\nconst _NOTIFY_SHRINK_TO = 32;\n\nexport interface _SignalDebugHooks {\n onCreate?: (signal: Signal<any>, initialValue: unknown) => void;\n onWrite?: (signal: Signal<any>, value: unknown) => void;\n}\n\nexport function _setSignalDebugHooks(hooks: _SignalDebugHooks | null): void {\n _state.signalDebugHooks = hooks;\n}\n\n/** @internal — notify buffer capacity, exposed for tests. */\nexport function _getNotifyBufSize(): number {\n return _state.notifyBuf.length;\n}\n\n// --- Signal ---\n\nexport class Signal<T> {\n private _value: T;\n private _subs = new Set<() => void>();\n\n constructor(initialValue: T) {\n this._value = initialValue;\n _state.signalDebugHooks?.onCreate?.(this, initialValue);\n }\n\n /** Read the current value. Subscribes the active effect if one exists. */\n get value(): T {\n if (_state.activeEffect) {\n this._subs.add(_state.activeEffect);\n _state.activeDeps?.add(this);\n }\n return this._value;\n }\n\n /** Write a new value. Notifies subscribers when the value changes. */\n set value(newValue: T) {\n if (Object.is(this._value, newValue)) return;\n this._value = newValue;\n _state.signalDebugHooks?.onWrite?.(this, newValue);\n this._notify();\n }\n\n /** Mutate the value via a updater function. */\n update(fn: (current: T) => T): void {\n this.value = fn(this._value);\n }\n\n /** Read without subscribing the active effect. */\n peek(): T {\n return this._value;\n }\n\n /** @internal */\n _removeSub(sub: () => void): void {\n this._subs.delete(sub);\n }\n\n private _notify(): void {\n if (_state.batchLevel > 0) {\n for (const s of this._subs) {\n if (!_state.pendingEffectsSet.has(s)) {\n _state.pendingEffectsSet.add(s);\n _state.pendingEffectsArr.push(s);\n }\n }\n return;\n }\n const base = _state.notifyBase;\n let len = 0;\n for (const s of this._subs) _state.notifyBuf[base + len++] = s;\n _state.notifyBase = base + len;\n try {\n for (let i = 0; i < len; i++) {\n const fn = _state.notifyBuf[base + i];\n _state.notifyBuf[base + i] = null!;\n fn?.();\n }\n } finally {\n _state.notifyBase = base;\n // Shrink oversized notify buffer after a low-usage top-level flush.\n if (\n base === 0 &&\n _state.notifyBuf.length > _NOTIFY_SHRINK_TRIGGER &&\n len < _NOTIFY_LOW_USAGE\n ) {\n _state.notifyBuf.length = _NOTIFY_SHRINK_TO;\n }\n }\n }\n\n dispose(): void {\n this._subs.clear();\n }\n}\n\n// --- Factories ---\n\nexport function signal<T>(initialValue: T): Signal<T> {\n return new Signal(initialValue);\n}\n\n/**\n * Runs `fn` and re-runs it whenever any signal read inside changes.\n * Returns a dispose function to tear down the effect.\n * If `fn` returns a function, it is called as cleanup before each re-run\n * and on disposal.\n */\nexport function effect(fn: () => void | (() => void)): () => void {\n let disposed = false;\n let cleanup: (() => void) | void;\n\n // Opt: Double buffering para evitar crear `new Set()` en cada ejecución\n let deps = new Set<Signal<any>>();\n let newDeps = new Set<Signal<any>>();\n\n const capturedErrorHandler = _state.activeErrorHandler;\n\n const execute = () => {\n if (disposed) return;\n if (typeof cleanup === \"function\") cleanup();\n\n // Intercambiamos los buffers. 'deps' ahora tiene los viejos, 'newDeps' está limpio para recolectar.\n const temp = deps;\n deps = newDeps;\n newDeps = temp;\n newDeps.clear();\n\n const ctx = _state.ctxPool.length > 0 ? _state.ctxPool.pop()! : { effect: null, deps: null };\n ctx.effect = _state.activeEffect;\n ctx.deps = _state.activeDeps;\n _state.ctxStack.push(ctx);\n _state.activeEffect = execute;\n _state.activeDeps = newDeps;\n\n _state.effectDepth++;\n if (_state.effectDepth > MAX_EFFECT_DEPTH) {\n _state.effectDepth = 0;\n // Restaurar desde el stack unificado\n const restored = _state.ctxStack.pop()!;\n _state.activeEffect = restored.effect;\n _state.activeDeps = restored.deps;\n restored.effect = null;\n restored.deps = null;\n _state.ctxPool.push(restored);\n throw new Error(\n \"[elur] Maximum effect re-execution depth exceeded (possible infinite loop).\"\n );\n }\n\n try {\n cleanup = fn();\n } catch (err) {\n if (capturedErrorHandler) {\n capturedErrorHandler(err);\n } else {\n throw err;\n }\n } finally {\n _state.effectDepth--;\n const restored = _state.ctxStack.pop()!;\n _state.activeEffect = restored.effect;\n _state.activeDeps = restored.deps;\n restored.effect = null; // limpiar referencias para GC\n restored.deps = null;\n _state.ctxPool.push(restored); // devolver al pool para reutilizar\n\n\n // Cleanup phase: Desuscribirse de señales que estaban en 'deps' pero NO en 'newDeps'\n for (const oldDep of deps) {\n if (!newDeps.has(oldDep)) {\n oldDep._removeSub(execute);\n }\n }\n }\n };\n\n execute();\n\n return () => {\n disposed = true;\n if (typeof cleanup === \"function\") cleanup();\n // Al desechar, usamos newDeps porque es el que quedó activo después del último execute\n for (const dep of newDeps) {\n dep._removeSub(execute);\n }\n newDeps.clear();\n deps.clear();\n };\n}\n\n/** Derived signal that recalculates when its dependencies change. */\nconst _computedSentinel = Symbol(\"elur-computed-uninitialized\");\n\nexport function computed<T>(\n fn: () => T,\n equals: (a: T, b: T) => boolean = Object.is,\n): Signal<T> & { dispose(): void } {\n const s = new Signal<T | typeof _computedSentinel>(_computedSentinel);\n let disposeEffect: (() => void) | null = null;\n let initialized = false;\n let disposed = false;\n\n const ensureInitialized = () => {\n if (initialized || disposed) return;\n initialized = true;\n // Important: initialize untracked so first computed evaluation does not\n // accidentally subscribe the currently running external effect.\n untrack(() => {\n disposeEffect = effect(() => {\n const next = fn();\n const prev = s.peek();\n // The first computed value must always be written; afterwards use\n // the supplied equality comparator (defaults to Object.is).\n if (prev === _computedSentinel || !equals(next, prev)) {\n s.value = next;\n }\n });\n });\n };\n\n const signalProto = Object.getPrototypeOf(s) as Signal<T>;\n const valueDescriptor = Object.getOwnPropertyDescriptor(signalProto, \"value\");\n if (!valueDescriptor?.get || !valueDescriptor?.set) {\n throw new Error(\"[elur] Internal error: Signal.value descriptor not found.\");\n }\n\n Object.defineProperty(s, \"value\", {\n get() {\n ensureInitialized();\n return valueDescriptor.get!.call(this) as T;\n },\n set(v: T) {\n valueDescriptor.set!.call(this, v);\n },\n configurable: true,\n });\n\n const originalDispose = s.dispose;\n\n s.dispose = () => {\n disposed = true;\n disposeEffect?.();\n disposeEffect = null;\n originalDispose.call(s); // Opt: Evitar el uso lento de .bind()\n };\n return s as Signal<T> & { dispose(): void };\n}\n\n/** Groups multiple signal writes so effects flush once at the end. */\nexport function batch(fn: () => void): void {\n _state.batchLevel++;\n try {\n fn();\n } finally {\n _state.batchLevel--;\n if (_state.batchLevel === 0 && _state.pendingEffectsArr.length > 0) {\n const len = _state.pendingEffectsArr.length;\n for (let i = 0; i < len; i++) _state.pendingEffectsArr[i]();\n _state.pendingEffectsArr.length = 0; // reset O(1) sin GC — key del cambio\n _state.pendingEffectsSet.clear();\n }\n }\n}\n\n/** Executes `fn` without subscribing to any signals read inside it. */\nexport function untrack<T>(fn: () => T): T {\n const prevEffect = _state.activeEffect;\n const prevDeps = _state.activeDeps;\n _state.activeEffect = null;\n _state.activeDeps = null;\n try {\n return fn();\n } finally {\n _state.activeEffect = prevEffect;\n _state.activeDeps = prevDeps;\n }\n}\n\n// --- watch ---\n\nexport interface WatchOptions {\n /** Fire the callback immediately with the current value. Default: `false`. */\n immediate?: boolean;\n /** Automatically dispose after the first callback invocation. Default: `false`. */\n once?: boolean;\n}\n\n/**\n * Watches a reactive source and calls `callback(newValue, oldValue)` on each change.\n * Accepts a Signal or a getter function. Returns a dispose function.\n */\nexport function watch<T>(\n source: Signal<T> | (() => T),\n callback: (newValue: T, oldValue: T | undefined) => void,\n options: WatchOptions = {}\n): () => void {\n const { immediate = false, once = false } = options;\n\n const getter: () => T =\n source instanceof Signal ? () => source.value : source;\n\n let oldValue: T | undefined;\n let isFirst = true;\n let disposed = false;\n\n const dispose = effect(() => {\n const newValue = getter();\n\n if (isFirst) {\n isFirst = false;\n if (immediate && !disposed) {\n const snap = newValue;\n untrack(() => callback(snap, undefined));\n if (once) { disposed = true; Promise.resolve().then(dispose); }\n }\n oldValue = newValue;\n return;\n }\n\n if (!disposed) {\n const snap = newValue;\n const prev = oldValue;\n oldValue = newValue;\n untrack(() => callback(snap, prev));\n if (once) { disposed = true; Promise.resolve().then(dispose); }\n }\n });\n\n return () => {\n disposed = true;\n dispose();\n };\n}\n\n// --- nextTick ---\n\n/** Returns a promise that resolves on the next microtask. Accepts an optional callback. */\nexport function nextTick(fn?: () => void): Promise<void> {\n return fn ? Promise.resolve().then(fn) : Promise.resolve();\n}"],"mappings":"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"}
1
+ {"version":3,"file":"signals.cjs","names":[],"sources":["../../src/elur/reactivity.ts"],"sourcesContent":["// --- Dependency tracking ---\n\ninterface _EffectCtx {\n effect: (() => void) | null;\n deps: Set<Signal<any>> | null;\n}\n\ninterface _ReactivityGlobalState {\n ctxPool: _EffectCtx[];\n ctxStack: _EffectCtx[];\n activeEffect: (() => void) | null;\n activeDeps: Set<Signal<any>> | null;\n activeErrorHandler: ((err: unknown) => void) | null;\n errorHandlerStack: (((err: unknown) => void) | null)[];\n batchLevel: number;\n pendingEffectsSet: Set<() => void>;\n pendingEffectsArr: (() => void)[];\n effectDepth: number;\n notifyBuf: ((() => void) | null)[];\n notifyBase: number;\n signalDebugHooks: _SignalDebugHooks | null;\n}\n\nfunction _createReactivityState(): _ReactivityGlobalState {\n return {\n ctxPool: [],\n ctxStack: [],\n activeEffect: null,\n activeDeps: null,\n activeErrorHandler: null,\n errorHandlerStack: [],\n batchLevel: 0,\n pendingEffectsSet: new Set<() => void>(),\n pendingEffectsArr: [],\n effectDepth: 0,\n notifyBuf: [],\n notifyBase: 0,\n signalDebugHooks: null,\n };\n}\n\nconst _reactivityStateKey = Symbol.for(\"@elurjs/core/reactivity-state\");\nconst _globalObj = globalThis as Record<PropertyKey, unknown>;\nconst _state = (() => {\n const existing = _globalObj[_reactivityStateKey] as _ReactivityGlobalState | undefined;\n if (existing) return existing;\n const created = _createReactivityState();\n _globalObj[_reactivityStateKey] = created;\n return created;\n})();\n\n// --- Error boundary support ---\n\n/**\n * @internal — Register an error boundary handler. All `effect()` calls made\n * synchronously while this handler is active will capture it. When those\n * effects re-run and throw, the captured handler is invoked.\n */\nexport function _pushErrorHandler(h: (err: unknown) => void): void {\n _state.errorHandlerStack.push(_state.activeErrorHandler);\n _state.activeErrorHandler = h;\n}\n\n/** @internal — Restore the previous error boundary handler. */\nexport function _popErrorHandler(): void {\n _state.activeErrorHandler = _state.errorHandlerStack.pop() ?? null;\n}\n\n// --- Batching ---\n\n/**\n * Guards against synchronous effect re-entrancy.\n *\n * Effects re-run synchronously when a signal they depend on changes. If an\n * effect writes to a signal it also reads, this creates a synchronous loop.\n * The guard below caps re-execution at MAX_EFFECT_DEPTH (100) iterations and\n * throws an error to prevent stack overflow.\n *\n * Throwing is deliberate: when the guard fires, the reactive graph is in an\n * inconsistent state — the effect partially executed, dependencies may be\n * stale, and continuing could produce incorrect UI. Throwing surfaces the\n * bug immediately instead of silently degrading.\n *\n * To avoid re-entrancy:\n * 1. Use `computed()` for derived state — computed signals cache their result\n * and only recompute when dependencies change. They never write to other\n * signals, so they can't loop.\n * 2. Use `watch()` for side effects — watch callbacks receive the new value;\n * if you need to update other signals, do it inside `batch()` to coalesce\n * notifications.\n * 3. Never write to a signal you read in the same effect — this is the direct\n * cause of re-entrancy. If you need to transform a value, use `computed()`\n * instead.\n * 4. Use `batch()` to group writes — batched writes flush once at the end,\n * preventing intermediate re-runs.\n */\n\nconst MAX_EFFECT_DEPTH = 100;\nconst _NOTIFY_SHRINK_TRIGGER = 64;\nconst _NOTIFY_LOW_USAGE = 16;\nconst _NOTIFY_SHRINK_TO = 32;\n\nexport interface _SignalDebugHooks {\n onCreate?: (signal: Signal<any>, initialValue: unknown) => void;\n onWrite?: (signal: Signal<any>, value: unknown) => void;\n}\n\nexport function _setSignalDebugHooks(hooks: _SignalDebugHooks | null): void {\n _state.signalDebugHooks = hooks;\n}\n\n/** @internal — notify buffer capacity, exposed for tests. */\nexport function _getNotifyBufSize(): number {\n return _state.notifyBuf.length;\n}\n\n// --- Signal ---\n\nexport class Signal<T> {\n private _value: T;\n private _subs = new Set<() => void>();\n\n constructor(initialValue: T) {\n this._value = initialValue;\n _state.signalDebugHooks?.onCreate?.(this, initialValue);\n }\n\n /** Read the current value. Subscribes the active effect if one exists. */\n get value(): T {\n if (_state.activeEffect) {\n this._subs.add(_state.activeEffect);\n _state.activeDeps?.add(this);\n }\n return this._value;\n }\n\n /** Write a new value. Notifies subscribers when the value changes. */\n set value(newValue: T) {\n if (Object.is(this._value, newValue)) return;\n this._value = newValue;\n _state.signalDebugHooks?.onWrite?.(this, newValue);\n this._notify();\n }\n\n /** Mutate the value via a updater function. */\n update(fn: (current: T) => T): void {\n this.value = fn(this._value);\n }\n\n /** Read without subscribing the active effect. */\n peek(): T {\n return this._value;\n }\n\n /** @internal */\n _removeSub(sub: () => void): void {\n this._subs.delete(sub);\n }\n\n private _notify(): void {\n if (_state.batchLevel > 0) {\n for (const s of this._subs) {\n if (!_state.pendingEffectsSet.has(s)) {\n _state.pendingEffectsSet.add(s);\n _state.pendingEffectsArr.push(s);\n }\n }\n return;\n }\n const base = _state.notifyBase;\n let len = 0;\n for (const s of this._subs) _state.notifyBuf[base + len++] = s;\n _state.notifyBase = base + len;\n try {\n for (let i = 0; i < len; i++) {\n const fn = _state.notifyBuf[base + i];\n _state.notifyBuf[base + i] = null!;\n fn?.();\n }\n } finally {\n _state.notifyBase = base;\n // Shrink oversized notify buffer after a low-usage top-level flush.\n if (\n base === 0 &&\n _state.notifyBuf.length > _NOTIFY_SHRINK_TRIGGER &&\n len < _NOTIFY_LOW_USAGE\n ) {\n _state.notifyBuf.length = _NOTIFY_SHRINK_TO;\n }\n }\n }\n\n dispose(): void {\n this._subs.clear();\n }\n}\n\n// --- Factories ---\n\nexport function signal<T>(initialValue: T): Signal<T> {\n return new Signal(initialValue);\n}\n\n/**\n * Runs `fn` and re-runs it whenever any signal read inside changes.\n * Returns a dispose function to tear down the effect.\n * If `fn` returns a function, it is called as cleanup before each re-run\n * and on disposal.\n */\nexport function effect(fn: () => void | (() => void)): () => void {\n let disposed = false;\n let cleanup: (() => void) | void;\n\n // Opt: Double buffering para evitar crear `new Set()` en cada ejecución\n let deps = new Set<Signal<any>>();\n let newDeps = new Set<Signal<any>>();\n\n const capturedErrorHandler = _state.activeErrorHandler;\n\n const execute = () => {\n if (disposed) return;\n if (typeof cleanup === \"function\") cleanup();\n\n // Intercambiamos los buffers. 'deps' ahora tiene los viejos, 'newDeps' está limpio para recolectar.\n const temp = deps;\n deps = newDeps;\n newDeps = temp;\n newDeps.clear();\n\n const ctx = _state.ctxPool.length > 0 ? _state.ctxPool.pop()! : { effect: null, deps: null };\n ctx.effect = _state.activeEffect;\n ctx.deps = _state.activeDeps;\n _state.ctxStack.push(ctx);\n _state.activeEffect = execute;\n _state.activeDeps = newDeps;\n\n _state.effectDepth++;\n if (_state.effectDepth > MAX_EFFECT_DEPTH) {\n _state.effectDepth = 0;\n // Restaurar desde el stack unificado\n const restored = _state.ctxStack.pop()!;\n _state.activeEffect = restored.effect;\n _state.activeDeps = restored.deps;\n restored.effect = null;\n restored.deps = null;\n _state.ctxPool.push(restored);\n throw new Error(\n \"[elur] Maximum effect re-execution depth exceeded (possible infinite loop).\"\n );\n }\n\n try {\n cleanup = fn();\n } catch (err) {\n if (capturedErrorHandler) {\n capturedErrorHandler(err);\n } else {\n throw err;\n }\n } finally {\n _state.effectDepth--;\n const restored = _state.ctxStack.pop()!;\n _state.activeEffect = restored.effect;\n _state.activeDeps = restored.deps;\n restored.effect = null; // limpiar referencias para GC\n restored.deps = null;\n _state.ctxPool.push(restored); // devolver al pool para reutilizar\n\n\n // Cleanup phase: Desuscribirse de señales que estaban en 'deps' pero NO en 'newDeps'\n for (const oldDep of deps) {\n if (!newDeps.has(oldDep)) {\n oldDep._removeSub(execute);\n }\n }\n }\n };\n\n execute();\n\n return () => {\n disposed = true;\n if (typeof cleanup === \"function\") cleanup();\n // Al desechar, usamos newDeps porque es el que quedó activo después del último execute\n for (const dep of newDeps) {\n dep._removeSub(execute);\n }\n newDeps.clear();\n deps.clear();\n };\n}\n\n/** Derived signal that recalculates when its dependencies change. */\nconst _computedSentinel = Symbol(\"elur-computed-uninitialized\");\n\nexport function computed<T>(\n fn: () => T,\n equals: (a: T, b: T) => boolean = Object.is,\n): Signal<T> & { dispose(): void } {\n const s = new Signal<T | typeof _computedSentinel>(_computedSentinel);\n let disposeEffect: (() => void) | null = null;\n let initialized = false;\n let disposed = false;\n\n const ensureInitialized = () => {\n if (initialized || disposed) return;\n initialized = true;\n // Important: initialize untracked so first computed evaluation does not\n // accidentally subscribe the currently running external effect.\n untrack(() => {\n disposeEffect = effect(() => {\n const next = fn();\n const prev = s.peek();\n // The first computed value must always be written; afterwards use\n // the supplied equality comparator (defaults to Object.is).\n if (prev === _computedSentinel || !equals(next, prev)) {\n s.value = next;\n }\n });\n });\n };\n\n const signalProto = Object.getPrototypeOf(s) as Signal<T>;\n const valueDescriptor = Object.getOwnPropertyDescriptor(signalProto, \"value\");\n if (!valueDescriptor?.get || !valueDescriptor?.set) {\n throw new Error(\"[elur] Internal error: Signal.value descriptor not found.\");\n }\n\n Object.defineProperty(s, \"value\", {\n get() {\n ensureInitialized();\n return valueDescriptor.get!.call(this) as T;\n },\n set(v: T) {\n valueDescriptor.set!.call(this, v);\n },\n configurable: true,\n });\n\n const originalDispose = s.dispose;\n\n s.dispose = () => {\n disposed = true;\n disposeEffect?.();\n disposeEffect = null;\n originalDispose.call(s); // Opt: Evitar el uso lento de .bind()\n };\n return s as Signal<T> & { dispose(): void };\n}\n\n/** Groups multiple signal writes so effects flush once at the end. */\nexport function batch(fn: () => void): void {\n _state.batchLevel++;\n try {\n fn();\n } finally {\n _state.batchLevel--;\n if (_state.batchLevel === 0 && _state.pendingEffectsArr.length > 0) {\n const len = _state.pendingEffectsArr.length;\n for (let i = 0; i < len; i++) _state.pendingEffectsArr[i]();\n _state.pendingEffectsArr.length = 0; // reset O(1) sin GC — key del cambio\n _state.pendingEffectsSet.clear();\n }\n }\n}\n\n/** Executes `fn` without subscribing to any signals read inside it. */\nexport function untrack<T>(fn: () => T): T {\n const prevEffect = _state.activeEffect;\n const prevDeps = _state.activeDeps;\n _state.activeEffect = null;\n _state.activeDeps = null;\n try {\n return fn();\n } finally {\n _state.activeEffect = prevEffect;\n _state.activeDeps = prevDeps;\n }\n}\n\n// --- watch ---\n\nexport interface WatchOptions {\n /** Fire the callback immediately with the current value. Default: `false`. */\n immediate?: boolean;\n /** Automatically dispose after the first callback invocation. Default: `false`. */\n once?: boolean;\n}\n\n/**\n * Watches a reactive source and calls `callback(newValue, oldValue)` on each change.\n * Accepts a Signal or a getter function. Returns a dispose function.\n */\nexport function watch<T>(\n source: Signal<T> | (() => T),\n callback: (newValue: T, oldValue: T | undefined) => void,\n options: WatchOptions = {}\n): () => void {\n const { immediate = false, once = false } = options;\n\n const getter: () => T =\n source instanceof Signal ? () => source.value : source;\n\n let oldValue: T | undefined;\n let isFirst = true;\n let disposed = false;\n\n const dispose = effect(() => {\n const newValue = getter();\n\n if (isFirst) {\n isFirst = false;\n if (immediate && !disposed) {\n const snap = newValue;\n untrack(() => callback(snap, undefined));\n if (once) { disposed = true; Promise.resolve().then(dispose); }\n }\n oldValue = newValue;\n return;\n }\n\n if (!disposed) {\n const snap = newValue;\n const prev = oldValue;\n oldValue = newValue;\n untrack(() => callback(snap, prev));\n if (once) { disposed = true; Promise.resolve().then(dispose); }\n }\n });\n\n return () => {\n disposed = true;\n dispose();\n };\n}\n\n// --- nextTick ---\n\n/** Returns a promise that resolves on the next microtask. Accepts an optional callback. */\nexport function nextTick(fn?: () => void): Promise<void> {\n return fn ? Promise.resolve().then(fn) : Promise.resolve();\n}"],"mappings":"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"}
@@ -16,7 +16,7 @@ function e() {
16
16
  signalDebugHooks: null
17
17
  };
18
18
  }
19
- var t = Symbol.for("elur/reactivity-state"), n = globalThis, r = (() => {
19
+ var t = Symbol.for("@elurjs/core/reactivity-state"), n = globalThis, r = (() => {
20
20
  let r = n[t];
21
21
  if (r) return r;
22
22
  let i = e();
@@ -1 +1 @@
1
- {"version":3,"file":"signals.js","names":[],"sources":["../../src/elur/reactivity.ts"],"sourcesContent":["// --- Dependency tracking ---\n\ninterface _EffectCtx {\n effect: (() => void) | null;\n deps: Set<Signal<any>> | null;\n}\n\ninterface _ReactivityGlobalState {\n ctxPool: _EffectCtx[];\n ctxStack: _EffectCtx[];\n activeEffect: (() => void) | null;\n activeDeps: Set<Signal<any>> | null;\n activeErrorHandler: ((err: unknown) => void) | null;\n errorHandlerStack: (((err: unknown) => void) | null)[];\n batchLevel: number;\n pendingEffectsSet: Set<() => void>;\n pendingEffectsArr: (() => void)[];\n effectDepth: number;\n notifyBuf: ((() => void) | null)[];\n notifyBase: number;\n signalDebugHooks: _SignalDebugHooks | null;\n}\n\nfunction _createReactivityState(): _ReactivityGlobalState {\n return {\n ctxPool: [],\n ctxStack: [],\n activeEffect: null,\n activeDeps: null,\n activeErrorHandler: null,\n errorHandlerStack: [],\n batchLevel: 0,\n pendingEffectsSet: new Set<() => void>(),\n pendingEffectsArr: [],\n effectDepth: 0,\n notifyBuf: [],\n notifyBase: 0,\n signalDebugHooks: null,\n };\n}\n\nconst _reactivityStateKey = Symbol.for(\"elur/reactivity-state\");\nconst _globalObj = globalThis as Record<PropertyKey, unknown>;\nconst _state = (() => {\n const existing = _globalObj[_reactivityStateKey] as _ReactivityGlobalState | undefined;\n if (existing) return existing;\n const created = _createReactivityState();\n _globalObj[_reactivityStateKey] = created;\n return created;\n})();\n\n// --- Error boundary support ---\n\n/**\n * @internal — Register an error boundary handler. All `effect()` calls made\n * synchronously while this handler is active will capture it. When those\n * effects re-run and throw, the captured handler is invoked.\n */\nexport function _pushErrorHandler(h: (err: unknown) => void): void {\n _state.errorHandlerStack.push(_state.activeErrorHandler);\n _state.activeErrorHandler = h;\n}\n\n/** @internal — Restore the previous error boundary handler. */\nexport function _popErrorHandler(): void {\n _state.activeErrorHandler = _state.errorHandlerStack.pop() ?? null;\n}\n\n// --- Batching ---\n\n/**\n * Guards against synchronous effect re-entrancy.\n *\n * Effects re-run synchronously when a signal they depend on changes. If an\n * effect writes to a signal it also reads, this creates a synchronous loop.\n * The guard below caps re-execution at MAX_EFFECT_DEPTH (100) iterations and\n * throws an error to prevent stack overflow.\n *\n * Throwing is deliberate: when the guard fires, the reactive graph is in an\n * inconsistent state — the effect partially executed, dependencies may be\n * stale, and continuing could produce incorrect UI. Throwing surfaces the\n * bug immediately instead of silently degrading.\n *\n * To avoid re-entrancy:\n * 1. Use `computed()` for derived state — computed signals cache their result\n * and only recompute when dependencies change. They never write to other\n * signals, so they can't loop.\n * 2. Use `watch()` for side effects — watch callbacks receive the new value;\n * if you need to update other signals, do it inside `batch()` to coalesce\n * notifications.\n * 3. Never write to a signal you read in the same effect — this is the direct\n * cause of re-entrancy. If you need to transform a value, use `computed()`\n * instead.\n * 4. Use `batch()` to group writes — batched writes flush once at the end,\n * preventing intermediate re-runs.\n */\n\nconst MAX_EFFECT_DEPTH = 100;\nconst _NOTIFY_SHRINK_TRIGGER = 64;\nconst _NOTIFY_LOW_USAGE = 16;\nconst _NOTIFY_SHRINK_TO = 32;\n\nexport interface _SignalDebugHooks {\n onCreate?: (signal: Signal<any>, initialValue: unknown) => void;\n onWrite?: (signal: Signal<any>, value: unknown) => void;\n}\n\nexport function _setSignalDebugHooks(hooks: _SignalDebugHooks | null): void {\n _state.signalDebugHooks = hooks;\n}\n\n/** @internal — notify buffer capacity, exposed for tests. */\nexport function _getNotifyBufSize(): number {\n return _state.notifyBuf.length;\n}\n\n// --- Signal ---\n\nexport class Signal<T> {\n private _value: T;\n private _subs = new Set<() => void>();\n\n constructor(initialValue: T) {\n this._value = initialValue;\n _state.signalDebugHooks?.onCreate?.(this, initialValue);\n }\n\n /** Read the current value. Subscribes the active effect if one exists. */\n get value(): T {\n if (_state.activeEffect) {\n this._subs.add(_state.activeEffect);\n _state.activeDeps?.add(this);\n }\n return this._value;\n }\n\n /** Write a new value. Notifies subscribers when the value changes. */\n set value(newValue: T) {\n if (Object.is(this._value, newValue)) return;\n this._value = newValue;\n _state.signalDebugHooks?.onWrite?.(this, newValue);\n this._notify();\n }\n\n /** Mutate the value via a updater function. */\n update(fn: (current: T) => T): void {\n this.value = fn(this._value);\n }\n\n /** Read without subscribing the active effect. */\n peek(): T {\n return this._value;\n }\n\n /** @internal */\n _removeSub(sub: () => void): void {\n this._subs.delete(sub);\n }\n\n private _notify(): void {\n if (_state.batchLevel > 0) {\n for (const s of this._subs) {\n if (!_state.pendingEffectsSet.has(s)) {\n _state.pendingEffectsSet.add(s);\n _state.pendingEffectsArr.push(s);\n }\n }\n return;\n }\n const base = _state.notifyBase;\n let len = 0;\n for (const s of this._subs) _state.notifyBuf[base + len++] = s;\n _state.notifyBase = base + len;\n try {\n for (let i = 0; i < len; i++) {\n const fn = _state.notifyBuf[base + i];\n _state.notifyBuf[base + i] = null!;\n fn?.();\n }\n } finally {\n _state.notifyBase = base;\n // Shrink oversized notify buffer after a low-usage top-level flush.\n if (\n base === 0 &&\n _state.notifyBuf.length > _NOTIFY_SHRINK_TRIGGER &&\n len < _NOTIFY_LOW_USAGE\n ) {\n _state.notifyBuf.length = _NOTIFY_SHRINK_TO;\n }\n }\n }\n\n dispose(): void {\n this._subs.clear();\n }\n}\n\n// --- Factories ---\n\nexport function signal<T>(initialValue: T): Signal<T> {\n return new Signal(initialValue);\n}\n\n/**\n * Runs `fn` and re-runs it whenever any signal read inside changes.\n * Returns a dispose function to tear down the effect.\n * If `fn` returns a function, it is called as cleanup before each re-run\n * and on disposal.\n */\nexport function effect(fn: () => void | (() => void)): () => void {\n let disposed = false;\n let cleanup: (() => void) | void;\n\n // Opt: Double buffering para evitar crear `new Set()` en cada ejecución\n let deps = new Set<Signal<any>>();\n let newDeps = new Set<Signal<any>>();\n\n const capturedErrorHandler = _state.activeErrorHandler;\n\n const execute = () => {\n if (disposed) return;\n if (typeof cleanup === \"function\") cleanup();\n\n // Intercambiamos los buffers. 'deps' ahora tiene los viejos, 'newDeps' está limpio para recolectar.\n const temp = deps;\n deps = newDeps;\n newDeps = temp;\n newDeps.clear();\n\n const ctx = _state.ctxPool.length > 0 ? _state.ctxPool.pop()! : { effect: null, deps: null };\n ctx.effect = _state.activeEffect;\n ctx.deps = _state.activeDeps;\n _state.ctxStack.push(ctx);\n _state.activeEffect = execute;\n _state.activeDeps = newDeps;\n\n _state.effectDepth++;\n if (_state.effectDepth > MAX_EFFECT_DEPTH) {\n _state.effectDepth = 0;\n // Restaurar desde el stack unificado\n const restored = _state.ctxStack.pop()!;\n _state.activeEffect = restored.effect;\n _state.activeDeps = restored.deps;\n restored.effect = null;\n restored.deps = null;\n _state.ctxPool.push(restored);\n throw new Error(\n \"[elur] Maximum effect re-execution depth exceeded (possible infinite loop).\"\n );\n }\n\n try {\n cleanup = fn();\n } catch (err) {\n if (capturedErrorHandler) {\n capturedErrorHandler(err);\n } else {\n throw err;\n }\n } finally {\n _state.effectDepth--;\n const restored = _state.ctxStack.pop()!;\n _state.activeEffect = restored.effect;\n _state.activeDeps = restored.deps;\n restored.effect = null; // limpiar referencias para GC\n restored.deps = null;\n _state.ctxPool.push(restored); // devolver al pool para reutilizar\n\n\n // Cleanup phase: Desuscribirse de señales que estaban en 'deps' pero NO en 'newDeps'\n for (const oldDep of deps) {\n if (!newDeps.has(oldDep)) {\n oldDep._removeSub(execute);\n }\n }\n }\n };\n\n execute();\n\n return () => {\n disposed = true;\n if (typeof cleanup === \"function\") cleanup();\n // Al desechar, usamos newDeps porque es el que quedó activo después del último execute\n for (const dep of newDeps) {\n dep._removeSub(execute);\n }\n newDeps.clear();\n deps.clear();\n };\n}\n\n/** Derived signal that recalculates when its dependencies change. */\nconst _computedSentinel = Symbol(\"elur-computed-uninitialized\");\n\nexport function computed<T>(\n fn: () => T,\n equals: (a: T, b: T) => boolean = Object.is,\n): Signal<T> & { dispose(): void } {\n const s = new Signal<T | typeof _computedSentinel>(_computedSentinel);\n let disposeEffect: (() => void) | null = null;\n let initialized = false;\n let disposed = false;\n\n const ensureInitialized = () => {\n if (initialized || disposed) return;\n initialized = true;\n // Important: initialize untracked so first computed evaluation does not\n // accidentally subscribe the currently running external effect.\n untrack(() => {\n disposeEffect = effect(() => {\n const next = fn();\n const prev = s.peek();\n // The first computed value must always be written; afterwards use\n // the supplied equality comparator (defaults to Object.is).\n if (prev === _computedSentinel || !equals(next, prev)) {\n s.value = next;\n }\n });\n });\n };\n\n const signalProto = Object.getPrototypeOf(s) as Signal<T>;\n const valueDescriptor = Object.getOwnPropertyDescriptor(signalProto, \"value\");\n if (!valueDescriptor?.get || !valueDescriptor?.set) {\n throw new Error(\"[elur] Internal error: Signal.value descriptor not found.\");\n }\n\n Object.defineProperty(s, \"value\", {\n get() {\n ensureInitialized();\n return valueDescriptor.get!.call(this) as T;\n },\n set(v: T) {\n valueDescriptor.set!.call(this, v);\n },\n configurable: true,\n });\n\n const originalDispose = s.dispose;\n\n s.dispose = () => {\n disposed = true;\n disposeEffect?.();\n disposeEffect = null;\n originalDispose.call(s); // Opt: Evitar el uso lento de .bind()\n };\n return s as Signal<T> & { dispose(): void };\n}\n\n/** Groups multiple signal writes so effects flush once at the end. */\nexport function batch(fn: () => void): void {\n _state.batchLevel++;\n try {\n fn();\n } finally {\n _state.batchLevel--;\n if (_state.batchLevel === 0 && _state.pendingEffectsArr.length > 0) {\n const len = _state.pendingEffectsArr.length;\n for (let i = 0; i < len; i++) _state.pendingEffectsArr[i]();\n _state.pendingEffectsArr.length = 0; // reset O(1) sin GC — key del cambio\n _state.pendingEffectsSet.clear();\n }\n }\n}\n\n/** Executes `fn` without subscribing to any signals read inside it. */\nexport function untrack<T>(fn: () => T): T {\n const prevEffect = _state.activeEffect;\n const prevDeps = _state.activeDeps;\n _state.activeEffect = null;\n _state.activeDeps = null;\n try {\n return fn();\n } finally {\n _state.activeEffect = prevEffect;\n _state.activeDeps = prevDeps;\n }\n}\n\n// --- watch ---\n\nexport interface WatchOptions {\n /** Fire the callback immediately with the current value. Default: `false`. */\n immediate?: boolean;\n /** Automatically dispose after the first callback invocation. Default: `false`. */\n once?: boolean;\n}\n\n/**\n * Watches a reactive source and calls `callback(newValue, oldValue)` on each change.\n * Accepts a Signal or a getter function. Returns a dispose function.\n */\nexport function watch<T>(\n source: Signal<T> | (() => T),\n callback: (newValue: T, oldValue: T | undefined) => void,\n options: WatchOptions = {}\n): () => void {\n const { immediate = false, once = false } = options;\n\n const getter: () => T =\n source instanceof Signal ? () => source.value : source;\n\n let oldValue: T | undefined;\n let isFirst = true;\n let disposed = false;\n\n const dispose = effect(() => {\n const newValue = getter();\n\n if (isFirst) {\n isFirst = false;\n if (immediate && !disposed) {\n const snap = newValue;\n untrack(() => callback(snap, undefined));\n if (once) { disposed = true; Promise.resolve().then(dispose); }\n }\n oldValue = newValue;\n return;\n }\n\n if (!disposed) {\n const snap = newValue;\n const prev = oldValue;\n oldValue = newValue;\n untrack(() => callback(snap, prev));\n if (once) { disposed = true; Promise.resolve().then(dispose); }\n }\n });\n\n return () => {\n disposed = true;\n dispose();\n };\n}\n\n// --- nextTick ---\n\n/** Returns a promise that resolves on the next microtask. Accepts an optional callback. */\nexport function nextTick(fn?: () => void): Promise<void> {\n return fn ? Promise.resolve().then(fn) : Promise.resolve();\n}"],"mappings":"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"}
1
+ {"version":3,"file":"signals.js","names":[],"sources":["../../src/elur/reactivity.ts"],"sourcesContent":["// --- Dependency tracking ---\n\ninterface _EffectCtx {\n effect: (() => void) | null;\n deps: Set<Signal<any>> | null;\n}\n\ninterface _ReactivityGlobalState {\n ctxPool: _EffectCtx[];\n ctxStack: _EffectCtx[];\n activeEffect: (() => void) | null;\n activeDeps: Set<Signal<any>> | null;\n activeErrorHandler: ((err: unknown) => void) | null;\n errorHandlerStack: (((err: unknown) => void) | null)[];\n batchLevel: number;\n pendingEffectsSet: Set<() => void>;\n pendingEffectsArr: (() => void)[];\n effectDepth: number;\n notifyBuf: ((() => void) | null)[];\n notifyBase: number;\n signalDebugHooks: _SignalDebugHooks | null;\n}\n\nfunction _createReactivityState(): _ReactivityGlobalState {\n return {\n ctxPool: [],\n ctxStack: [],\n activeEffect: null,\n activeDeps: null,\n activeErrorHandler: null,\n errorHandlerStack: [],\n batchLevel: 0,\n pendingEffectsSet: new Set<() => void>(),\n pendingEffectsArr: [],\n effectDepth: 0,\n notifyBuf: [],\n notifyBase: 0,\n signalDebugHooks: null,\n };\n}\n\nconst _reactivityStateKey = Symbol.for(\"@elurjs/core/reactivity-state\");\nconst _globalObj = globalThis as Record<PropertyKey, unknown>;\nconst _state = (() => {\n const existing = _globalObj[_reactivityStateKey] as _ReactivityGlobalState | undefined;\n if (existing) return existing;\n const created = _createReactivityState();\n _globalObj[_reactivityStateKey] = created;\n return created;\n})();\n\n// --- Error boundary support ---\n\n/**\n * @internal — Register an error boundary handler. All `effect()` calls made\n * synchronously while this handler is active will capture it. When those\n * effects re-run and throw, the captured handler is invoked.\n */\nexport function _pushErrorHandler(h: (err: unknown) => void): void {\n _state.errorHandlerStack.push(_state.activeErrorHandler);\n _state.activeErrorHandler = h;\n}\n\n/** @internal — Restore the previous error boundary handler. */\nexport function _popErrorHandler(): void {\n _state.activeErrorHandler = _state.errorHandlerStack.pop() ?? null;\n}\n\n// --- Batching ---\n\n/**\n * Guards against synchronous effect re-entrancy.\n *\n * Effects re-run synchronously when a signal they depend on changes. If an\n * effect writes to a signal it also reads, this creates a synchronous loop.\n * The guard below caps re-execution at MAX_EFFECT_DEPTH (100) iterations and\n * throws an error to prevent stack overflow.\n *\n * Throwing is deliberate: when the guard fires, the reactive graph is in an\n * inconsistent state — the effect partially executed, dependencies may be\n * stale, and continuing could produce incorrect UI. Throwing surfaces the\n * bug immediately instead of silently degrading.\n *\n * To avoid re-entrancy:\n * 1. Use `computed()` for derived state — computed signals cache their result\n * and only recompute when dependencies change. They never write to other\n * signals, so they can't loop.\n * 2. Use `watch()` for side effects — watch callbacks receive the new value;\n * if you need to update other signals, do it inside `batch()` to coalesce\n * notifications.\n * 3. Never write to a signal you read in the same effect — this is the direct\n * cause of re-entrancy. If you need to transform a value, use `computed()`\n * instead.\n * 4. Use `batch()` to group writes — batched writes flush once at the end,\n * preventing intermediate re-runs.\n */\n\nconst MAX_EFFECT_DEPTH = 100;\nconst _NOTIFY_SHRINK_TRIGGER = 64;\nconst _NOTIFY_LOW_USAGE = 16;\nconst _NOTIFY_SHRINK_TO = 32;\n\nexport interface _SignalDebugHooks {\n onCreate?: (signal: Signal<any>, initialValue: unknown) => void;\n onWrite?: (signal: Signal<any>, value: unknown) => void;\n}\n\nexport function _setSignalDebugHooks(hooks: _SignalDebugHooks | null): void {\n _state.signalDebugHooks = hooks;\n}\n\n/** @internal — notify buffer capacity, exposed for tests. */\nexport function _getNotifyBufSize(): number {\n return _state.notifyBuf.length;\n}\n\n// --- Signal ---\n\nexport class Signal<T> {\n private _value: T;\n private _subs = new Set<() => void>();\n\n constructor(initialValue: T) {\n this._value = initialValue;\n _state.signalDebugHooks?.onCreate?.(this, initialValue);\n }\n\n /** Read the current value. Subscribes the active effect if one exists. */\n get value(): T {\n if (_state.activeEffect) {\n this._subs.add(_state.activeEffect);\n _state.activeDeps?.add(this);\n }\n return this._value;\n }\n\n /** Write a new value. Notifies subscribers when the value changes. */\n set value(newValue: T) {\n if (Object.is(this._value, newValue)) return;\n this._value = newValue;\n _state.signalDebugHooks?.onWrite?.(this, newValue);\n this._notify();\n }\n\n /** Mutate the value via a updater function. */\n update(fn: (current: T) => T): void {\n this.value = fn(this._value);\n }\n\n /** Read without subscribing the active effect. */\n peek(): T {\n return this._value;\n }\n\n /** @internal */\n _removeSub(sub: () => void): void {\n this._subs.delete(sub);\n }\n\n private _notify(): void {\n if (_state.batchLevel > 0) {\n for (const s of this._subs) {\n if (!_state.pendingEffectsSet.has(s)) {\n _state.pendingEffectsSet.add(s);\n _state.pendingEffectsArr.push(s);\n }\n }\n return;\n }\n const base = _state.notifyBase;\n let len = 0;\n for (const s of this._subs) _state.notifyBuf[base + len++] = s;\n _state.notifyBase = base + len;\n try {\n for (let i = 0; i < len; i++) {\n const fn = _state.notifyBuf[base + i];\n _state.notifyBuf[base + i] = null!;\n fn?.();\n }\n } finally {\n _state.notifyBase = base;\n // Shrink oversized notify buffer after a low-usage top-level flush.\n if (\n base === 0 &&\n _state.notifyBuf.length > _NOTIFY_SHRINK_TRIGGER &&\n len < _NOTIFY_LOW_USAGE\n ) {\n _state.notifyBuf.length = _NOTIFY_SHRINK_TO;\n }\n }\n }\n\n dispose(): void {\n this._subs.clear();\n }\n}\n\n// --- Factories ---\n\nexport function signal<T>(initialValue: T): Signal<T> {\n return new Signal(initialValue);\n}\n\n/**\n * Runs `fn` and re-runs it whenever any signal read inside changes.\n * Returns a dispose function to tear down the effect.\n * If `fn` returns a function, it is called as cleanup before each re-run\n * and on disposal.\n */\nexport function effect(fn: () => void | (() => void)): () => void {\n let disposed = false;\n let cleanup: (() => void) | void;\n\n // Opt: Double buffering para evitar crear `new Set()` en cada ejecución\n let deps = new Set<Signal<any>>();\n let newDeps = new Set<Signal<any>>();\n\n const capturedErrorHandler = _state.activeErrorHandler;\n\n const execute = () => {\n if (disposed) return;\n if (typeof cleanup === \"function\") cleanup();\n\n // Intercambiamos los buffers. 'deps' ahora tiene los viejos, 'newDeps' está limpio para recolectar.\n const temp = deps;\n deps = newDeps;\n newDeps = temp;\n newDeps.clear();\n\n const ctx = _state.ctxPool.length > 0 ? _state.ctxPool.pop()! : { effect: null, deps: null };\n ctx.effect = _state.activeEffect;\n ctx.deps = _state.activeDeps;\n _state.ctxStack.push(ctx);\n _state.activeEffect = execute;\n _state.activeDeps = newDeps;\n\n _state.effectDepth++;\n if (_state.effectDepth > MAX_EFFECT_DEPTH) {\n _state.effectDepth = 0;\n // Restaurar desde el stack unificado\n const restored = _state.ctxStack.pop()!;\n _state.activeEffect = restored.effect;\n _state.activeDeps = restored.deps;\n restored.effect = null;\n restored.deps = null;\n _state.ctxPool.push(restored);\n throw new Error(\n \"[elur] Maximum effect re-execution depth exceeded (possible infinite loop).\"\n );\n }\n\n try {\n cleanup = fn();\n } catch (err) {\n if (capturedErrorHandler) {\n capturedErrorHandler(err);\n } else {\n throw err;\n }\n } finally {\n _state.effectDepth--;\n const restored = _state.ctxStack.pop()!;\n _state.activeEffect = restored.effect;\n _state.activeDeps = restored.deps;\n restored.effect = null; // limpiar referencias para GC\n restored.deps = null;\n _state.ctxPool.push(restored); // devolver al pool para reutilizar\n\n\n // Cleanup phase: Desuscribirse de señales que estaban en 'deps' pero NO en 'newDeps'\n for (const oldDep of deps) {\n if (!newDeps.has(oldDep)) {\n oldDep._removeSub(execute);\n }\n }\n }\n };\n\n execute();\n\n return () => {\n disposed = true;\n if (typeof cleanup === \"function\") cleanup();\n // Al desechar, usamos newDeps porque es el que quedó activo después del último execute\n for (const dep of newDeps) {\n dep._removeSub(execute);\n }\n newDeps.clear();\n deps.clear();\n };\n}\n\n/** Derived signal that recalculates when its dependencies change. */\nconst _computedSentinel = Symbol(\"elur-computed-uninitialized\");\n\nexport function computed<T>(\n fn: () => T,\n equals: (a: T, b: T) => boolean = Object.is,\n): Signal<T> & { dispose(): void } {\n const s = new Signal<T | typeof _computedSentinel>(_computedSentinel);\n let disposeEffect: (() => void) | null = null;\n let initialized = false;\n let disposed = false;\n\n const ensureInitialized = () => {\n if (initialized || disposed) return;\n initialized = true;\n // Important: initialize untracked so first computed evaluation does not\n // accidentally subscribe the currently running external effect.\n untrack(() => {\n disposeEffect = effect(() => {\n const next = fn();\n const prev = s.peek();\n // The first computed value must always be written; afterwards use\n // the supplied equality comparator (defaults to Object.is).\n if (prev === _computedSentinel || !equals(next, prev)) {\n s.value = next;\n }\n });\n });\n };\n\n const signalProto = Object.getPrototypeOf(s) as Signal<T>;\n const valueDescriptor = Object.getOwnPropertyDescriptor(signalProto, \"value\");\n if (!valueDescriptor?.get || !valueDescriptor?.set) {\n throw new Error(\"[elur] Internal error: Signal.value descriptor not found.\");\n }\n\n Object.defineProperty(s, \"value\", {\n get() {\n ensureInitialized();\n return valueDescriptor.get!.call(this) as T;\n },\n set(v: T) {\n valueDescriptor.set!.call(this, v);\n },\n configurable: true,\n });\n\n const originalDispose = s.dispose;\n\n s.dispose = () => {\n disposed = true;\n disposeEffect?.();\n disposeEffect = null;\n originalDispose.call(s); // Opt: Evitar el uso lento de .bind()\n };\n return s as Signal<T> & { dispose(): void };\n}\n\n/** Groups multiple signal writes so effects flush once at the end. */\nexport function batch(fn: () => void): void {\n _state.batchLevel++;\n try {\n fn();\n } finally {\n _state.batchLevel--;\n if (_state.batchLevel === 0 && _state.pendingEffectsArr.length > 0) {\n const len = _state.pendingEffectsArr.length;\n for (let i = 0; i < len; i++) _state.pendingEffectsArr[i]();\n _state.pendingEffectsArr.length = 0; // reset O(1) sin GC — key del cambio\n _state.pendingEffectsSet.clear();\n }\n }\n}\n\n/** Executes `fn` without subscribing to any signals read inside it. */\nexport function untrack<T>(fn: () => T): T {\n const prevEffect = _state.activeEffect;\n const prevDeps = _state.activeDeps;\n _state.activeEffect = null;\n _state.activeDeps = null;\n try {\n return fn();\n } finally {\n _state.activeEffect = prevEffect;\n _state.activeDeps = prevDeps;\n }\n}\n\n// --- watch ---\n\nexport interface WatchOptions {\n /** Fire the callback immediately with the current value. Default: `false`. */\n immediate?: boolean;\n /** Automatically dispose after the first callback invocation. Default: `false`. */\n once?: boolean;\n}\n\n/**\n * Watches a reactive source and calls `callback(newValue, oldValue)` on each change.\n * Accepts a Signal or a getter function. Returns a dispose function.\n */\nexport function watch<T>(\n source: Signal<T> | (() => T),\n callback: (newValue: T, oldValue: T | undefined) => void,\n options: WatchOptions = {}\n): () => void {\n const { immediate = false, once = false } = options;\n\n const getter: () => T =\n source instanceof Signal ? () => source.value : source;\n\n let oldValue: T | undefined;\n let isFirst = true;\n let disposed = false;\n\n const dispose = effect(() => {\n const newValue = getter();\n\n if (isFirst) {\n isFirst = false;\n if (immediate && !disposed) {\n const snap = newValue;\n untrack(() => callback(snap, undefined));\n if (once) { disposed = true; Promise.resolve().then(dispose); }\n }\n oldValue = newValue;\n return;\n }\n\n if (!disposed) {\n const snap = newValue;\n const prev = oldValue;\n oldValue = newValue;\n untrack(() => callback(snap, prev));\n if (once) { disposed = true; Promise.resolve().then(dispose); }\n }\n });\n\n return () => {\n disposed = true;\n dispose();\n };\n}\n\n// --- nextTick ---\n\n/** Returns a promise that resolves on the next microtask. Accepts an optional callback. */\nexport function nextTick(fn?: () => void): Promise<void> {\n return fn ? Promise.resolve().then(fn) : Promise.resolve();\n}"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- const e=require(`./types.cjs`),t=require(`./bindings.cjs`);function n(e,t){let n=new Uint8Array(e.length),r=``;for(let i=0;i<e.length;i++){let a=e[i];if(n[i]===1&&(a[0]===`"`||a[0]===`'`)&&(a=a.slice(1)),i<t.length){let e=t[i];if(e.type===`node`)r+=a+`<!--elur-${i}-->`;else if(e.type===`event`){let t=`@${e.modifiers.length?`${e.eventName}.${e.modifiers.join(`.`)}`:e.eventName}=`.length+ +!!e.hadOpenQuote;r+=a.slice(0,-t)+` data-elur-e-${i}="${e.eventName}"`,e.hadOpenQuote&&(n[i+1]=1)}else{let t=`${e.attrName}=`.length+ +!!e.hadOpenQuote;r+=a.slice(0,-t)+` data-elur-a-${i}="${e.attrName}"`,e.hadOpenQuote&&(n[i+1]=1)}}else r+=a}return r}var r=new WeakMap,i=new WeakMap;function a(a,...o){let s=r.get(a);if(!s){let e=[],n=``;for(let r=0;r<a.length-1;r++)n+=a[r],e.push(t.detectContext(n)),n+=`__elur__`;s={contexts:e},r.set(a,s)}let c=s.contexts,l={version:1,strings:a,values:o,contexts:c};function u(){let e=i.get(a);if(e)return e;if(typeof document>`u`)throw Error(`[elur] DOM rendering requires a document. Use elur/server on the server.`);let t=document.createElement(`template`);t.innerHTML=n(a,c);let r=Array(c.length).fill(null),o=t.content,s=document.createTreeWalker(o,NodeFilter.SHOW_ELEMENT|NodeFilter.SHOW_COMMENT),l=0,u;for(;u=s.nextNode();)if(l++,u.nodeType===8){let e=u.nodeValue;if(e&&e.startsWith(`elur-`)){let t=parseInt(e.slice(5),10);isNaN(t)||(r[t]={nodeIndex:l})}}else if(u.nodeType===1){let e=u,t=Array.from(e.attributes);for(let n=0;n<t.length;n++){let i=t[n],a=i.name;if(a.startsWith(`data-elur-e-`)){let t=parseInt(a.slice(12),10);isNaN(t)||(r[t]={nodeIndex:l,name:i.value}),e.removeAttribute(a);continue}if(a.startsWith(`data-elur-a-`)){let t=parseInt(a.slice(12),10);isNaN(t)||(r[t]={nodeIndex:l,name:i.value}),e.removeAttribute(a)}}}return e={tpl:t,pathMap:r},i.set(a,e),e}function d(e,n){let{tpl:r,pathMap:i}=u(),a=r.content.cloneNode(!0),{disposes:s,postMountHooks:l}=t.activateBindings(a,c,o,i),d=document.createTextNode(``),f=document.createTextNode(``);return e.insertBefore(d,n),e.insertBefore(a,n),e.insertBefore(f,n),l.forEach(e=>e()),()=>{for(let e=s.length-1;e>=0;e--)s[e]();let e=d.nextSibling;for(;e&&e!==f;){let t=e.nextSibling;e.parentNode?.removeChild(e),e=t}d.parentNode?.removeChild(d),f.parentNode?.removeChild(f)}}return{__isElurTemplate:!0,[e.ELUR_TEMPLATE_DESCRIPTOR]:l,_render:d,mount(e){let t=typeof e==`string`?document.querySelector(e):e;if(!t)throw Error(`[elur] mount: contenedor no encontrado: ${e}`);let n=d(t,null);return{unmount(){n()}}}}}exports.buildHTML=n,exports.html=a;
1
+ const e=require(`./types.cjs`),t=require(`./bindings.cjs`);function n(e,t){let n=new Uint8Array(e.length),r=``;for(let i=0;i<e.length;i++){let a=e[i];if(n[i]===1&&(a[0]===`"`||a[0]===`'`)&&(a=a.slice(1)),i<t.length){let e=t[i];if(e.type===`node`)r+=a+`<!--elur-${i}-->`;else if(e.type===`event`){let t=`@${e.modifiers.length?`${e.eventName}.${e.modifiers.join(`.`)}`:e.eventName}=`.length+ +!!e.hadOpenQuote;r+=a.slice(0,-t)+` data-elur-e-${i}="${e.eventName}"`,e.hadOpenQuote&&(n[i+1]=1)}else{let t=`${e.attrName}=`.length+ +!!e.hadOpenQuote;r+=a.slice(0,-t)+` data-elur-a-${i}="${e.attrName}"`,e.hadOpenQuote&&(n[i+1]=1)}}else r+=a}return r}var r=new WeakMap,i=new WeakMap;function a(a,...o){let s=r.get(a);if(!s){let e=[],n=``;for(let r=0;r<a.length-1;r++)n+=a[r],e.push(t.detectContext(n)),n+=`__elur__`;s={contexts:e},r.set(a,s)}let c=s.contexts,l={version:1,strings:a,values:o,contexts:c};function u(){let e=i.get(a);if(e)return e;if(typeof document>`u`)throw Error(`[elur] DOM rendering requires a document. Use @elurjs/core/server on the server.`);let t=document.createElement(`template`);t.innerHTML=n(a,c);let r=Array(c.length).fill(null),o=t.content,s=document.createTreeWalker(o,NodeFilter.SHOW_ELEMENT|NodeFilter.SHOW_COMMENT),l=0,u;for(;u=s.nextNode();)if(l++,u.nodeType===8){let e=u.nodeValue;if(e&&e.startsWith(`elur-`)){let t=parseInt(e.slice(5),10);isNaN(t)||(r[t]={nodeIndex:l})}}else if(u.nodeType===1){let e=u,t=Array.from(e.attributes);for(let n=0;n<t.length;n++){let i=t[n],a=i.name;if(a.startsWith(`data-elur-e-`)){let t=parseInt(a.slice(12),10);isNaN(t)||(r[t]={nodeIndex:l,name:i.value}),e.removeAttribute(a);continue}if(a.startsWith(`data-elur-a-`)){let t=parseInt(a.slice(12),10);isNaN(t)||(r[t]={nodeIndex:l,name:i.value}),e.removeAttribute(a)}}}return e={tpl:t,pathMap:r},i.set(a,e),e}function d(e,n){let{tpl:r,pathMap:i}=u(),a=r.content.cloneNode(!0),{disposes:s,postMountHooks:l}=t.activateBindings(a,c,o,i),d=document.createTextNode(``),f=document.createTextNode(``);return e.insertBefore(d,n),e.insertBefore(a,n),e.insertBefore(f,n),l.forEach(e=>e()),()=>{for(let e=s.length-1;e>=0;e--)s[e]();let e=d.nextSibling;for(;e&&e!==f;){let t=e.nextSibling;e.parentNode?.removeChild(e),e=t}d.parentNode?.removeChild(d),f.parentNode?.removeChild(f)}}return{__isElurTemplate:!0,[e.ELUR_TEMPLATE_DESCRIPTOR]:l,_render:d,mount(e){let t=typeof e==`string`?document.querySelector(e):e;if(!t)throw Error(`[elur] mount: contenedor no encontrado: ${e}`);let n=d(t,null);return{unmount(){n()}}}}}exports.buildHTML=n,exports.html=a;
2
2
  //# sourceMappingURL=html.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"html.cjs","names":[],"sources":["../../../../src/elur/template/html.ts"],"sourcesContent":["import { ELUR_TEMPLATE_DESCRIPTOR, type ElurTemplate, type ElurMountHandle, type TemplateDescriptor } from \"./types.js\";\nimport { detectContext, activateBindings } from \"./bindings.js\";\nimport type { BindingContext } from \"./bindings.js\";\n\n// =============================================================================\n// --- Static HTML construction with markers ---\n// =============================================================================\n\n/**\n * Builds the static HTML string, replacing each interpolated value with\n * a comment marker (node), data-elur-e-N (event), or data-elur-a-N (attribute).\n */\nexport function buildHTML(\n strings: readonly string[],\n contexts: BindingContext[]\n): string {\n const skipLeading = new Uint8Array(strings.length);\n let result = \"\";\n\n for (let i = 0; i < strings.length; i++) {\n let s = strings[i];\n\n if (skipLeading[i] === 1 && (s[0] === '\"' || s[0] === \"'\")) {\n s = s.slice(1);\n }\n\n if (i < contexts.length) {\n const ctx = contexts[i];\n\n if (ctx.type === \"node\") {\n result += s + `<!--elur-${i}-->`;\n } else if (ctx.type === \"event\") {\n const full = ctx.modifiers.length\n ? `${ctx.eventName}.${ctx.modifiers.join(\".\")}`\n : ctx.eventName;\n const cut = `@${full}=`.length + (ctx.hadOpenQuote ? 1 : 0);\n result += s.slice(0, -cut) + ` data-elur-e-${i}=\"${ctx.eventName}\"`;\n if (ctx.hadOpenQuote) skipLeading[i + 1] = 1;\n } else {\n const cut =\n `${ctx.attrName}=`.length + (ctx.hadOpenQuote ? 1 : 0);\n result += s.slice(0, -cut) + ` data-elur-a-${i}=\"${ctx.attrName}\"`;\n if (ctx.hadOpenQuote) skipLeading[i + 1] = 1;\n }\n } else {\n result += s;\n }\n }\n\n return result;\n}\n\n// =============================================================================\n// --- Template cache ---\n// =============================================================================\n\ninterface DescriptorCache {\n contexts: BindingContext[];\n}\n\ninterface TemplateCache {\n tpl: HTMLTemplateElement;\n pathMap: Array<{ nodeIndex: number; name?: string } | null>;\n}\n\nconst _descriptorCache = new WeakMap<TemplateStringsArray, DescriptorCache>();\nconst _templateCache = new WeakMap<TemplateStringsArray, TemplateCache>();\n\n// =============================================================================\n// --- html`` tag function ---\n// =============================================================================\n\nexport function html(\n strings: TemplateStringsArray,\n ...values: unknown[]\n): ElurTemplate {\n // NOTE: Partial attribute interpolation (`class=\"btn ${size}\"`) is handled\n // at compile time by @elurjs/vite-plugin-elur. Without the plugin,\n // only full bindings (`class=${value}`) are supported.\n let descriptorCache = _descriptorCache.get(strings);\n if (!descriptorCache) {\n const contexts: BindingContext[] = [];\n let accumulated = \"\";\n for (let i = 0; i < strings.length - 1; i++) {\n accumulated += strings[i];\n contexts.push(detectContext(accumulated));\n accumulated += \"__elur__\";\n }\n descriptorCache = { contexts };\n _descriptorCache.set(strings, descriptorCache);\n }\n\n const contexts = descriptorCache.contexts;\n const descriptor: TemplateDescriptor = { version: 1, strings, values, contexts };\n\n function getTemplateCache(): TemplateCache {\n let cached = _templateCache.get(strings);\n if (cached) return cached;\n if (typeof document === \"undefined\") {\n throw new Error(\"[elur] DOM rendering requires a document. Use elur/server on the server.\");\n }\n\n const tpl = document.createElement(\"template\");\n tpl.innerHTML = buildHTML(strings, contexts);\n const pathMap = new Array<{ nodeIndex: number; name?: string } | null>(contexts.length).fill(null);\n const root = tpl.content;\n const walker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT);\n let nodeIndex = 0;\n let wNode: Node | null;\n\n while ((wNode = walker.nextNode())) {\n nodeIndex++;\n if (wNode.nodeType === 8) {\n const val = wNode.nodeValue;\n if (val && val.startsWith(\"elur-\")) {\n const idx = parseInt(val.slice(5), 10);\n if (!isNaN(idx)) pathMap[idx] = { nodeIndex };\n }\n } else if (wNode.nodeType === 1) {\n const el = wNode as Element;\n const attrs = Array.from(el.attributes);\n for (let i = 0; i < attrs.length; i++) {\n const attr = attrs[i];\n const name = attr.name;\n if (name.startsWith(\"data-elur-e-\")) {\n const idx = parseInt(name.slice(12), 10);\n if (!isNaN(idx)) pathMap[idx] = { nodeIndex, name: attr.value };\n el.removeAttribute(name);\n continue;\n }\n if (name.startsWith(\"data-elur-a-\")) {\n const idx = parseInt(name.slice(12), 10);\n if (!isNaN(idx)) pathMap[idx] = { nodeIndex, name: attr.value };\n el.removeAttribute(name);\n }\n }\n }\n }\n\n cached = { tpl, pathMap };\n _templateCache.set(strings, cached);\n return cached;\n }\n\n function _render(parent: Node, before: Node | null): () => void {\n const { tpl, pathMap } = getTemplateCache();\n const fragment = tpl.content.cloneNode(true) as DocumentFragment;\n\n const { disposes, postMountHooks } = activateBindings(\n fragment, contexts, values, pathMap\n );\n\n const startMarker = document.createTextNode(\"\");\n const endMarker = document.createTextNode(\"\")\n\n parent.insertBefore(startMarker, before);\n parent.insertBefore(fragment, before);\n parent.insertBefore(endMarker, before);\n\n postMountHooks.forEach((cb) => cb());\n\n return () => {\n for (let i = disposes.length - 1; i >= 0; i--) {\n disposes[i]();\n }\n let node = startMarker.nextSibling;\n while (node && node !== endMarker) {\n const next = node.nextSibling;\n node.parentNode?.removeChild(node);\n node = next;\n }\n startMarker.parentNode?.removeChild(startMarker);\n endMarker.parentNode?.removeChild(endMarker);\n };\n }\n\n const elurTemplate: ElurTemplate = {\n __isElurTemplate: true,\n [ELUR_TEMPLATE_DESCRIPTOR]: descriptor,\n\n _render,\n\n mount(container: Element | string): ElurMountHandle {\n const el =\n typeof container === \"string\"\n ? (document.querySelector(container) as Element)\n : container;\n\n if (!el) {\n throw new Error(`[elur] mount: contenedor no encontrado: ${container}`);\n }\n\n const cleanup = _render(el, null);\n\n return {\n unmount() {\n cleanup();\n },\n };\n },\n };\n\n return elurTemplate;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"html.cjs","names":[],"sources":["../../../../src/elur/template/html.ts"],"sourcesContent":["import { ELUR_TEMPLATE_DESCRIPTOR, type ElurTemplate, type ElurMountHandle, type TemplateDescriptor } from \"./types.js\";\nimport { detectContext, activateBindings } from \"./bindings.js\";\nimport type { BindingContext } from \"./bindings.js\";\n\n// =============================================================================\n// --- Static HTML construction with markers ---\n// =============================================================================\n\n/**\n * Builds the static HTML string, replacing each interpolated value with\n * a comment marker (node), data-elur-e-N (event), or data-elur-a-N (attribute).\n */\nexport function buildHTML(\n strings: readonly string[],\n contexts: BindingContext[]\n): string {\n const skipLeading = new Uint8Array(strings.length);\n let result = \"\";\n\n for (let i = 0; i < strings.length; i++) {\n let s = strings[i];\n\n if (skipLeading[i] === 1 && (s[0] === '\"' || s[0] === \"'\")) {\n s = s.slice(1);\n }\n\n if (i < contexts.length) {\n const ctx = contexts[i];\n\n if (ctx.type === \"node\") {\n result += s + `<!--elur-${i}-->`;\n } else if (ctx.type === \"event\") {\n const full = ctx.modifiers.length\n ? `${ctx.eventName}.${ctx.modifiers.join(\".\")}`\n : ctx.eventName;\n const cut = `@${full}=`.length + (ctx.hadOpenQuote ? 1 : 0);\n result += s.slice(0, -cut) + ` data-elur-e-${i}=\"${ctx.eventName}\"`;\n if (ctx.hadOpenQuote) skipLeading[i + 1] = 1;\n } else {\n const cut =\n `${ctx.attrName}=`.length + (ctx.hadOpenQuote ? 1 : 0);\n result += s.slice(0, -cut) + ` data-elur-a-${i}=\"${ctx.attrName}\"`;\n if (ctx.hadOpenQuote) skipLeading[i + 1] = 1;\n }\n } else {\n result += s;\n }\n }\n\n return result;\n}\n\n// =============================================================================\n// --- Template cache ---\n// =============================================================================\n\ninterface DescriptorCache {\n contexts: BindingContext[];\n}\n\ninterface TemplateCache {\n tpl: HTMLTemplateElement;\n pathMap: Array<{ nodeIndex: number; name?: string } | null>;\n}\n\nconst _descriptorCache = new WeakMap<TemplateStringsArray, DescriptorCache>();\nconst _templateCache = new WeakMap<TemplateStringsArray, TemplateCache>();\n\n// =============================================================================\n// --- html`` tag function ---\n// =============================================================================\n\nexport function html(\n strings: TemplateStringsArray,\n ...values: unknown[]\n): ElurTemplate {\n // NOTE: Partial attribute interpolation (`class=\"btn ${size}\"`) is handled\n // at compile time by @elurjs/vite-plugin-elur. Without the plugin,\n // only full bindings (`class=${value}`) are supported.\n let descriptorCache = _descriptorCache.get(strings);\n if (!descriptorCache) {\n const contexts: BindingContext[] = [];\n let accumulated = \"\";\n for (let i = 0; i < strings.length - 1; i++) {\n accumulated += strings[i];\n contexts.push(detectContext(accumulated));\n accumulated += \"__elur__\";\n }\n descriptorCache = { contexts };\n _descriptorCache.set(strings, descriptorCache);\n }\n\n const contexts = descriptorCache.contexts;\n const descriptor: TemplateDescriptor = { version: 1, strings, values, contexts };\n\n function getTemplateCache(): TemplateCache {\n let cached = _templateCache.get(strings);\n if (cached) return cached;\n if (typeof document === \"undefined\") {\n throw new Error(\"[elur] DOM rendering requires a document. Use @elurjs/core/server on the server.\");\n }\n\n const tpl = document.createElement(\"template\");\n tpl.innerHTML = buildHTML(strings, contexts);\n const pathMap = new Array<{ nodeIndex: number; name?: string } | null>(contexts.length).fill(null);\n const root = tpl.content;\n const walker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT);\n let nodeIndex = 0;\n let wNode: Node | null;\n\n while ((wNode = walker.nextNode())) {\n nodeIndex++;\n if (wNode.nodeType === 8) {\n const val = wNode.nodeValue;\n if (val && val.startsWith(\"elur-\")) {\n const idx = parseInt(val.slice(5), 10);\n if (!isNaN(idx)) pathMap[idx] = { nodeIndex };\n }\n } else if (wNode.nodeType === 1) {\n const el = wNode as Element;\n const attrs = Array.from(el.attributes);\n for (let i = 0; i < attrs.length; i++) {\n const attr = attrs[i];\n const name = attr.name;\n if (name.startsWith(\"data-elur-e-\")) {\n const idx = parseInt(name.slice(12), 10);\n if (!isNaN(idx)) pathMap[idx] = { nodeIndex, name: attr.value };\n el.removeAttribute(name);\n continue;\n }\n if (name.startsWith(\"data-elur-a-\")) {\n const idx = parseInt(name.slice(12), 10);\n if (!isNaN(idx)) pathMap[idx] = { nodeIndex, name: attr.value };\n el.removeAttribute(name);\n }\n }\n }\n }\n\n cached = { tpl, pathMap };\n _templateCache.set(strings, cached);\n return cached;\n }\n\n function _render(parent: Node, before: Node | null): () => void {\n const { tpl, pathMap } = getTemplateCache();\n const fragment = tpl.content.cloneNode(true) as DocumentFragment;\n\n const { disposes, postMountHooks } = activateBindings(\n fragment, contexts, values, pathMap\n );\n\n const startMarker = document.createTextNode(\"\");\n const endMarker = document.createTextNode(\"\")\n\n parent.insertBefore(startMarker, before);\n parent.insertBefore(fragment, before);\n parent.insertBefore(endMarker, before);\n\n postMountHooks.forEach((cb) => cb());\n\n return () => {\n for (let i = disposes.length - 1; i >= 0; i--) {\n disposes[i]();\n }\n let node = startMarker.nextSibling;\n while (node && node !== endMarker) {\n const next = node.nextSibling;\n node.parentNode?.removeChild(node);\n node = next;\n }\n startMarker.parentNode?.removeChild(startMarker);\n endMarker.parentNode?.removeChild(endMarker);\n };\n }\n\n const elurTemplate: ElurTemplate = {\n __isElurTemplate: true,\n [ELUR_TEMPLATE_DESCRIPTOR]: descriptor,\n\n _render,\n\n mount(container: Element | string): ElurMountHandle {\n const el =\n typeof container === \"string\"\n ? (document.querySelector(container) as Element)\n : container;\n\n if (!el) {\n throw new Error(`[elur] mount: contenedor no encontrado: ${container}`);\n }\n\n const cleanup = _render(el, null);\n\n return {\n unmount() {\n cleanup();\n },\n };\n },\n };\n\n return elurTemplate;\n}\n"],"mappings":"2DAYA,SAAgB,EACZ,EACA,EACM,CACN,IAAM,EAAc,IAAI,WAAW,EAAQ,OAAO,CAC9C,EAAS,GAEb,IAAK,IAAI,EAAI,EAAG,EAAI,EAAQ,OAAQ,IAAK,CACrC,IAAI,EAAI,EAAQ,GAMhB,GAJI,EAAY,KAAO,IAAM,EAAE,KAAO,KAAO,EAAE,KAAO,OAClD,EAAI,EAAE,MAAM,EAAE,EAGd,EAAI,EAAS,OAAQ,CACrB,IAAM,EAAM,EAAS,GAErB,GAAI,EAAI,OAAS,OACb,GAAU,EAAI,YAAY,EAAE,aACrB,EAAI,OAAS,QAAS,CAI7B,IAAM,EAAM,IAHC,EAAI,UAAU,OACrB,GAAG,EAAI,UAAU,GAAG,EAAI,UAAU,KAAK,IAAI,GAC3C,EAAI,UACW,GAAG,QAAU,KAAI,aACtC,GAAU,EAAE,MAAM,EAAG,CAAC,EAAI,CAAG,gBAAgB,EAAE,IAAI,EAAI,UAAU,GAC7D,EAAI,eAAc,EAAY,EAAI,GAAK,OACxC,CACH,IAAM,EACF,GAAG,EAAI,SAAS,GAAG,QAAU,KAAI,aACrC,GAAU,EAAE,MAAM,EAAG,CAAC,EAAI,CAAG,gBAAgB,EAAE,IAAI,EAAI,SAAS,GAC5D,EAAI,eAAc,EAAY,EAAI,GAAK,SAG/C,GAAU,EAIlB,OAAO,EAgBX,IAAM,EAAmB,IAAI,QACvB,EAAiB,IAAI,QAM3B,SAAgB,EACZ,EACA,GAAG,EACS,CAIZ,IAAI,EAAkB,EAAiB,IAAI,EAAQ,CACnD,GAAI,CAAC,EAAiB,CAClB,IAAM,EAA6B,EAAE,CACjC,EAAc,GAClB,IAAK,IAAI,EAAI,EAAG,EAAI,EAAQ,OAAS,EAAG,IACpC,GAAe,EAAQ,GACvB,EAAS,KAAK,EAAA,cAAc,EAAY,CAAC,CACzC,GAAe,WAEnB,EAAkB,CAAE,WAAU,CAC9B,EAAiB,IAAI,EAAS,EAAgB,CAGlD,IAAM,EAAW,EAAgB,SAC3B,EAAiC,CAAE,QAAS,EAAG,UAAS,SAAQ,WAAU,CAEhF,SAAS,GAAkC,CACvC,IAAI,EAAS,EAAe,IAAI,EAAQ,CACxC,GAAI,EAAQ,OAAO,EACnB,GAAI,OAAO,SAAa,IACpB,MAAU,MAAM,mFAAmF,CAGvG,IAAM,EAAM,SAAS,cAAc,WAAW,CAC9C,EAAI,UAAY,EAAU,EAAS,EAAS,CAC5C,IAAM,EAAc,MAAmD,EAAS,OAAO,CAAC,KAAK,KAAK,CAC5F,EAAO,EAAI,QACX,EAAS,SAAS,iBAAiB,EAAM,WAAW,aAAe,WAAW,aAAa,CAC7F,EAAY,EACZ,EAEJ,KAAQ,EAAQ,EAAO,UAAU,EAE7B,GADA,IACI,EAAM,WAAa,EAAG,CACtB,IAAM,EAAM,EAAM,UAClB,GAAI,GAAO,EAAI,WAAW,QAAQ,CAAE,CAChC,IAAM,EAAM,SAAS,EAAI,MAAM,EAAE,CAAE,GAAG,CACjC,MAAM,EAAI,GAAE,EAAQ,GAAO,CAAE,YAAW,WAE1C,EAAM,WAAa,EAAG,CAC7B,IAAM,EAAK,EACL,EAAQ,MAAM,KAAK,EAAG,WAAW,CACvC,IAAK,IAAI,EAAI,EAAG,EAAI,EAAM,OAAQ,IAAK,CACnC,IAAM,EAAO,EAAM,GACb,EAAO,EAAK,KAClB,GAAI,EAAK,WAAW,eAAe,CAAE,CACjC,IAAM,EAAM,SAAS,EAAK,MAAM,GAAG,CAAE,GAAG,CACnC,MAAM,EAAI,GAAE,EAAQ,GAAO,CAAE,YAAW,KAAM,EAAK,MAAO,EAC/D,EAAG,gBAAgB,EAAK,CACxB,SAEJ,GAAI,EAAK,WAAW,eAAe,CAAE,CACjC,IAAM,EAAM,SAAS,EAAK,MAAM,GAAG,CAAE,GAAG,CACnC,MAAM,EAAI,GAAE,EAAQ,GAAO,CAAE,YAAW,KAAM,EAAK,MAAO,EAC/D,EAAG,gBAAgB,EAAK,GAQxC,MAFA,GAAS,CAAE,MAAK,UAAS,CACzB,EAAe,IAAI,EAAS,EAAO,CAC5B,EAGX,SAAS,EAAQ,EAAc,EAAiC,CAC5D,GAAM,CAAE,MAAK,WAAY,GAAkB,CACrC,EAAW,EAAI,QAAQ,UAAU,GAAK,CAEtC,CAAE,WAAU,kBAAmB,EAAA,iBACjC,EAAU,EAAU,EAAQ,EAC/B,CAEK,EAAc,SAAS,eAAe,GAAG,CACzC,EAAY,SAAS,eAAe,GAAG,CAQ7C,OANA,EAAO,aAAa,EAAa,EAAO,CACxC,EAAO,aAAa,EAAU,EAAO,CACrC,EAAO,aAAa,EAAW,EAAO,CAEtC,EAAe,QAAS,GAAO,GAAI,CAAC,KAEvB,CACT,IAAK,IAAI,EAAI,EAAS,OAAS,EAAG,GAAK,EAAG,IACtC,EAAS,IAAI,CAEjB,IAAI,EAAO,EAAY,YACvB,KAAO,GAAQ,IAAS,GAAW,CAC/B,IAAM,EAAO,EAAK,YAClB,EAAK,YAAY,YAAY,EAAK,CAClC,EAAO,EAEX,EAAY,YAAY,YAAY,EAAY,CAChD,EAAU,YAAY,YAAY,EAAU,EA8BpD,MA1BmC,CAC/B,iBAAkB,IACjB,EAAA,0BAA2B,EAE5B,UAEA,MAAM,EAA8C,CAChD,IAAM,EACF,OAAO,GAAc,SACd,SAAS,cAAc,EAAU,CAClC,EAEV,GAAI,CAAC,EACD,MAAU,MAAM,2CAA2C,IAAY,CAG3E,IAAM,EAAU,EAAQ,EAAI,KAAK,CAEjC,MAAO,CACH,SAAU,CACN,GAAS,EAEhB,EAER"}
@@ -36,7 +36,7 @@ function o(o, ...s) {
36
36
  function d() {
37
37
  let e = a.get(o);
38
38
  if (e) return e;
39
- if (typeof document > "u") throw Error("[elur] DOM rendering requires a document. Use elur/server on the server.");
39
+ if (typeof document > "u") throw Error("[elur] DOM rendering requires a document. Use @elurjs/core/server on the server.");
40
40
  let t = document.createElement("template");
41
41
  t.innerHTML = r(o, l);
42
42
  let n = Array(l.length).fill(null), i = t.content, s = document.createTreeWalker(i, NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT), c = 0, u;
@@ -1 +1 @@
1
- {"version":3,"file":"html.js","names":[],"sources":["../../../../src/elur/template/html.ts"],"sourcesContent":["import { ELUR_TEMPLATE_DESCRIPTOR, type ElurTemplate, type ElurMountHandle, type TemplateDescriptor } from \"./types.js\";\nimport { detectContext, activateBindings } from \"./bindings.js\";\nimport type { BindingContext } from \"./bindings.js\";\n\n// =============================================================================\n// --- Static HTML construction with markers ---\n// =============================================================================\n\n/**\n * Builds the static HTML string, replacing each interpolated value with\n * a comment marker (node), data-elur-e-N (event), or data-elur-a-N (attribute).\n */\nexport function buildHTML(\n strings: readonly string[],\n contexts: BindingContext[]\n): string {\n const skipLeading = new Uint8Array(strings.length);\n let result = \"\";\n\n for (let i = 0; i < strings.length; i++) {\n let s = strings[i];\n\n if (skipLeading[i] === 1 && (s[0] === '\"' || s[0] === \"'\")) {\n s = s.slice(1);\n }\n\n if (i < contexts.length) {\n const ctx = contexts[i];\n\n if (ctx.type === \"node\") {\n result += s + `<!--elur-${i}-->`;\n } else if (ctx.type === \"event\") {\n const full = ctx.modifiers.length\n ? `${ctx.eventName}.${ctx.modifiers.join(\".\")}`\n : ctx.eventName;\n const cut = `@${full}=`.length + (ctx.hadOpenQuote ? 1 : 0);\n result += s.slice(0, -cut) + ` data-elur-e-${i}=\"${ctx.eventName}\"`;\n if (ctx.hadOpenQuote) skipLeading[i + 1] = 1;\n } else {\n const cut =\n `${ctx.attrName}=`.length + (ctx.hadOpenQuote ? 1 : 0);\n result += s.slice(0, -cut) + ` data-elur-a-${i}=\"${ctx.attrName}\"`;\n if (ctx.hadOpenQuote) skipLeading[i + 1] = 1;\n }\n } else {\n result += s;\n }\n }\n\n return result;\n}\n\n// =============================================================================\n// --- Template cache ---\n// =============================================================================\n\ninterface DescriptorCache {\n contexts: BindingContext[];\n}\n\ninterface TemplateCache {\n tpl: HTMLTemplateElement;\n pathMap: Array<{ nodeIndex: number; name?: string } | null>;\n}\n\nconst _descriptorCache = new WeakMap<TemplateStringsArray, DescriptorCache>();\nconst _templateCache = new WeakMap<TemplateStringsArray, TemplateCache>();\n\n// =============================================================================\n// --- html`` tag function ---\n// =============================================================================\n\nexport function html(\n strings: TemplateStringsArray,\n ...values: unknown[]\n): ElurTemplate {\n // NOTE: Partial attribute interpolation (`class=\"btn ${size}\"`) is handled\n // at compile time by @elurjs/vite-plugin-elur. Without the plugin,\n // only full bindings (`class=${value}`) are supported.\n let descriptorCache = _descriptorCache.get(strings);\n if (!descriptorCache) {\n const contexts: BindingContext[] = [];\n let accumulated = \"\";\n for (let i = 0; i < strings.length - 1; i++) {\n accumulated += strings[i];\n contexts.push(detectContext(accumulated));\n accumulated += \"__elur__\";\n }\n descriptorCache = { contexts };\n _descriptorCache.set(strings, descriptorCache);\n }\n\n const contexts = descriptorCache.contexts;\n const descriptor: TemplateDescriptor = { version: 1, strings, values, contexts };\n\n function getTemplateCache(): TemplateCache {\n let cached = _templateCache.get(strings);\n if (cached) return cached;\n if (typeof document === \"undefined\") {\n throw new Error(\"[elur] DOM rendering requires a document. Use elur/server on the server.\");\n }\n\n const tpl = document.createElement(\"template\");\n tpl.innerHTML = buildHTML(strings, contexts);\n const pathMap = new Array<{ nodeIndex: number; name?: string } | null>(contexts.length).fill(null);\n const root = tpl.content;\n const walker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT);\n let nodeIndex = 0;\n let wNode: Node | null;\n\n while ((wNode = walker.nextNode())) {\n nodeIndex++;\n if (wNode.nodeType === 8) {\n const val = wNode.nodeValue;\n if (val && val.startsWith(\"elur-\")) {\n const idx = parseInt(val.slice(5), 10);\n if (!isNaN(idx)) pathMap[idx] = { nodeIndex };\n }\n } else if (wNode.nodeType === 1) {\n const el = wNode as Element;\n const attrs = Array.from(el.attributes);\n for (let i = 0; i < attrs.length; i++) {\n const attr = attrs[i];\n const name = attr.name;\n if (name.startsWith(\"data-elur-e-\")) {\n const idx = parseInt(name.slice(12), 10);\n if (!isNaN(idx)) pathMap[idx] = { nodeIndex, name: attr.value };\n el.removeAttribute(name);\n continue;\n }\n if (name.startsWith(\"data-elur-a-\")) {\n const idx = parseInt(name.slice(12), 10);\n if (!isNaN(idx)) pathMap[idx] = { nodeIndex, name: attr.value };\n el.removeAttribute(name);\n }\n }\n }\n }\n\n cached = { tpl, pathMap };\n _templateCache.set(strings, cached);\n return cached;\n }\n\n function _render(parent: Node, before: Node | null): () => void {\n const { tpl, pathMap } = getTemplateCache();\n const fragment = tpl.content.cloneNode(true) as DocumentFragment;\n\n const { disposes, postMountHooks } = activateBindings(\n fragment, contexts, values, pathMap\n );\n\n const startMarker = document.createTextNode(\"\");\n const endMarker = document.createTextNode(\"\")\n\n parent.insertBefore(startMarker, before);\n parent.insertBefore(fragment, before);\n parent.insertBefore(endMarker, before);\n\n postMountHooks.forEach((cb) => cb());\n\n return () => {\n for (let i = disposes.length - 1; i >= 0; i--) {\n disposes[i]();\n }\n let node = startMarker.nextSibling;\n while (node && node !== endMarker) {\n const next = node.nextSibling;\n node.parentNode?.removeChild(node);\n node = next;\n }\n startMarker.parentNode?.removeChild(startMarker);\n endMarker.parentNode?.removeChild(endMarker);\n };\n }\n\n const elurTemplate: ElurTemplate = {\n __isElurTemplate: true,\n [ELUR_TEMPLATE_DESCRIPTOR]: descriptor,\n\n _render,\n\n mount(container: Element | string): ElurMountHandle {\n const el =\n typeof container === \"string\"\n ? (document.querySelector(container) as Element)\n : container;\n\n if (!el) {\n throw new Error(`[elur] mount: contenedor no encontrado: ${container}`);\n }\n\n const cleanup = _render(el, null);\n\n return {\n unmount() {\n cleanup();\n },\n };\n },\n };\n\n return elurTemplate;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"html.js","names":[],"sources":["../../../../src/elur/template/html.ts"],"sourcesContent":["import { ELUR_TEMPLATE_DESCRIPTOR, type ElurTemplate, type ElurMountHandle, type TemplateDescriptor } from \"./types.js\";\nimport { detectContext, activateBindings } from \"./bindings.js\";\nimport type { BindingContext } from \"./bindings.js\";\n\n// =============================================================================\n// --- Static HTML construction with markers ---\n// =============================================================================\n\n/**\n * Builds the static HTML string, replacing each interpolated value with\n * a comment marker (node), data-elur-e-N (event), or data-elur-a-N (attribute).\n */\nexport function buildHTML(\n strings: readonly string[],\n contexts: BindingContext[]\n): string {\n const skipLeading = new Uint8Array(strings.length);\n let result = \"\";\n\n for (let i = 0; i < strings.length; i++) {\n let s = strings[i];\n\n if (skipLeading[i] === 1 && (s[0] === '\"' || s[0] === \"'\")) {\n s = s.slice(1);\n }\n\n if (i < contexts.length) {\n const ctx = contexts[i];\n\n if (ctx.type === \"node\") {\n result += s + `<!--elur-${i}-->`;\n } else if (ctx.type === \"event\") {\n const full = ctx.modifiers.length\n ? `${ctx.eventName}.${ctx.modifiers.join(\".\")}`\n : ctx.eventName;\n const cut = `@${full}=`.length + (ctx.hadOpenQuote ? 1 : 0);\n result += s.slice(0, -cut) + ` data-elur-e-${i}=\"${ctx.eventName}\"`;\n if (ctx.hadOpenQuote) skipLeading[i + 1] = 1;\n } else {\n const cut =\n `${ctx.attrName}=`.length + (ctx.hadOpenQuote ? 1 : 0);\n result += s.slice(0, -cut) + ` data-elur-a-${i}=\"${ctx.attrName}\"`;\n if (ctx.hadOpenQuote) skipLeading[i + 1] = 1;\n }\n } else {\n result += s;\n }\n }\n\n return result;\n}\n\n// =============================================================================\n// --- Template cache ---\n// =============================================================================\n\ninterface DescriptorCache {\n contexts: BindingContext[];\n}\n\ninterface TemplateCache {\n tpl: HTMLTemplateElement;\n pathMap: Array<{ nodeIndex: number; name?: string } | null>;\n}\n\nconst _descriptorCache = new WeakMap<TemplateStringsArray, DescriptorCache>();\nconst _templateCache = new WeakMap<TemplateStringsArray, TemplateCache>();\n\n// =============================================================================\n// --- html`` tag function ---\n// =============================================================================\n\nexport function html(\n strings: TemplateStringsArray,\n ...values: unknown[]\n): ElurTemplate {\n // NOTE: Partial attribute interpolation (`class=\"btn ${size}\"`) is handled\n // at compile time by @elurjs/vite-plugin-elur. Without the plugin,\n // only full bindings (`class=${value}`) are supported.\n let descriptorCache = _descriptorCache.get(strings);\n if (!descriptorCache) {\n const contexts: BindingContext[] = [];\n let accumulated = \"\";\n for (let i = 0; i < strings.length - 1; i++) {\n accumulated += strings[i];\n contexts.push(detectContext(accumulated));\n accumulated += \"__elur__\";\n }\n descriptorCache = { contexts };\n _descriptorCache.set(strings, descriptorCache);\n }\n\n const contexts = descriptorCache.contexts;\n const descriptor: TemplateDescriptor = { version: 1, strings, values, contexts };\n\n function getTemplateCache(): TemplateCache {\n let cached = _templateCache.get(strings);\n if (cached) return cached;\n if (typeof document === \"undefined\") {\n throw new Error(\"[elur] DOM rendering requires a document. Use @elurjs/core/server on the server.\");\n }\n\n const tpl = document.createElement(\"template\");\n tpl.innerHTML = buildHTML(strings, contexts);\n const pathMap = new Array<{ nodeIndex: number; name?: string } | null>(contexts.length).fill(null);\n const root = tpl.content;\n const walker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT);\n let nodeIndex = 0;\n let wNode: Node | null;\n\n while ((wNode = walker.nextNode())) {\n nodeIndex++;\n if (wNode.nodeType === 8) {\n const val = wNode.nodeValue;\n if (val && val.startsWith(\"elur-\")) {\n const idx = parseInt(val.slice(5), 10);\n if (!isNaN(idx)) pathMap[idx] = { nodeIndex };\n }\n } else if (wNode.nodeType === 1) {\n const el = wNode as Element;\n const attrs = Array.from(el.attributes);\n for (let i = 0; i < attrs.length; i++) {\n const attr = attrs[i];\n const name = attr.name;\n if (name.startsWith(\"data-elur-e-\")) {\n const idx = parseInt(name.slice(12), 10);\n if (!isNaN(idx)) pathMap[idx] = { nodeIndex, name: attr.value };\n el.removeAttribute(name);\n continue;\n }\n if (name.startsWith(\"data-elur-a-\")) {\n const idx = parseInt(name.slice(12), 10);\n if (!isNaN(idx)) pathMap[idx] = { nodeIndex, name: attr.value };\n el.removeAttribute(name);\n }\n }\n }\n }\n\n cached = { tpl, pathMap };\n _templateCache.set(strings, cached);\n return cached;\n }\n\n function _render(parent: Node, before: Node | null): () => void {\n const { tpl, pathMap } = getTemplateCache();\n const fragment = tpl.content.cloneNode(true) as DocumentFragment;\n\n const { disposes, postMountHooks } = activateBindings(\n fragment, contexts, values, pathMap\n );\n\n const startMarker = document.createTextNode(\"\");\n const endMarker = document.createTextNode(\"\")\n\n parent.insertBefore(startMarker, before);\n parent.insertBefore(fragment, before);\n parent.insertBefore(endMarker, before);\n\n postMountHooks.forEach((cb) => cb());\n\n return () => {\n for (let i = disposes.length - 1; i >= 0; i--) {\n disposes[i]();\n }\n let node = startMarker.nextSibling;\n while (node && node !== endMarker) {\n const next = node.nextSibling;\n node.parentNode?.removeChild(node);\n node = next;\n }\n startMarker.parentNode?.removeChild(startMarker);\n endMarker.parentNode?.removeChild(endMarker);\n };\n }\n\n const elurTemplate: ElurTemplate = {\n __isElurTemplate: true,\n [ELUR_TEMPLATE_DESCRIPTOR]: descriptor,\n\n _render,\n\n mount(container: Element | string): ElurMountHandle {\n const el =\n typeof container === \"string\"\n ? (document.querySelector(container) as Element)\n : container;\n\n if (!el) {\n throw new Error(`[elur] mount: contenedor no encontrado: ${container}`);\n }\n\n const cleanup = _render(el, null);\n\n return {\n unmount() {\n cleanup();\n },\n };\n },\n };\n\n return elurTemplate;\n}\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- var e=Symbol.for(`elur/template-descriptor`),t=Symbol.for(`elur/render-protocol`),n={partialAttributeInterpolation:!1};function r(){return{el:null}}var i={SCOPE:`elur-scope`,ERROR_BOUNDARY:`elur-eb`,TRANSITION:`elur-t`,KEYED_START:`elur-ks`,KEYED_END:`elur-ke`,KEYED_ZONE:`elur-kz`};function a(e){return typeof e==`object`&&!!e&&e.__isElurTemplate===!0}function o(e){return typeof e==`object`&&!!e&&e.__isKeyedList===!0}exports.COMMENT=i,exports.ELUR_RENDER_PROTOCOL=t,exports.ELUR_TEMPLATE_DESCRIPTOR=e,exports.isElurTemplate=a,exports.isKeyedList=o,exports.ref=r,exports.templateFeatures=n;
1
+ var e=Symbol.for(`@elurjs/core/template-descriptor`),t=Symbol.for(`@elurjs/core/render-protocol`),n={partialAttributeInterpolation:!1};function r(){return{el:null}}var i={SCOPE:`elur-scope`,ERROR_BOUNDARY:`elur-eb`,TRANSITION:`elur-t`,KEYED_START:`elur-ks`,KEYED_END:`elur-ke`,KEYED_ZONE:`elur-kz`};function a(e){return typeof e==`object`&&!!e&&e.__isElurTemplate===!0}function o(e){return typeof e==`object`&&!!e&&e.__isKeyedList===!0}exports.COMMENT=i,exports.ELUR_RENDER_PROTOCOL=t,exports.ELUR_TEMPLATE_DESCRIPTOR=e,exports.isElurTemplate=a,exports.isKeyedList=o,exports.ref=r,exports.templateFeatures=n;
2
2
  //# sourceMappingURL=types.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.cjs","names":[],"sources":["../../../../src/elur/template/types.ts"],"sourcesContent":["// =============================================================================\n// --- Public types ---\n// =============================================================================\n\nexport type TemplateBindingContext =\n | { type: \"node\" }\n | { type: \"event\"; eventName: string; modifiers: string[]; hadOpenQuote: boolean }\n | { type: \"attr\"; attrName: string; hadOpenQuote: boolean; url?: boolean; executable?: boolean };\n\nexport interface TemplateDescriptor {\n readonly version: 1;\n readonly strings: readonly string[];\n readonly values: readonly unknown[];\n readonly contexts: readonly TemplateBindingContext[];\n}\n\nexport interface ServerRenderProtocolContext {\n readonly markers: boolean;\n readonly signal?: AbortSignal;\n readonly context?: unknown;\n render(value: unknown, options?: { markers?: boolean }): Promise<string>;\n}\n\n/** Context passed to a custom value's `mountDom` protocol during client-side mount. */\nexport interface DomProtocolContext {\n readonly parent: Node;\n readonly before: Node | null;\n readonly context?: unknown;\n}\n\n/** Context passed to a custom value's `hydrateDom` protocol during hydration. */\nexport interface HydrationProtocolContext {\n readonly parent: Node;\n readonly bounds: { start: Comment; end: Comment } | null;\n readonly context?: unknown;\n /** Remounts a value inside the current bounds (used as fallback). */\n render(value: unknown): unknown;\n}\n\nexport interface ElurRenderProtocol {\n renderServer?(context: ServerRenderProtocolContext): string | Promise<string>;\n mountDom?(context: DomProtocolContext): (() => void) | void;\n hydrateDom?(context: HydrationProtocolContext): (() => void) | void;\n}\n\nexport const ELUR_TEMPLATE_DESCRIPTOR = Symbol.for(\"elur/template-descriptor\");\nexport const ELUR_RENDER_PROTOCOL = Symbol.for(\"elur/render-protocol\");\n\n/**\n * Runtime feature capabilities, for tooling to detect support without\n * inferring it from version strings.\n *\n * NOTE: Partial attribute interpolation is now handled at compile time by\n * @elurjs/vite-plugin-elur. The core runtime does not support it natively.\n * Use the Vite plugin for partial interpolation support.\n */\nexport const templateFeatures = {\n /** Partial attribute interpolation (`class=\"btn ${size}\"`) is supported. */\n partialAttributeInterpolation: false,\n} as const;\n\nexport interface ElurTemplate {\n readonly __isElurTemplate: true;\n readonly [ELUR_TEMPLATE_DESCRIPTOR]?: TemplateDescriptor;\n readonly [ELUR_RENDER_PROTOCOL]?: ElurRenderProtocol;\n /** Mounts the template into a container element (public / root API). */\n mount(container: Element | string): ElurMountHandle;\n /** @internal Renders before `before` node (or appends to `parent`). Returns cleanup. */\n _render(parent: Node, before: Node | null): () => void;\n}\n\nexport interface ElurMountHandle {\n unmount(): void;\n}\n\n/** Direct reference to a DOM element, assigned on mount and cleared on unmount. */\nexport interface ElurRef<T extends Element = Element> {\n el: T | null;\n}\n\n/** Creates an empty `ElurRef`. Use as `ref` attribute value in templates. */\nexport function ref<T extends Element = Element>(): ElurRef<T> {\n return { el: null };\n}\n\n/** Keyed list result for efficient DOM diffing via `repeat()`. */\nexport interface KeyedList<T = unknown> {\n readonly __isKeyedList: true;\n readonly items: T[];\n readonly keyFn: (item: T, index: number) => string | number;\n readonly renderFn: (item: T, index: number) => ElurTemplate | import(\"../lifecycle.js\").ElurComponent;\n}\n\nexport interface KEntry {\n start: Comment;\n end: Comment;\n cleanup: () => void;\n}\n\n/** Opaque token for a named portal target. */\nexport interface PortalOutlet {\n readonly __isPortalOutlet: true;\n /** @internal */\n _container: Element | null;\n}\n\n/** Fallback: a static template/component, or a factory receiving the error. */\nexport type ErrorFallback =\n | ElurTemplate\n | import(\"../lifecycle.js\").ElurComponent\n | ((err: unknown) => ElurTemplate | import(\"../lifecycle.js\").ElurComponent);\n\n/** Content that can be wrapped with `transition()`. */\nexport type TransitionContent =\n | ElurTemplate\n | import(\"../lifecycle.js\").ElurComponent\n | (() => ElurTemplate | import(\"../lifecycle.js\").ElurComponent | null);\n\nexport const COMMENT = {\n SCOPE: \"elur-scope\",\n ERROR_BOUNDARY: \"elur-eb\",\n TRANSITION: \"elur-t\",\n KEYED_START: \"elur-ks\",\n KEYED_END: \"elur-ke\",\n KEYED_ZONE: \"elur-kz\",\n} as const;\n\n// =============================================================================\n// --- DOM inspection helpers ---\n// =============================================================================\n\nexport function isElurTemplate(v: unknown): v is ElurTemplate {\n return (\n v != null &&\n typeof v === \"object\" &&\n (v as Record<string, unknown>).__isElurTemplate === true\n );\n}\n\nexport function isKeyedList(v: unknown): v is KeyedList {\n return (\n v != null &&\n typeof v === \"object\" &&\n (v as Record<string, unknown>).__isKeyedList === true\n );\n}\n"],"mappings":"AA6CA,IAAa,EAA2B,OAAO,IAAI,2BAA2B,CACjE,EAAuB,OAAO,IAAI,uBAAuB,CAUzD,EAAmB,CAE5B,8BAA+B,GAClC,CAsBD,SAAgB,GAA+C,CAC3D,MAAO,CAAE,GAAI,KAAM,CAoCvB,IAAa,EAAU,CACnB,MAAO,aACP,eAAgB,UAChB,WAAY,SACZ,YAAa,UACb,UAAW,UACX,WAAY,UACf,CAMD,SAAgB,EAAe,EAA+B,CAC1D,OAEI,OAAO,GAAM,YADb,GAEC,EAA8B,mBAAqB,GAI5D,SAAgB,EAAY,EAA4B,CACpD,OAEI,OAAO,GAAM,YADb,GAEC,EAA8B,gBAAkB"}
1
+ {"version":3,"file":"types.cjs","names":[],"sources":["../../../../src/elur/template/types.ts"],"sourcesContent":["// =============================================================================\n// --- Public types ---\n// =============================================================================\n\nexport type TemplateBindingContext =\n | { type: \"node\" }\n | { type: \"event\"; eventName: string; modifiers: string[]; hadOpenQuote: boolean }\n | { type: \"attr\"; attrName: string; hadOpenQuote: boolean; url?: boolean; executable?: boolean };\n\nexport interface TemplateDescriptor {\n readonly version: 1;\n readonly strings: readonly string[];\n readonly values: readonly unknown[];\n readonly contexts: readonly TemplateBindingContext[];\n}\n\nexport interface ServerRenderProtocolContext {\n readonly markers: boolean;\n readonly signal?: AbortSignal;\n readonly context?: unknown;\n render(value: unknown, options?: { markers?: boolean }): Promise<string>;\n}\n\n/** Context passed to a custom value's `mountDom` protocol during client-side mount. */\nexport interface DomProtocolContext {\n readonly parent: Node;\n readonly before: Node | null;\n readonly context?: unknown;\n}\n\n/** Context passed to a custom value's `hydrateDom` protocol during hydration. */\nexport interface HydrationProtocolContext {\n readonly parent: Node;\n readonly bounds: { start: Comment; end: Comment } | null;\n readonly context?: unknown;\n /** Remounts a value inside the current bounds (used as fallback). */\n render(value: unknown): unknown;\n}\n\nexport interface ElurRenderProtocol {\n renderServer?(context: ServerRenderProtocolContext): string | Promise<string>;\n mountDom?(context: DomProtocolContext): (() => void) | void;\n hydrateDom?(context: HydrationProtocolContext): (() => void) | void;\n}\n\nexport const ELUR_TEMPLATE_DESCRIPTOR = Symbol.for(\"@elurjs/core/template-descriptor\");\nexport const ELUR_RENDER_PROTOCOL = Symbol.for(\"@elurjs/core/render-protocol\");\n\n/**\n * Runtime feature capabilities, for tooling to detect support without\n * inferring it from version strings.\n *\n * NOTE: Partial attribute interpolation is now handled at compile time by\n * @elurjs/vite-plugin-elur. The core runtime does not support it natively.\n * Use the Vite plugin for partial interpolation support.\n */\nexport const templateFeatures = {\n /** Partial attribute interpolation (`class=\"btn ${size}\"`) is supported. */\n partialAttributeInterpolation: false,\n} as const;\n\nexport interface ElurTemplate {\n readonly __isElurTemplate: true;\n readonly [ELUR_TEMPLATE_DESCRIPTOR]?: TemplateDescriptor;\n readonly [ELUR_RENDER_PROTOCOL]?: ElurRenderProtocol;\n /** Mounts the template into a container element (public / root API). */\n mount(container: Element | string): ElurMountHandle;\n /** @internal Renders before `before` node (or appends to `parent`). Returns cleanup. */\n _render(parent: Node, before: Node | null): () => void;\n}\n\nexport interface ElurMountHandle {\n unmount(): void;\n}\n\n/** Direct reference to a DOM element, assigned on mount and cleared on unmount. */\nexport interface ElurRef<T extends Element = Element> {\n el: T | null;\n}\n\n/** Creates an empty `ElurRef`. Use as `ref` attribute value in templates. */\nexport function ref<T extends Element = Element>(): ElurRef<T> {\n return { el: null };\n}\n\n/** Keyed list result for efficient DOM diffing via `repeat()`. */\nexport interface KeyedList<T = unknown> {\n readonly __isKeyedList: true;\n readonly items: T[];\n readonly keyFn: (item: T, index: number) => string | number;\n readonly renderFn: (item: T, index: number) => ElurTemplate | import(\"../lifecycle.js\").ElurComponent;\n}\n\nexport interface KEntry {\n start: Comment;\n end: Comment;\n cleanup: () => void;\n}\n\n/** Opaque token for a named portal target. */\nexport interface PortalOutlet {\n readonly __isPortalOutlet: true;\n /** @internal */\n _container: Element | null;\n}\n\n/** Fallback: a static template/component, or a factory receiving the error. */\nexport type ErrorFallback =\n | ElurTemplate\n | import(\"../lifecycle.js\").ElurComponent\n | ((err: unknown) => ElurTemplate | import(\"../lifecycle.js\").ElurComponent);\n\n/** Content that can be wrapped with `transition()`. */\nexport type TransitionContent =\n | ElurTemplate\n | import(\"../lifecycle.js\").ElurComponent\n | (() => ElurTemplate | import(\"../lifecycle.js\").ElurComponent | null);\n\nexport const COMMENT = {\n SCOPE: \"elur-scope\",\n ERROR_BOUNDARY: \"elur-eb\",\n TRANSITION: \"elur-t\",\n KEYED_START: \"elur-ks\",\n KEYED_END: \"elur-ke\",\n KEYED_ZONE: \"elur-kz\",\n} as const;\n\n// =============================================================================\n// --- DOM inspection helpers ---\n// =============================================================================\n\nexport function isElurTemplate(v: unknown): v is ElurTemplate {\n return (\n v != null &&\n typeof v === \"object\" &&\n (v as Record<string, unknown>).__isElurTemplate === true\n );\n}\n\nexport function isKeyedList(v: unknown): v is KeyedList {\n return (\n v != null &&\n typeof v === \"object\" &&\n (v as Record<string, unknown>).__isKeyedList === true\n );\n}\n"],"mappings":"AA6CA,IAAa,EAA2B,OAAO,IAAI,mCAAmC,CACzE,EAAuB,OAAO,IAAI,+BAA+B,CAUjE,EAAmB,CAE5B,8BAA+B,GAClC,CAsBD,SAAgB,GAA+C,CAC3D,MAAO,CAAE,GAAI,KAAM,CAoCvB,IAAa,EAAU,CACnB,MAAO,aACP,eAAgB,UAChB,WAAY,SACZ,YAAa,UACb,UAAW,UACX,WAAY,UACf,CAMD,SAAgB,EAAe,EAA+B,CAC1D,OAEI,OAAO,GAAM,YADb,GAEC,EAA8B,mBAAqB,GAI5D,SAAgB,EAAY,EAA4B,CACpD,OAEI,OAAO,GAAM,YADb,GAEC,EAA8B,gBAAkB"}
@@ -1,5 +1,5 @@
1
1
  //#region src/elur/template/types.ts
2
- var e = Symbol.for("elur/template-descriptor"), t = Symbol.for("elur/render-protocol"), n = { partialAttributeInterpolation: !1 };
2
+ var e = Symbol.for("@elurjs/core/template-descriptor"), t = Symbol.for("@elurjs/core/render-protocol"), n = { partialAttributeInterpolation: !1 };
3
3
  function r() {
4
4
  return { el: null };
5
5
  }
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","names":[],"sources":["../../../../src/elur/template/types.ts"],"sourcesContent":["// =============================================================================\n// --- Public types ---\n// =============================================================================\n\nexport type TemplateBindingContext =\n | { type: \"node\" }\n | { type: \"event\"; eventName: string; modifiers: string[]; hadOpenQuote: boolean }\n | { type: \"attr\"; attrName: string; hadOpenQuote: boolean; url?: boolean; executable?: boolean };\n\nexport interface TemplateDescriptor {\n readonly version: 1;\n readonly strings: readonly string[];\n readonly values: readonly unknown[];\n readonly contexts: readonly TemplateBindingContext[];\n}\n\nexport interface ServerRenderProtocolContext {\n readonly markers: boolean;\n readonly signal?: AbortSignal;\n readonly context?: unknown;\n render(value: unknown, options?: { markers?: boolean }): Promise<string>;\n}\n\n/** Context passed to a custom value's `mountDom` protocol during client-side mount. */\nexport interface DomProtocolContext {\n readonly parent: Node;\n readonly before: Node | null;\n readonly context?: unknown;\n}\n\n/** Context passed to a custom value's `hydrateDom` protocol during hydration. */\nexport interface HydrationProtocolContext {\n readonly parent: Node;\n readonly bounds: { start: Comment; end: Comment } | null;\n readonly context?: unknown;\n /** Remounts a value inside the current bounds (used as fallback). */\n render(value: unknown): unknown;\n}\n\nexport interface ElurRenderProtocol {\n renderServer?(context: ServerRenderProtocolContext): string | Promise<string>;\n mountDom?(context: DomProtocolContext): (() => void) | void;\n hydrateDom?(context: HydrationProtocolContext): (() => void) | void;\n}\n\nexport const ELUR_TEMPLATE_DESCRIPTOR = Symbol.for(\"elur/template-descriptor\");\nexport const ELUR_RENDER_PROTOCOL = Symbol.for(\"elur/render-protocol\");\n\n/**\n * Runtime feature capabilities, for tooling to detect support without\n * inferring it from version strings.\n *\n * NOTE: Partial attribute interpolation is now handled at compile time by\n * @elurjs/vite-plugin-elur. The core runtime does not support it natively.\n * Use the Vite plugin for partial interpolation support.\n */\nexport const templateFeatures = {\n /** Partial attribute interpolation (`class=\"btn ${size}\"`) is supported. */\n partialAttributeInterpolation: false,\n} as const;\n\nexport interface ElurTemplate {\n readonly __isElurTemplate: true;\n readonly [ELUR_TEMPLATE_DESCRIPTOR]?: TemplateDescriptor;\n readonly [ELUR_RENDER_PROTOCOL]?: ElurRenderProtocol;\n /** Mounts the template into a container element (public / root API). */\n mount(container: Element | string): ElurMountHandle;\n /** @internal Renders before `before` node (or appends to `parent`). Returns cleanup. */\n _render(parent: Node, before: Node | null): () => void;\n}\n\nexport interface ElurMountHandle {\n unmount(): void;\n}\n\n/** Direct reference to a DOM element, assigned on mount and cleared on unmount. */\nexport interface ElurRef<T extends Element = Element> {\n el: T | null;\n}\n\n/** Creates an empty `ElurRef`. Use as `ref` attribute value in templates. */\nexport function ref<T extends Element = Element>(): ElurRef<T> {\n return { el: null };\n}\n\n/** Keyed list result for efficient DOM diffing via `repeat()`. */\nexport interface KeyedList<T = unknown> {\n readonly __isKeyedList: true;\n readonly items: T[];\n readonly keyFn: (item: T, index: number) => string | number;\n readonly renderFn: (item: T, index: number) => ElurTemplate | import(\"../lifecycle.js\").ElurComponent;\n}\n\nexport interface KEntry {\n start: Comment;\n end: Comment;\n cleanup: () => void;\n}\n\n/** Opaque token for a named portal target. */\nexport interface PortalOutlet {\n readonly __isPortalOutlet: true;\n /** @internal */\n _container: Element | null;\n}\n\n/** Fallback: a static template/component, or a factory receiving the error. */\nexport type ErrorFallback =\n | ElurTemplate\n | import(\"../lifecycle.js\").ElurComponent\n | ((err: unknown) => ElurTemplate | import(\"../lifecycle.js\").ElurComponent);\n\n/** Content that can be wrapped with `transition()`. */\nexport type TransitionContent =\n | ElurTemplate\n | import(\"../lifecycle.js\").ElurComponent\n | (() => ElurTemplate | import(\"../lifecycle.js\").ElurComponent | null);\n\nexport const COMMENT = {\n SCOPE: \"elur-scope\",\n ERROR_BOUNDARY: \"elur-eb\",\n TRANSITION: \"elur-t\",\n KEYED_START: \"elur-ks\",\n KEYED_END: \"elur-ke\",\n KEYED_ZONE: \"elur-kz\",\n} as const;\n\n// =============================================================================\n// --- DOM inspection helpers ---\n// =============================================================================\n\nexport function isElurTemplate(v: unknown): v is ElurTemplate {\n return (\n v != null &&\n typeof v === \"object\" &&\n (v as Record<string, unknown>).__isElurTemplate === true\n );\n}\n\nexport function isKeyedList(v: unknown): v is KeyedList {\n return (\n v != null &&\n typeof v === \"object\" &&\n (v as Record<string, unknown>).__isKeyedList === true\n );\n}\n"],"mappings":";AA6CA,IAAa,IAA2B,OAAO,IAAI,2BAA2B,EACjE,IAAuB,OAAO,IAAI,uBAAuB,EAUzD,IAAmB,EAE5B,+BAA+B,IAClC;AAsBD,SAAgB,IAA+C;AAC3D,QAAO,EAAE,IAAI,MAAM;;AAoCvB,IAAa,IAAU;CACnB,OAAO;CACP,gBAAgB;CAChB,YAAY;CACZ,aAAa;CACb,WAAW;CACX,YAAY;CACf;AAMD,SAAgB,EAAe,GAA+B;AAC1D,QAEI,OAAO,KAAM,cADb,KAEC,EAA8B,qBAAqB;;AAI5D,SAAgB,EAAY,GAA4B;AACpD,QAEI,OAAO,KAAM,cADb,KAEC,EAA8B,kBAAkB"}
1
+ {"version":3,"file":"types.js","names":[],"sources":["../../../../src/elur/template/types.ts"],"sourcesContent":["// =============================================================================\n// --- Public types ---\n// =============================================================================\n\nexport type TemplateBindingContext =\n | { type: \"node\" }\n | { type: \"event\"; eventName: string; modifiers: string[]; hadOpenQuote: boolean }\n | { type: \"attr\"; attrName: string; hadOpenQuote: boolean; url?: boolean; executable?: boolean };\n\nexport interface TemplateDescriptor {\n readonly version: 1;\n readonly strings: readonly string[];\n readonly values: readonly unknown[];\n readonly contexts: readonly TemplateBindingContext[];\n}\n\nexport interface ServerRenderProtocolContext {\n readonly markers: boolean;\n readonly signal?: AbortSignal;\n readonly context?: unknown;\n render(value: unknown, options?: { markers?: boolean }): Promise<string>;\n}\n\n/** Context passed to a custom value's `mountDom` protocol during client-side mount. */\nexport interface DomProtocolContext {\n readonly parent: Node;\n readonly before: Node | null;\n readonly context?: unknown;\n}\n\n/** Context passed to a custom value's `hydrateDom` protocol during hydration. */\nexport interface HydrationProtocolContext {\n readonly parent: Node;\n readonly bounds: { start: Comment; end: Comment } | null;\n readonly context?: unknown;\n /** Remounts a value inside the current bounds (used as fallback). */\n render(value: unknown): unknown;\n}\n\nexport interface ElurRenderProtocol {\n renderServer?(context: ServerRenderProtocolContext): string | Promise<string>;\n mountDom?(context: DomProtocolContext): (() => void) | void;\n hydrateDom?(context: HydrationProtocolContext): (() => void) | void;\n}\n\nexport const ELUR_TEMPLATE_DESCRIPTOR = Symbol.for(\"@elurjs/core/template-descriptor\");\nexport const ELUR_RENDER_PROTOCOL = Symbol.for(\"@elurjs/core/render-protocol\");\n\n/**\n * Runtime feature capabilities, for tooling to detect support without\n * inferring it from version strings.\n *\n * NOTE: Partial attribute interpolation is now handled at compile time by\n * @elurjs/vite-plugin-elur. The core runtime does not support it natively.\n * Use the Vite plugin for partial interpolation support.\n */\nexport const templateFeatures = {\n /** Partial attribute interpolation (`class=\"btn ${size}\"`) is supported. */\n partialAttributeInterpolation: false,\n} as const;\n\nexport interface ElurTemplate {\n readonly __isElurTemplate: true;\n readonly [ELUR_TEMPLATE_DESCRIPTOR]?: TemplateDescriptor;\n readonly [ELUR_RENDER_PROTOCOL]?: ElurRenderProtocol;\n /** Mounts the template into a container element (public / root API). */\n mount(container: Element | string): ElurMountHandle;\n /** @internal Renders before `before` node (or appends to `parent`). Returns cleanup. */\n _render(parent: Node, before: Node | null): () => void;\n}\n\nexport interface ElurMountHandle {\n unmount(): void;\n}\n\n/** Direct reference to a DOM element, assigned on mount and cleared on unmount. */\nexport interface ElurRef<T extends Element = Element> {\n el: T | null;\n}\n\n/** Creates an empty `ElurRef`. Use as `ref` attribute value in templates. */\nexport function ref<T extends Element = Element>(): ElurRef<T> {\n return { el: null };\n}\n\n/** Keyed list result for efficient DOM diffing via `repeat()`. */\nexport interface KeyedList<T = unknown> {\n readonly __isKeyedList: true;\n readonly items: T[];\n readonly keyFn: (item: T, index: number) => string | number;\n readonly renderFn: (item: T, index: number) => ElurTemplate | import(\"../lifecycle.js\").ElurComponent;\n}\n\nexport interface KEntry {\n start: Comment;\n end: Comment;\n cleanup: () => void;\n}\n\n/** Opaque token for a named portal target. */\nexport interface PortalOutlet {\n readonly __isPortalOutlet: true;\n /** @internal */\n _container: Element | null;\n}\n\n/** Fallback: a static template/component, or a factory receiving the error. */\nexport type ErrorFallback =\n | ElurTemplate\n | import(\"../lifecycle.js\").ElurComponent\n | ((err: unknown) => ElurTemplate | import(\"../lifecycle.js\").ElurComponent);\n\n/** Content that can be wrapped with `transition()`. */\nexport type TransitionContent =\n | ElurTemplate\n | import(\"../lifecycle.js\").ElurComponent\n | (() => ElurTemplate | import(\"../lifecycle.js\").ElurComponent | null);\n\nexport const COMMENT = {\n SCOPE: \"elur-scope\",\n ERROR_BOUNDARY: \"elur-eb\",\n TRANSITION: \"elur-t\",\n KEYED_START: \"elur-ks\",\n KEYED_END: \"elur-ke\",\n KEYED_ZONE: \"elur-kz\",\n} as const;\n\n// =============================================================================\n// --- DOM inspection helpers ---\n// =============================================================================\n\nexport function isElurTemplate(v: unknown): v is ElurTemplate {\n return (\n v != null &&\n typeof v === \"object\" &&\n (v as Record<string, unknown>).__isElurTemplate === true\n );\n}\n\nexport function isKeyedList(v: unknown): v is KeyedList {\n return (\n v != null &&\n typeof v === \"object\" &&\n (v as Record<string, unknown>).__isKeyedList === true\n );\n}\n"],"mappings":";AA6CA,IAAa,IAA2B,OAAO,IAAI,mCAAmC,EACzE,IAAuB,OAAO,IAAI,+BAA+B,EAUjE,IAAmB,EAE5B,+BAA+B,IAClC;AAsBD,SAAgB,IAA+C;AAC3D,QAAO,EAAE,IAAI,MAAM;;AAoCvB,IAAa,IAAU;CACnB,OAAO;CACP,gBAAgB;CAChB,YAAY;CACZ,aAAa;CACb,WAAW;CACX,YAAY;CACf;AAMD,SAAgB,EAAe,GAA+B;AAC1D,QAEI,OAAO,KAAM,cADb,KAEC,EAA8B,qBAAqB;;AAI5D,SAAgB,EAAY,GAA4B;AACpD,QAEI,OAAO,KAAM,cADb,KAEC,EAA8B,kBAAkB"}
@@ -1,2 +1,2 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});function e(){return{ctxPool:[],ctxStack:[],activeEffect:null,activeDeps:null,activeErrorHandler:null,errorHandlerStack:[],batchLevel:0,pendingEffectsSet:new Set,pendingEffectsArr:[],effectDepth:0,notifyBuf:[],notifyBase:0,signalDebugHooks:null}}var t=Symbol.for(`elur/reactivity-state`),n=globalThis,r=(()=>{let r=n[t];if(r)return r;let i=e();return n[t]=i,i})();function i(e){r.errorHandlerStack.push(r.activeErrorHandler),r.activeErrorHandler=e}function a(){r.activeErrorHandler=r.errorHandlerStack.pop()??null}var o=100,s=64,c=16,l=32;function u(e){r.signalDebugHooks=e}function d(){return r.notifyBuf.length}var f=class{_value;_subs=new Set;constructor(e){this._value=e,r.signalDebugHooks?.onCreate?.(this,e)}get value(){return r.activeEffect&&(this._subs.add(r.activeEffect),r.activeDeps?.add(this)),this._value}set value(e){Object.is(this._value,e)||(this._value=e,r.signalDebugHooks?.onWrite?.(this,e),this._notify())}update(e){this.value=e(this._value)}peek(){return this._value}_removeSub(e){this._subs.delete(e)}_notify(){if(r.batchLevel>0){for(let e of this._subs)r.pendingEffectsSet.has(e)||(r.pendingEffectsSet.add(e),r.pendingEffectsArr.push(e));return}let e=r.notifyBase,t=0;for(let n of this._subs)r.notifyBuf[e+ t++]=n;r.notifyBase=e+t;try{for(let n=0;n<t;n++){let t=r.notifyBuf[e+n];r.notifyBuf[e+n]=null,t?.()}}finally{r.notifyBase=e,e===0&&r.notifyBuf.length>s&&t<c&&(r.notifyBuf.length=l)}}dispose(){this._subs.clear()}};function p(e){return new f(e)}function m(e){let t=!1,n,i=new Set,a=new Set,s=r.activeErrorHandler,c=()=>{if(t)return;typeof n==`function`&&n();let l=i;i=a,a=l,a.clear();let u=r.ctxPool.length>0?r.ctxPool.pop():{effect:null,deps:null};if(u.effect=r.activeEffect,u.deps=r.activeDeps,r.ctxStack.push(u),r.activeEffect=c,r.activeDeps=a,r.effectDepth++,r.effectDepth>o){r.effectDepth=0;let e=r.ctxStack.pop();throw r.activeEffect=e.effect,r.activeDeps=e.deps,e.effect=null,e.deps=null,r.ctxPool.push(e),Error(`[elur] Maximum effect re-execution depth exceeded (possible infinite loop).`)}try{n=e()}catch(e){if(s)s(e);else throw e}finally{r.effectDepth--;let e=r.ctxStack.pop();r.activeEffect=e.effect,r.activeDeps=e.deps,e.effect=null,e.deps=null,r.ctxPool.push(e);for(let e of i)a.has(e)||e._removeSub(c)}};return c(),()=>{t=!0,typeof n==`function`&&n();for(let e of a)e._removeSub(c);a.clear(),i.clear()}}var h=Symbol(`elur-computed-uninitialized`);function g(e,t=Object.is){let n=new f(h),r=null,i=!1,a=!1,o=()=>{i||a||(i=!0,v(()=>{r=m(()=>{let r=e(),i=n.peek();(i===h||!t(r,i))&&(n.value=r)})}))},s=Object.getOwnPropertyDescriptor(Object.getPrototypeOf(n),`value`);if(!s?.get||!s?.set)throw Error(`[elur] Internal error: Signal.value descriptor not found.`);Object.defineProperty(n,`value`,{get(){return o(),s.get.call(this)},set(e){s.set.call(this,e)},configurable:!0});let c=n.dispose;return n.dispose=()=>{a=!0,r?.(),r=null,c.call(n)},n}function _(e){r.batchLevel++;try{e()}finally{if(r.batchLevel--,r.batchLevel===0&&r.pendingEffectsArr.length>0){let e=r.pendingEffectsArr.length;for(let t=0;t<e;t++)r.pendingEffectsArr[t]();r.pendingEffectsArr.length=0,r.pendingEffectsSet.clear()}}}function v(e){let t=r.activeEffect,n=r.activeDeps;r.activeEffect=null,r.activeDeps=null;try{return e()}finally{r.activeEffect=t,r.activeDeps=n}}function y(e,t,n={}){let{immediate:r=!1,once:i=!1}=n,a=e instanceof f?()=>e.value:e,o,s=!0,c=!1,l=m(()=>{let e=a();if(s){if(s=!1,r&&!c){let n=e;v(()=>t(n,void 0)),i&&(c=!0,Promise.resolve().then(l))}o=e;return}if(!c){let n=e,r=o;o=e,v(()=>t(n,r)),i&&(c=!0,Promise.resolve().then(l))}});return()=>{c=!0,l()}}function b(e){return e?Promise.resolve().then(e):Promise.resolve()}exports.Signal=f,exports._getNotifyBufSize=d,exports._popErrorHandler=a,exports._pushErrorHandler=i,exports._setSignalDebugHooks=u,exports.batch=_,exports.computed=g,exports.effect=m,exports.nextTick=b,exports.signal=p,exports.untrack=v,exports.watch=y;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});function e(){return{ctxPool:[],ctxStack:[],activeEffect:null,activeDeps:null,activeErrorHandler:null,errorHandlerStack:[],batchLevel:0,pendingEffectsSet:new Set,pendingEffectsArr:[],effectDepth:0,notifyBuf:[],notifyBase:0,signalDebugHooks:null}}var t=Symbol.for(`@elurjs/core/reactivity-state`),n=globalThis,r=(()=>{let r=n[t];if(r)return r;let i=e();return n[t]=i,i})();function i(e){r.errorHandlerStack.push(r.activeErrorHandler),r.activeErrorHandler=e}function a(){r.activeErrorHandler=r.errorHandlerStack.pop()??null}var o=100,s=64,c=16,l=32;function u(e){r.signalDebugHooks=e}function d(){return r.notifyBuf.length}var f=class{_value;_subs=new Set;constructor(e){this._value=e,r.signalDebugHooks?.onCreate?.(this,e)}get value(){return r.activeEffect&&(this._subs.add(r.activeEffect),r.activeDeps?.add(this)),this._value}set value(e){Object.is(this._value,e)||(this._value=e,r.signalDebugHooks?.onWrite?.(this,e),this._notify())}update(e){this.value=e(this._value)}peek(){return this._value}_removeSub(e){this._subs.delete(e)}_notify(){if(r.batchLevel>0){for(let e of this._subs)r.pendingEffectsSet.has(e)||(r.pendingEffectsSet.add(e),r.pendingEffectsArr.push(e));return}let e=r.notifyBase,t=0;for(let n of this._subs)r.notifyBuf[e+ t++]=n;r.notifyBase=e+t;try{for(let n=0;n<t;n++){let t=r.notifyBuf[e+n];r.notifyBuf[e+n]=null,t?.()}}finally{r.notifyBase=e,e===0&&r.notifyBuf.length>s&&t<c&&(r.notifyBuf.length=l)}}dispose(){this._subs.clear()}};function p(e){return new f(e)}function m(e){let t=!1,n,i=new Set,a=new Set,s=r.activeErrorHandler,c=()=>{if(t)return;typeof n==`function`&&n();let l=i;i=a,a=l,a.clear();let u=r.ctxPool.length>0?r.ctxPool.pop():{effect:null,deps:null};if(u.effect=r.activeEffect,u.deps=r.activeDeps,r.ctxStack.push(u),r.activeEffect=c,r.activeDeps=a,r.effectDepth++,r.effectDepth>o){r.effectDepth=0;let e=r.ctxStack.pop();throw r.activeEffect=e.effect,r.activeDeps=e.deps,e.effect=null,e.deps=null,r.ctxPool.push(e),Error(`[elur] Maximum effect re-execution depth exceeded (possible infinite loop).`)}try{n=e()}catch(e){if(s)s(e);else throw e}finally{r.effectDepth--;let e=r.ctxStack.pop();r.activeEffect=e.effect,r.activeDeps=e.deps,e.effect=null,e.deps=null,r.ctxPool.push(e);for(let e of i)a.has(e)||e._removeSub(c)}};return c(),()=>{t=!0,typeof n==`function`&&n();for(let e of a)e._removeSub(c);a.clear(),i.clear()}}var h=Symbol(`elur-computed-uninitialized`);function g(e,t=Object.is){let n=new f(h),r=null,i=!1,a=!1,o=()=>{i||a||(i=!0,v(()=>{r=m(()=>{let r=e(),i=n.peek();(i===h||!t(r,i))&&(n.value=r)})}))},s=Object.getOwnPropertyDescriptor(Object.getPrototypeOf(n),`value`);if(!s?.get||!s?.set)throw Error(`[elur] Internal error: Signal.value descriptor not found.`);Object.defineProperty(n,`value`,{get(){return o(),s.get.call(this)},set(e){s.set.call(this,e)},configurable:!0});let c=n.dispose;return n.dispose=()=>{a=!0,r?.(),r=null,c.call(n)},n}function _(e){r.batchLevel++;try{e()}finally{if(r.batchLevel--,r.batchLevel===0&&r.pendingEffectsArr.length>0){let e=r.pendingEffectsArr.length;for(let t=0;t<e;t++)r.pendingEffectsArr[t]();r.pendingEffectsArr.length=0,r.pendingEffectsSet.clear()}}}function v(e){let t=r.activeEffect,n=r.activeDeps;r.activeEffect=null,r.activeDeps=null;try{return e()}finally{r.activeEffect=t,r.activeDeps=n}}function y(e,t,n={}){let{immediate:r=!1,once:i=!1}=n,a=e instanceof f?()=>e.value:e,o,s=!0,c=!1,l=m(()=>{let e=a();if(s){if(s=!1,r&&!c){let n=e;v(()=>t(n,void 0)),i&&(c=!0,Promise.resolve().then(l))}o=e;return}if(!c){let n=e,r=o;o=e,v(()=>t(n,r)),i&&(c=!0,Promise.resolve().then(l))}});return()=>{c=!0,l()}}function b(e){return e?Promise.resolve().then(e):Promise.resolve()}exports.Signal=f,exports._getNotifyBufSize=d,exports._popErrorHandler=a,exports._pushErrorHandler=i,exports._setSignalDebugHooks=u,exports.batch=_,exports.computed=g,exports.effect=m,exports.nextTick=b,exports.signal=p,exports.untrack=v,exports.watch=y;
2
2
  //# sourceMappingURL=signals.cjs.map
@@ -16,7 +16,7 @@ function e() {
16
16
  signalDebugHooks: null
17
17
  };
18
18
  }
19
- var t = Symbol.for("elur/reactivity-state"), n = globalThis, r = (() => {
19
+ var t = Symbol.for("@elurjs/core/reactivity-state"), n = globalThis, r = (() => {
20
20
  let r = n[t];
21
21
  if (r) return r;
22
22
  let i = e();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@elurjs/core",
3
- "version": "3.5.0",
3
+ "version": "3.5.1",
4
4
  "description": "A lightweight, fully reactive framework — no virtual DOM, no compiler, just signals and tagged templates.",
5
5
  "license": "MIT",
6
6
  "author": "Deiver Vasquez",