@elurjs/core 3.5.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.
Files changed (191) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +157 -0
  3. package/dist/lib/async.cjs +16 -0
  4. package/dist/lib/async.js +123 -0
  5. package/dist/lib/component.cjs +2 -0
  6. package/dist/lib/component.js +66 -0
  7. package/dist/lib/context.cjs +2 -0
  8. package/dist/lib/context.js +52 -0
  9. package/dist/lib/devtools.cjs +59 -0
  10. package/dist/lib/devtools.js +419 -0
  11. package/dist/lib/elur/async.cjs +16 -0
  12. package/dist/lib/elur/async.cjs.map +1 -0
  13. package/dist/lib/elur/async.d.cts +32 -0
  14. package/dist/lib/elur/async.d.ts +32 -0
  15. package/dist/lib/elur/async.js +123 -0
  16. package/dist/lib/elur/async.js.map +1 -0
  17. package/dist/lib/elur/component.cjs +2 -0
  18. package/dist/lib/elur/component.cjs.map +1 -0
  19. package/dist/lib/elur/component.d.cts +17 -0
  20. package/dist/lib/elur/component.d.ts +17 -0
  21. package/dist/lib/elur/component.js +66 -0
  22. package/dist/lib/elur/component.js.map +1 -0
  23. package/dist/lib/elur/context.cjs +2 -0
  24. package/dist/lib/elur/context.cjs.map +1 -0
  25. package/dist/lib/elur/context.d.cts +29 -0
  26. package/dist/lib/elur/context.d.ts +29 -0
  27. package/dist/lib/elur/context.js +52 -0
  28. package/dist/lib/elur/context.js.map +1 -0
  29. package/dist/lib/elur/devtools.cjs +59 -0
  30. package/dist/lib/elur/devtools.cjs.map +1 -0
  31. package/dist/lib/elur/devtools.d.cts +24 -0
  32. package/dist/lib/elur/devtools.d.ts +24 -0
  33. package/dist/lib/elur/devtools.js +419 -0
  34. package/dist/lib/elur/devtools.js.map +1 -0
  35. package/dist/lib/elur/form.cjs +2 -0
  36. package/dist/lib/elur/form.cjs.map +1 -0
  37. package/dist/lib/elur/form.d.cts +283 -0
  38. package/dist/lib/elur/form.d.ts +283 -0
  39. package/dist/lib/elur/form.js +315 -0
  40. package/dist/lib/elur/form.js.map +1 -0
  41. package/dist/lib/elur/hydrate/index.cjs +2 -0
  42. package/dist/lib/elur/hydrate/index.cjs.map +1 -0
  43. package/dist/lib/elur/hydrate/index.d.cts +13 -0
  44. package/dist/lib/elur/hydrate/index.d.ts +13 -0
  45. package/dist/lib/elur/hydrate/index.js +410 -0
  46. package/dist/lib/elur/hydrate/index.js.map +1 -0
  47. package/dist/lib/elur/index.d.cts +19 -0
  48. package/dist/lib/elur/index.d.ts +19 -0
  49. package/dist/lib/elur/lifecycle.cjs +2 -0
  50. package/dist/lib/elur/lifecycle.cjs.map +1 -0
  51. package/dist/lib/elur/lifecycle.d.cts +45 -0
  52. package/dist/lib/elur/lifecycle.d.ts +45 -0
  53. package/dist/lib/elur/lifecycle.js +39 -0
  54. package/dist/lib/elur/lifecycle.js.map +1 -0
  55. package/dist/lib/elur/plugins.cjs +2 -0
  56. package/dist/lib/elur/plugins.cjs.map +1 -0
  57. package/dist/lib/elur/plugins.d.cts +48 -0
  58. package/dist/lib/elur/plugins.d.ts +48 -0
  59. package/dist/lib/elur/plugins.js +59 -0
  60. package/dist/lib/elur/plugins.js.map +1 -0
  61. package/dist/lib/elur/reactivity.cjs +2 -0
  62. package/dist/lib/elur/reactivity.cjs.map +1 -0
  63. package/dist/lib/elur/reactivity.d.cts +60 -0
  64. package/dist/lib/elur/reactivity.d.ts +60 -0
  65. package/dist/lib/elur/reactivity.js +188 -0
  66. package/dist/lib/elur/reactivity.js.map +1 -0
  67. package/dist/lib/elur/router.cjs +12 -0
  68. package/dist/lib/elur/router.cjs.map +1 -0
  69. package/dist/lib/elur/router.d.cts +137 -0
  70. package/dist/lib/elur/router.d.ts +137 -0
  71. package/dist/lib/elur/router.js +513 -0
  72. package/dist/lib/elur/router.js.map +1 -0
  73. package/dist/lib/elur/server/index.cjs +2 -0
  74. package/dist/lib/elur/server/index.cjs.map +1 -0
  75. package/dist/lib/elur/server/index.d.cts +44 -0
  76. package/dist/lib/elur/server/index.d.ts +44 -0
  77. package/dist/lib/elur/server/index.js +307 -0
  78. package/dist/lib/elur/server/index.js.map +1 -0
  79. package/dist/lib/elur/store.cjs +2 -0
  80. package/dist/lib/elur/store.cjs.map +1 -0
  81. package/dist/lib/elur/store.d.cts +137 -0
  82. package/dist/lib/elur/store.d.ts +137 -0
  83. package/dist/lib/elur/store.js +143 -0
  84. package/dist/lib/elur/store.js.map +1 -0
  85. package/dist/lib/elur/template/bindings.cjs +2 -0
  86. package/dist/lib/elur/template/bindings.cjs.map +1 -0
  87. package/dist/lib/elur/template/bindings.d.cts +40 -0
  88. package/dist/lib/elur/template/bindings.d.ts +40 -0
  89. package/dist/lib/elur/template/bindings.js +214 -0
  90. package/dist/lib/elur/template/bindings.js.map +1 -0
  91. package/dist/lib/elur/template/dom-write.cjs +2 -0
  92. package/dist/lib/elur/template/dom-write.cjs.map +1 -0
  93. package/dist/lib/elur/template/dom-write.d.cts +5 -0
  94. package/dist/lib/elur/template/dom-write.d.ts +5 -0
  95. package/dist/lib/elur/template/dom-write.js +16 -0
  96. package/dist/lib/elur/template/dom-write.js.map +1 -0
  97. package/dist/lib/elur/template/error-boundary.cjs +2 -0
  98. package/dist/lib/elur/template/error-boundary.cjs.map +1 -0
  99. package/dist/lib/elur/template/error-boundary.d.cts +7 -0
  100. package/dist/lib/elur/template/error-boundary.d.ts +7 -0
  101. package/dist/lib/elur/template/error-boundary.js +90 -0
  102. package/dist/lib/elur/template/error-boundary.js.map +1 -0
  103. package/dist/lib/elur/template/html.cjs +2 -0
  104. package/dist/lib/elur/template/html.cjs.map +1 -0
  105. package/dist/lib/elur/template/html.d.cts +8 -0
  106. package/dist/lib/elur/template/html.d.ts +8 -0
  107. package/dist/lib/elur/template/html.js +104 -0
  108. package/dist/lib/elur/template/html.js.map +1 -0
  109. package/dist/lib/elur/template/index.cjs +1 -0
  110. package/dist/lib/elur/template/index.d.cts +15 -0
  111. package/dist/lib/elur/template/index.d.ts +15 -0
  112. package/dist/lib/elur/template/index.js +13 -0
  113. package/dist/lib/elur/template/keyed-diff.cjs +2 -0
  114. package/dist/lib/elur/template/keyed-diff.cjs.map +1 -0
  115. package/dist/lib/elur/template/keyed-diff.d.cts +32 -0
  116. package/dist/lib/elur/template/keyed-diff.d.ts +32 -0
  117. package/dist/lib/elur/template/keyed-diff.js +100 -0
  118. package/dist/lib/elur/template/keyed-diff.js.map +1 -0
  119. package/dist/lib/elur/template/keyed.cjs +2 -0
  120. package/dist/lib/elur/template/keyed.cjs.map +1 -0
  121. package/dist/lib/elur/template/keyed.d.cts +27 -0
  122. package/dist/lib/elur/template/keyed.d.ts +27 -0
  123. package/dist/lib/elur/template/keyed.js +52 -0
  124. package/dist/lib/elur/template/keyed.js.map +1 -0
  125. package/dist/lib/elur/template/mount-helpers.cjs +2 -0
  126. package/dist/lib/elur/template/mount-helpers.cjs.map +1 -0
  127. package/dist/lib/elur/template/mount-helpers.d.cts +29 -0
  128. package/dist/lib/elur/template/mount-helpers.d.ts +29 -0
  129. package/dist/lib/elur/template/mount-helpers.js +132 -0
  130. package/dist/lib/elur/template/mount-helpers.js.map +1 -0
  131. package/dist/lib/elur/template/node-binding.cjs +2 -0
  132. package/dist/lib/elur/template/node-binding.cjs.map +1 -0
  133. package/dist/lib/elur/template/node-binding.d.cts +6 -0
  134. package/dist/lib/elur/template/node-binding.d.ts +6 -0
  135. package/dist/lib/elur/template/node-binding.js +95 -0
  136. package/dist/lib/elur/template/node-binding.js.map +1 -0
  137. package/dist/lib/elur/template/portal.cjs +2 -0
  138. package/dist/lib/elur/template/portal.cjs.map +1 -0
  139. package/dist/lib/elur/template/portal.d.cts +19 -0
  140. package/dist/lib/elur/template/portal.d.ts +19 -0
  141. package/dist/lib/elur/template/portal.js +49 -0
  142. package/dist/lib/elur/template/portal.js.map +1 -0
  143. package/dist/lib/elur/template/raw.cjs +2 -0
  144. package/dist/lib/elur/template/raw.cjs.map +1 -0
  145. package/dist/lib/elur/template/raw.d.cts +9 -0
  146. package/dist/lib/elur/template/raw.d.ts +9 -0
  147. package/dist/lib/elur/template/raw.js +29 -0
  148. package/dist/lib/elur/template/raw.js.map +1 -0
  149. package/dist/lib/elur/template/sanitize.cjs +2 -0
  150. package/dist/lib/elur/template/sanitize.cjs.map +1 -0
  151. package/dist/lib/elur/template/sanitize.d.cts +16 -0
  152. package/dist/lib/elur/template/sanitize.d.ts +16 -0
  153. package/dist/lib/elur/template/sanitize.js +29 -0
  154. package/dist/lib/elur/template/sanitize.js.map +1 -0
  155. package/dist/lib/elur/template/transitions.cjs +2 -0
  156. package/dist/lib/elur/template/transitions.cjs.map +1 -0
  157. package/dist/lib/elur/template/transitions.d.cts +43 -0
  158. package/dist/lib/elur/template/transitions.d.ts +43 -0
  159. package/dist/lib/elur/template/transitions.js +96 -0
  160. package/dist/lib/elur/template/transitions.js.map +1 -0
  161. package/dist/lib/elur/template/types.cjs +2 -0
  162. package/dist/lib/elur/template/types.cjs.map +1 -0
  163. package/dist/lib/elur/template/types.d.cts +114 -0
  164. package/dist/lib/elur/template/types.d.ts +114 -0
  165. package/dist/lib/elur/template/types.js +23 -0
  166. package/dist/lib/elur/template/types.js.map +1 -0
  167. package/dist/lib/elur.cjs +1 -0
  168. package/dist/lib/elur.js +18 -0
  169. package/dist/lib/form.cjs +2 -0
  170. package/dist/lib/form.js +315 -0
  171. package/dist/lib/hydrate.cjs +2 -0
  172. package/dist/lib/hydrate.js +410 -0
  173. package/dist/lib/index.cjs +1 -0
  174. package/dist/lib/index.d.cts +2 -0
  175. package/dist/lib/index.d.ts +2 -0
  176. package/dist/lib/index.js +18 -0
  177. package/dist/lib/lifecycle.cjs +2 -0
  178. package/dist/lib/lifecycle.js +39 -0
  179. package/dist/lib/plugins.cjs +2 -0
  180. package/dist/lib/plugins.js +59 -0
  181. package/dist/lib/router.cjs +12 -0
  182. package/dist/lib/router.js +513 -0
  183. package/dist/lib/server.cjs +2 -0
  184. package/dist/lib/server.js +307 -0
  185. package/dist/lib/signals.cjs +2 -0
  186. package/dist/lib/signals.js +188 -0
  187. package/dist/lib/store.cjs +2 -0
  188. package/dist/lib/store.js +143 -0
  189. package/dist/lib/template.cjs +1 -0
  190. package/dist/lib/template.js +13 -0
  191. package/package.json +216 -0
@@ -0,0 +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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"}
@@ -0,0 +1 @@
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`./elur/template/types.cjs`),t=require(`./elur/template/keyed.cjs`),n=require(`./elur/template/keyed-diff.cjs`),r=require(`./elur/template/dom-write.cjs`),i=require(`./elur/template/node-binding.cjs`),a=require(`./elur/template/sanitize.cjs`),o=require(`./elur/template/bindings.cjs`),s=require(`./elur/template/html.cjs`),c=require(`./elur/template/raw.cjs`),l=require(`./elur/template/transitions.cjs`),u=require(`./elur/template/portal.cjs`),d=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=o._activateBindingsWithNodes,exports._activateDelegatedEvent=o.activateDelegatedEvent,exports._activateNodeBinding=i.activateNodeBinding,exports._createKeyedMount=n.createKeyedMount,exports._ensureDelegatedEvent=o._ensureDelegatedEvent,exports._getKeyedSequence=t.getSequence,exports._queueDOMWrite=r.queueDOMWrite,exports._reconcileKeyedList=n.reconcileKeyedList,exports._setDelegatedEvent=o._setDelegatedEvent,exports.buildHTML=s.buildHTML,exports.createErrorBoundary=d.createErrorBoundary,exports.createPortalOutlet=u.createPortalOutlet,exports.html=s.html,exports.injectOutlet=u.injectOutlet,exports.isElurTemplate=e.isElurTemplate,exports.isExecutableAttrName=a.isExecutableAttrName,exports.isKeyedList=e.isKeyedList,exports.isUrlAttrName=a.isUrlAttrName,exports.portal=u.portal,exports.portalOutlet=u.portalOutlet,exports.provideOutlet=u.provideOutlet,exports.raw=c.raw,exports.ref=e.ref,exports.repeat=t.repeat,exports.sanitizeUrl=a.sanitizeUrl,exports.showWhen=o.showWhen,exports.templateFeatures=e.templateFeatures,exports.transition=l.transition;
@@ -0,0 +1,15 @@
1
+ export type { ElurTemplate, ElurMountHandle, ElurRef, KeyedList, KEntry, PortalOutlet, ErrorFallback, TransitionContent, TemplateBindingContext, TemplateDescriptor, ElurRenderProtocol, ServerRenderProtocolContext, DomProtocolContext, HydrationProtocolContext } from "./types.js";
2
+ export { ref, isElurTemplate, isKeyedList, COMMENT, ELUR_TEMPLATE_DESCRIPTOR, ELUR_RENDER_PROTOCOL, templateFeatures } from "./types.js";
3
+ export { html, buildHTML } from "./html.js";
4
+ export { raw } from "./raw.js";
5
+ export { showWhen } from "./bindings.js";
6
+ export { _activateBindingsWithNodes, activateDelegatedEvent as _activateDelegatedEvent, _ensureDelegatedEvent, _setDelegatedEvent, } from "./bindings.js";
7
+ export { activateNodeBinding as _activateNodeBinding } from "./node-binding.js";
8
+ export { queueDOMWrite as _queueDOMWrite } from "./dom-write.js";
9
+ export { sanitizeUrl, isUrlAttrName, isExecutableAttrName } from "./sanitize.js";
10
+ export { repeat, getSequence as _getKeyedSequence } from "./keyed.js";
11
+ export { createKeyedMount as _createKeyedMount, reconcileKeyedList as _reconcileKeyedList, } from "./keyed-diff.js";
12
+ export { transition } from "./transitions.js";
13
+ export type { TransitionOptions } from "./transitions.js";
14
+ export { portal, portalOutlet, createPortalOutlet, provideOutlet, injectOutlet } from "./portal.js";
15
+ export { createErrorBoundary } from "./error-boundary.js";
@@ -0,0 +1,15 @@
1
+ export type { ElurTemplate, ElurMountHandle, ElurRef, KeyedList, KEntry, PortalOutlet, ErrorFallback, TransitionContent, TemplateBindingContext, TemplateDescriptor, ElurRenderProtocol, ServerRenderProtocolContext, DomProtocolContext, HydrationProtocolContext } from "./types.js";
2
+ export { ref, isElurTemplate, isKeyedList, COMMENT, ELUR_TEMPLATE_DESCRIPTOR, ELUR_RENDER_PROTOCOL, templateFeatures } from "./types.js";
3
+ export { html, buildHTML } from "./html.js";
4
+ export { raw } from "./raw.js";
5
+ export { showWhen } from "./bindings.js";
6
+ export { _activateBindingsWithNodes, activateDelegatedEvent as _activateDelegatedEvent, _ensureDelegatedEvent, _setDelegatedEvent, } from "./bindings.js";
7
+ export { activateNodeBinding as _activateNodeBinding } from "./node-binding.js";
8
+ export { queueDOMWrite as _queueDOMWrite } from "./dom-write.js";
9
+ export { sanitizeUrl, isUrlAttrName, isExecutableAttrName } from "./sanitize.js";
10
+ export { repeat, getSequence as _getKeyedSequence } from "./keyed.js";
11
+ export { createKeyedMount as _createKeyedMount, reconcileKeyedList as _reconcileKeyedList, } from "./keyed-diff.js";
12
+ export { transition } from "./transitions.js";
13
+ export type { TransitionOptions } from "./transitions.js";
14
+ export { portal, portalOutlet, createPortalOutlet, provideOutlet, injectOutlet } from "./portal.js";
15
+ export { createErrorBoundary } from "./error-boundary.js";
@@ -0,0 +1,13 @@
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 { getSequence as s, repeat as c } from "./elur/template/keyed.js";
3
+ import { createKeyedMount as l, reconcileKeyedList as u } from "./elur/template/keyed-diff.js";
4
+ import { queueDOMWrite as d } from "./elur/template/dom-write.js";
5
+ import { activateNodeBinding as f } from "./elur/template/node-binding.js";
6
+ import { isExecutableAttrName as p, isUrlAttrName as m, sanitizeUrl as h } from "./elur/template/sanitize.js";
7
+ import { _activateBindingsWithNodes as g, _ensureDelegatedEvent as _, _setDelegatedEvent as v, activateDelegatedEvent as y, showWhen as b } from "./elur/template/bindings.js";
8
+ import { buildHTML as x, html as S } from "./elur/template/html.js";
9
+ import { raw as C } from "./elur/template/raw.js";
10
+ import { transition as w } from "./elur/template/transitions.js";
11
+ import { createPortalOutlet as T, injectOutlet as E, portal as D, portalOutlet as O, provideOutlet as k } from "./elur/template/portal.js";
12
+ import { createErrorBoundary as A } from "./elur/template/error-boundary.js";
13
+ export { e as COMMENT, t as ELUR_RENDER_PROTOCOL, n as ELUR_TEMPLATE_DESCRIPTOR, g as _activateBindingsWithNodes, y as _activateDelegatedEvent, f as _activateNodeBinding, l as _createKeyedMount, _ as _ensureDelegatedEvent, s as _getKeyedSequence, d as _queueDOMWrite, u as _reconcileKeyedList, v as _setDelegatedEvent, x as buildHTML, A as createErrorBoundary, T as createPortalOutlet, S as html, E as injectOutlet, r as isElurTemplate, p as isExecutableAttrName, i as isKeyedList, m as isUrlAttrName, D as portal, O as portalOutlet, k as provideOutlet, C as raw, a as ref, c as repeat, h as sanitizeUrl, b as showWhen, o as templateFeatures, w as transition };
@@ -0,0 +1,2 @@
1
+ const e=require(`../../signals.cjs`),t=require(`./types.cjs`),n=require(`../../lifecycle.cjs`),r=require(`./mount-helpers.cjs`),i=require(`./keyed.cjs`);function a(e){return(i,a,o)=>{if(n.isElurComponent(i))return r._mountComponentWithCtx(i,a,o,e);if(t.isElurTemplate(i))return i._render(a,o);if(i!=null&&i!==!1){let e=document.createTextNode(String(i));return a.insertBefore(e,o),()=>e.parentNode?.removeChild(e)}return()=>{}}}function o(t){let{zoneStart:n,anchor:r,state:a,prevOrder:o,list:s,mount:c}=t,l=r.parentNode;if(!l)return;let u=s.items.map((e,t)=>s.keyFn(e,t)),d=new Set(u),f=!1;if(a.size>0){for(let e of a.keys())if(d.has(e)){f=!0;break}}if(!f){if(a.size>0){let e=document.createRange();e.setStartAfter(n),e.setEndBefore(r),e.deleteContents();for(let e of a.values())e.cleanup();a.clear()}if(u.length>0){let n=document.createDocumentFragment();e.batch(()=>{for(let e=0;e<u.length;e++){let r=u[e],i=s.items[e],o=document.createTextNode(``),l=document.createTextNode(``);n.appendChild(o),n.appendChild(l);let d=c(s.renderFn(i,e),n,l);a.has(r)&&t.onDuplicateKey?.(r),a.set(r,{start:o,end:l,cleanup:d})}}),l.insertBefore(n,r)}o.length=0,o.push(...u);return}let p=new Map;for(let e=0;e<u.length;e++)p.set(u[e],e);let m=new Int32Array(u.length),h=!1,g=0;for(let e=0;e<o.length;e++){let t=o[e],n=p.get(t);if(n===void 0){let e=a.get(t);e.cleanup();let n=e.start;for(;n;){let t=n===e.end?null:n.nextSibling;if(n.parentNode?.removeChild(n),!t)break;n=t}a.delete(t)}else m[n]=e+1,n>=g?g=n:h=!0}let _=h?i.getSequence(m):[],v=_.length-1,y=r;for(let e=u.length-1;e>=0;e--){let n=u[e];if(m[e]===0){let r=s.items[e],i=document.createTextNode(``),o=document.createTextNode(``),u=document.createDocumentFragment();u.appendChild(i),u.appendChild(o);let d=c(s.renderFn(r,e),u,o);a.has(n)&&t.onDuplicateKey?.(n),a.set(n,{start:i,end:o,cleanup:d}),l.insertBefore(u,y),y=i}else{let t=a.get(n);if(h)if(v<0||e!==_[v]){let e=t.start;for(;e;){let n=e===t.end?null:e.nextSibling;if(l.insertBefore(e,y),!n)break;e=n}}else v--;y=t.start}}o.length=0,o.push(...u)}exports.createKeyedMount=a,exports.reconcileKeyedList=o;
2
+ //# sourceMappingURL=keyed-diff.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"keyed-diff.cjs","names":[],"sources":["../../../../src/elur/template/keyed-diff.ts"],"sourcesContent":["import { batch } from \"../reactivity.js\";\nimport { isElurComponent } from \"../lifecycle.js\";\nimport { _mountComponentWithCtx } from \"./mount-helpers.js\";\nimport { isElurTemplate, type KEntry, type KeyedList } from \"./types.js\";\nimport { getSequence, type RepeatKey } from \"./keyed.js\";\n\n// =============================================================================\n// --- Shared keyed list reconciliation (mount + hydrate) ---\n// =============================================================================\n\n/**\n * Mounts a single keyed item's rendered value before `endMarker` inside `parent`.\n * Used by the DOM renderer and the hydration renderer so both engines share the\n * exact same reconciliation semantics.\n */\nexport function createKeyedMount(\n ctxSnapshot: Map<unknown, unknown>[],\n): (rendered: unknown, parent: Node, endMarker: Node) => () => void {\n return (rendered: unknown, parent: Node, endMarker: Node): (() => void) => {\n if (isElurComponent(rendered)) {\n return _mountComponentWithCtx(rendered, parent, endMarker, ctxSnapshot);\n }\n if (isElurTemplate(rendered)) {\n return rendered._render(parent, endMarker);\n }\n if (rendered != null && rendered !== false) {\n const node = document.createTextNode(String(rendered));\n parent.insertBefore(node, endMarker);\n return () => node.parentNode?.removeChild(node);\n }\n return () => { };\n };\n}\n\nexport interface KeyedDiffOptions {\n /** Node marking the start of the keyed zone. */\n zoneStart: Node;\n /** End boundary; new content is inserted before this node. */\n anchor: Node;\n /** Live map of key → entry (start/end markers + cleanup). */\n state: Map<RepeatKey, KEntry>;\n /** Key order from the previous reconciliation pass. */\n prevOrder: RepeatKey[];\n /** The current keyed list value. */\n list: KeyedList;\n /** Mounts a freshly rendered item into the DOM. */\n mount: (rendered: unknown, parent: Node, endMarker: Node) => () => void;\n /** Context snapshot for component mounts inside the effect. */\n ctxSnapshot?: Map<unknown, unknown>[];\n /** Called when a duplicate key is encountered. */\n onDuplicateKey?: (key: RepeatKey) => void;\n}\n\n/**\n * Reconciles a keyed list between `zoneStart` and `anchor` using the same LIS\n * algorithm used by the DOM renderer. Total replacement (O(1)) when no key\n * survives; otherwise remove/insert/move with minimal DOM operations.\n */\nexport function reconcileKeyedList(opts: KeyedDiffOptions): void {\n const { zoneStart, anchor, state, prevOrder, list, mount } = opts;\n const parent = anchor.parentNode;\n if (!parent) return;\n\n const newKeyOrder: RepeatKey[] = list.items.map((item, idx) => list.keyFn(item as never, idx));\n const newKeySet = new Set(newKeyOrder);\n\n let anyKeysSurvive = false;\n if (state.size > 0) {\n for (const k of state.keys()) {\n if (newKeySet.has(k)) {\n anyKeysSurvive = true;\n break;\n }\n }\n }\n\n // 1. Initial render or total replacement (O(1) path)\n if (!anyKeysSurvive) {\n if (state.size > 0) {\n const range = document.createRange();\n range.setStartAfter(zoneStart);\n range.setEndBefore(anchor);\n range.deleteContents();\n for (const entry of state.values()) entry.cleanup();\n state.clear();\n }\n\n if (newKeyOrder.length > 0) {\n const frag = document.createDocumentFragment();\n batch(() => {\n for (let i = 0; i < newKeyOrder.length; i++) {\n const key = newKeyOrder[i];\n const item = list.items[i];\n const start = document.createTextNode(\"\") as unknown as Comment;\n const end = document.createTextNode(\"\") as unknown as Comment;\n\n frag.appendChild(start);\n frag.appendChild(end);\n\n const rendered = list.renderFn(item as never, i);\n const cleanup = mount(rendered, frag, end);\n\n if (state.has(key)) opts.onDuplicateKey?.(key);\n state.set(key, { start, end, cleanup });\n }\n });\n parent.insertBefore(frag, anchor);\n }\n prevOrder.length = 0;\n prevOrder.push(...newKeyOrder);\n return;\n }\n\n // 2. Reconciliation with LIS\n const keyToNewIndex = new Map<RepeatKey, number>();\n for (let i = 0; i < newKeyOrder.length; i++) {\n keyToNewIndex.set(newKeyOrder[i], i);\n }\n\n const newIndexToOldIndexMap = new Int32Array(newKeyOrder.length);\n let moved = false;\n let maxNewIndexSoFar = 0;\n\n for (let i = 0; i < prevOrder.length; i++) {\n const key = prevOrder[i];\n const newIndex = keyToNewIndex.get(key);\n\n if (newIndex === undefined) {\n const entry = state.get(key)!;\n entry.cleanup();\n let node: Node | null = entry.start;\n while (node) {\n const next: ChildNode | null = node === entry.end ? null : node.nextSibling;\n node.parentNode?.removeChild(node);\n if (!next) break;\n node = next;\n }\n state.delete(key);\n } else {\n newIndexToOldIndexMap[newIndex] = i + 1;\n if (newIndex >= maxNewIndexSoFar) {\n maxNewIndexSoFar = newIndex;\n } else {\n moved = true;\n }\n }\n }\n\n const increasingNewIndexSequence = moved ? getSequence(newIndexToOldIndexMap) : [];\n let j = increasingNewIndexSequence.length - 1;\n let insertionPoint: Node = anchor;\n\n for (let i = newKeyOrder.length - 1; i >= 0; i--) {\n const key = newKeyOrder[i];\n const isNew = newIndexToOldIndexMap[i] === 0;\n\n if (isNew) {\n const it = list.items[i];\n const sMarker = document.createTextNode(\"\") as unknown as Comment;\n const eMarker = document.createTextNode(\"\") as unknown as Comment;\n const frag = document.createDocumentFragment();\n\n frag.appendChild(sMarker);\n frag.appendChild(eMarker);\n\n const rendered = list.renderFn(it as never, i);\n const cleanup = mount(rendered, frag, eMarker);\n\n if (state.has(key)) opts.onDuplicateKey?.(key);\n state.set(key, { start: sMarker, end: eMarker, cleanup });\n parent.insertBefore(frag, insertionPoint);\n insertionPoint = sMarker;\n } else {\n const entry = state.get(key)!;\n if (moved) {\n if (j < 0 || i !== increasingNewIndexSequence[j]) {\n let node: Node | null = entry.start;\n while (node) {\n const next: ChildNode | null = node === entry.end ? null : node.nextSibling;\n parent.insertBefore(node, insertionPoint);\n if (!next) break;\n node = next;\n }\n } else {\n j--;\n }\n }\n insertionPoint = entry.start;\n }\n }\n\n prevOrder.length = 0;\n prevOrder.push(...newKeyOrder);\n}"],"mappings":"yJAeA,SAAgB,EACZ,EACgE,CAChE,OAAQ,EAAmB,EAAc,IAAkC,CACvE,GAAI,EAAA,gBAAgB,EAAS,CACzB,OAAO,EAAA,uBAAuB,EAAU,EAAQ,EAAW,EAAY,CAE3E,GAAI,EAAA,eAAe,EAAS,CACxB,OAAO,EAAS,QAAQ,EAAQ,EAAU,CAE9C,GAAI,GAAY,MAAQ,IAAa,GAAO,CACxC,IAAM,EAAO,SAAS,eAAe,OAAO,EAAS,CAAC,CAEtD,OADA,EAAO,aAAa,EAAM,EAAU,KACvB,EAAK,YAAY,YAAY,EAAK,CAEnD,UAAa,IA4BrB,SAAgB,EAAmB,EAA8B,CAC7D,GAAM,CAAE,YAAW,SAAQ,QAAO,YAAW,OAAM,SAAU,EACvD,EAAS,EAAO,WACtB,GAAI,CAAC,EAAQ,OAEb,IAAM,EAA2B,EAAK,MAAM,KAAK,EAAM,IAAQ,EAAK,MAAM,EAAe,EAAI,CAAC,CACxF,EAAY,IAAI,IAAI,EAAY,CAElC,EAAiB,GACrB,GAAI,EAAM,KAAO,OACR,IAAM,KAAK,EAAM,MAAM,CACxB,GAAI,EAAU,IAAI,EAAE,CAAE,CAClB,EAAiB,GACjB,OAMZ,GAAI,CAAC,EAAgB,CACjB,GAAI,EAAM,KAAO,EAAG,CAChB,IAAM,EAAQ,SAAS,aAAa,CACpC,EAAM,cAAc,EAAU,CAC9B,EAAM,aAAa,EAAO,CAC1B,EAAM,gBAAgB,CACtB,IAAK,IAAM,KAAS,EAAM,QAAQ,CAAE,EAAM,SAAS,CACnD,EAAM,OAAO,CAGjB,GAAI,EAAY,OAAS,EAAG,CACxB,IAAM,EAAO,SAAS,wBAAwB,CAC9C,EAAA,UAAY,CACR,IAAK,IAAI,EAAI,EAAG,EAAI,EAAY,OAAQ,IAAK,CACzC,IAAM,EAAM,EAAY,GAClB,EAAO,EAAK,MAAM,GAClB,EAAQ,SAAS,eAAe,GAAG,CACnC,EAAM,SAAS,eAAe,GAAG,CAEvC,EAAK,YAAY,EAAM,CACvB,EAAK,YAAY,EAAI,CAGrB,IAAM,EAAU,EADC,EAAK,SAAS,EAAe,EAAE,CAChB,EAAM,EAAI,CAEtC,EAAM,IAAI,EAAI,EAAE,EAAK,iBAAiB,EAAI,CAC9C,EAAM,IAAI,EAAK,CAAE,QAAO,MAAK,UAAS,CAAC,GAE7C,CACF,EAAO,aAAa,EAAM,EAAO,CAErC,EAAU,OAAS,EACnB,EAAU,KAAK,GAAG,EAAY,CAC9B,OAIJ,IAAM,EAAgB,IAAI,IAC1B,IAAK,IAAI,EAAI,EAAG,EAAI,EAAY,OAAQ,IACpC,EAAc,IAAI,EAAY,GAAI,EAAE,CAGxC,IAAM,EAAwB,IAAI,WAAW,EAAY,OAAO,CAC5D,EAAQ,GACR,EAAmB,EAEvB,IAAK,IAAI,EAAI,EAAG,EAAI,EAAU,OAAQ,IAAK,CACvC,IAAM,EAAM,EAAU,GAChB,EAAW,EAAc,IAAI,EAAI,CAEvC,GAAI,IAAa,IAAA,GAAW,CACxB,IAAM,EAAQ,EAAM,IAAI,EAAI,CAC5B,EAAM,SAAS,CACf,IAAI,EAAoB,EAAM,MAC9B,KAAO,GAAM,CACT,IAAM,EAAyB,IAAS,EAAM,IAAM,KAAO,EAAK,YAEhE,GADA,EAAK,YAAY,YAAY,EAAK,CAC9B,CAAC,EAAM,MACX,EAAO,EAEX,EAAM,OAAO,EAAI,MAEjB,EAAsB,GAAY,EAAI,EAClC,GAAY,EACZ,EAAmB,EAEnB,EAAQ,GAKpB,IAAM,EAA6B,EAAQ,EAAA,YAAY,EAAsB,CAAG,EAAE,CAC9E,EAAI,EAA2B,OAAS,EACxC,EAAuB,EAE3B,IAAK,IAAI,EAAI,EAAY,OAAS,EAAG,GAAK,EAAG,IAAK,CAC9C,IAAM,EAAM,EAAY,GAGxB,GAFc,EAAsB,KAAO,EAEhC,CACP,IAAM,EAAK,EAAK,MAAM,GAChB,EAAU,SAAS,eAAe,GAAG,CACrC,EAAU,SAAS,eAAe,GAAG,CACrC,EAAO,SAAS,wBAAwB,CAE9C,EAAK,YAAY,EAAQ,CACzB,EAAK,YAAY,EAAQ,CAGzB,IAAM,EAAU,EADC,EAAK,SAAS,EAAa,EAAE,CACd,EAAM,EAAQ,CAE1C,EAAM,IAAI,EAAI,EAAE,EAAK,iBAAiB,EAAI,CAC9C,EAAM,IAAI,EAAK,CAAE,MAAO,EAAS,IAAK,EAAS,UAAS,CAAC,CACzD,EAAO,aAAa,EAAM,EAAe,CACzC,EAAiB,MACd,CACH,IAAM,EAAQ,EAAM,IAAI,EAAI,CAC5B,GAAI,EACA,GAAI,EAAI,GAAK,IAAM,EAA2B,GAAI,CAC9C,IAAI,EAAoB,EAAM,MAC9B,KAAO,GAAM,CACT,IAAM,EAAyB,IAAS,EAAM,IAAM,KAAO,EAAK,YAEhE,GADA,EAAO,aAAa,EAAM,EAAe,CACrC,CAAC,EAAM,MACX,EAAO,QAGX,IAGR,EAAiB,EAAM,OAI/B,EAAU,OAAS,EACnB,EAAU,KAAK,GAAG,EAAY"}
@@ -0,0 +1,32 @@
1
+ import { type KEntry, type KeyedList } from "./types.js";
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;
@@ -0,0 +1,32 @@
1
+ import { type KEntry, type KeyedList } from "./types.js";
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;
@@ -0,0 +1,100 @@
1
+ import { batch as e } from "../../signals.js";
2
+ import { isElurTemplate as t } from "./types.js";
3
+ import { isElurComponent as n } from "../../lifecycle.js";
4
+ import { _mountComponentWithCtx as r } from "./mount-helpers.js";
5
+ import { getSequence as i } from "./keyed.js";
6
+ //#region src/elur/template/keyed-diff.ts
7
+ function a(e) {
8
+ return (i, a, o) => {
9
+ if (n(i)) return r(i, a, o, e);
10
+ if (t(i)) return i._render(a, o);
11
+ if (i != null && i !== !1) {
12
+ let e = document.createTextNode(String(i));
13
+ return a.insertBefore(e, o), () => e.parentNode?.removeChild(e);
14
+ }
15
+ return () => {};
16
+ };
17
+ }
18
+ function o(t) {
19
+ let { zoneStart: n, anchor: r, state: a, prevOrder: o, list: s, mount: c } = t, l = r.parentNode;
20
+ if (!l) return;
21
+ let u = s.items.map((e, t) => s.keyFn(e, t)), d = new Set(u), f = !1;
22
+ if (a.size > 0) {
23
+ for (let e of a.keys()) if (d.has(e)) {
24
+ f = !0;
25
+ break;
26
+ }
27
+ }
28
+ if (!f) {
29
+ if (a.size > 0) {
30
+ let e = document.createRange();
31
+ e.setStartAfter(n), e.setEndBefore(r), e.deleteContents();
32
+ for (let e of a.values()) e.cleanup();
33
+ a.clear();
34
+ }
35
+ if (u.length > 0) {
36
+ let n = document.createDocumentFragment();
37
+ e(() => {
38
+ for (let e = 0; e < u.length; e++) {
39
+ let r = u[e], i = s.items[e], o = document.createTextNode(""), l = document.createTextNode("");
40
+ n.appendChild(o), n.appendChild(l);
41
+ let d = c(s.renderFn(i, e), n, l);
42
+ a.has(r) && t.onDuplicateKey?.(r), a.set(r, {
43
+ start: o,
44
+ end: l,
45
+ cleanup: d
46
+ });
47
+ }
48
+ }), l.insertBefore(n, r);
49
+ }
50
+ o.length = 0, o.push(...u);
51
+ return;
52
+ }
53
+ let p = /* @__PURE__ */ new Map();
54
+ for (let e = 0; e < u.length; e++) p.set(u[e], e);
55
+ let m = new Int32Array(u.length), h = !1, g = 0;
56
+ for (let e = 0; e < o.length; e++) {
57
+ let t = o[e], n = p.get(t);
58
+ if (n === void 0) {
59
+ let e = a.get(t);
60
+ e.cleanup();
61
+ let n = e.start;
62
+ for (; n;) {
63
+ let t = n === e.end ? null : n.nextSibling;
64
+ if (n.parentNode?.removeChild(n), !t) break;
65
+ n = t;
66
+ }
67
+ a.delete(t);
68
+ } else m[n] = e + 1, n >= g ? g = n : h = !0;
69
+ }
70
+ let _ = h ? i(m) : [], v = _.length - 1, y = r;
71
+ for (let e = u.length - 1; e >= 0; e--) {
72
+ let n = u[e];
73
+ if (m[e] === 0) {
74
+ let r = s.items[e], i = document.createTextNode(""), o = document.createTextNode(""), u = document.createDocumentFragment();
75
+ u.appendChild(i), u.appendChild(o);
76
+ let d = c(s.renderFn(r, e), u, o);
77
+ a.has(n) && t.onDuplicateKey?.(n), a.set(n, {
78
+ start: i,
79
+ end: o,
80
+ cleanup: d
81
+ }), l.insertBefore(u, y), y = i;
82
+ } else {
83
+ let t = a.get(n);
84
+ if (h) if (v < 0 || e !== _[v]) {
85
+ let e = t.start;
86
+ for (; e;) {
87
+ let n = e === t.end ? null : e.nextSibling;
88
+ if (l.insertBefore(e, y), !n) break;
89
+ e = n;
90
+ }
91
+ } else v--;
92
+ y = t.start;
93
+ }
94
+ }
95
+ o.length = 0, o.push(...u);
96
+ }
97
+ //#endregion
98
+ export { a as createKeyedMount, o as reconcileKeyedList };
99
+
100
+ //# sourceMappingURL=keyed-diff.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"keyed-diff.js","names":[],"sources":["../../../../src/elur/template/keyed-diff.ts"],"sourcesContent":["import { batch } from \"../reactivity.js\";\nimport { isElurComponent } from \"../lifecycle.js\";\nimport { _mountComponentWithCtx } from \"./mount-helpers.js\";\nimport { isElurTemplate, type KEntry, type KeyedList } from \"./types.js\";\nimport { getSequence, type RepeatKey } from \"./keyed.js\";\n\n// =============================================================================\n// --- Shared keyed list reconciliation (mount + hydrate) ---\n// =============================================================================\n\n/**\n * Mounts a single keyed item's rendered value before `endMarker` inside `parent`.\n * Used by the DOM renderer and the hydration renderer so both engines share the\n * exact same reconciliation semantics.\n */\nexport function createKeyedMount(\n ctxSnapshot: Map<unknown, unknown>[],\n): (rendered: unknown, parent: Node, endMarker: Node) => () => void {\n return (rendered: unknown, parent: Node, endMarker: Node): (() => void) => {\n if (isElurComponent(rendered)) {\n return _mountComponentWithCtx(rendered, parent, endMarker, ctxSnapshot);\n }\n if (isElurTemplate(rendered)) {\n return rendered._render(parent, endMarker);\n }\n if (rendered != null && rendered !== false) {\n const node = document.createTextNode(String(rendered));\n parent.insertBefore(node, endMarker);\n return () => node.parentNode?.removeChild(node);\n }\n return () => { };\n };\n}\n\nexport interface KeyedDiffOptions {\n /** Node marking the start of the keyed zone. */\n zoneStart: Node;\n /** End boundary; new content is inserted before this node. */\n anchor: Node;\n /** Live map of key → entry (start/end markers + cleanup). */\n state: Map<RepeatKey, KEntry>;\n /** Key order from the previous reconciliation pass. */\n prevOrder: RepeatKey[];\n /** The current keyed list value. */\n list: KeyedList;\n /** Mounts a freshly rendered item into the DOM. */\n mount: (rendered: unknown, parent: Node, endMarker: Node) => () => void;\n /** Context snapshot for component mounts inside the effect. */\n ctxSnapshot?: Map<unknown, unknown>[];\n /** Called when a duplicate key is encountered. */\n onDuplicateKey?: (key: RepeatKey) => void;\n}\n\n/**\n * Reconciles a keyed list between `zoneStart` and `anchor` using the same LIS\n * algorithm used by the DOM renderer. Total replacement (O(1)) when no key\n * survives; otherwise remove/insert/move with minimal DOM operations.\n */\nexport function reconcileKeyedList(opts: KeyedDiffOptions): void {\n const { zoneStart, anchor, state, prevOrder, list, mount } = opts;\n const parent = anchor.parentNode;\n if (!parent) return;\n\n const newKeyOrder: RepeatKey[] = list.items.map((item, idx) => list.keyFn(item as never, idx));\n const newKeySet = new Set(newKeyOrder);\n\n let anyKeysSurvive = false;\n if (state.size > 0) {\n for (const k of state.keys()) {\n if (newKeySet.has(k)) {\n anyKeysSurvive = true;\n break;\n }\n }\n }\n\n // 1. Initial render or total replacement (O(1) path)\n if (!anyKeysSurvive) {\n if (state.size > 0) {\n const range = document.createRange();\n range.setStartAfter(zoneStart);\n range.setEndBefore(anchor);\n range.deleteContents();\n for (const entry of state.values()) entry.cleanup();\n state.clear();\n }\n\n if (newKeyOrder.length > 0) {\n const frag = document.createDocumentFragment();\n batch(() => {\n for (let i = 0; i < newKeyOrder.length; i++) {\n const key = newKeyOrder[i];\n const item = list.items[i];\n const start = document.createTextNode(\"\") as unknown as Comment;\n const end = document.createTextNode(\"\") as unknown as Comment;\n\n frag.appendChild(start);\n frag.appendChild(end);\n\n const rendered = list.renderFn(item as never, i);\n const cleanup = mount(rendered, frag, end);\n\n if (state.has(key)) opts.onDuplicateKey?.(key);\n state.set(key, { start, end, cleanup });\n }\n });\n parent.insertBefore(frag, anchor);\n }\n prevOrder.length = 0;\n prevOrder.push(...newKeyOrder);\n return;\n }\n\n // 2. Reconciliation with LIS\n const keyToNewIndex = new Map<RepeatKey, number>();\n for (let i = 0; i < newKeyOrder.length; i++) {\n keyToNewIndex.set(newKeyOrder[i], i);\n }\n\n const newIndexToOldIndexMap = new Int32Array(newKeyOrder.length);\n let moved = false;\n let maxNewIndexSoFar = 0;\n\n for (let i = 0; i < prevOrder.length; i++) {\n const key = prevOrder[i];\n const newIndex = keyToNewIndex.get(key);\n\n if (newIndex === undefined) {\n const entry = state.get(key)!;\n entry.cleanup();\n let node: Node | null = entry.start;\n while (node) {\n const next: ChildNode | null = node === entry.end ? null : node.nextSibling;\n node.parentNode?.removeChild(node);\n if (!next) break;\n node = next;\n }\n state.delete(key);\n } else {\n newIndexToOldIndexMap[newIndex] = i + 1;\n if (newIndex >= maxNewIndexSoFar) {\n maxNewIndexSoFar = newIndex;\n } else {\n moved = true;\n }\n }\n }\n\n const increasingNewIndexSequence = moved ? getSequence(newIndexToOldIndexMap) : [];\n let j = increasingNewIndexSequence.length - 1;\n let insertionPoint: Node = anchor;\n\n for (let i = newKeyOrder.length - 1; i >= 0; i--) {\n const key = newKeyOrder[i];\n const isNew = newIndexToOldIndexMap[i] === 0;\n\n if (isNew) {\n const it = list.items[i];\n const sMarker = document.createTextNode(\"\") as unknown as Comment;\n const eMarker = document.createTextNode(\"\") as unknown as Comment;\n const frag = document.createDocumentFragment();\n\n frag.appendChild(sMarker);\n frag.appendChild(eMarker);\n\n const rendered = list.renderFn(it as never, i);\n const cleanup = mount(rendered, frag, eMarker);\n\n if (state.has(key)) opts.onDuplicateKey?.(key);\n state.set(key, { start: sMarker, end: eMarker, cleanup });\n parent.insertBefore(frag, insertionPoint);\n insertionPoint = sMarker;\n } else {\n const entry = state.get(key)!;\n if (moved) {\n if (j < 0 || i !== increasingNewIndexSequence[j]) {\n let node: Node | null = entry.start;\n while (node) {\n const next: ChildNode | null = node === entry.end ? null : node.nextSibling;\n parent.insertBefore(node, insertionPoint);\n if (!next) break;\n node = next;\n }\n } else {\n j--;\n }\n }\n insertionPoint = entry.start;\n }\n }\n\n prevOrder.length = 0;\n prevOrder.push(...newKeyOrder);\n}"],"mappings":"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"}
@@ -0,0 +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;
2
+ //# sourceMappingURL=keyed.cjs.map
@@ -0,0 +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 `using positional fallback. Non-serializable keys cannot preserve identity across SSR/hydration.`,\n );\n return `__elur-key:${index}`;\n}\n\nexport function 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\nexport function 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\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,SAAgB,EAAa,EAAuB,CAChD,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,SAAgB,EAAe,EAAuB,CAClD,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"}
@@ -0,0 +1,27 @@
1
+ import type { ElurTemplate, KeyedList, KEntry } from "./types.js";
2
+ import type { ElurComponent } from "../lifecycle.js";
3
+ /**
4
+ * Creates a keyed list for efficient DOM reconciliation.
5
+ * Use instead of `.map()` when the list changes frequently.
6
+ */
7
+ export declare function repeat<T>(items: T[], keyFn: (item: T, index: number) => string | number, renderFn: (item: T, index: number) => ElurTemplate | ElurComponent): KeyedList<T>;
8
+ export type RepeatKey = string | number;
9
+ /**
10
+ * Normalizes a repeat() key to a serializable form. Keys must be strings or
11
+ * numbers to preserve identity across SSR/hydration. Anything else produces a
12
+ * diagnostic warning and a deterministic positional fallback so that server
13
+ * and client agree without silent `String(key)` collisions.
14
+ */
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
+ /** Serializes a repeat() key for the SSR keyed marker (base64 JSON, safe for HTML comments). */
19
+ export declare function serializeRepeatKey(key: RepeatKey): string;
20
+ /** Decodes a repeat() key from a keyed hydration marker. */
21
+ export declare function deserializeRepeatKey(serialized: string): RepeatKey;
22
+ /**
23
+ * Returns the indices of the Longest Increasing Subsequence.
24
+ * Used to minimize DOM operations during list diffing.
25
+ */
26
+ export declare function getSequence(arr: Int32Array | number[]): number[];
27
+ export type { KEntry };
@@ -0,0 +1,27 @@
1
+ import type { ElurTemplate, KeyedList, KEntry } from "./types.js";
2
+ import type { ElurComponent } from "../lifecycle.js";
3
+ /**
4
+ * Creates a keyed list for efficient DOM reconciliation.
5
+ * Use instead of `.map()` when the list changes frequently.
6
+ */
7
+ export declare function repeat<T>(items: T[], keyFn: (item: T, index: number) => string | number, renderFn: (item: T, index: number) => ElurTemplate | ElurComponent): KeyedList<T>;
8
+ export type RepeatKey = string | number;
9
+ /**
10
+ * Normalizes a repeat() key to a serializable form. Keys must be strings or
11
+ * numbers to preserve identity across SSR/hydration. Anything else produces a
12
+ * diagnostic warning and a deterministic positional fallback so that server
13
+ * and client agree without silent `String(key)` collisions.
14
+ */
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
+ /** Serializes a repeat() key for the SSR keyed marker (base64 JSON, safe for HTML comments). */
19
+ export declare function serializeRepeatKey(key: RepeatKey): string;
20
+ /** Decodes a repeat() key from a keyed hydration marker. */
21
+ export declare function deserializeRepeatKey(serialized: string): RepeatKey;
22
+ /**
23
+ * Returns the indices of the Longest Increasing Subsequence.
24
+ * Used to minimize DOM operations during list diffing.
25
+ */
26
+ export declare function getSequence(arr: Int32Array | number[]): number[];
27
+ export type { KEntry };
@@ -0,0 +1,52 @@
1
+ //#region src/elur/template/keyed.ts
2
+ function e(e, t, n) {
3
+ return {
4
+ __isKeyedList: !0,
5
+ items: e,
6
+ keyFn: t,
7
+ renderFn: n
8
+ };
9
+ }
10
+ function t(e, t) {
11
+ 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}`);
12
+ }
13
+ function n(e) {
14
+ let t = new TextEncoder().encode(e), n = "";
15
+ for (let e = 0; e < t.length; e += 32768) n += String.fromCharCode(...t.subarray(e, e + 32768));
16
+ return btoa(n);
17
+ }
18
+ function r(e) {
19
+ let t = atob(e), n = new Uint8Array(t.length);
20
+ for (let e = 0; e < t.length; e++) n[e] = t.charCodeAt(e);
21
+ return new TextDecoder().decode(n);
22
+ }
23
+ function i(e) {
24
+ return n(JSON.stringify(e));
25
+ }
26
+ function a(e) {
27
+ try {
28
+ let t = JSON.parse(r(e));
29
+ if (typeof t == "string" || typeof t == "number") return t;
30
+ } catch {}
31
+ return e;
32
+ }
33
+ function o(e) {
34
+ let t = e.slice(), n = [0], r, i, a, o, s, c = e.length;
35
+ for (r = 0; r < c; r++) {
36
+ let c = e[r];
37
+ if (c !== 0) {
38
+ if (i = n[n.length - 1], e[i] < c) {
39
+ t[r] = i, n.push(r);
40
+ continue;
41
+ }
42
+ for (a = 0, o = n.length - 1; a < o;) s = a + o >> 1, e[n[s]] < c ? a = s + 1 : o = s;
43
+ c < e[n[a]] && (a > 0 && (t[r] = n[a - 1]), n[a] = r);
44
+ }
45
+ }
46
+ for (a = n.length, o = n[a - 1]; a-- > 0;) n[a] = o, o = t[o];
47
+ return n;
48
+ }
49
+ //#endregion
50
+ export { a as deserializeRepeatKey, o as getSequence, t as normalizeRepeatKey, e as repeat, i as serializeRepeatKey };
51
+
52
+ //# sourceMappingURL=keyed.js.map
@@ -0,0 +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 `using positional fallback. Non-serializable keys cannot preserve identity across SSR/hydration.`,\n );\n return `__elur-key:${index}`;\n}\n\nexport function 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\nexport function 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\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,SAAgB,EAAa,GAAuB;CAChD,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,SAAgB,EAAe,GAAuB;CAClD,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"}
@@ -0,0 +1,2 @@
1
+ const e=require(`../../lifecycle.cjs`),t=require(`../../context.cjs`);function n(n,r,i){e._debugComponentMountStart(n),t._pushComponentContext();let a;try{try{n.onInit?.()}catch(e){if(n.onError)n.onError(e);else throw e}a=n.render()._render(r,i)}finally{e._debugComponentMountEnd(n),t._popComponentContext()}let o;try{let e=n.onMount?.();typeof e==`function`&&(o=e)}catch(e){if(n.onError)n.onError(e);else throw e}return()=>{try{n.onUnmount?.()}catch{}try{o?.()}catch{}a(),e._debugComponentUnmount(n)}}function r(n,r,i){e._debugComponentMountStart(n),t._pushComponentContext();let a;try{try{n.onInit?.()}catch{}a=n.render()._render(r,i)}finally{e._debugComponentMountEnd(n),t._popComponentContext()}let o;try{let e=n.onMount?.();typeof e==`function`&&(o=e)}catch{}return()=>{try{n.onUnmount?.()}catch{}try{o?.()}catch{}a(),e._debugComponentUnmount(n)}}function i(n,r,i,a){e._debugComponentMountStart(n);let o;try{t._withComponentContext(a,()=>{try{n.onInit?.()}catch(e){if(n.onError)n.onError(e);else throw e}o=n.render()._render(r,i)})}finally{e._debugComponentMountEnd(n)}let s;try{let e=n.onMount?.();typeof e==`function`&&(s=e)}catch(e){if(n.onError)n.onError(e);else throw e}return()=>{try{n.onUnmount?.()}catch{}try{s?.()}catch{}o(),e._debugComponentUnmount(n)}}function a(n,r,i,a,o){e._debugComponentMountStart(n),t._pushComponentContext();let s;try{try{n.onInit?.()}catch(e){if(n.onError)n.onError(e);else throw e}s=n.render()._render(r,i)}finally{e._debugComponentMountEnd(n),t._popComponentContext()}let c;a.push(()=>{try{let e=n.onMount?.();typeof e==`function`&&(c=e)}catch(e){if(n.onError)n.onError(e);else throw e}}),o.push(()=>{try{n.onUnmount?.()}catch{}try{c?.()}catch{}s(),e._debugComponentUnmount(n)})}exports._mountComponent=n,exports._mountComponentDeferred=a,exports._mountComponentSilent=r,exports._mountComponentWithCtx=i;
2
+ //# sourceMappingURL=mount-helpers.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mount-helpers.cjs","names":[],"sources":["../../../../src/elur/template/mount-helpers.ts"],"sourcesContent":["import {\n _debugComponentMountStart,\n _debugComponentMountEnd,\n _debugComponentUnmount,\n type ElurComponent,\n} from \"../lifecycle.js\";\nimport {\n _captureContextSnapshot,\n _pushComponentContext,\n _popComponentContext,\n _withComponentContext,\n} from \"../context.js\";\n\n// =============================================================================\n// --- Component mounting helpers ---\n// =============================================================================\n\n/**\n * Renders a ElurComponent into the DOM and calls onMount immediately.\n * Propagates errors through onError (or re-throws if not present).\n * Returns a full cleanup function (onUnmount + mountCleanup + renderCleanup).\n */\nexport function _mountComponent(\n inst: ElurComponent,\n parent: Node,\n before: Node | null,\n): () => void {\n _debugComponentMountStart(inst);\n _pushComponentContext();\n let renderCleanup!: () => void;\n try {\n try { inst.onInit?.(); } catch (e) { if (inst.onError) inst.onError(e); else throw e; }\n renderCleanup = inst.render()._render(parent, before);\n } finally {\n _debugComponentMountEnd(inst);\n _popComponentContext();\n }\n let mountCleanup: (() => void) | undefined;\n try {\n const ret = inst.onMount?.();\n if (typeof ret === \"function\") mountCleanup = ret;\n } catch (e) {\n if (inst.onError) inst.onError(e); else throw e;\n }\n return () => {\n try { inst.onUnmount?.(); } catch { /* ignore */ }\n try { mountCleanup?.(); } catch { /* ignore */ }\n renderCleanup();\n _debugComponentUnmount(inst);\n };\n}\n\n/**\n * Same as `_mountComponent` but silently swallows all lifecycle errors.\n * Used for transition content and error boundary fallbacks where errors\n * inside the fallback/transition itself must not propagate.\n */\nexport function _mountComponentSilent(\n inst: ElurComponent,\n parent: Node,\n before: Node | null,\n): () => void {\n _debugComponentMountStart(inst);\n _pushComponentContext();\n let renderCleanup!: () => void;\n try {\n try { inst.onInit?.(); } catch { /* ignore */ }\n renderCleanup = inst.render()._render(parent, before);\n } finally {\n _debugComponentMountEnd(inst);\n _popComponentContext();\n }\n let mountRet: (() => void) | undefined;\n try {\n const ret = inst.onMount?.();\n if (typeof ret === \"function\") mountRet = ret;\n } catch { /* ignore */ }\n return () => {\n try { inst.onUnmount?.(); } catch { /* ignore */ }\n try { mountRet?.(); } catch { /* ignore */ }\n renderCleanup();\n _debugComponentUnmount(inst);\n };\n}\n\n/**\n * Renders a ElurComponent using a captured context snapshot.\n * Used for dynamic/keyed rendering inside reactive effects, where the\n * provide/inject context must be inherited from the point of declaration.\n * Calls onMount immediately. Returns a full cleanup function.\n */\nexport function _mountComponentWithCtx(\n inst: ElurComponent,\n parent: Node,\n before: Node | null,\n ctxSnapshot: ReturnType<typeof _captureContextSnapshot>,\n): () => void {\n _debugComponentMountStart(inst);\n let renderCleanup!: () => void;\n try {\n _withComponentContext(ctxSnapshot, () => {\n try { inst.onInit?.(); } catch (e) { if (inst.onError) inst.onError(e); else throw e; }\n renderCleanup = inst.render()._render(parent, before);\n });\n } finally {\n _debugComponentMountEnd(inst);\n }\n let mountCleanup: (() => void) | undefined;\n try {\n const ret = inst.onMount?.();\n if (typeof ret === \"function\") mountCleanup = ret;\n } catch (e) {\n if (inst.onError) inst.onError(e); else throw e;\n }\n return () => {\n try { inst.onUnmount?.(); } catch { /* ignore */ }\n try { mountCleanup?.(); } catch { /* ignore */ }\n renderCleanup();\n _debugComponentUnmount(inst);\n };\n}\n\n/**\n * Renders a ElurComponent with *deferred* onMount — used inside `html` template\n * fragments where the DOM nodes are still in a DocumentFragment and onMount must\n * fire only after the fragment is inserted into the live document.\n *\n * Pushes the full cleanup into `disposes` and the onMount call into `postMountHooks`.\n */\nexport function _mountComponentDeferred(\n inst: ElurComponent,\n parent: Node,\n before: Node | null,\n postMountHooks: Array<() => void>,\n disposes: Array<() => void>,\n): void {\n _debugComponentMountStart(inst);\n _pushComponentContext();\n let renderCleanup!: () => void;\n try {\n try { inst.onInit?.(); } catch (e) { if (inst.onError) inst.onError(e); else throw e; }\n renderCleanup = inst.render()._render(parent, before);\n } finally {\n _debugComponentMountEnd(inst);\n _popComponentContext();\n }\n let mountCleanup: (() => void) | undefined;\n postMountHooks.push(() => {\n try {\n const ret = inst.onMount?.();\n if (typeof ret === \"function\") mountCleanup = ret;\n } catch (e) {\n if (inst.onError) inst.onError(e); else throw e;\n }\n });\n disposes.push(() => {\n try { inst.onUnmount?.(); } catch { /* ignore */ }\n try { mountCleanup?.(); } catch { /* ignore */ }\n renderCleanup();\n _debugComponentUnmount(inst);\n });\n}\n"],"mappings":"sEAsBA,SAAgB,EACZ,EACA,EACA,EACU,CACV,EAAA,0BAA0B,EAAK,CAC/B,EAAA,uBAAuB,CACvB,IAAI,EACJ,GAAI,CACA,GAAI,CAAE,EAAK,UAAU,OAAW,EAAG,CAAE,GAAI,EAAK,QAAS,EAAK,QAAQ,EAAE,MAAO,MAAM,EACnF,EAAgB,EAAK,QAAQ,CAAC,QAAQ,EAAQ,EAAO,QAC/C,CACN,EAAA,wBAAwB,EAAK,CAC7B,EAAA,sBAAsB,CAE1B,IAAI,EACJ,GAAI,CACA,IAAM,EAAM,EAAK,WAAW,CACxB,OAAO,GAAQ,aAAY,EAAe,SACzC,EAAG,CACR,GAAI,EAAK,QAAS,EAAK,QAAQ,EAAE,MAAO,MAAM,EAElD,UAAa,CACT,GAAI,CAAE,EAAK,aAAa,MAAU,EAClC,GAAI,CAAE,KAAgB,MAAU,EAChC,GAAe,CACf,EAAA,uBAAuB,EAAK,EASpC,SAAgB,EACZ,EACA,EACA,EACU,CACV,EAAA,0BAA0B,EAAK,CAC/B,EAAA,uBAAuB,CACvB,IAAI,EACJ,GAAI,CACA,GAAI,CAAE,EAAK,UAAU,MAAU,EAC/B,EAAgB,EAAK,QAAQ,CAAC,QAAQ,EAAQ,EAAO,QAC/C,CACN,EAAA,wBAAwB,EAAK,CAC7B,EAAA,sBAAsB,CAE1B,IAAI,EACJ,GAAI,CACA,IAAM,EAAM,EAAK,WAAW,CACxB,OAAO,GAAQ,aAAY,EAAW,QACtC,EACR,UAAa,CACT,GAAI,CAAE,EAAK,aAAa,MAAU,EAClC,GAAI,CAAE,KAAY,MAAU,EAC5B,GAAe,CACf,EAAA,uBAAuB,EAAK,EAUpC,SAAgB,EACZ,EACA,EACA,EACA,EACU,CACV,EAAA,0BAA0B,EAAK,CAC/B,IAAI,EACJ,GAAI,CACA,EAAA,sBAAsB,MAAmB,CACrC,GAAI,CAAE,EAAK,UAAU,OAAW,EAAG,CAAE,GAAI,EAAK,QAAS,EAAK,QAAQ,EAAE,MAAO,MAAM,EACnF,EAAgB,EAAK,QAAQ,CAAC,QAAQ,EAAQ,EAAO,EACvD,QACI,CACN,EAAA,wBAAwB,EAAK,CAEjC,IAAI,EACJ,GAAI,CACA,IAAM,EAAM,EAAK,WAAW,CACxB,OAAO,GAAQ,aAAY,EAAe,SACzC,EAAG,CACR,GAAI,EAAK,QAAS,EAAK,QAAQ,EAAE,MAAO,MAAM,EAElD,UAAa,CACT,GAAI,CAAE,EAAK,aAAa,MAAU,EAClC,GAAI,CAAE,KAAgB,MAAU,EAChC,GAAe,CACf,EAAA,uBAAuB,EAAK,EAWpC,SAAgB,EACZ,EACA,EACA,EACA,EACA,EACI,CACJ,EAAA,0BAA0B,EAAK,CAC/B,EAAA,uBAAuB,CACvB,IAAI,EACJ,GAAI,CACA,GAAI,CAAE,EAAK,UAAU,OAAW,EAAG,CAAE,GAAI,EAAK,QAAS,EAAK,QAAQ,EAAE,MAAO,MAAM,EACnF,EAAgB,EAAK,QAAQ,CAAC,QAAQ,EAAQ,EAAO,QAC/C,CACN,EAAA,wBAAwB,EAAK,CAC7B,EAAA,sBAAsB,CAE1B,IAAI,EACJ,EAAe,SAAW,CACtB,GAAI,CACA,IAAM,EAAM,EAAK,WAAW,CACxB,OAAO,GAAQ,aAAY,EAAe,SACzC,EAAG,CACR,GAAI,EAAK,QAAS,EAAK,QAAQ,EAAE,MAAO,MAAM,IAEpD,CACF,EAAS,SAAW,CAChB,GAAI,CAAE,EAAK,aAAa,MAAU,EAClC,GAAI,CAAE,KAAgB,MAAU,EAChC,GAAe,CACf,EAAA,uBAAuB,EAAK,EAC9B"}
@@ -0,0 +1,29 @@
1
+ import { type ElurComponent } from "../lifecycle.js";
2
+ import { _captureContextSnapshot } from "../context.js";
3
+ /**
4
+ * Renders a ElurComponent into the DOM and calls onMount immediately.
5
+ * Propagates errors through onError (or re-throws if not present).
6
+ * Returns a full cleanup function (onUnmount + mountCleanup + renderCleanup).
7
+ */
8
+ export declare function _mountComponent(inst: ElurComponent, parent: Node, before: Node | null): () => void;
9
+ /**
10
+ * Same as `_mountComponent` but silently swallows all lifecycle errors.
11
+ * Used for transition content and error boundary fallbacks where errors
12
+ * inside the fallback/transition itself must not propagate.
13
+ */
14
+ export declare function _mountComponentSilent(inst: ElurComponent, parent: Node, before: Node | null): () => void;
15
+ /**
16
+ * Renders a ElurComponent using a captured context snapshot.
17
+ * Used for dynamic/keyed rendering inside reactive effects, where the
18
+ * provide/inject context must be inherited from the point of declaration.
19
+ * Calls onMount immediately. Returns a full cleanup function.
20
+ */
21
+ export declare function _mountComponentWithCtx(inst: ElurComponent, parent: Node, before: Node | null, ctxSnapshot: ReturnType<typeof _captureContextSnapshot>): () => void;
22
+ /**
23
+ * Renders a ElurComponent with *deferred* onMount — used inside `html` template
24
+ * fragments where the DOM nodes are still in a DocumentFragment and onMount must
25
+ * fire only after the fragment is inserted into the live document.
26
+ *
27
+ * Pushes the full cleanup into `disposes` and the onMount call into `postMountHooks`.
28
+ */
29
+ export declare function _mountComponentDeferred(inst: ElurComponent, parent: Node, before: Node | null, postMountHooks: Array<() => void>, disposes: Array<() => void>): void;
@@ -0,0 +1,29 @@
1
+ import { type ElurComponent } from "../lifecycle.js";
2
+ import { _captureContextSnapshot } from "../context.js";
3
+ /**
4
+ * Renders a ElurComponent into the DOM and calls onMount immediately.
5
+ * Propagates errors through onError (or re-throws if not present).
6
+ * Returns a full cleanup function (onUnmount + mountCleanup + renderCleanup).
7
+ */
8
+ export declare function _mountComponent(inst: ElurComponent, parent: Node, before: Node | null): () => void;
9
+ /**
10
+ * Same as `_mountComponent` but silently swallows all lifecycle errors.
11
+ * Used for transition content and error boundary fallbacks where errors
12
+ * inside the fallback/transition itself must not propagate.
13
+ */
14
+ export declare function _mountComponentSilent(inst: ElurComponent, parent: Node, before: Node | null): () => void;
15
+ /**
16
+ * Renders a ElurComponent using a captured context snapshot.
17
+ * Used for dynamic/keyed rendering inside reactive effects, where the
18
+ * provide/inject context must be inherited from the point of declaration.
19
+ * Calls onMount immediately. Returns a full cleanup function.
20
+ */
21
+ export declare function _mountComponentWithCtx(inst: ElurComponent, parent: Node, before: Node | null, ctxSnapshot: ReturnType<typeof _captureContextSnapshot>): () => void;
22
+ /**
23
+ * Renders a ElurComponent with *deferred* onMount — used inside `html` template
24
+ * fragments where the DOM nodes are still in a DocumentFragment and onMount must
25
+ * fire only after the fragment is inserted into the live document.
26
+ *
27
+ * Pushes the full cleanup into `disposes` and the onMount call into `postMountHooks`.
28
+ */
29
+ export declare function _mountComponentDeferred(inst: ElurComponent, parent: Node, before: Node | null, postMountHooks: Array<() => void>, disposes: Array<() => void>): void;