@elurjs/core 3.6.2 → 3.7.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/lib/async.cjs +1 -1
- package/dist/lib/async.js +1 -1
- package/dist/lib/component.cjs +1 -2
- package/dist/lib/component.js +2 -66
- package/dist/lib/context.cjs +1 -1
- package/dist/lib/context.js +35 -23
- package/dist/lib/devtools.cjs +1 -1
- package/dist/lib/devtools.js +1 -1
- package/dist/lib/elur/async.cjs +1 -1
- package/dist/lib/elur/async.cjs.map +1 -1
- package/dist/lib/elur/async.js +1 -1
- package/dist/lib/elur/component.cjs +1 -2
- package/dist/lib/elur/component.d.cts +1 -17
- package/dist/lib/elur/component.d.ts +1 -17
- package/dist/lib/elur/component.js +2 -66
- package/dist/lib/elur/context.cjs +1 -1
- package/dist/lib/elur/context.cjs.map +1 -1
- package/dist/lib/elur/context.d.cts +5 -0
- package/dist/lib/elur/context.d.ts +5 -0
- package/dist/lib/elur/context.js +35 -23
- package/dist/lib/elur/context.js.map +1 -1
- package/dist/lib/elur/devtools.cjs +1 -1
- package/dist/lib/elur/devtools.cjs.map +1 -1
- package/dist/lib/elur/devtools.js +1 -1
- package/dist/lib/elur/form.cjs +1 -1
- package/dist/lib/elur/form.cjs.map +1 -1
- package/dist/lib/elur/form.js +1 -1
- package/dist/lib/elur/hydrate/index.cjs +1 -2
- package/dist/lib/elur/hydrate/index.d.cts +1 -13
- package/dist/lib/elur/hydrate/index.d.ts +1 -13
- package/dist/lib/elur/hydrate/index.js +2 -410
- package/dist/lib/elur/lifecycle.cjs +1 -1
- package/dist/lib/elur/lifecycle.cjs.map +1 -1
- package/dist/lib/elur/lifecycle.d.cts +27 -0
- package/dist/lib/elur/lifecycle.d.ts +27 -0
- package/dist/lib/elur/lifecycle.js +4 -0
- package/dist/lib/elur/lifecycle.js.map +1 -1
- package/dist/lib/elur/next/component.d.cts +281 -0
- package/dist/lib/elur/next/component.d.ts +281 -0
- package/dist/lib/elur/next/dom-write.d.cts +18 -0
- package/dist/lib/elur/next/dom-write.d.ts +18 -0
- package/dist/lib/elur/next/hydrate.d.cts +14 -0
- package/dist/lib/elur/next/hydrate.d.ts +14 -0
- package/dist/lib/elur/next/keyed-diff.d.cts +46 -0
- package/dist/lib/elur/next/keyed-diff.d.ts +46 -0
- package/dist/lib/elur/next/mount-helpers.d.cts +25 -0
- package/dist/lib/elur/next/mount-helpers.d.ts +25 -0
- package/dist/lib/elur/next/mount.d.cts +29 -0
- package/dist/lib/elur/next/mount.d.ts +29 -0
- package/dist/lib/elur/next/node-binding.d.cts +6 -0
- package/dist/lib/elur/next/node-binding.d.ts +6 -0
- package/dist/lib/elur/next/reactivity.d.cts +193 -0
- package/dist/lib/elur/next/reactivity.d.ts +193 -0
- package/dist/lib/elur/next-2/component.cjs +2 -0
- package/dist/lib/elur/next-2/component.cjs.map +1 -0
- package/dist/lib/elur/next-2/component.d.cts +283 -0
- package/dist/lib/elur/next-2/component.d.ts +283 -0
- package/dist/lib/elur/next-2/component.js +340 -0
- package/dist/lib/elur/next-2/component.js.map +1 -0
- package/dist/lib/elur/next-2/dom-write.cjs +2 -0
- package/dist/lib/elur/next-2/dom-write.cjs.map +1 -0
- package/dist/lib/elur/next-2/dom-write.d.cts +18 -0
- package/dist/lib/elur/next-2/dom-write.d.ts +18 -0
- package/dist/lib/elur/next-2/dom-write.js +31 -0
- package/dist/lib/elur/next-2/dom-write.js.map +1 -0
- package/dist/lib/elur/next-2/hydrate.cjs +2 -0
- package/dist/lib/elur/next-2/hydrate.cjs.map +1 -0
- package/dist/lib/elur/next-2/hydrate.d.cts +30 -0
- package/dist/lib/elur/next-2/hydrate.d.ts +30 -0
- package/dist/lib/elur/next-2/hydrate.js +449 -0
- package/dist/lib/elur/next-2/hydrate.js.map +1 -0
- package/dist/lib/elur/next-2/keyed-diff.cjs +2 -0
- package/dist/lib/elur/next-2/keyed-diff.cjs.map +1 -0
- package/dist/lib/elur/next-2/keyed-diff.d.cts +79 -0
- package/dist/lib/elur/next-2/keyed-diff.d.ts +79 -0
- package/dist/lib/elur/next-2/keyed-diff.js +208 -0
- package/dist/lib/elur/next-2/keyed-diff.js.map +1 -0
- package/dist/lib/elur/next-2/mount-helpers.cjs +2 -0
- package/dist/lib/elur/next-2/mount-helpers.cjs.map +1 -0
- package/dist/lib/elur/next-2/mount-helpers.d.cts +25 -0
- package/dist/lib/elur/next-2/mount-helpers.d.ts +25 -0
- package/dist/lib/elur/next-2/mount-helpers.js +87 -0
- package/dist/lib/elur/next-2/mount-helpers.js.map +1 -0
- package/dist/lib/elur/next-2/mount.cjs +2 -0
- package/dist/lib/elur/next-2/mount.cjs.map +1 -0
- package/dist/lib/elur/next-2/mount.d.cts +29 -0
- package/dist/lib/elur/next-2/mount.d.ts +29 -0
- package/dist/lib/elur/next-2/mount.js +34 -0
- package/dist/lib/elur/next-2/mount.js.map +1 -0
- package/dist/lib/elur/next-2/node-binding.cjs +2 -0
- package/dist/lib/elur/next-2/node-binding.cjs.map +1 -0
- package/dist/lib/elur/next-2/node-binding.d.cts +6 -0
- package/dist/lib/elur/next-2/node-binding.d.ts +6 -0
- package/dist/lib/elur/next-2/node-binding.js +130 -0
- package/dist/lib/elur/next-2/node-binding.js.map +1 -0
- package/dist/lib/elur/next-2/reactivity.cjs +2 -0
- package/dist/lib/elur/next-2/reactivity.cjs.map +1 -0
- package/dist/lib/elur/next-2/reactivity.d.cts +220 -0
- package/dist/lib/elur/next-2/reactivity.d.ts +220 -0
- package/dist/lib/elur/next-2/reactivity.js +614 -0
- package/dist/lib/elur/next-2/reactivity.js.map +1 -0
- package/dist/lib/elur/next-2/scheduler.cjs +2 -0
- package/dist/lib/elur/next-2/scheduler.cjs.map +1 -0
- package/dist/lib/elur/next-2/scheduler.d.cts +23 -0
- package/dist/lib/elur/next-2/scheduler.d.ts +23 -0
- package/dist/lib/elur/next-2/scheduler.js +26 -0
- package/dist/lib/elur/next-2/scheduler.js.map +1 -0
- package/dist/lib/elur/plugins.cjs +1 -1
- package/dist/lib/elur/plugins.cjs.map +1 -1
- package/dist/lib/elur/plugins.js +1 -1
- package/dist/lib/elur/reactivity.cjs +1 -2
- package/dist/lib/elur/reactivity.d.cts +1 -67
- package/dist/lib/elur/reactivity.d.ts +1 -67
- package/dist/lib/elur/reactivity.js +2 -218
- package/dist/lib/elur/router.cjs +1 -1
- package/dist/lib/elur/router.cjs.map +1 -1
- package/dist/lib/elur/router.js +1 -1
- package/dist/lib/elur/server/index.cjs +1 -1
- package/dist/lib/elur/server/index.cjs.map +1 -1
- package/dist/lib/elur/server/index.js +175 -107
- package/dist/lib/elur/server/index.js.map +1 -1
- package/dist/lib/elur/store.cjs +1 -1
- package/dist/lib/elur/store.cjs.map +1 -1
- package/dist/lib/elur/store.js +1 -1
- package/dist/lib/elur/template/bindings.cjs +1 -1
- package/dist/lib/elur/template/bindings.cjs.map +1 -1
- package/dist/lib/elur/template/bindings.js +98 -84
- package/dist/lib/elur/template/bindings.js.map +1 -1
- package/dist/lib/elur/template/dom-write.d.cts +1 -5
- package/dist/lib/elur/template/dom-write.d.ts +1 -5
- package/dist/lib/elur/template/error-boundary.cjs +1 -1
- package/dist/lib/elur/template/error-boundary.cjs.map +1 -1
- package/dist/lib/elur/template/error-boundary.js +56 -50
- package/dist/lib/elur/template/error-boundary.js.map +1 -1
- package/dist/lib/elur/template/html.cjs +1 -1
- package/dist/lib/elur/template/html.cjs.map +1 -1
- package/dist/lib/elur/template/html.js +40 -37
- package/dist/lib/elur/template/html.js.map +1 -1
- package/dist/lib/elur/template/index.cjs +1 -1
- package/dist/lib/elur/template/index.d.cts +2 -1
- package/dist/lib/elur/template/index.d.ts +2 -1
- package/dist/lib/elur/template/index.js +13 -12
- package/dist/lib/elur/template/keyed-diff.d.cts +1 -32
- package/dist/lib/elur/template/keyed-diff.d.ts +1 -32
- package/dist/lib/elur/template/keyed.cjs +1 -1
- package/dist/lib/elur/template/keyed.cjs.map +1 -1
- package/dist/lib/elur/template/keyed.d.cts +10 -2
- package/dist/lib/elur/template/keyed.d.ts +10 -2
- package/dist/lib/elur/template/keyed.js +12 -1
- package/dist/lib/elur/template/keyed.js.map +1 -1
- package/dist/lib/elur/template/mount-helpers.d.cts +1 -29
- package/dist/lib/elur/template/mount-helpers.d.ts +1 -29
- package/dist/lib/elur/template/node-binding.d.cts +1 -6
- package/dist/lib/elur/template/node-binding.d.ts +1 -6
- package/dist/lib/elur/template/portal.cjs +1 -1
- package/dist/lib/elur/template/portal.cjs.map +1 -1
- package/dist/lib/elur/template/portal.js +1 -1
- package/dist/lib/elur/template/transitions.cjs +1 -1
- package/dist/lib/elur/template/transitions.cjs.map +1 -1
- package/dist/lib/elur/template/transitions.js +2 -2
- package/dist/lib/elur/template/types.cjs +1 -1
- package/dist/lib/elur/template/types.cjs.map +1 -1
- package/dist/lib/elur/template/types.d.cts +55 -0
- package/dist/lib/elur/template/types.d.ts +55 -0
- package/dist/lib/elur/template/types.js +5 -1
- package/dist/lib/elur/template/types.js.map +1 -1
- package/dist/lib/elur.cjs +1 -1
- package/dist/lib/elur.js +2 -2
- package/dist/lib/form.cjs +1 -1
- package/dist/lib/form.js +1 -1
- package/dist/lib/hydrate.cjs +1 -2
- package/dist/lib/hydrate.js +2 -410
- package/dist/lib/index.cjs +1 -1
- package/dist/lib/index.js +2 -2
- package/dist/lib/lifecycle.cjs +1 -1
- package/dist/lib/lifecycle.js +4 -0
- package/dist/lib/plugins.cjs +1 -1
- package/dist/lib/plugins.js +1 -1
- package/dist/lib/router.cjs +1 -1
- package/dist/lib/router.js +1 -1
- package/dist/lib/server.cjs +1 -1
- package/dist/lib/server.js +175 -107
- package/dist/lib/signals.cjs +1 -2
- package/dist/lib/signals.js +2 -218
- package/dist/lib/store.cjs +1 -1
- package/dist/lib/store.js +1 -1
- package/dist/lib/template.cjs +1 -1
- package/dist/lib/template.js +13 -12
- package/package.json +7 -9
- package/dist/lib/elur/component.cjs.map +0 -1
- package/dist/lib/elur/component.js.map +0 -1
- package/dist/lib/elur/hydrate/index.cjs.map +0 -1
- package/dist/lib/elur/hydrate/index.js.map +0 -1
- package/dist/lib/elur/reactivity.cjs.map +0 -1
- package/dist/lib/elur/reactivity.js.map +0 -1
- package/dist/lib/elur/template/dom-write.cjs +0 -2
- package/dist/lib/elur/template/dom-write.cjs.map +0 -1
- package/dist/lib/elur/template/dom-write.js +0 -16
- package/dist/lib/elur/template/dom-write.js.map +0 -1
- package/dist/lib/elur/template/keyed-diff.cjs +0 -2
- package/dist/lib/elur/template/keyed-diff.cjs.map +0 -1
- package/dist/lib/elur/template/keyed-diff.js +0 -100
- package/dist/lib/elur/template/keyed-diff.js.map +0 -1
- package/dist/lib/elur/template/mount-helpers.cjs +0 -2
- package/dist/lib/elur/template/mount-helpers.cjs.map +0 -1
- package/dist/lib/elur/template/mount-helpers.js +0 -132
- package/dist/lib/elur/template/mount-helpers.js.map +0 -1
- package/dist/lib/elur/template/node-binding.cjs +0 -2
- package/dist/lib/elur/template/node-binding.cjs.map +0 -1
- package/dist/lib/elur/template/node-binding.js +0 -95
- package/dist/lib/elur/template/node-binding.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"error-boundary.js","names":[],"sources":["../../../../src/elur/template/error-boundary.ts"],"sourcesContent":["import { _pushErrorHandler, _popErrorHandler } from \"../reactivity.js\";\nimport { isElurComponent } from \"../lifecycle.js\";\nimport type { ElurComponent } from \"../lifecycle.js\";\nimport { _pushComponentContext, _popComponentContext } from \"../context.js\";\nimport type { ElurTemplate, ElurMountHandle, ErrorFallback } from \"./types.js\";\nimport { COMMENT } from \"./types.js\";\nimport { _mountComponentSilent } from \"./mount-helpers.js\";\n\n// =============================================================================\n// --- Error Boundary ---\n// =============================================================================\n\n/**\n * Wraps `content` in an error boundary. If rendering or a reactive update\n * throws, the boundary tears down the broken subtree and renders `fallback`.\n */\nexport function createErrorBoundary(\n content: ElurTemplate | ElurComponent,\n fallback: ErrorFallback\n): ElurTemplate {\n return {\n __isElurTemplate: true as const,\n\n mount(container: Element | string): ElurMountHandle {\n const el =\n typeof container === \"string\"\n ? (document.querySelector(container) ?? document.body)\n : container;\n const cleanup = this._render(el, null);\n return { unmount: cleanup };\n },\n\n _render(parent: Node, before: Node | null): () => void {\n const marker = document.createComment(COMMENT.ERROR_BOUNDARY);\n parent.insertBefore(marker, before);\n\n let activeCleanup: (() => void) | null = null;\n let errored = false;\n let initialRenderDone = false;\n let deferredError: unknown = undefined;\n let hasDeferredError = false;\n\n // Renders the fallback outside the error handler window.\n // Uses marker.parentNode (not captured `parent`) because `parent` may be\n // a stale DocumentFragment that was already flushed to the live DOM.\n const renderFallback = (err: unknown): void => {\n const liveParent = marker.parentNode;\n if (!liveParent) return;\n\n let fb: ElurTemplate | ElurComponent;\n try {\n fb =\n typeof fallback === \"function\" && !isElurComponent(fallback as object)\n ? (fallback as (err: unknown) => ElurTemplate | ElurComponent)(err)\n : (fallback as ElurTemplate | ElurComponent);\n } catch (e) {\n console.error(\"[elur] Error boundary fallback threw while producing the fallback UI:\", e);\n activeCleanup = renderBrokenFallback(liveParent, before);\n return;\n }\n\n // Capture reactive errors from effects created inside the fallback.\n _pushErrorHandler(fallbackReactiveErrorHandler);\n try {\n if (isElurComponent(fb)) {\n activeCleanup = _mountComponentSilent(fb, liveParent, before);\n } else {\n activeCleanup = fb._render(liveParent, before);\n }\n } catch (e) {\n console.error(\"[elur] Error boundary fallback threw during render:\", e);\n activeCleanup?.();\n activeCleanup = renderBrokenFallback(liveParent, before);\n } finally {\n _popErrorHandler();\n }\n };\n\n const fallbackReactiveErrorHandler = (e: unknown): void => {\n console.error(\"[elur] Error boundary fallback threw during a reactive update:\", e);\n activeCleanup?.();\n activeCleanup = null;\n const liveParent = marker.parentNode;\n if (liveParent) {\n activeCleanup = renderBrokenFallback(liveParent, before);\n }\n };\n\n const renderBrokenFallback = (liveParent: Node, before: Node | null): (() => void) => {\n const el = document.createElement(\"div\");\n el.setAttribute(\"data-elur-error-boundary\", \"fallback-failed\");\n el.textContent = \"[elur] Error boundary fallback failed to render.\";\n liveParent.insertBefore(el, before);\n return () => el.remove();\n };\n\n // Called by effects inside `content` when they throw\n const handleReactiveError = (err: unknown): void => {\n if (errored) return;\n errored = true;\n if (initialRenderDone) {\n activeCleanup?.();\n activeCleanup = null;\n renderFallback(err);\n } else {\n deferredError = err;\n hasDeferredError = true;\n }\n };\n\n _pushErrorHandler(handleReactiveError);\n try {\n if (isElurComponent(content)) {\n
|
|
1
|
+
{"version":3,"file":"error-boundary.js","names":[],"sources":["../../../../src/elur/template/error-boundary.ts"],"sourcesContent":["import { _pushErrorHandler, _popErrorHandler } from \"../reactivity.js\";\nimport { isElurComponent } from \"../lifecycle.js\";\nimport type { ElurComponent } from \"../lifecycle.js\";\nimport { _pushComponentContext, _popComponentContext } from \"../context.js\";\nimport type { ElurTemplate, ElurMountHandle, ErrorFallback } from \"./types.js\";\nimport { COMMENT } from \"./types.js\";\nimport { _deferOnMount, _mountComponentSilent, _postMountScopeSub } from \"./mount-helpers.js\";\n\n// =============================================================================\n// --- Error Boundary ---\n// =============================================================================\n\n/**\n * Wraps `content` in an error boundary. If rendering or a reactive update\n * throws, the boundary tears down the broken subtree and renders `fallback`.\n */\nexport function createErrorBoundary(\n content: ElurTemplate | ElurComponent,\n fallback: ErrorFallback\n): ElurTemplate {\n return {\n __isElurTemplate: true as const,\n\n mount(container: Element | string): ElurMountHandle {\n const el =\n typeof container === \"string\"\n ? (document.querySelector(container) ?? document.body)\n : container;\n const cleanup = this._render(el, null);\n return { unmount: cleanup };\n },\n\n _render(parent: Node, before: Node | null): () => void {\n const marker = document.createComment(COMMENT.ERROR_BOUNDARY);\n parent.insertBefore(marker, before);\n\n let activeCleanup: (() => void) | null = null;\n const runActive = (): void => { activeCleanup?.(); };\n let errored = false;\n let initialRenderDone = false;\n let deferredError: unknown = undefined;\n let hasDeferredError = false;\n\n // Renders the fallback outside the error handler window.\n // Uses marker.parentNode (not captured `parent`) because `parent` may be\n // a stale DocumentFragment that was already flushed to the live DOM.\n const renderFallback = (err: unknown): void => {\n const liveParent = marker.parentNode;\n if (!liveParent) return;\n\n let fb: ElurTemplate | ElurComponent;\n try {\n fb =\n typeof fallback === \"function\" && !isElurComponent(fallback as object)\n ? (fallback as (err: unknown) => ElurTemplate | ElurComponent)(err)\n : (fallback as ElurTemplate | ElurComponent);\n } catch (e) {\n console.error(\"[elur] Error boundary fallback threw while producing the fallback UI:\", e);\n activeCleanup = renderBrokenFallback(liveParent, before);\n return;\n }\n\n // Capture reactive errors from effects created inside the fallback.\n _pushErrorHandler(fallbackReactiveErrorHandler);\n try {\n if (isElurComponent(fb)) {\n activeCleanup = _mountComponentSilent(fb, liveParent, before);\n } else {\n activeCleanup = fb._render(liveParent, before);\n }\n } catch (e) {\n console.error(\"[elur] Error boundary fallback threw during render:\", e);\n activeCleanup?.();\n activeCleanup = renderBrokenFallback(liveParent, before);\n } finally {\n _popErrorHandler();\n }\n };\n\n const fallbackReactiveErrorHandler = (e: unknown): void => {\n console.error(\"[elur] Error boundary fallback threw during a reactive update:\", e);\n activeCleanup?.();\n activeCleanup = null;\n const liveParent = marker.parentNode;\n if (liveParent) {\n activeCleanup = renderBrokenFallback(liveParent, before);\n }\n };\n\n const renderBrokenFallback = (liveParent: Node, before: Node | null): (() => void) => {\n const el = document.createElement(\"div\");\n el.setAttribute(\"data-elur-error-boundary\", \"fallback-failed\");\n el.textContent = \"[elur] Error boundary fallback failed to render.\";\n liveParent.insertBefore(el, before);\n return () => el.remove();\n };\n\n // Called by effects inside `content` when they throw\n const handleReactiveError = (err: unknown): void => {\n if (errored) return;\n errored = true;\n if (initialRenderDone) {\n activeCleanup?.();\n activeCleanup = null;\n renderFallback(err);\n } else {\n deferredError = err;\n hasDeferredError = true;\n }\n };\n\n _pushErrorHandler(handleReactiveError);\n try {\n // Sub-cola de onMount: si el contenido lanza, sus hooks\n // diferidos se descartan; si no, se fusionan a la cola del\n // render externo y corren post-commit.\n _postMountScopeSub(() => {\n if (isElurComponent(content)) {\n _pushComponentContext();\n try {\n try { content.onInit?.(); } catch (e) {\n if (content.onError) content.onError(e); else throw e;\n }\n activeCleanup = content.render()._render(parent, before);\n } finally {\n _popComponentContext();\n }\n if (!errored) {\n _deferOnMount(() => {\n try {\n const ret = content.onMount?.();\n const prev = activeCleanup;\n activeCleanup = () => {\n try { content.onUnmount?.(); } catch { /* ignore */ }\n if (typeof ret === \"function\") try { ret(); } catch { /* ignore */ }\n prev?.();\n };\n } catch (e) {\n if (content.onError) content.onError(e); else throw e;\n }\n });\n }\n } else {\n activeCleanup = content._render(parent, before);\n }\n });\n } catch (err) {\n errored = true;\n runActive();\n activeCleanup = null;\n deferredError = err;\n hasDeferredError = true;\n } finally {\n _popErrorHandler();\n initialRenderDone = true;\n }\n\n if (hasDeferredError) {\n runActive();\n activeCleanup = null;\n renderFallback(deferredError);\n }\n\n return () => {\n activeCleanup?.();\n marker.remove();\n };\n },\n };\n}\n"],"mappings":";;;;;;AAgBA,SAAgB,EACZ,GACA,GACY;AACZ,QAAO;EACH,kBAAkB;EAElB,MAAM,GAA8C;GAChD,IAAM,IACF,OAAO,KAAc,WACd,SAAS,cAAc,EAAU,IAAI,SAAS,OAC/C;AAEV,UAAO,EAAE,SADO,KAAK,QAAQ,GAAI,KAAK,EACX;;EAG/B,QAAQ,GAAc,GAAiC;GACnD,IAAM,IAAS,SAAS,cAAc,EAAQ,eAAe;AAC7D,KAAO,aAAa,GAAQ,EAAO;GAEnC,IAAI,IAAqC,MACnC,UAAwB;AAAE,SAAiB;MAC7C,IAAU,IACV,IAAoB,IACpB,GACA,IAAmB,IAKjB,KAAkB,MAAuB;IAC3C,IAAM,IAAa,EAAO;AAC1B,QAAI,CAAC,EAAY;IAEjB,IAAI;AACJ,QAAI;AACA,SACI,OAAO,KAAa,cAAc,CAAC,EAAgB,EAAmB,GAC/D,EAA4D,EAAI,GAChE;aACN,GAAG;AAER,KADA,QAAQ,MAAM,yEAAyE,EAAE,EACzF,IAAgB,EAAqB,GAAY,EAAO;AACxD;;AAIJ,MAAkB,EAA6B;AAC/C,QAAI;AACA,KAGI,IAHA,EAAgB,EAAG,GACH,EAAsB,GAAI,GAAY,EAAO,GAE7C,EAAG,QAAQ,GAAY,EAAO;aAE7C,GAAG;AAGR,KAFA,QAAQ,MAAM,uDAAuD,EAAE,EACvE,KAAiB,EACjB,IAAgB,EAAqB,GAAY,EAAO;cAClD;AACN,QAAkB;;MAIpB,KAAgC,MAAqB;AAGvD,IAFA,QAAQ,MAAM,kEAAkE,EAAE,EAClF,KAAiB,EACjB,IAAgB;IAChB,IAAM,IAAa,EAAO;AAC1B,IAAI,MACA,IAAgB,EAAqB,GAAY,EAAO;MAI1D,KAAwB,GAAkB,MAAsC;IAClF,IAAM,IAAK,SAAS,cAAc,MAAM;AAIxC,WAHA,EAAG,aAAa,4BAA4B,kBAAkB,EAC9D,EAAG,cAAc,oDACjB,EAAW,aAAa,GAAI,EAAO,QACtB,EAAG,QAAQ;;AAiB5B,MAb6B,MAAuB;AAC5C,UACJ,IAAU,IACN,KACA,KAAiB,EACjB,IAAgB,MAChB,EAAe,EAAI,KAEnB,IAAgB,GAChB,IAAmB;KAIW;AACtC,OAAI;AAIA,YAAyB;AACrB,SAAI,EAAgB,EAAQ,EAAE;AAC1B,SAAuB;AACvB,UAAI;AACA,WAAI;AAAE,UAAQ,UAAU;gBAAW,GAAG;AAClC,YAAI,EAAQ,QAAS,GAAQ,QAAQ,EAAE;YAAO,OAAM;;AAExD,WAAgB,EAAQ,QAAQ,CAAC,QAAQ,GAAQ,EAAO;gBAClD;AACN,UAAsB;;AAE1B,MAAK,KACD,QAAoB;AAChB,WAAI;QACA,IAAM,IAAM,EAAQ,WAAW,EACzB,IAAO;AACb,kBAAsB;AAClB,aAAI;AAAE,YAAQ,aAAa;iBAAU;AACrC,aAAI,OAAO,KAAQ,WAAY,KAAI;AAAE,aAAK;iBAAU;AACpD,cAAQ;;gBAEP,GAAG;AACR,YAAI,EAAQ,QAAS,GAAQ,QAAQ,EAAE;YAAO,OAAM;;QAE1D;WAGN,KAAgB,EAAQ,QAAQ,GAAQ,EAAO;MAErD;YACG,GAAK;AAKV,IAJA,IAAU,IACV,GAAW,EACX,IAAgB,MAChB,IAAgB,GAChB,IAAmB;aACb;AAEN,IADA,GAAkB,EAClB,IAAoB;;AASxB,UANI,MACA,GAAW,EACX,IAAgB,MAChB,EAAe,EAAc,SAGpB;AAET,IADA,KAAiB,EACjB,EAAO,QAAQ;;;EAG1B"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const e=require(`./types.cjs`),t=require(`./bindings.cjs`);function
|
|
1
|
+
const e=require(`./types.cjs`),t=require(`../next-2/mount-helpers.cjs`),n=require(`./bindings.cjs`);function r(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 i=new WeakMap,a=new WeakMap;function o(o,...s){let c=i.get(o);if(!c){let e=[],t=``;for(let r=0;r<o.length-1;r++)t+=o[r],e.push(n.detectContext(t)),t+=`__elur__`;c={contexts:e},i.set(o,c)}let l=c.contexts,u={version:1,strings:o,values:s,contexts:l};function d(){let e=a.get(o);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=r(o,l);let n=Array(l.length).fill(null),i=t.content,s=document.createTreeWalker(i,NodeFilter.SHOW_ELEMENT|NodeFilter.SHOW_COMMENT),c=0,u;for(;u=s.nextNode();)if(c++,u.nodeType===8){let e=u.nodeValue;if(e&&e.startsWith(`elur-`)){let t=parseInt(e.slice(5),10);isNaN(t)||(n[t]={nodeIndex:c})}}else if(u.nodeType===1){let e=u,t=Array.from(e.attributes);for(let r=0;r<t.length;r++){let i=t[r],a=i.name;if(a.startsWith(`data-elur-e-`)){let t=parseInt(a.slice(12),10);isNaN(t)||(n[t]={nodeIndex:c,name:i.value}),e.removeAttribute(a);continue}if(a.startsWith(`data-elur-a-`)){let t=parseInt(a.slice(12),10);isNaN(t)||(n[t]={nodeIndex:c,name:i.value}),e.removeAttribute(a)}}}return e={tpl:t,pathMap:n},a.set(o,e),e}function f(e,r){return t._postMountScope(()=>{let{tpl:t,pathMap:i}=d(),a=t.content.cloneNode(!0),{disposes:o,postMountHooks:c}=n.activateBindings(a,l,s,i),u=document.createTextNode(``),f=document.createTextNode(``);return e.insertBefore(u,r),e.insertBefore(a,r),e.insertBefore(f,r),c.forEach(e=>e()),()=>{for(let e=o.length-1;e>=0;e--)o[e]();let e=u.nextSibling;for(;e&&e!==f;){let t=e.nextSibling;e.parentNode?.removeChild(e),e=t}u.parentNode?.removeChild(u),f.parentNode?.removeChild(f)}})}return{__isElurTemplate:!0,[e.ELUR_TEMPLATE_DESCRIPTOR]:u,_render:f,mount(e){let t=typeof e==`string`?document.querySelector(e):e;if(!t)throw Error(`[elur] mount: contenedor no encontrado: ${e}`);let n=f(t,null),r=!1;return{unmount(){r||(r=!0,n())}}}}}exports.buildHTML=r,exports.html=o;
|
|
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 @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
|
+
{"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 { _postMountScope } from \"./mount-helpers.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 // _postMountScope: los onMount de componentes montados dentro del\n // fragment se disparan al commit del render más externo — nunca\n // con el subárbol todavía detached.\n return _postMountScope(() => {\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\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 let done = false;\n return {\n unmount() {\n if (done) return;\n done = true;\n cleanup();\n },\n };\n },\n };\n\n return elurTemplate;\n }\n"],"mappings":"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"}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { ELUR_TEMPLATE_DESCRIPTOR as e } from "./types.js";
|
|
2
|
-
import {
|
|
2
|
+
import { _postMountScope as t } from "../next-2/mount-helpers.js";
|
|
3
|
+
import { activateBindings as n, detectContext as r } from "./bindings.js";
|
|
3
4
|
//#region src/elur/template/html.ts
|
|
4
|
-
function
|
|
5
|
+
function i(e, t) {
|
|
5
6
|
let n = new Uint8Array(e.length), r = "";
|
|
6
7
|
for (let i = 0; i < e.length; i++) {
|
|
7
8
|
let a = e[i];
|
|
@@ -19,35 +20,35 @@ function r(e, t) {
|
|
|
19
20
|
}
|
|
20
21
|
return r;
|
|
21
22
|
}
|
|
22
|
-
var
|
|
23
|
-
function
|
|
24
|
-
let
|
|
25
|
-
if (!
|
|
23
|
+
var a = /* @__PURE__ */ new WeakMap(), o = /* @__PURE__ */ new WeakMap();
|
|
24
|
+
function s(s, ...c) {
|
|
25
|
+
let l = a.get(s);
|
|
26
|
+
if (!l) {
|
|
26
27
|
let e = [], t = "";
|
|
27
|
-
for (let
|
|
28
|
-
|
|
28
|
+
for (let n = 0; n < s.length - 1; n++) t += s[n], e.push(r(t)), t += "__elur__";
|
|
29
|
+
l = { contexts: e }, a.set(s, l);
|
|
29
30
|
}
|
|
30
|
-
let
|
|
31
|
+
let u = l.contexts, d = {
|
|
31
32
|
version: 1,
|
|
32
|
-
strings:
|
|
33
|
-
values:
|
|
34
|
-
contexts:
|
|
33
|
+
strings: s,
|
|
34
|
+
values: c,
|
|
35
|
+
contexts: u
|
|
35
36
|
};
|
|
36
|
-
function
|
|
37
|
-
let e =
|
|
37
|
+
function f() {
|
|
38
|
+
let e = o.get(s);
|
|
38
39
|
if (e) return e;
|
|
39
40
|
if (typeof document > "u") throw Error("[elur] DOM rendering requires a document. Use @elurjs/core/server on the server.");
|
|
40
41
|
let t = document.createElement("template");
|
|
41
|
-
t.innerHTML =
|
|
42
|
-
let n = Array(
|
|
43
|
-
for (;
|
|
44
|
-
let e =
|
|
42
|
+
t.innerHTML = i(s, u);
|
|
43
|
+
let n = Array(u.length).fill(null), r = t.content, a = document.createTreeWalker(r, NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT), c = 0, l;
|
|
44
|
+
for (; l = a.nextNode();) if (c++, l.nodeType === 8) {
|
|
45
|
+
let e = l.nodeValue;
|
|
45
46
|
if (e && e.startsWith("elur-")) {
|
|
46
47
|
let t = parseInt(e.slice(5), 10);
|
|
47
48
|
isNaN(t) || (n[t] = { nodeIndex: c });
|
|
48
49
|
}
|
|
49
|
-
} else if (
|
|
50
|
-
let e =
|
|
50
|
+
} else if (l.nodeType === 1) {
|
|
51
|
+
let e = l, t = Array.from(e.attributes);
|
|
51
52
|
for (let r = 0; r < t.length; r++) {
|
|
52
53
|
let i = t[r], a = i.name;
|
|
53
54
|
if (a.startsWith("data-elur-e-")) {
|
|
@@ -70,35 +71,37 @@ function o(o, ...s) {
|
|
|
70
71
|
return e = {
|
|
71
72
|
tpl: t,
|
|
72
73
|
pathMap: n
|
|
73
|
-
},
|
|
74
|
+
}, o.set(s, e), e;
|
|
74
75
|
}
|
|
75
|
-
function
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
76
|
+
function p(e, r) {
|
|
77
|
+
return t(() => {
|
|
78
|
+
let { tpl: t, pathMap: i } = f(), a = t.content.cloneNode(!0), { disposes: o, postMountHooks: s } = n(a, u, c, i), l = document.createTextNode(""), d = document.createTextNode("");
|
|
79
|
+
return e.insertBefore(l, r), e.insertBefore(a, r), e.insertBefore(d, r), s.forEach((e) => e()), () => {
|
|
80
|
+
for (let e = o.length - 1; e >= 0; e--) o[e]();
|
|
81
|
+
let e = l.nextSibling;
|
|
82
|
+
for (; e && e !== d;) {
|
|
83
|
+
let t = e.nextSibling;
|
|
84
|
+
e.parentNode?.removeChild(e), e = t;
|
|
85
|
+
}
|
|
86
|
+
l.parentNode?.removeChild(l), d.parentNode?.removeChild(d);
|
|
87
|
+
};
|
|
88
|
+
});
|
|
86
89
|
}
|
|
87
90
|
return {
|
|
88
91
|
__isElurTemplate: !0,
|
|
89
|
-
[e]:
|
|
90
|
-
_render:
|
|
92
|
+
[e]: d,
|
|
93
|
+
_render: p,
|
|
91
94
|
mount(e) {
|
|
92
95
|
let t = typeof e == "string" ? document.querySelector(e) : e;
|
|
93
96
|
if (!t) throw Error(`[elur] mount: contenedor no encontrado: ${e}`);
|
|
94
|
-
let n =
|
|
97
|
+
let n = p(t, null), r = !1;
|
|
95
98
|
return { unmount() {
|
|
96
|
-
n();
|
|
99
|
+
r || (r = !0, n());
|
|
97
100
|
} };
|
|
98
101
|
}
|
|
99
102
|
};
|
|
100
103
|
}
|
|
101
104
|
//#endregion
|
|
102
|
-
export {
|
|
105
|
+
export { i as buildHTML, s as html };
|
|
103
106
|
|
|
104
107
|
//# sourceMappingURL=html.js.map
|
|
@@ -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 @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
|
+
{"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 { _postMountScope } from \"./mount-helpers.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 // _postMountScope: los onMount de componentes montados dentro del\n // fragment se disparan al commit del render más externo — nunca\n // con el subárbol todavía detached.\n return _postMountScope(() => {\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\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 let done = false;\n return {\n unmount() {\n if (done) return;\n done = true;\n cleanup();\n },\n };\n },\n };\n\n return elurTemplate;\n }\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`./elur/template/types.cjs`),t=require(`./elur/
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`./elur/template/types.cjs`),t=require(`./elur/next-2/mount-helpers.cjs`),n=require(`./elur/template/keyed.cjs`),r=require(`./elur/next-2/keyed-diff.cjs`),i=require(`./elur/next-2/dom-write.cjs`),a=require(`./elur/next-2/node-binding.cjs`),o=require(`./elur/template/sanitize.cjs`),s=require(`./elur/template/bindings.cjs`),c=require(`./elur/template/html.cjs`),l=require(`./elur/template/raw.cjs`),u=require(`./elur/template/transitions.cjs`),d=require(`./elur/template/portal.cjs`),f=require(`./elur/template/error-boundary.cjs`);exports.COMMENT=e.COMMENT,exports.ELUR_RENDER_PROTOCOL=e.ELUR_RENDER_PROTOCOL,exports.ELUR_TEMPLATE_DESCRIPTOR=e.ELUR_TEMPLATE_DESCRIPTOR,exports._activateBindingsWithNodes=s._activateBindingsWithNodes,exports._activateDelegatedEvent=s.activateDelegatedEvent,exports._activateNodeBinding=a.activateNodeBinding,exports._createKeyedMount=r.createKeyedMount,exports._deferOnMount=t._deferOnMount,exports._ensureDelegatedEvent=s._ensureDelegatedEvent,exports._getKeyedSequence=n.getSequence,exports._keyedItemsEqual=n._keyedItemsEqual,exports._postMountScope=t._postMountScope,exports._postMountScopeSub=t._postMountScopeSub,exports._queueDOMWrite=i.queueDOMWrite,exports._reconcileKeyedList=r.reconcileKeyedList,exports._setDelegatedEvent=s._setDelegatedEvent,exports.buildHTML=c.buildHTML,exports.createErrorBoundary=f.createErrorBoundary,exports.createPortalOutlet=d.createPortalOutlet,exports.html=c.html,exports.injectOutlet=d.injectOutlet,exports.isElurTemplate=e.isElurTemplate,exports.isExecutableAttrName=o.isExecutableAttrName,exports.isKeyedList=e.isKeyedList,exports.isUrlAttrName=o.isUrlAttrName,exports.portal=d.portal,exports.portalOutlet=d.portalOutlet,exports.provideOutlet=d.provideOutlet,exports.raw=l.raw,exports.ref=e.ref,exports.repeat=n.repeat,exports.sanitizeUrl=o.sanitizeUrl,exports.showWhen=s.showWhen,exports.templateFeatures=e.templateFeatures,exports.transition=u.transition;
|
|
@@ -7,8 +7,9 @@ export { _activateBindingsWithNodes, activateDelegatedEvent as _activateDelegate
|
|
|
7
7
|
export { activateNodeBinding as _activateNodeBinding } from "./node-binding.js";
|
|
8
8
|
export { queueDOMWrite as _queueDOMWrite } from "./dom-write.js";
|
|
9
9
|
export { sanitizeUrl, isUrlAttrName, isExecutableAttrName } from "./sanitize.js";
|
|
10
|
-
export { repeat, getSequence as _getKeyedSequence } from "./keyed.js";
|
|
10
|
+
export { repeat, getSequence as _getKeyedSequence, _keyedItemsEqual } from "./keyed.js";
|
|
11
11
|
export { createKeyedMount as _createKeyedMount, reconcileKeyedList as _reconcileKeyedList, } from "./keyed-diff.js";
|
|
12
|
+
export { _postMountScope, _postMountScopeSub, _deferOnMount } from "./mount-helpers.js";
|
|
12
13
|
export { transition } from "./transitions.js";
|
|
13
14
|
export type { TransitionOptions } from "./transitions.js";
|
|
14
15
|
export { portal, portalOutlet, createPortalOutlet, provideOutlet, injectOutlet } from "./portal.js";
|
|
@@ -7,8 +7,9 @@ export { _activateBindingsWithNodes, activateDelegatedEvent as _activateDelegate
|
|
|
7
7
|
export { activateNodeBinding as _activateNodeBinding } from "./node-binding.js";
|
|
8
8
|
export { queueDOMWrite as _queueDOMWrite } from "./dom-write.js";
|
|
9
9
|
export { sanitizeUrl, isUrlAttrName, isExecutableAttrName } from "./sanitize.js";
|
|
10
|
-
export { repeat, getSequence as _getKeyedSequence } from "./keyed.js";
|
|
10
|
+
export { repeat, getSequence as _getKeyedSequence, _keyedItemsEqual } from "./keyed.js";
|
|
11
11
|
export { createKeyedMount as _createKeyedMount, reconcileKeyedList as _reconcileKeyedList, } from "./keyed-diff.js";
|
|
12
|
+
export { _postMountScope, _postMountScopeSub, _deferOnMount } from "./mount-helpers.js";
|
|
12
13
|
export { transition } from "./transitions.js";
|
|
13
14
|
export type { TransitionOptions } from "./transitions.js";
|
|
14
15
|
export { portal, portalOutlet, createPortalOutlet, provideOutlet, injectOutlet } from "./portal.js";
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { COMMENT as e, ELUR_RENDER_PROTOCOL as t, ELUR_TEMPLATE_DESCRIPTOR as n, isElurTemplate as r, isKeyedList as i, ref as a, templateFeatures as o } from "./elur/template/types.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
|
|
2
|
+
import { _deferOnMount as s, _postMountScope as c, _postMountScopeSub as l } from "./elur/next-2/mount-helpers.js";
|
|
3
|
+
import { _keyedItemsEqual as u, getSequence as d, repeat as f } from "./elur/template/keyed.js";
|
|
4
|
+
import { createKeyedMount as p, reconcileKeyedList as m } from "./elur/next-2/keyed-diff.js";
|
|
5
|
+
import { queueDOMWrite as h } from "./elur/next-2/dom-write.js";
|
|
6
|
+
import { activateNodeBinding as g } from "./elur/next-2/node-binding.js";
|
|
7
|
+
import { isExecutableAttrName as _, isUrlAttrName as v, sanitizeUrl as y } from "./elur/template/sanitize.js";
|
|
8
|
+
import { _activateBindingsWithNodes as b, _ensureDelegatedEvent as x, _setDelegatedEvent as S, activateDelegatedEvent as C, showWhen as w } from "./elur/template/bindings.js";
|
|
9
|
+
import { buildHTML as T, html as E } from "./elur/template/html.js";
|
|
10
|
+
import { raw as D } from "./elur/template/raw.js";
|
|
11
|
+
import { transition as O } from "./elur/template/transitions.js";
|
|
12
|
+
import { createPortalOutlet as k, injectOutlet as A, portal as j, portalOutlet as M, provideOutlet as N } from "./elur/template/portal.js";
|
|
13
|
+
import { createErrorBoundary as P } from "./elur/template/error-boundary.js";
|
|
14
|
+
export { e as COMMENT, t as ELUR_RENDER_PROTOCOL, n as ELUR_TEMPLATE_DESCRIPTOR, b as _activateBindingsWithNodes, C as _activateDelegatedEvent, g as _activateNodeBinding, p as _createKeyedMount, s as _deferOnMount, x as _ensureDelegatedEvent, d as _getKeyedSequence, u as _keyedItemsEqual, c as _postMountScope, l as _postMountScopeSub, h as _queueDOMWrite, m as _reconcileKeyedList, S as _setDelegatedEvent, T as buildHTML, P as createErrorBoundary, k as createPortalOutlet, E as html, A as injectOutlet, r as isElurTemplate, _ as isExecutableAttrName, i as isKeyedList, v as isUrlAttrName, j as portal, M as portalOutlet, N as provideOutlet, D as raw, a as ref, f as repeat, y as sanitizeUrl, w as showWhen, o as templateFeatures, O as transition };
|
|
@@ -1,32 +1 @@
|
|
|
1
|
-
|
|
2
|
-
import { type RepeatKey } from "./keyed.js";
|
|
3
|
-
/**
|
|
4
|
-
* Mounts a single keyed item's rendered value before `endMarker` inside `parent`.
|
|
5
|
-
* Used by the DOM renderer and the hydration renderer so both engines share the
|
|
6
|
-
* exact same reconciliation semantics.
|
|
7
|
-
*/
|
|
8
|
-
export declare function createKeyedMount(ctxSnapshot: Map<unknown, unknown>[]): (rendered: unknown, parent: Node, endMarker: Node) => () => void;
|
|
9
|
-
export interface KeyedDiffOptions {
|
|
10
|
-
/** Node marking the start of the keyed zone. */
|
|
11
|
-
zoneStart: Node;
|
|
12
|
-
/** End boundary; new content is inserted before this node. */
|
|
13
|
-
anchor: Node;
|
|
14
|
-
/** Live map of key → entry (start/end markers + cleanup). */
|
|
15
|
-
state: Map<RepeatKey, KEntry>;
|
|
16
|
-
/** Key order from the previous reconciliation pass. */
|
|
17
|
-
prevOrder: RepeatKey[];
|
|
18
|
-
/** The current keyed list value. */
|
|
19
|
-
list: KeyedList;
|
|
20
|
-
/** Mounts a freshly rendered item into the DOM. */
|
|
21
|
-
mount: (rendered: unknown, parent: Node, endMarker: Node) => () => void;
|
|
22
|
-
/** Context snapshot for component mounts inside the effect. */
|
|
23
|
-
ctxSnapshot?: Map<unknown, unknown>[];
|
|
24
|
-
/** Called when a duplicate key is encountered. */
|
|
25
|
-
onDuplicateKey?: (key: RepeatKey) => void;
|
|
26
|
-
}
|
|
27
|
-
/**
|
|
28
|
-
* Reconciles a keyed list between `zoneStart` and `anchor` using the same LIS
|
|
29
|
-
* algorithm used by the DOM renderer. Total replacement (O(1)) when no key
|
|
30
|
-
* survives; otherwise remove/insert/move with minimal DOM operations.
|
|
31
|
-
*/
|
|
32
|
-
export declare function reconcileKeyedList(opts: KeyedDiffOptions): void;
|
|
1
|
+
export * from "../next-2/keyed-diff.js";
|
|
@@ -1,32 +1 @@
|
|
|
1
|
-
|
|
2
|
-
import { type RepeatKey } from "./keyed.js";
|
|
3
|
-
/**
|
|
4
|
-
* Mounts a single keyed item's rendered value before `endMarker` inside `parent`.
|
|
5
|
-
* Used by the DOM renderer and the hydration renderer so both engines share the
|
|
6
|
-
* exact same reconciliation semantics.
|
|
7
|
-
*/
|
|
8
|
-
export declare function createKeyedMount(ctxSnapshot: Map<unknown, unknown>[]): (rendered: unknown, parent: Node, endMarker: Node) => () => void;
|
|
9
|
-
export interface KeyedDiffOptions {
|
|
10
|
-
/** Node marking the start of the keyed zone. */
|
|
11
|
-
zoneStart: Node;
|
|
12
|
-
/** End boundary; new content is inserted before this node. */
|
|
13
|
-
anchor: Node;
|
|
14
|
-
/** Live map of key → entry (start/end markers + cleanup). */
|
|
15
|
-
state: Map<RepeatKey, KEntry>;
|
|
16
|
-
/** Key order from the previous reconciliation pass. */
|
|
17
|
-
prevOrder: RepeatKey[];
|
|
18
|
-
/** The current keyed list value. */
|
|
19
|
-
list: KeyedList;
|
|
20
|
-
/** Mounts a freshly rendered item into the DOM. */
|
|
21
|
-
mount: (rendered: unknown, parent: Node, endMarker: Node) => () => void;
|
|
22
|
-
/** Context snapshot for component mounts inside the effect. */
|
|
23
|
-
ctxSnapshot?: Map<unknown, unknown>[];
|
|
24
|
-
/** Called when a duplicate key is encountered. */
|
|
25
|
-
onDuplicateKey?: (key: RepeatKey) => void;
|
|
26
|
-
}
|
|
27
|
-
/**
|
|
28
|
-
* Reconciles a keyed list between `zoneStart` and `anchor` using the same LIS
|
|
29
|
-
* algorithm used by the DOM renderer. Total replacement (O(1)) when no key
|
|
30
|
-
* survives; otherwise remove/insert/move with minimal DOM operations.
|
|
31
|
-
*/
|
|
32
|
-
export declare function reconcileKeyedList(opts: KeyedDiffOptions): void;
|
|
1
|
+
export * from "../next-2/keyed-diff.js";
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
function e(e,t,n){return{__isKeyedList:!0,items:e,keyFn:t,renderFn:n}}function t(e,t){return typeof e==`string`||typeof e==`number`?e:(console.warn(`[elur] repeat(): key at index ${t} is not a string or number (got ${typeof e}); using positional fallback. Non-serializable keys cannot preserve identity across SSR/hydration.`),`__elur-key:${t}`)}function n(e){let t=new TextEncoder().encode(e),n=``;for(let e=0;e<t.length;e+=32768)n+=String.fromCharCode(...t.subarray(e,e+32768));return btoa(n)}function r(e){let t=atob(e),n=new Uint8Array(t.length);for(let e=0;e<t.length;e++)n[e]=t.charCodeAt(e);return new TextDecoder().decode(n)}function i(e){return n(JSON.stringify(e))}function a(e){try{let t=JSON.parse(r(e));if(typeof t==`string`||typeof t==`number`)return t}catch{}return e}function o(e){let t=e.slice(),n=[0],r,i,a,o,s,c=e.length;for(r=0;r<c;r++){let c=e[r];if(c!==0){if(i=n[n.length-1],e[i]<c){t[r]=i,n.push(r);continue}for(a=0,o=n.length-1;a<o;)s=a+o>>1,e[n[s]]<c?a=s+1:o=s;c<e[n[a]]&&(a>0&&(t[r]=n[a-1]),n[a]=r)}}for(a=n.length,o=n[a-1];a-- >0;)n[a]=o,o=t[o];return n}exports.deserializeRepeatKey=a,exports.getSequence=o,exports.normalizeRepeatKey=t,exports.repeat=e,exports.serializeRepeatKey=i;
|
|
1
|
+
function e(e,t,n){return{__isKeyedList:!0,items:e,keyFn:t,renderFn:n}}function t(e,t){return typeof e==`string`||typeof e==`number`?e:(console.warn(`[elur] repeat(): key at index ${t} is not a string or number (got ${typeof e}); using positional fallback. Non-serializable keys cannot preserve identity across SSR/hydration.`),`__elur-key:${t}`)}function n(e){let t=new TextEncoder().encode(e),n=``;for(let e=0;e<t.length;e+=32768)n+=String.fromCharCode(...t.subarray(e,e+32768));return btoa(n)}function r(e){let t=atob(e),n=new Uint8Array(t.length);for(let e=0;e<t.length;e++)n[e]=t.charCodeAt(e);return new TextDecoder().decode(n)}function i(e){return n(JSON.stringify(e))}function a(e){try{let t=JSON.parse(r(e));if(typeof t==`string`||typeof t==`number`)return t}catch{}return e}function o(e){let t=e.slice(),n=[0],r,i,a,o,s,c=e.length;for(r=0;r<c;r++){let c=e[r];if(c!==0){if(i=n[n.length-1],e[i]<c){t[r]=i,n.push(r);continue}for(a=0,o=n.length-1;a<o;)s=a+o>>1,e[n[s]]<c?a=s+1:o=s;c<e[n[a]]&&(a>0&&(t[r]=n[a-1]),n[a]=r)}}for(a=n.length,o=n[a-1];a-- >0;)n[a]=o,o=t[o];return n}function s(e,t){if(e===t)return!0;if(typeof e!=`object`||typeof t!=`object`||e===null||t===null)return!1;let n=Object.keys(e),r=Object.keys(t);if(n.length!==r.length)return!1;for(let r=0;r<n.length;r++){let i=n[r];if(e[i]!==t[i])return!1}return!0}exports._keyedItemsEqual=s,exports.deserializeRepeatKey=a,exports.getSequence=o,exports.normalizeRepeatKey=t,exports.repeat=e,exports.serializeRepeatKey=i;
|
|
2
2
|
//# sourceMappingURL=keyed.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"keyed.cjs","names":[],"sources":["../../../../src/elur/template/keyed.ts"],"sourcesContent":["import type { ElurTemplate, KeyedList, KEntry } from \"./types.js\";\nimport type { ElurComponent } from \"../lifecycle.js\";\n\n// =============================================================================\n// --- repeat() ---\n// =============================================================================\n\n/**\n * Creates a keyed list for efficient DOM reconciliation.\n * Use instead of `.map()` when the list changes frequently.\n */\nexport function repeat<T>(\n items: T[],\n keyFn: (item: T, index: number) => string | number,\n renderFn: (item: T, index: number) => ElurTemplate | ElurComponent\n): KeyedList<T> {\n return { __isKeyedList: true as const, items, keyFn, renderFn };\n}\n\n// =============================================================================\n// --- Key serialization for SSR/hydration markers ---\n// =============================================================================\n\nexport type RepeatKey = string | number;\n\n/**\n * Normalizes a repeat() key to a serializable form. Keys must be strings or\n * numbers to preserve identity across SSR/hydration. Anything else produces a\n * diagnostic warning and a deterministic positional fallback so that server\n * and client agree without silent `String(key)` collisions.\n */\nexport function normalizeRepeatKey(key: unknown, index: number): RepeatKey {\n if (typeof key === \"string\" || typeof key === \"number\") return key;\n console.warn(\n `[elur] repeat(): key at index ${index} is not a string or number (got ${typeof key}); ` +\n
|
|
1
|
+
{"version":3,"file":"keyed.cjs","names":[],"sources":["../../../../src/elur/template/keyed.ts"],"sourcesContent":["import type { ElurTemplate, KeyedList, KEntry } from \"./types.js\";\nimport type { ElurComponent } from \"../lifecycle.js\";\n\n// =============================================================================\n// --- repeat() ---\n// =============================================================================\n\n/**\n * Creates a keyed list for efficient DOM reconciliation.\n * Use instead of `.map()` when the list changes frequently.\n */\nexport function repeat<T>(\n items: T[],\n keyFn: (item: T, index: number) => string | number,\n renderFn: (item: T, index: number) => ElurTemplate | ElurComponent\n): KeyedList<T> {\n return { __isKeyedList: true as const, items, keyFn, renderFn };\n}\n\n// =============================================================================\n// --- Key serialization for SSR/hydration markers ---\n// =============================================================================\n\nexport type RepeatKey = string | number;\n\n/**\n * Normalizes a repeat() key to a serializable form. Keys must be strings or\n * numbers to preserve identity across SSR/hydration. Anything else produces a\n * diagnostic warning and a deterministic positional fallback so that server\n * and client agree without silent `String(key)` collisions.\n */\nexport function normalizeRepeatKey(key: unknown, index: number): RepeatKey {\n if (typeof key === \"string\" || typeof key === \"number\") return key;\n console.warn(\n `[elur] repeat(): key at index ${index} is not a string or number (got ${typeof key}); ` +\n `using positional fallback. Non-serializable keys cannot preserve identity across SSR/hydration.`,\n );\n return `__elur-key:${index}`;\n}\n\nfunction utf8ToBase64(value: string): string {\n const bytes = new TextEncoder().encode(value);\n let binary = \"\";\n for (let i = 0; i < bytes.length; i += 0x8000) {\n binary += String.fromCharCode(...bytes.subarray(i, i + 0x8000));\n }\n return btoa(binary);\n}\n\nfunction utf8FromBase64(value: string): string {\n const binary = atob(value);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);\n return new TextDecoder().decode(bytes);\n}\n\n/** Serializes a repeat() key for the SSR keyed marker (base64 JSON, safe for HTML comments). */\nexport function serializeRepeatKey(key: RepeatKey): string {\n return utf8ToBase64(JSON.stringify(key));\n}\n\n/** Decodes a repeat() key from a keyed hydration marker. */\nexport function deserializeRepeatKey(serialized: string): RepeatKey {\n try {\n const parsed: unknown = JSON.parse(utf8FromBase64(serialized));\n if (typeof parsed === \"string\" || typeof parsed === \"number\") return parsed;\n } catch {\n // fall through\n }\n return serialized;\n}\n\n// =============================================================================\n// --- Longest Increasing Subsequence (LIS) ---\n// =============================================================================\n\n/**\n * Returns the indices of the Longest Increasing Subsequence.\n * Used to minimize DOM operations during list diffing.\n */\nexport function getSequence(arr: Int32Array | number[]): number[] {\n const p = arr.slice();\n const result = [0];\n let i, j, u, v, c;\n const len = arr.length;\n for (i = 0; i < len; i++) {\n const arrI = arr[i];\n if (arrI !== 0) {\n j = result[result.length - 1];\n if (arr[j] < arrI) {\n p[i] = j;\n result.push(i);\n continue;\n }\n u = 0;\n v = result.length - 1;\n while (u < v) {\n c = (u + v) >> 1;\n if (arr[result[c]] < arrI) {\n u = c + 1;\n } else {\n v = c;\n }\n }\n if (arrI < arr[result[u]]) {\n if (u > 0) {\n p[i] = result[u - 1];\n }\n result[u] = i;\n }\n }\n }\n u = result.length;\n v = result[u - 1];\n while (u-- > 0) {\n result[u] = v;\n v = p[v];\n }\n return result;\n}\n\n/**\n * C.16.4: igualdad shallow de items de lista — misma key + objeto nuevo con\n * campos idénticos → el row se conserva (DOM, estado, bindings). Cualquier\n * campo distinto → re-mount in-place (los bindings capturaron el objeto\n * viejo por valor y no hay accessors que actualizar). Identidad `===`\n * primero (fast path para el caso común: mismos objetos reordenados).\n *\n * @internal — usado por keyed-diff (estable y next-2) y el runtime compilado.\n */\nexport function _keyedItemsEqual(a: unknown, b: unknown): boolean {\n if (a === b) return true;\n if (typeof a !== \"object\" || typeof b !== \"object\" || a === null || b === null) {\n return false;\n }\n const ka = Object.keys(a as object);\n const kb = Object.keys(b as object);\n if (ka.length !== kb.length) return false;\n for (let i = 0; i < ka.length; i++) {\n const k = ka[i];\n if ((a as Record<string, unknown>)[k] !== (b as Record<string, unknown>)[k]) {\n return false;\n }\n }\n return true;\n}\n\nexport type { KEntry };\n"],"mappings":"AAWA,SAAgB,EACZ,EACA,EACA,EACY,CACZ,MAAO,CAAE,cAAe,GAAe,QAAO,QAAO,WAAU,CAenE,SAAgB,EAAmB,EAAc,EAA0B,CAMvE,OALI,OAAO,GAAQ,UAAY,OAAO,GAAQ,SAAiB,GAC/D,QAAQ,KACJ,iCAAiC,EAAM,kCAAkC,OAAO,EAAI,oGAEvF,CACM,cAAc,KAGzB,SAAS,EAAa,EAAuB,CACzC,IAAM,EAAQ,IAAI,aAAa,CAAC,OAAO,EAAM,CACzC,EAAS,GACb,IAAK,IAAI,EAAI,EAAG,EAAI,EAAM,OAAQ,GAAK,MACnC,GAAU,OAAO,aAAa,GAAG,EAAM,SAAS,EAAG,EAAI,MAAO,CAAC,CAEnE,OAAO,KAAK,EAAO,CAGvB,SAAS,EAAe,EAAuB,CAC3C,IAAM,EAAS,KAAK,EAAM,CACpB,EAAQ,IAAI,WAAW,EAAO,OAAO,CAC3C,IAAK,IAAI,EAAI,EAAG,EAAI,EAAO,OAAQ,IAAK,EAAM,GAAK,EAAO,WAAW,EAAE,CACvE,OAAO,IAAI,aAAa,CAAC,OAAO,EAAM,CAI1C,SAAgB,EAAmB,EAAwB,CACvD,OAAO,EAAa,KAAK,UAAU,EAAI,CAAC,CAI5C,SAAgB,EAAqB,EAA+B,CAChE,GAAI,CACA,IAAM,EAAkB,KAAK,MAAM,EAAe,EAAW,CAAC,CAC9D,GAAI,OAAO,GAAW,UAAY,OAAO,GAAW,SAAU,OAAO,OACjE,EAGR,OAAO,EAWX,SAAgB,EAAY,EAAsC,CAC9D,IAAM,EAAI,EAAI,OAAO,CACf,EAAS,CAAC,EAAE,CACd,EAAG,EAAG,EAAG,EAAG,EACV,EAAM,EAAI,OAChB,IAAK,EAAI,EAAG,EAAI,EAAK,IAAK,CACtB,IAAM,EAAO,EAAI,GACjB,GAAI,IAAS,EAAG,CAEZ,GADA,EAAI,EAAO,EAAO,OAAS,GACvB,EAAI,GAAK,EAAM,CACf,EAAE,GAAK,EACP,EAAO,KAAK,EAAE,CACd,SAIJ,IAFA,EAAI,EACJ,EAAI,EAAO,OAAS,EACb,EAAI,GACP,EAAK,EAAI,GAAM,EACX,EAAI,EAAO,IAAM,EACjB,EAAI,EAAI,EAER,EAAI,EAGR,EAAO,EAAI,EAAO,MACd,EAAI,IACJ,EAAE,GAAK,EAAO,EAAI,IAEtB,EAAO,GAAK,IAMxB,IAFA,EAAI,EAAO,OACX,EAAI,EAAO,EAAI,GACR,KAAM,GACT,EAAO,GAAK,EACZ,EAAI,EAAE,GAEV,OAAO,EAYX,SAAgB,EAAiB,EAAY,EAAqB,CAC9D,GAAI,IAAM,EAAG,MAAO,GACpB,GAAI,OAAO,GAAM,UAAY,OAAO,GAAM,UAAY,IAAM,MAAQ,IAAM,KACtE,MAAO,GAEX,IAAM,EAAK,OAAO,KAAK,EAAY,CAC7B,EAAK,OAAO,KAAK,EAAY,CACnC,GAAI,EAAG,SAAW,EAAG,OAAQ,MAAO,GACpC,IAAK,IAAI,EAAI,EAAG,EAAI,EAAG,OAAQ,IAAK,CAChC,IAAM,EAAI,EAAG,GACb,GAAK,EAA8B,KAAQ,EAA8B,GACrE,MAAO,GAGf,MAAO"}
|
|
@@ -13,8 +13,6 @@ export type RepeatKey = string | number;
|
|
|
13
13
|
* and client agree without silent `String(key)` collisions.
|
|
14
14
|
*/
|
|
15
15
|
export declare function normalizeRepeatKey(key: unknown, index: number): RepeatKey;
|
|
16
|
-
export declare function utf8ToBase64(value: string): string;
|
|
17
|
-
export declare function utf8FromBase64(value: string): string;
|
|
18
16
|
/** Serializes a repeat() key for the SSR keyed marker (base64 JSON, safe for HTML comments). */
|
|
19
17
|
export declare function serializeRepeatKey(key: RepeatKey): string;
|
|
20
18
|
/** Decodes a repeat() key from a keyed hydration marker. */
|
|
@@ -24,4 +22,14 @@ export declare function deserializeRepeatKey(serialized: string): RepeatKey;
|
|
|
24
22
|
* Used to minimize DOM operations during list diffing.
|
|
25
23
|
*/
|
|
26
24
|
export declare function getSequence(arr: Int32Array | number[]): number[];
|
|
25
|
+
/**
|
|
26
|
+
* C.16.4: igualdad shallow de items de lista — misma key + objeto nuevo con
|
|
27
|
+
* campos idénticos → el row se conserva (DOM, estado, bindings). Cualquier
|
|
28
|
+
* campo distinto → re-mount in-place (los bindings capturaron el objeto
|
|
29
|
+
* viejo por valor y no hay accessors que actualizar). Identidad `===`
|
|
30
|
+
* primero (fast path para el caso común: mismos objetos reordenados).
|
|
31
|
+
*
|
|
32
|
+
* @internal — usado por keyed-diff (estable y next-2) y el runtime compilado.
|
|
33
|
+
*/
|
|
34
|
+
export declare function _keyedItemsEqual(a: unknown, b: unknown): boolean;
|
|
27
35
|
export type { KEntry };
|
|
@@ -13,8 +13,6 @@ export type RepeatKey = string | number;
|
|
|
13
13
|
* and client agree without silent `String(key)` collisions.
|
|
14
14
|
*/
|
|
15
15
|
export declare function normalizeRepeatKey(key: unknown, index: number): RepeatKey;
|
|
16
|
-
export declare function utf8ToBase64(value: string): string;
|
|
17
|
-
export declare function utf8FromBase64(value: string): string;
|
|
18
16
|
/** Serializes a repeat() key for the SSR keyed marker (base64 JSON, safe for HTML comments). */
|
|
19
17
|
export declare function serializeRepeatKey(key: RepeatKey): string;
|
|
20
18
|
/** Decodes a repeat() key from a keyed hydration marker. */
|
|
@@ -24,4 +22,14 @@ export declare function deserializeRepeatKey(serialized: string): RepeatKey;
|
|
|
24
22
|
* Used to minimize DOM operations during list diffing.
|
|
25
23
|
*/
|
|
26
24
|
export declare function getSequence(arr: Int32Array | number[]): number[];
|
|
25
|
+
/**
|
|
26
|
+
* C.16.4: igualdad shallow de items de lista — misma key + objeto nuevo con
|
|
27
|
+
* campos idénticos → el row se conserva (DOM, estado, bindings). Cualquier
|
|
28
|
+
* campo distinto → re-mount in-place (los bindings capturaron el objeto
|
|
29
|
+
* viejo por valor y no hay accessors que actualizar). Identidad `===`
|
|
30
|
+
* primero (fast path para el caso común: mismos objetos reordenados).
|
|
31
|
+
*
|
|
32
|
+
* @internal — usado por keyed-diff (estable y next-2) y el runtime compilado.
|
|
33
|
+
*/
|
|
34
|
+
export declare function _keyedItemsEqual(a: unknown, b: unknown): boolean;
|
|
27
35
|
export type { KEntry };
|
|
@@ -46,7 +46,18 @@ function o(e) {
|
|
|
46
46
|
for (a = n.length, o = n[a - 1]; a-- > 0;) n[a] = o, o = t[o];
|
|
47
47
|
return n;
|
|
48
48
|
}
|
|
49
|
+
function s(e, t) {
|
|
50
|
+
if (e === t) return !0;
|
|
51
|
+
if (typeof e != "object" || typeof t != "object" || e === null || t === null) return !1;
|
|
52
|
+
let n = Object.keys(e), r = Object.keys(t);
|
|
53
|
+
if (n.length !== r.length) return !1;
|
|
54
|
+
for (let r = 0; r < n.length; r++) {
|
|
55
|
+
let i = n[r];
|
|
56
|
+
if (e[i] !== t[i]) return !1;
|
|
57
|
+
}
|
|
58
|
+
return !0;
|
|
59
|
+
}
|
|
49
60
|
//#endregion
|
|
50
|
-
export { a as deserializeRepeatKey, o as getSequence, t as normalizeRepeatKey, e as repeat, i as serializeRepeatKey };
|
|
61
|
+
export { s as _keyedItemsEqual, a as deserializeRepeatKey, o as getSequence, t as normalizeRepeatKey, e as repeat, i as serializeRepeatKey };
|
|
51
62
|
|
|
52
63
|
//# sourceMappingURL=keyed.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"keyed.js","names":[],"sources":["../../../../src/elur/template/keyed.ts"],"sourcesContent":["import type { ElurTemplate, KeyedList, KEntry } from \"./types.js\";\nimport type { ElurComponent } from \"../lifecycle.js\";\n\n// =============================================================================\n// --- repeat() ---\n// =============================================================================\n\n/**\n * Creates a keyed list for efficient DOM reconciliation.\n * Use instead of `.map()` when the list changes frequently.\n */\nexport function repeat<T>(\n items: T[],\n keyFn: (item: T, index: number) => string | number,\n renderFn: (item: T, index: number) => ElurTemplate | ElurComponent\n): KeyedList<T> {\n return { __isKeyedList: true as const, items, keyFn, renderFn };\n}\n\n// =============================================================================\n// --- Key serialization for SSR/hydration markers ---\n// =============================================================================\n\nexport type RepeatKey = string | number;\n\n/**\n * Normalizes a repeat() key to a serializable form. Keys must be strings or\n * numbers to preserve identity across SSR/hydration. Anything else produces a\n * diagnostic warning and a deterministic positional fallback so that server\n * and client agree without silent `String(key)` collisions.\n */\nexport function normalizeRepeatKey(key: unknown, index: number): RepeatKey {\n if (typeof key === \"string\" || typeof key === \"number\") return key;\n console.warn(\n `[elur] repeat(): key at index ${index} is not a string or number (got ${typeof key}); ` +\n
|
|
1
|
+
{"version":3,"file":"keyed.js","names":[],"sources":["../../../../src/elur/template/keyed.ts"],"sourcesContent":["import type { ElurTemplate, KeyedList, KEntry } from \"./types.js\";\nimport type { ElurComponent } from \"../lifecycle.js\";\n\n// =============================================================================\n// --- repeat() ---\n// =============================================================================\n\n/**\n * Creates a keyed list for efficient DOM reconciliation.\n * Use instead of `.map()` when the list changes frequently.\n */\nexport function repeat<T>(\n items: T[],\n keyFn: (item: T, index: number) => string | number,\n renderFn: (item: T, index: number) => ElurTemplate | ElurComponent\n): KeyedList<T> {\n return { __isKeyedList: true as const, items, keyFn, renderFn };\n}\n\n// =============================================================================\n// --- Key serialization for SSR/hydration markers ---\n// =============================================================================\n\nexport type RepeatKey = string | number;\n\n/**\n * Normalizes a repeat() key to a serializable form. Keys must be strings or\n * numbers to preserve identity across SSR/hydration. Anything else produces a\n * diagnostic warning and a deterministic positional fallback so that server\n * and client agree without silent `String(key)` collisions.\n */\nexport function normalizeRepeatKey(key: unknown, index: number): RepeatKey {\n if (typeof key === \"string\" || typeof key === \"number\") return key;\n console.warn(\n `[elur] repeat(): key at index ${index} is not a string or number (got ${typeof key}); ` +\n `using positional fallback. Non-serializable keys cannot preserve identity across SSR/hydration.`,\n );\n return `__elur-key:${index}`;\n}\n\nfunction utf8ToBase64(value: string): string {\n const bytes = new TextEncoder().encode(value);\n let binary = \"\";\n for (let i = 0; i < bytes.length; i += 0x8000) {\n binary += String.fromCharCode(...bytes.subarray(i, i + 0x8000));\n }\n return btoa(binary);\n}\n\nfunction utf8FromBase64(value: string): string {\n const binary = atob(value);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);\n return new TextDecoder().decode(bytes);\n}\n\n/** Serializes a repeat() key for the SSR keyed marker (base64 JSON, safe for HTML comments). */\nexport function serializeRepeatKey(key: RepeatKey): string {\n return utf8ToBase64(JSON.stringify(key));\n}\n\n/** Decodes a repeat() key from a keyed hydration marker. */\nexport function deserializeRepeatKey(serialized: string): RepeatKey {\n try {\n const parsed: unknown = JSON.parse(utf8FromBase64(serialized));\n if (typeof parsed === \"string\" || typeof parsed === \"number\") return parsed;\n } catch {\n // fall through\n }\n return serialized;\n}\n\n// =============================================================================\n// --- Longest Increasing Subsequence (LIS) ---\n// =============================================================================\n\n/**\n * Returns the indices of the Longest Increasing Subsequence.\n * Used to minimize DOM operations during list diffing.\n */\nexport function getSequence(arr: Int32Array | number[]): number[] {\n const p = arr.slice();\n const result = [0];\n let i, j, u, v, c;\n const len = arr.length;\n for (i = 0; i < len; i++) {\n const arrI = arr[i];\n if (arrI !== 0) {\n j = result[result.length - 1];\n if (arr[j] < arrI) {\n p[i] = j;\n result.push(i);\n continue;\n }\n u = 0;\n v = result.length - 1;\n while (u < v) {\n c = (u + v) >> 1;\n if (arr[result[c]] < arrI) {\n u = c + 1;\n } else {\n v = c;\n }\n }\n if (arrI < arr[result[u]]) {\n if (u > 0) {\n p[i] = result[u - 1];\n }\n result[u] = i;\n }\n }\n }\n u = result.length;\n v = result[u - 1];\n while (u-- > 0) {\n result[u] = v;\n v = p[v];\n }\n return result;\n}\n\n/**\n * C.16.4: igualdad shallow de items de lista — misma key + objeto nuevo con\n * campos idénticos → el row se conserva (DOM, estado, bindings). Cualquier\n * campo distinto → re-mount in-place (los bindings capturaron el objeto\n * viejo por valor y no hay accessors que actualizar). Identidad `===`\n * primero (fast path para el caso común: mismos objetos reordenados).\n *\n * @internal — usado por keyed-diff (estable y next-2) y el runtime compilado.\n */\nexport function _keyedItemsEqual(a: unknown, b: unknown): boolean {\n if (a === b) return true;\n if (typeof a !== \"object\" || typeof b !== \"object\" || a === null || b === null) {\n return false;\n }\n const ka = Object.keys(a as object);\n const kb = Object.keys(b as object);\n if (ka.length !== kb.length) return false;\n for (let i = 0; i < ka.length; i++) {\n const k = ka[i];\n if ((a as Record<string, unknown>)[k] !== (b as Record<string, unknown>)[k]) {\n return false;\n }\n }\n return true;\n}\n\nexport type { KEntry };\n"],"mappings":";AAWA,SAAgB,EACZ,GACA,GACA,GACY;AACZ,QAAO;EAAE,eAAe;EAAe;EAAO;EAAO;EAAU;;AAenE,SAAgB,EAAmB,GAAc,GAA0B;AAMvE,QALI,OAAO,KAAQ,YAAY,OAAO,KAAQ,WAAiB,KAC/D,QAAQ,KACJ,iCAAiC,EAAM,kCAAkC,OAAO,EAAI,oGAEvF,EACM,cAAc;;AAGzB,SAAS,EAAa,GAAuB;CACzC,IAAM,IAAQ,IAAI,aAAa,CAAC,OAAO,EAAM,EACzC,IAAS;AACb,MAAK,IAAI,IAAI,GAAG,IAAI,EAAM,QAAQ,KAAK,MACnC,MAAU,OAAO,aAAa,GAAG,EAAM,SAAS,GAAG,IAAI,MAAO,CAAC;AAEnE,QAAO,KAAK,EAAO;;AAGvB,SAAS,EAAe,GAAuB;CAC3C,IAAM,IAAS,KAAK,EAAM,EACpB,IAAQ,IAAI,WAAW,EAAO,OAAO;AAC3C,MAAK,IAAI,IAAI,GAAG,IAAI,EAAO,QAAQ,IAAK,GAAM,KAAK,EAAO,WAAW,EAAE;AACvE,QAAO,IAAI,aAAa,CAAC,OAAO,EAAM;;AAI1C,SAAgB,EAAmB,GAAwB;AACvD,QAAO,EAAa,KAAK,UAAU,EAAI,CAAC;;AAI5C,SAAgB,EAAqB,GAA+B;AAChE,KAAI;EACA,IAAM,IAAkB,KAAK,MAAM,EAAe,EAAW,CAAC;AAC9D,MAAI,OAAO,KAAW,YAAY,OAAO,KAAW,SAAU,QAAO;SACjE;AAGR,QAAO;;AAWX,SAAgB,EAAY,GAAsC;CAC9D,IAAM,IAAI,EAAI,OAAO,EACf,IAAS,CAAC,EAAE,EACd,GAAG,GAAG,GAAG,GAAG,GACV,IAAM,EAAI;AAChB,MAAK,IAAI,GAAG,IAAI,GAAK,KAAK;EACtB,IAAM,IAAO,EAAI;AACjB,MAAI,MAAS,GAAG;AAEZ,OADA,IAAI,EAAO,EAAO,SAAS,IACvB,EAAI,KAAK,GAAM;AAEf,IADA,EAAE,KAAK,GACP,EAAO,KAAK,EAAE;AACd;;AAIJ,QAFA,IAAI,GACJ,IAAI,EAAO,SAAS,GACb,IAAI,GAEP,CADA,IAAK,IAAI,KAAM,GACX,EAAI,EAAO,MAAM,IACjB,IAAI,IAAI,IAER,IAAI;AAGZ,GAAI,IAAO,EAAI,EAAO,QACd,IAAI,MACJ,EAAE,KAAK,EAAO,IAAI,KAEtB,EAAO,KAAK;;;AAMxB,MAFA,IAAI,EAAO,QACX,IAAI,EAAO,IAAI,IACR,MAAM,GAET,CADA,EAAO,KAAK,GACZ,IAAI,EAAE;AAEV,QAAO;;AAYX,SAAgB,EAAiB,GAAY,GAAqB;AAC9D,KAAI,MAAM,EAAG,QAAO;AACpB,KAAI,OAAO,KAAM,YAAY,OAAO,KAAM,YAAY,MAAM,QAAQ,MAAM,KACtE,QAAO;CAEX,IAAM,IAAK,OAAO,KAAK,EAAY,EAC7B,IAAK,OAAO,KAAK,EAAY;AACnC,KAAI,EAAG,WAAW,EAAG,OAAQ,QAAO;AACpC,MAAK,IAAI,IAAI,GAAG,IAAI,EAAG,QAAQ,KAAK;EAChC,IAAM,IAAI,EAAG;AACb,MAAK,EAA8B,OAAQ,EAA8B,GACrE,QAAO;;AAGf,QAAO"}
|