@elurjs/core 3.6.1 → 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.
Files changed (213) hide show
  1. package/dist/lib/async.cjs +1 -1
  2. package/dist/lib/async.js +1 -1
  3. package/dist/lib/component.cjs +1 -2
  4. package/dist/lib/component.js +2 -66
  5. package/dist/lib/context.cjs +1 -1
  6. package/dist/lib/context.js +35 -23
  7. package/dist/lib/devtools.cjs +1 -1
  8. package/dist/lib/devtools.js +1 -1
  9. package/dist/lib/elur/async.cjs +1 -1
  10. package/dist/lib/elur/async.cjs.map +1 -1
  11. package/dist/lib/elur/async.js +1 -1
  12. package/dist/lib/elur/component.cjs +1 -2
  13. package/dist/lib/elur/component.d.cts +1 -17
  14. package/dist/lib/elur/component.d.ts +1 -17
  15. package/dist/lib/elur/component.js +2 -66
  16. package/dist/lib/elur/context.cjs +1 -1
  17. package/dist/lib/elur/context.cjs.map +1 -1
  18. package/dist/lib/elur/context.d.cts +5 -0
  19. package/dist/lib/elur/context.d.ts +5 -0
  20. package/dist/lib/elur/context.js +35 -23
  21. package/dist/lib/elur/context.js.map +1 -1
  22. package/dist/lib/elur/devtools.cjs +1 -1
  23. package/dist/lib/elur/devtools.cjs.map +1 -1
  24. package/dist/lib/elur/devtools.js +1 -1
  25. package/dist/lib/elur/form.cjs +1 -1
  26. package/dist/lib/elur/form.cjs.map +1 -1
  27. package/dist/lib/elur/form.js +1 -1
  28. package/dist/lib/elur/hydrate/index.cjs +1 -2
  29. package/dist/lib/elur/hydrate/index.d.cts +1 -13
  30. package/dist/lib/elur/hydrate/index.d.ts +1 -13
  31. package/dist/lib/elur/hydrate/index.js +2 -410
  32. package/dist/lib/elur/lifecycle.cjs +1 -1
  33. package/dist/lib/elur/lifecycle.cjs.map +1 -1
  34. package/dist/lib/elur/lifecycle.d.cts +27 -0
  35. package/dist/lib/elur/lifecycle.d.ts +27 -0
  36. package/dist/lib/elur/lifecycle.js +4 -0
  37. package/dist/lib/elur/lifecycle.js.map +1 -1
  38. package/dist/lib/elur/next/component.d.cts +281 -0
  39. package/dist/lib/elur/next/component.d.ts +281 -0
  40. package/dist/lib/elur/next/dom-write.d.cts +18 -0
  41. package/dist/lib/elur/next/dom-write.d.ts +18 -0
  42. package/dist/lib/elur/next/hydrate.d.cts +14 -0
  43. package/dist/lib/elur/next/hydrate.d.ts +14 -0
  44. package/dist/lib/elur/next/keyed-diff.d.cts +46 -0
  45. package/dist/lib/elur/next/keyed-diff.d.ts +46 -0
  46. package/dist/lib/elur/next/mount-helpers.d.cts +25 -0
  47. package/dist/lib/elur/next/mount-helpers.d.ts +25 -0
  48. package/dist/lib/elur/next/mount.d.cts +29 -0
  49. package/dist/lib/elur/next/mount.d.ts +29 -0
  50. package/dist/lib/elur/next/node-binding.d.cts +6 -0
  51. package/dist/lib/elur/next/node-binding.d.ts +6 -0
  52. package/dist/lib/elur/next/reactivity.d.cts +193 -0
  53. package/dist/lib/elur/next/reactivity.d.ts +193 -0
  54. package/dist/lib/elur/next-2/component.cjs +2 -0
  55. package/dist/lib/elur/next-2/component.cjs.map +1 -0
  56. package/dist/lib/elur/next-2/component.d.cts +283 -0
  57. package/dist/lib/elur/next-2/component.d.ts +283 -0
  58. package/dist/lib/elur/next-2/component.js +340 -0
  59. package/dist/lib/elur/next-2/component.js.map +1 -0
  60. package/dist/lib/elur/next-2/dom-write.cjs +2 -0
  61. package/dist/lib/elur/next-2/dom-write.cjs.map +1 -0
  62. package/dist/lib/elur/next-2/dom-write.d.cts +18 -0
  63. package/dist/lib/elur/next-2/dom-write.d.ts +18 -0
  64. package/dist/lib/elur/next-2/dom-write.js +31 -0
  65. package/dist/lib/elur/next-2/dom-write.js.map +1 -0
  66. package/dist/lib/elur/next-2/hydrate.cjs +2 -0
  67. package/dist/lib/elur/next-2/hydrate.cjs.map +1 -0
  68. package/dist/lib/elur/next-2/hydrate.d.cts +30 -0
  69. package/dist/lib/elur/next-2/hydrate.d.ts +30 -0
  70. package/dist/lib/elur/next-2/hydrate.js +449 -0
  71. package/dist/lib/elur/next-2/hydrate.js.map +1 -0
  72. package/dist/lib/elur/next-2/keyed-diff.cjs +2 -0
  73. package/dist/lib/elur/next-2/keyed-diff.cjs.map +1 -0
  74. package/dist/lib/elur/next-2/keyed-diff.d.cts +79 -0
  75. package/dist/lib/elur/next-2/keyed-diff.d.ts +79 -0
  76. package/dist/lib/elur/next-2/keyed-diff.js +208 -0
  77. package/dist/lib/elur/next-2/keyed-diff.js.map +1 -0
  78. package/dist/lib/elur/next-2/mount-helpers.cjs +2 -0
  79. package/dist/lib/elur/next-2/mount-helpers.cjs.map +1 -0
  80. package/dist/lib/elur/next-2/mount-helpers.d.cts +25 -0
  81. package/dist/lib/elur/next-2/mount-helpers.d.ts +25 -0
  82. package/dist/lib/elur/next-2/mount-helpers.js +87 -0
  83. package/dist/lib/elur/next-2/mount-helpers.js.map +1 -0
  84. package/dist/lib/elur/next-2/mount.cjs +2 -0
  85. package/dist/lib/elur/next-2/mount.cjs.map +1 -0
  86. package/dist/lib/elur/next-2/mount.d.cts +29 -0
  87. package/dist/lib/elur/next-2/mount.d.ts +29 -0
  88. package/dist/lib/elur/next-2/mount.js +34 -0
  89. package/dist/lib/elur/next-2/mount.js.map +1 -0
  90. package/dist/lib/elur/next-2/node-binding.cjs +2 -0
  91. package/dist/lib/elur/next-2/node-binding.cjs.map +1 -0
  92. package/dist/lib/elur/next-2/node-binding.d.cts +6 -0
  93. package/dist/lib/elur/next-2/node-binding.d.ts +6 -0
  94. package/dist/lib/elur/next-2/node-binding.js +130 -0
  95. package/dist/lib/elur/next-2/node-binding.js.map +1 -0
  96. package/dist/lib/elur/next-2/reactivity.cjs +2 -0
  97. package/dist/lib/elur/next-2/reactivity.cjs.map +1 -0
  98. package/dist/lib/elur/next-2/reactivity.d.cts +220 -0
  99. package/dist/lib/elur/next-2/reactivity.d.ts +220 -0
  100. package/dist/lib/elur/next-2/reactivity.js +614 -0
  101. package/dist/lib/elur/next-2/reactivity.js.map +1 -0
  102. package/dist/lib/elur/next-2/scheduler.cjs +2 -0
  103. package/dist/lib/elur/next-2/scheduler.cjs.map +1 -0
  104. package/dist/lib/elur/next-2/scheduler.d.cts +23 -0
  105. package/dist/lib/elur/next-2/scheduler.d.ts +23 -0
  106. package/dist/lib/elur/next-2/scheduler.js +26 -0
  107. package/dist/lib/elur/next-2/scheduler.js.map +1 -0
  108. package/dist/lib/elur/plugins.cjs +1 -1
  109. package/dist/lib/elur/plugins.cjs.map +1 -1
  110. package/dist/lib/elur/plugins.js +1 -1
  111. package/dist/lib/elur/reactivity.cjs +1 -2
  112. package/dist/lib/elur/reactivity.d.cts +1 -67
  113. package/dist/lib/elur/reactivity.d.ts +1 -67
  114. package/dist/lib/elur/reactivity.js +2 -218
  115. package/dist/lib/elur/router.cjs +2 -2
  116. package/dist/lib/elur/router.cjs.map +1 -1
  117. package/dist/lib/elur/router.js +2 -2
  118. package/dist/lib/elur/router.js.map +1 -1
  119. package/dist/lib/elur/server/index.cjs +1 -1
  120. package/dist/lib/elur/server/index.cjs.map +1 -1
  121. package/dist/lib/elur/server/index.js +180 -108
  122. package/dist/lib/elur/server/index.js.map +1 -1
  123. package/dist/lib/elur/store.cjs +1 -1
  124. package/dist/lib/elur/store.cjs.map +1 -1
  125. package/dist/lib/elur/store.js +10 -4
  126. package/dist/lib/elur/store.js.map +1 -1
  127. package/dist/lib/elur/template/bindings.cjs +1 -1
  128. package/dist/lib/elur/template/bindings.cjs.map +1 -1
  129. package/dist/lib/elur/template/bindings.js +98 -84
  130. package/dist/lib/elur/template/bindings.js.map +1 -1
  131. package/dist/lib/elur/template/dom-write.d.cts +1 -5
  132. package/dist/lib/elur/template/dom-write.d.ts +1 -5
  133. package/dist/lib/elur/template/error-boundary.cjs +1 -1
  134. package/dist/lib/elur/template/error-boundary.cjs.map +1 -1
  135. package/dist/lib/elur/template/error-boundary.js +56 -50
  136. package/dist/lib/elur/template/error-boundary.js.map +1 -1
  137. package/dist/lib/elur/template/html.cjs +1 -1
  138. package/dist/lib/elur/template/html.cjs.map +1 -1
  139. package/dist/lib/elur/template/html.js +40 -37
  140. package/dist/lib/elur/template/html.js.map +1 -1
  141. package/dist/lib/elur/template/index.cjs +1 -1
  142. package/dist/lib/elur/template/index.d.cts +2 -1
  143. package/dist/lib/elur/template/index.d.ts +2 -1
  144. package/dist/lib/elur/template/index.js +13 -12
  145. package/dist/lib/elur/template/keyed-diff.d.cts +1 -32
  146. package/dist/lib/elur/template/keyed-diff.d.ts +1 -32
  147. package/dist/lib/elur/template/keyed.cjs +1 -1
  148. package/dist/lib/elur/template/keyed.cjs.map +1 -1
  149. package/dist/lib/elur/template/keyed.d.cts +10 -2
  150. package/dist/lib/elur/template/keyed.d.ts +10 -2
  151. package/dist/lib/elur/template/keyed.js +12 -1
  152. package/dist/lib/elur/template/keyed.js.map +1 -1
  153. package/dist/lib/elur/template/mount-helpers.d.cts +1 -29
  154. package/dist/lib/elur/template/mount-helpers.d.ts +1 -29
  155. package/dist/lib/elur/template/node-binding.d.cts +1 -6
  156. package/dist/lib/elur/template/node-binding.d.ts +1 -6
  157. package/dist/lib/elur/template/portal.cjs +1 -1
  158. package/dist/lib/elur/template/portal.cjs.map +1 -1
  159. package/dist/lib/elur/template/portal.js +1 -1
  160. package/dist/lib/elur/template/transitions.cjs +1 -1
  161. package/dist/lib/elur/template/transitions.cjs.map +1 -1
  162. package/dist/lib/elur/template/transitions.js +2 -2
  163. package/dist/lib/elur/template/types.cjs +1 -1
  164. package/dist/lib/elur/template/types.cjs.map +1 -1
  165. package/dist/lib/elur/template/types.d.cts +55 -0
  166. package/dist/lib/elur/template/types.d.ts +55 -0
  167. package/dist/lib/elur/template/types.js +5 -1
  168. package/dist/lib/elur/template/types.js.map +1 -1
  169. package/dist/lib/elur.cjs +1 -1
  170. package/dist/lib/elur.js +2 -2
  171. package/dist/lib/form.cjs +1 -1
  172. package/dist/lib/form.js +1 -1
  173. package/dist/lib/hydrate.cjs +1 -2
  174. package/dist/lib/hydrate.js +2 -410
  175. package/dist/lib/index.cjs +1 -1
  176. package/dist/lib/index.js +2 -2
  177. package/dist/lib/lifecycle.cjs +1 -1
  178. package/dist/lib/lifecycle.js +4 -0
  179. package/dist/lib/plugins.cjs +1 -1
  180. package/dist/lib/plugins.js +1 -1
  181. package/dist/lib/router.cjs +2 -2
  182. package/dist/lib/router.js +2 -2
  183. package/dist/lib/server.cjs +1 -1
  184. package/dist/lib/server.js +180 -108
  185. package/dist/lib/signals.cjs +1 -2
  186. package/dist/lib/signals.js +2 -218
  187. package/dist/lib/store.cjs +1 -1
  188. package/dist/lib/store.js +10 -4
  189. package/dist/lib/template.cjs +1 -1
  190. package/dist/lib/template.js +13 -12
  191. package/package.json +7 -9
  192. package/dist/lib/elur/component.cjs.map +0 -1
  193. package/dist/lib/elur/component.js.map +0 -1
  194. package/dist/lib/elur/hydrate/index.cjs.map +0 -1
  195. package/dist/lib/elur/hydrate/index.js.map +0 -1
  196. package/dist/lib/elur/reactivity.cjs.map +0 -1
  197. package/dist/lib/elur/reactivity.js.map +0 -1
  198. package/dist/lib/elur/template/dom-write.cjs +0 -2
  199. package/dist/lib/elur/template/dom-write.cjs.map +0 -1
  200. package/dist/lib/elur/template/dom-write.js +0 -16
  201. package/dist/lib/elur/template/dom-write.js.map +0 -1
  202. package/dist/lib/elur/template/keyed-diff.cjs +0 -2
  203. package/dist/lib/elur/template/keyed-diff.cjs.map +0 -1
  204. package/dist/lib/elur/template/keyed-diff.js +0 -100
  205. package/dist/lib/elur/template/keyed-diff.js.map +0 -1
  206. package/dist/lib/elur/template/mount-helpers.cjs +0 -2
  207. package/dist/lib/elur/template/mount-helpers.cjs.map +0 -1
  208. package/dist/lib/elur/template/mount-helpers.js +0 -132
  209. package/dist/lib/elur/template/mount-helpers.js.map +0 -1
  210. package/dist/lib/elur/template/node-binding.cjs +0 -2
  211. package/dist/lib/elur/template/node-binding.cjs.map +0 -1
  212. package/dist/lib/elur/template/node-binding.js +0 -95
  213. package/dist/lib/elur/template/node-binding.js.map +0 -1
@@ -1 +0,0 @@
1
- {"version":3,"file":"signals.js","names":[],"sources":["../../src/elur/reactivity.ts"],"sourcesContent":["// --- Dependency tracking ---\n\ninterface _EffectCtx {\n effect: (() => void) | null;\n deps: Set<Signal<any>> | null;\n}\n\ninterface _ReactivityGlobalState {\n ctxPool: _EffectCtx[];\n ctxStack: _EffectCtx[];\n activeEffect: (() => void) | null;\n activeDeps: Set<Signal<any>> | null;\n activeErrorHandler: ((err: unknown) => void) | null;\n errorHandlerStack: (((err: unknown) => void) | null)[];\n batchLevel: number;\n pendingEffectsSet: Set<() => void>;\n pendingEffectsArr: (() => void)[];\n effectDepth: number;\n notifyBuf: ((() => void) | null)[];\n notifyBase: number;\n signalDebugHooks: _SignalDebugHooks | null;\n /**\n * @internal Multi-subscriber registry backing `signalDebugHooks`.\n * The hot path always reads the single `signalDebugHooks` object; this\n * set only exists so devtools-style consumers can coexist.\n */\n signalDebugHookSet?: Set<_SignalDebugHooks>;\n /**\n * @internal Component debug hooks live here (not module-local) so they\n * work across duplicated module instances. Managed by lifecycle.ts.\n */\n componentDebugHooks?: {\n onMountStart?: (inst: unknown) => void;\n onMountEnd?: (inst: unknown) => void;\n onUnmount?: (inst: unknown) => void;\n } | null;\n /** @internal Multi-subscriber registry backing `componentDebugHooks`. */\n componentDebugHookSet?: Set<NonNullable<_ReactivityGlobalState[\"componentDebugHooks\"]>>;\n}\n\nfunction _createReactivityState(): _ReactivityGlobalState {\n return {\n ctxPool: [],\n ctxStack: [],\n activeEffect: null,\n activeDeps: null,\n activeErrorHandler: null,\n errorHandlerStack: [],\n batchLevel: 0,\n pendingEffectsSet: new Set<() => void>(),\n pendingEffectsArr: [],\n effectDepth: 0,\n notifyBuf: [],\n notifyBase: 0,\n signalDebugHooks: null,\n };\n}\n\nconst _reactivityStateKey = Symbol.for(\"@elurjs/core/reactivity-state\");\nconst _globalObj = globalThis as Record<PropertyKey, unknown>;\nconst _state = (() => {\n const existing = _globalObj[_reactivityStateKey] as _ReactivityGlobalState | undefined;\n if (existing) {\n // Another module may have pre-created the state object with only a\n // subset of fields (e.g. lifecycle.ts registering component hooks\n // before this module evaluated). Fill in any missing defaults.\n const defaults = _createReactivityState() as unknown as Record<string, unknown>;\n const target = existing as unknown as Record<string, unknown>;\n for (const key of Object.keys(defaults)) {\n if (!(key in target)) target[key] = defaults[key];\n }\n return existing;\n }\n const created = _createReactivityState();\n _globalObj[_reactivityStateKey] = created;\n return created;\n})();\n\n// --- Error boundary support ---\n\n/**\n * @internal — Register an error boundary handler. All `effect()` calls made\n * synchronously while this handler is active will capture it. When those\n * effects re-run and throw, the captured handler is invoked.\n */\nexport function _pushErrorHandler(h: (err: unknown) => void): void {\n _state.errorHandlerStack.push(_state.activeErrorHandler);\n _state.activeErrorHandler = h;\n}\n\n/** @internal — Restore the previous error boundary handler. */\nexport function _popErrorHandler(): void {\n _state.activeErrorHandler = _state.errorHandlerStack.pop() ?? null;\n}\n\n// --- Batching ---\n\n/**\n * Guards against synchronous effect re-entrancy.\n *\n * Effects re-run synchronously when a signal they depend on changes. If an\n * effect writes to a signal it also reads, this creates a synchronous loop.\n * The guard below caps re-execution at MAX_EFFECT_DEPTH (100) iterations and\n * throws an error to prevent stack overflow.\n *\n * Throwing is deliberate: when the guard fires, the reactive graph is in an\n * inconsistent state — the effect partially executed, dependencies may be\n * stale, and continuing could produce incorrect UI. Throwing surfaces the\n * bug immediately instead of silently degrading.\n *\n * To avoid re-entrancy:\n * 1. Use `computed()` for derived state — computed signals cache their result\n * and only recompute when dependencies change. They never write to other\n * signals, so they can't loop.\n * 2. Use `watch()` for side effects — watch callbacks receive the new value;\n * if you need to update other signals, do it inside `batch()` to coalesce\n * notifications.\n * 3. Never write to a signal you read in the same effect — this is the direct\n * cause of re-entrancy. If you need to transform a value, use `computed()`\n * instead.\n * 4. Use `batch()` to group writes — batched writes flush once at the end,\n * preventing intermediate re-runs.\n */\n\nconst MAX_EFFECT_DEPTH = 100;\nconst _NOTIFY_SHRINK_TRIGGER = 64;\nconst _NOTIFY_LOW_USAGE = 16;\nconst _NOTIFY_SHRINK_TO = 32;\n\nexport interface _SignalDebugHooks {\n onCreate?: (signal: Signal<any>, initialValue: unknown) => void;\n onWrite?: (signal: Signal<any>, value: unknown) => void;\n}\n\n/**\n * Keeps `signalDebugHooks` as a single object on the hot path. Only when\n * more than one subscriber is registered do we install a dispatcher.\n */\nfunction _syncSignalDebugHooks(): void {\n const set = _state.signalDebugHookSet;\n if (!set || set.size === 0) {\n _state.signalDebugHooks = null;\n return;\n }\n if (set.size === 1) {\n _state.signalDebugHooks = set.values().next().value ?? null;\n return;\n }\n _state.signalDebugHooks = {\n onCreate(signal, initialValue) {\n for (const hooks of set) hooks.onCreate?.(signal, initialValue);\n },\n onWrite(signal, value) {\n for (const hooks of set) hooks.onWrite?.(signal, value);\n },\n };\n}\n\nexport function _setSignalDebugHooks(hooks: _SignalDebugHooks | null): void {\n const set = new Set<_SignalDebugHooks>();\n if (hooks) set.add(hooks);\n _state.signalDebugHookSet = set;\n _syncSignalDebugHooks();\n}\n\n/**\n * @internal — Adds a debug hook subscriber WITHOUT replacing existing ones\n * (unlike `_setSignalDebugHooks`). Returns an unsubscribe function.\n * Zero cost when no subscribers are registered: the setter keeps reading a\n * single `signalDebugHooks` object.\n */\nexport function _addSignalDebugHooks(hooks: _SignalDebugHooks): () => void {\n let set = _state.signalDebugHookSet;\n if (!set) {\n set = new Set<_SignalDebugHooks>();\n if (_state.signalDebugHooks) set.add(_state.signalDebugHooks);\n _state.signalDebugHookSet = set;\n }\n set.add(hooks);\n _syncSignalDebugHooks();\n return () => {\n set.delete(hooks);\n _syncSignalDebugHooks();\n };\n}\n\n/** @internal — notify buffer capacity, exposed for tests. */\nexport function _getNotifyBufSize(): number {\n return _state.notifyBuf.length;\n}\n\n// --- Signal ---\n\nexport class Signal<T> {\n private _value: T;\n private _subs = new Set<() => void>();\n\n constructor(initialValue: T) {\n this._value = initialValue;\n _state.signalDebugHooks?.onCreate?.(this, initialValue);\n }\n\n /** Read the current value. Subscribes the active effect if one exists. */\n get value(): T {\n if (_state.activeEffect) {\n this._subs.add(_state.activeEffect);\n _state.activeDeps?.add(this);\n }\n return this._value;\n }\n\n /** Write a new value. Notifies subscribers when the value changes. */\n set value(newValue: T) {\n if (Object.is(this._value, newValue)) return;\n this._value = newValue;\n _state.signalDebugHooks?.onWrite?.(this, newValue);\n this._notify();\n }\n\n /** Mutate the value via a updater function. */\n update(fn: (current: T) => T): void {\n this.value = fn(this._value);\n }\n\n /** Read without subscribing the active effect. */\n peek(): T {\n return this._value;\n }\n\n /** @internal */\n _removeSub(sub: () => void): void {\n this._subs.delete(sub);\n }\n\n private _notify(): void {\n if (_state.batchLevel > 0) {\n for (const s of this._subs) {\n if (!_state.pendingEffectsSet.has(s)) {\n _state.pendingEffectsSet.add(s);\n _state.pendingEffectsArr.push(s);\n }\n }\n return;\n }\n const base = _state.notifyBase;\n let len = 0;\n for (const s of this._subs) _state.notifyBuf[base + len++] = s;\n _state.notifyBase = base + len;\n try {\n for (let i = 0; i < len; i++) {\n const fn = _state.notifyBuf[base + i];\n _state.notifyBuf[base + i] = null!;\n fn?.();\n }\n } finally {\n _state.notifyBase = base;\n // Shrink oversized notify buffer after a low-usage top-level flush.\n if (\n base === 0 &&\n _state.notifyBuf.length > _NOTIFY_SHRINK_TRIGGER &&\n len < _NOTIFY_LOW_USAGE\n ) {\n _state.notifyBuf.length = _NOTIFY_SHRINK_TO;\n }\n }\n }\n\n dispose(): void {\n this._subs.clear();\n }\n}\n\n// --- Factories ---\n\nexport function signal<T>(initialValue: T): Signal<T> {\n return new Signal(initialValue);\n}\n\n/**\n * Runs `fn` and re-runs it whenever any signal read inside changes.\n * Returns a dispose function to tear down the effect.\n * If `fn` returns a function, it is called as cleanup before each re-run\n * and on disposal.\n */\nexport function effect(fn: () => void | (() => void)): () => void {\n let disposed = false;\n let cleanup: (() => void) | void;\n\n // Opt: Double buffering para evitar crear `new Set()` en cada ejecución\n let deps = new Set<Signal<any>>();\n let newDeps = new Set<Signal<any>>();\n\n const capturedErrorHandler = _state.activeErrorHandler;\n\n const execute = () => {\n if (disposed) return;\n if (typeof cleanup === \"function\") cleanup();\n\n // Intercambiamos los buffers. 'deps' ahora tiene los viejos, 'newDeps' está limpio para recolectar.\n const temp = deps;\n deps = newDeps;\n newDeps = temp;\n newDeps.clear();\n\n const ctx = _state.ctxPool.length > 0 ? _state.ctxPool.pop()! : { effect: null, deps: null };\n ctx.effect = _state.activeEffect;\n ctx.deps = _state.activeDeps;\n _state.ctxStack.push(ctx);\n _state.activeEffect = execute;\n _state.activeDeps = newDeps;\n\n _state.effectDepth++;\n if (_state.effectDepth > MAX_EFFECT_DEPTH) {\n _state.effectDepth = 0;\n // Restaurar desde el stack unificado\n const restored = _state.ctxStack.pop()!;\n _state.activeEffect = restored.effect;\n _state.activeDeps = restored.deps;\n restored.effect = null;\n restored.deps = null;\n _state.ctxPool.push(restored);\n throw new Error(\n \"[elur] Maximum effect re-execution depth exceeded (possible infinite loop).\"\n );\n }\n\n try {\n cleanup = fn();\n } catch (err) {\n if (capturedErrorHandler) {\n capturedErrorHandler(err);\n } else {\n throw err;\n }\n } finally {\n _state.effectDepth--;\n const restored = _state.ctxStack.pop()!;\n _state.activeEffect = restored.effect;\n _state.activeDeps = restored.deps;\n restored.effect = null; // limpiar referencias para GC\n restored.deps = null;\n _state.ctxPool.push(restored); // devolver al pool para reutilizar\n\n\n // Cleanup phase: Desuscribirse de señales que estaban en 'deps' pero NO en 'newDeps'\n for (const oldDep of deps) {\n if (!newDeps.has(oldDep)) {\n oldDep._removeSub(execute);\n }\n }\n }\n };\n\n execute();\n\n return () => {\n disposed = true;\n if (typeof cleanup === \"function\") cleanup();\n // Al desechar, usamos newDeps porque es el que quedó activo después del último execute\n for (const dep of newDeps) {\n dep._removeSub(execute);\n }\n newDeps.clear();\n deps.clear();\n };\n}\n\n/** Derived signal that recalculates when its dependencies change. */\nconst _computedSentinel = Symbol(\"elur-computed-uninitialized\");\n\nexport function computed<T>(\n fn: () => T,\n equals: (a: T, b: T) => boolean = Object.is,\n): Signal<T> & { dispose(): void } {\n const s = new Signal<T | typeof _computedSentinel>(_computedSentinel);\n let disposeEffect: (() => void) | null = null;\n let initialized = false;\n let disposed = false;\n\n const ensureInitialized = () => {\n if (initialized || disposed) return;\n initialized = true;\n // Important: initialize untracked so first computed evaluation does not\n // accidentally subscribe the currently running external effect.\n untrack(() => {\n disposeEffect = effect(() => {\n const next = fn();\n const prev = s.peek();\n // The first computed value must always be written; afterwards use\n // the supplied equality comparator (defaults to Object.is).\n if (prev === _computedSentinel || !equals(next, prev)) {\n s.value = next;\n }\n });\n });\n };\n\n const signalProto = Object.getPrototypeOf(s) as Signal<T>;\n const valueDescriptor = Object.getOwnPropertyDescriptor(signalProto, \"value\");\n if (!valueDescriptor?.get || !valueDescriptor?.set) {\n throw new Error(\"[elur] Internal error: Signal.value descriptor not found.\");\n }\n\n Object.defineProperty(s, \"value\", {\n get() {\n ensureInitialized();\n return valueDescriptor.get!.call(this) as T;\n },\n set(v: T) {\n valueDescriptor.set!.call(this, v);\n },\n configurable: true,\n });\n\n const originalDispose = s.dispose;\n\n s.dispose = () => {\n disposed = true;\n disposeEffect?.();\n disposeEffect = null;\n originalDispose.call(s); // Opt: Evitar el uso lento de .bind()\n };\n return s as Signal<T> & { dispose(): void };\n}\n\n/** Groups multiple signal writes so effects flush once at the end. */\nexport function batch(fn: () => void): void {\n _state.batchLevel++;\n try {\n fn();\n } finally {\n _state.batchLevel--;\n if (_state.batchLevel === 0 && _state.pendingEffectsArr.length > 0) {\n const len = _state.pendingEffectsArr.length;\n for (let i = 0; i < len; i++) _state.pendingEffectsArr[i]();\n _state.pendingEffectsArr.length = 0; // reset O(1) sin GC — key del cambio\n _state.pendingEffectsSet.clear();\n }\n }\n}\n\n/** Executes `fn` without subscribing to any signals read inside it. */\nexport function untrack<T>(fn: () => T): T {\n const prevEffect = _state.activeEffect;\n const prevDeps = _state.activeDeps;\n _state.activeEffect = null;\n _state.activeDeps = null;\n try {\n return fn();\n } finally {\n _state.activeEffect = prevEffect;\n _state.activeDeps = prevDeps;\n }\n}\n\n// --- watch ---\n\nexport interface WatchOptions {\n /** Fire the callback immediately with the current value. Default: `false`. */\n immediate?: boolean;\n /** Automatically dispose after the first callback invocation. Default: `false`. */\n once?: boolean;\n}\n\n/**\n * Watches a reactive source and calls `callback(newValue, oldValue)` on each change.\n * Accepts a Signal or a getter function. Returns a dispose function.\n */\nexport function watch<T>(\n source: Signal<T> | (() => T),\n callback: (newValue: T, oldValue: T | undefined) => void,\n options: WatchOptions = {}\n): () => void {\n const { immediate = false, once = false } = options;\n\n const getter: () => T =\n source instanceof Signal ? () => source.value : source;\n\n let oldValue: T | undefined;\n let isFirst = true;\n let disposed = false;\n\n const dispose = effect(() => {\n const newValue = getter();\n\n if (isFirst) {\n isFirst = false;\n if (immediate && !disposed) {\n const snap = newValue;\n untrack(() => callback(snap, undefined));\n if (once) { disposed = true; Promise.resolve().then(dispose); }\n }\n oldValue = newValue;\n return;\n }\n\n if (!disposed) {\n const snap = newValue;\n const prev = oldValue;\n oldValue = newValue;\n untrack(() => callback(snap, prev));\n if (once) { disposed = true; Promise.resolve().then(dispose); }\n }\n });\n\n return () => {\n disposed = true;\n dispose();\n };\n}\n\n// --- nextTick ---\n\n/** Returns a promise that resolves on the next microtask. Accepts an optional callback. */\nexport function nextTick(fn?: () => void): Promise<void> {\n return fn ? Promise.resolve().then(fn) : Promise.resolve();\n}"],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- var e=new Set,t=!1;function n(n){e.add(n),t||(t=!0,queueMicrotask(()=>{for(let t of e)try{t()}catch(e){console.error(`[Elur] Error in DOM write task:`,e)}e.clear(),t=!1}))}exports.queueDOMWrite=n;
2
- //# sourceMappingURL=dom-write.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"dom-write.cjs","names":[],"sources":["../../../../src/elur/template/dom-write.ts"],"sourcesContent":["// =============================================================================\n// --- DOM Write Batching (Microtask Queue) ---\n// =============================================================================\n\nconst _domWriteQueue = new Set<() => void>();\nlet _isDomWriteScheduled = false;\n\n/**\n * Queues a DOM mutation to run in the next microtask.\n * Avoids Layout Thrashing by grouping multiple writes into a single frame.\n */\nexport function queueDOMWrite(task: () => void): void {\n _domWriteQueue.add(task);\n if (!_isDomWriteScheduled) {\n _isDomWriteScheduled = true;\n queueMicrotask(() => {\n for (const t of _domWriteQueue) {\n try {\n t();\n } catch (e) {\n // Evitamos que un error rompa el hilo entero\n console.error(\"[Elur] Error in DOM write task:\", e);\n }\n }\n _domWriteQueue.clear();\n _isDomWriteScheduled = false;\n });\n }\n}\n"],"mappings":"AAIA,IAAM,EAAiB,IAAI,IACvB,EAAuB,GAM3B,SAAgB,EAAc,EAAwB,CAClD,EAAe,IAAI,EAAK,CACnB,IACD,EAAuB,GACvB,mBAAqB,CACjB,IAAK,IAAM,KAAK,EACZ,GAAI,CACA,GAAG,OACE,EAAG,CAER,QAAQ,MAAM,kCAAmC,EAAE,CAG3D,EAAe,OAAO,CACtB,EAAuB,IACzB"}
@@ -1,16 +0,0 @@
1
- //#region src/elur/template/dom-write.ts
2
- var e = /* @__PURE__ */ new Set(), t = !1;
3
- function n(n) {
4
- e.add(n), t || (t = !0, queueMicrotask(() => {
5
- for (let t of e) try {
6
- t();
7
- } catch (e) {
8
- console.error("[Elur] Error in DOM write task:", e);
9
- }
10
- e.clear(), t = !1;
11
- }));
12
- }
13
- //#endregion
14
- export { n as queueDOMWrite };
15
-
16
- //# sourceMappingURL=dom-write.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"dom-write.js","names":[],"sources":["../../../../src/elur/template/dom-write.ts"],"sourcesContent":["// =============================================================================\n// --- DOM Write Batching (Microtask Queue) ---\n// =============================================================================\n\nconst _domWriteQueue = new Set<() => void>();\nlet _isDomWriteScheduled = false;\n\n/**\n * Queues a DOM mutation to run in the next microtask.\n * Avoids Layout Thrashing by grouping multiple writes into a single frame.\n */\nexport function queueDOMWrite(task: () => void): void {\n _domWriteQueue.add(task);\n if (!_isDomWriteScheduled) {\n _isDomWriteScheduled = true;\n queueMicrotask(() => {\n for (const t of _domWriteQueue) {\n try {\n t();\n } catch (e) {\n // Evitamos que un error rompa el hilo entero\n console.error(\"[Elur] Error in DOM write task:\", e);\n }\n }\n _domWriteQueue.clear();\n _isDomWriteScheduled = false;\n });\n }\n}\n"],"mappings":";AAIA,IAAM,oBAAiB,IAAI,KAAiB,EACxC,IAAuB;AAM3B,SAAgB,EAAc,GAAwB;AAElD,CADA,EAAe,IAAI,EAAK,EACnB,MACD,IAAuB,IACvB,qBAAqB;AACjB,OAAK,IAAM,KAAK,EACZ,KAAI;AACA,MAAG;WACE,GAAG;AAER,WAAQ,MAAM,mCAAmC,EAAE;;AAI3D,EADA,EAAe,OAAO,EACtB,IAAuB;GACzB"}
@@ -1,2 +0,0 @@
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
@@ -1 +0,0 @@
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":"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"}
@@ -1,100 +0,0 @@
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
@@ -1 +0,0 @@
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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"}
@@ -1,2 +0,0 @@
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
@@ -1 +0,0 @@
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"}
@@ -1,132 +0,0 @@
1
- import { _debugComponentMountEnd as e, _debugComponentMountStart as t, _debugComponentUnmount as n } from "../../lifecycle.js";
2
- import { _popComponentContext as r, _pushComponentContext as i, _withComponentContext as a } from "../../context.js";
3
- //#region src/elur/template/mount-helpers.ts
4
- function o(a, o, s) {
5
- t(a), i();
6
- let c;
7
- try {
8
- try {
9
- a.onInit?.();
10
- } catch (e) {
11
- if (a.onError) a.onError(e);
12
- else throw e;
13
- }
14
- c = a.render()._render(o, s);
15
- } finally {
16
- e(a), r();
17
- }
18
- let l;
19
- try {
20
- let e = a.onMount?.();
21
- typeof e == "function" && (l = e);
22
- } catch (e) {
23
- if (a.onError) a.onError(e);
24
- else throw e;
25
- }
26
- return () => {
27
- try {
28
- a.onUnmount?.();
29
- } catch {}
30
- try {
31
- l?.();
32
- } catch {}
33
- c(), n(a);
34
- };
35
- }
36
- function s(a, o, s) {
37
- t(a), i();
38
- let c;
39
- try {
40
- try {
41
- a.onInit?.();
42
- } catch {}
43
- c = a.render()._render(o, s);
44
- } finally {
45
- e(a), r();
46
- }
47
- let l;
48
- try {
49
- let e = a.onMount?.();
50
- typeof e == "function" && (l = e);
51
- } catch {}
52
- return () => {
53
- try {
54
- a.onUnmount?.();
55
- } catch {}
56
- try {
57
- l?.();
58
- } catch {}
59
- c(), n(a);
60
- };
61
- }
62
- function c(r, i, o, s) {
63
- t(r);
64
- let c;
65
- try {
66
- a(s, () => {
67
- try {
68
- r.onInit?.();
69
- } catch (e) {
70
- if (r.onError) r.onError(e);
71
- else throw e;
72
- }
73
- c = r.render()._render(i, o);
74
- });
75
- } finally {
76
- e(r);
77
- }
78
- let l;
79
- try {
80
- let e = r.onMount?.();
81
- typeof e == "function" && (l = e);
82
- } catch (e) {
83
- if (r.onError) r.onError(e);
84
- else throw e;
85
- }
86
- return () => {
87
- try {
88
- r.onUnmount?.();
89
- } catch {}
90
- try {
91
- l?.();
92
- } catch {}
93
- c(), n(r);
94
- };
95
- }
96
- function l(a, o, s, c, l) {
97
- t(a), i();
98
- let u;
99
- try {
100
- try {
101
- a.onInit?.();
102
- } catch (e) {
103
- if (a.onError) a.onError(e);
104
- else throw e;
105
- }
106
- u = a.render()._render(o, s);
107
- } finally {
108
- e(a), r();
109
- }
110
- let d;
111
- c.push(() => {
112
- try {
113
- let e = a.onMount?.();
114
- typeof e == "function" && (d = e);
115
- } catch (e) {
116
- if (a.onError) a.onError(e);
117
- else throw e;
118
- }
119
- }), l.push(() => {
120
- try {
121
- a.onUnmount?.();
122
- } catch {}
123
- try {
124
- d?.();
125
- } catch {}
126
- u(), n(a);
127
- });
128
- }
129
- //#endregion
130
- export { o as _mountComponent, l as _mountComponentDeferred, s as _mountComponentSilent, c as _mountComponentWithCtx };
131
-
132
- //# sourceMappingURL=mount-helpers.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"mount-helpers.js","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":";;;AAsBA,SAAgB,EACZ,GACA,GACA,GACU;AAEV,CADA,EAA0B,EAAK,EAC/B,GAAuB;CACvB,IAAI;AACJ,KAAI;AACA,MAAI;AAAE,KAAK,UAAU;WAAW,GAAG;AAAE,OAAI,EAAK,QAAS,GAAK,QAAQ,EAAE;OAAO,OAAM;;AACnF,MAAgB,EAAK,QAAQ,CAAC,QAAQ,GAAQ,EAAO;WAC/C;AAEN,EADA,EAAwB,EAAK,EAC7B,GAAsB;;CAE1B,IAAI;AACJ,KAAI;EACA,IAAM,IAAM,EAAK,WAAW;AAC5B,EAAI,OAAO,KAAQ,eAAY,IAAe;UACzC,GAAG;AACR,MAAI,EAAK,QAAS,GAAK,QAAQ,EAAE;MAAO,OAAM;;AAElD,cAAa;AACT,MAAI;AAAE,KAAK,aAAa;UAAU;AAClC,MAAI;AAAE,QAAgB;UAAU;AAEhC,EADA,GAAe,EACf,EAAuB,EAAK;;;AASpC,SAAgB,EACZ,GACA,GACA,GACU;AAEV,CADA,EAA0B,EAAK,EAC/B,GAAuB;CACvB,IAAI;AACJ,KAAI;AACA,MAAI;AAAE,KAAK,UAAU;UAAU;AAC/B,MAAgB,EAAK,QAAQ,CAAC,QAAQ,GAAQ,EAAO;WAC/C;AAEN,EADA,EAAwB,EAAK,EAC7B,GAAsB;;CAE1B,IAAI;AACJ,KAAI;EACA,IAAM,IAAM,EAAK,WAAW;AAC5B,EAAI,OAAO,KAAQ,eAAY,IAAW;SACtC;AACR,cAAa;AACT,MAAI;AAAE,KAAK,aAAa;UAAU;AAClC,MAAI;AAAE,QAAY;UAAU;AAE5B,EADA,GAAe,EACf,EAAuB,EAAK;;;AAUpC,SAAgB,EACZ,GACA,GACA,GACA,GACU;AACV,GAA0B,EAAK;CAC/B,IAAI;AACJ,KAAI;AACA,IAAsB,SAAmB;AACrC,OAAI;AAAE,MAAK,UAAU;YAAW,GAAG;AAAE,QAAI,EAAK,QAAS,GAAK,QAAQ,EAAE;QAAO,OAAM;;AACnF,OAAgB,EAAK,QAAQ,CAAC,QAAQ,GAAQ,EAAO;IACvD;WACI;AACN,IAAwB,EAAK;;CAEjC,IAAI;AACJ,KAAI;EACA,IAAM,IAAM,EAAK,WAAW;AAC5B,EAAI,OAAO,KAAQ,eAAY,IAAe;UACzC,GAAG;AACR,MAAI,EAAK,QAAS,GAAK,QAAQ,EAAE;MAAO,OAAM;;AAElD,cAAa;AACT,MAAI;AAAE,KAAK,aAAa;UAAU;AAClC,MAAI;AAAE,QAAgB;UAAU;AAEhC,EADA,GAAe,EACf,EAAuB,EAAK;;;AAWpC,SAAgB,EACZ,GACA,GACA,GACA,GACA,GACI;AAEJ,CADA,EAA0B,EAAK,EAC/B,GAAuB;CACvB,IAAI;AACJ,KAAI;AACA,MAAI;AAAE,KAAK,UAAU;WAAW,GAAG;AAAE,OAAI,EAAK,QAAS,GAAK,QAAQ,EAAE;OAAO,OAAM;;AACnF,MAAgB,EAAK,QAAQ,CAAC,QAAQ,GAAQ,EAAO;WAC/C;AAEN,EADA,EAAwB,EAAK,EAC7B,GAAsB;;CAE1B,IAAI;AASJ,CARA,EAAe,WAAW;AACtB,MAAI;GACA,IAAM,IAAM,EAAK,WAAW;AAC5B,GAAI,OAAO,KAAQ,eAAY,IAAe;WACzC,GAAG;AACR,OAAI,EAAK,QAAS,GAAK,QAAQ,EAAE;OAAO,OAAM;;GAEpD,EACF,EAAS,WAAW;AAChB,MAAI;AAAE,KAAK,aAAa;UAAU;AAClC,MAAI;AAAE,QAAgB;UAAU;AAEhC,EADA,GAAe,EACf,EAAuB,EAAK;GAC9B"}
@@ -1,2 +0,0 @@
1
- const e=require(`../../signals.cjs`),t=require(`./types.cjs`),n=require(`../../lifecycle.cjs`),r=require(`../../context.cjs`),i=require(`./mount-helpers.cjs`),a=require(`./keyed-diff.cjs`),o=require(`./dom-write.cjs`);function s(s,c,l,u){if(typeof c!=`function`){if(typeof c==`object`&&c&&c[t.ELUR_RENDER_PROTOCOL]!=null){let e=c[t.ELUR_RENDER_PROTOCOL];if(e.mountDom){let t=e.mountDom({parent:s.parentNode,before:s});t&&l.push(t);return}}if(n.isElurComponent(c))i._mountComponentDeferred(c,s.parentNode,s,u,l);else if(t.isElurTemplate(c))l.push(c._render(s.parentNode,s));else if(t.isKeyedList(c)){let e=r._captureContextSnapshot(),t=new Map,n=document.createTextNode(``);s.parentNode.insertBefore(n,s),a.reconcileKeyedList({zoneStart:n,anchor:s,state:t,prevOrder:[],list:c,mount:a.createKeyedMount(e),ctxSnapshot:e,onDuplicateKey:e=>{console.warn(`[elur] repeat(): duplicate key "${e}". Keys must be unique; the previous entry leaks (orphaned nodes + live effects).`)}}),l.push(()=>{for(let e of t.values())e.cleanup();t.clear()})}else if(Array.isArray(c))for(let e of c)n.isElurComponent(e)?i._mountComponentDeferred(e,s.parentNode,s,u,l):t.isElurTemplate(e)?e._render(s.parentNode,s):e!=null&&e!==!1&&s.parentNode.insertBefore(document.createTextNode(String(e)),s);else c!=null&&c!==!1&&s.parentNode.insertBefore(document.createTextNode(String(c)),s);return}let d=null,f=null,p=null,m=[],h=null,g=r._captureContextSnapshot(),_=a.createKeyedMount(g),v=!1,y=``,b=!0,x=e.effect(()=>{let e=c();if(typeof e==`string`||typeof e==`number`){y=String(e);let t=()=>{v=!1,f&&=(f(),null),d?d.nodeValue=y:(d=document.createTextNode(y),s.parentNode.insertBefore(d,s))};b?(b=!1,t()):v||(v=!0,o.queueDOMWrite(t));return}if(v=!1,b=!1,d&&=(d.parentNode?.removeChild(d),null),f&&=(f(),null),!(e==null||e===!1))if(typeof e==`object`&&e&&e[t.ELUR_RENDER_PROTOCOL]!=null){let n=e[t.ELUR_RENDER_PROTOCOL];n.mountDom?f=n.mountDom({parent:s.parentNode,before:s})??null:(d=document.createTextNode(String(e)),s.parentNode.insertBefore(d,s))}else if(t.isElurTemplate(e))f=e._render(s.parentNode,s);else if(n.isElurComponent(e))f=i._mountComponentWithCtx(e,s.parentNode,s,g);else if(t.isKeyedList(e))p||(p=new Map,h=document.createTextNode(``),s.parentNode.insertBefore(h,s)),a.reconcileKeyedList({zoneStart:h,anchor:s,state:p,prevOrder:m,list:e,mount:_,onDuplicateKey:e=>{console.warn(`[elur] repeat(): duplicate key "${e}". Keys must be unique; the previous entry leaks (orphaned nodes + live effects).`)}});else if(Array.isArray(e)){let r=[];for(let a of e)if(n.isElurComponent(a))r.push(i._mountComponent(a,s.parentNode,s));else if(t.isElurTemplate(a))r.push(a._render(s.parentNode,s));else if(a!=null&&a!==!1){let e=document.createTextNode(String(a));s.parentNode.insertBefore(e,s),r.push(()=>e.parentNode?.removeChild(e))}f=()=>r.forEach(e=>e())}else d=document.createTextNode(String(e)),s.parentNode.insertBefore(d,s)});l.push(()=>{if(x(),f&&=(f(),null),d&&=(d.parentNode?.removeChild(d),null),p){for(let e of p.values())e.cleanup();p=null,h=null}})}exports.activateNodeBinding=s;
2
- //# sourceMappingURL=node-binding.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"node-binding.cjs","names":[],"sources":["../../../../src/elur/template/node-binding.ts"],"sourcesContent":["import { effect } from \"../reactivity.js\";\nimport { isElurComponent } from \"../lifecycle.js\";\nimport { _captureContextSnapshot } from \"../context.js\";\nimport type { KEntry } from \"./types.js\";\nimport type { RepeatKey } from \"./keyed.js\";\nimport { isElurTemplate, isKeyedList, ELUR_RENDER_PROTOCOL } from \"./types.js\";\nimport {\n _mountComponent,\n _mountComponentWithCtx,\n _mountComponentDeferred,\n} from \"./mount-helpers.js\";\nimport { createKeyedMount, reconcileKeyedList } from \"./keyed-diff.js\";\nimport { queueDOMWrite } from \"./dom-write.js\";\n\n// =============================================================================\n// --- Reactive node binding ---\n// =============================================================================\n\n/**\n * Activates a reactive node binding at `anchor`.\n * Handles: text, ElurTemplate, ElurComponent, KeyedList, Array, and static values.\n * Pushes dispose functions into `disposes`.\n */\nexport function activateNodeBinding(\n anchor: Text,\n value: unknown,\n disposes: Array<() => void>,\n postMountHooks: Array<() => void>,\n): void {\n if (typeof value !== \"function\") {\n if (value != null && typeof value === \"object\" && (value as Record<PropertyKey, unknown>)[ELUR_RENDER_PROTOCOL] != null) {\n const proto = (value as Record<PropertyKey, unknown>)[ELUR_RENDER_PROTOCOL] as { mountDom?: (ctx: import(\"./types.js\").DomProtocolContext) => (() => void) | void };\n if (proto.mountDom) {\n const cleanup = proto.mountDom({\n parent: anchor.parentNode!,\n before: anchor,\n });\n if (cleanup) disposes.push(cleanup);\n return;\n }\n }\n if (isElurComponent(value)) {\n _mountComponentDeferred(value, anchor.parentNode!, anchor, postMountHooks, disposes);\n } else if (isElurTemplate(value)) {\n disposes.push(value._render(anchor.parentNode!, anchor));\n } else if (isKeyedList(value)) {\n // Static keyed list (`repeat(...)` directly, without a getter):\n // mirror the reactive path so a direct keyed value never falls\n // through to `String(value)`.\n const ctxSnapshot = _captureContextSnapshot();\n const keyedState = new Map<RepeatKey, KEntry>();\n const keyedZoneStart = document.createTextNode(\"\");\n anchor.parentNode!.insertBefore(keyedZoneStart, anchor);\n reconcileKeyedList({\n zoneStart: keyedZoneStart,\n anchor,\n state: keyedState,\n prevOrder: [],\n list: value,\n mount: createKeyedMount(ctxSnapshot),\n ctxSnapshot,\n onDuplicateKey: (key) => {\n console.warn(`[elur] repeat(): duplicate key \"${key}\". Keys must be unique; the previous entry leaks (orphaned nodes + live effects).`);\n },\n });\n disposes.push(() => {\n for (const entry of keyedState.values()) {\n entry.cleanup();\n }\n keyedState.clear();\n });\n } else if (Array.isArray(value)) {\n for (const item of value) {\n if (isElurComponent(item)) {\n _mountComponentDeferred(item, anchor.parentNode!, anchor, postMountHooks, disposes);\n } else if (isElurTemplate(item)) {\n item._render(anchor.parentNode!, anchor);\n } else if (item != null && item !== false) {\n anchor.parentNode!.insertBefore(\n document.createTextNode(String(item)),\n anchor\n );\n }\n }\n } else if (value != null && value !== false) {\n anchor.parentNode!.insertBefore(\n document.createTextNode(String(value)),\n anchor\n );\n }\n return;\n }\n\n // Reactive function path\n let textNode: Text | null = null;\n let innerCleanup: (() => void) | null = null;\n\n type Key = RepeatKey;\n let keyedState: Map<Key, KEntry> | null = null;\n let prevKeyOrder: Key[] = [];\n let keyedZoneStart: Node | null = null;\n\n const ctxSnapshot = _captureContextSnapshot();\n const keyedMount = createKeyedMount(ctxSnapshot);\n\n let _textQueued = false;\n let _pendingText = \"\";\n let _isFirstText = true;\n\n const dispose = effect(() => {\n const v = (value as () => unknown)();\n\n if (typeof v === \"string\" || typeof v === \"number\") {\n _pendingText = String(v);\n\n const update = () => {\n _textQueued = false;\n if (innerCleanup) {\n innerCleanup();\n innerCleanup = null;\n }\n if (!textNode) {\n textNode = document.createTextNode(_pendingText);\n anchor.parentNode!.insertBefore(textNode, anchor);\n } else {\n textNode.nodeValue = _pendingText;\n }\n };\n\n if (_isFirstText) {\n _isFirstText = false;\n update();\n } else if (!_textQueued) {\n _textQueued = true;\n queueDOMWrite(update);\n }\n return;\n }\n\n _textQueued = false;\n _isFirstText = false;\n\n if (textNode) {\n textNode.parentNode?.removeChild(textNode);\n textNode = null;\n }\n if (innerCleanup) {\n innerCleanup();\n innerCleanup = null;\n }\n\n if (v == null || v === false) {\n // Empty\n } else if (v != null && typeof v === \"object\" && (v as Record<PropertyKey, unknown>)[ELUR_RENDER_PROTOCOL] != null) {\n const proto = (v as Record<PropertyKey, unknown>)[ELUR_RENDER_PROTOCOL] as { mountDom?: (ctx: import(\"./types.js\").DomProtocolContext) => (() => void) | void };\n if (proto.mountDom) {\n innerCleanup = proto.mountDom({ parent: anchor.parentNode!, before: anchor }) ?? null;\n } else {\n textNode = document.createTextNode(String(v));\n anchor.parentNode!.insertBefore(textNode, anchor);\n }\n } else if (isElurTemplate(v)) {\n innerCleanup = v._render(anchor.parentNode!, anchor);\n } else if (isElurComponent(v)) {\n innerCleanup = _mountComponentWithCtx(v, anchor.parentNode!, anchor, ctxSnapshot);\n } else if (isKeyedList(v)) {\n\n if (!keyedState) {\n keyedState = new Map();\n keyedZoneStart = document.createTextNode(\"\");\n anchor.parentNode!.insertBefore(keyedZoneStart, anchor);\n }\n\n reconcileKeyedList({\n zoneStart: keyedZoneStart!,\n anchor,\n state: keyedState,\n prevOrder: prevKeyOrder,\n list: v,\n mount: keyedMount,\n onDuplicateKey: (key) => {\n console.warn(`[elur] repeat(): duplicate key \"${key}\". Keys must be unique; the previous entry leaks (orphaned nodes + live effects).`);\n },\n });\n } else if (Array.isArray(v)) {\n const cleanups: Array<() => void> = [];\n for (const item of v) {\n if (isElurComponent(item)) {\n cleanups.push(_mountComponent(item, anchor.parentNode!, anchor));\n } else if (isElurTemplate(item)) {\n cleanups.push(item._render(anchor.parentNode!, anchor));\n } else if (item != null && item !== false) {\n const t = document.createTextNode(String(item));\n anchor.parentNode!.insertBefore(t, anchor);\n cleanups.push(() => t.parentNode?.removeChild(t));\n }\n }\n innerCleanup = () => cleanups.forEach((c) => c());\n } else {\n textNode = document.createTextNode(String(v));\n anchor.parentNode!.insertBefore(textNode, anchor);\n }\n });\n\n disposes.push(() => {\n dispose();\n if (innerCleanup) {\n innerCleanup();\n innerCleanup = null;\n }\n if (textNode) {\n textNode.parentNode?.removeChild(textNode);\n textNode = null;\n }\n if (keyedState) {\n for (const entry of keyedState.values()) {\n entry.cleanup();\n }\n keyedState = null;\n keyedZoneStart = null;\n }\n });\n}\n"],"mappings":"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"}
@@ -1,95 +0,0 @@
1
- import { effect as e } from "../../signals.js";
2
- import { ELUR_RENDER_PROTOCOL as t, isElurTemplate as n, isKeyedList as r } from "./types.js";
3
- import { isElurComponent as i } from "../../lifecycle.js";
4
- import { _captureContextSnapshot as a } from "../../context.js";
5
- import { _mountComponent as o, _mountComponentDeferred as s, _mountComponentWithCtx as c } from "./mount-helpers.js";
6
- import { createKeyedMount as l, reconcileKeyedList as u } from "./keyed-diff.js";
7
- import { queueDOMWrite as d } from "./dom-write.js";
8
- //#region src/elur/template/node-binding.ts
9
- function f(f, p, m, h) {
10
- if (typeof p != "function") {
11
- if (typeof p == "object" && p && p[t] != null) {
12
- let e = p[t];
13
- if (e.mountDom) {
14
- let t = e.mountDom({
15
- parent: f.parentNode,
16
- before: f
17
- });
18
- t && m.push(t);
19
- return;
20
- }
21
- }
22
- if (i(p)) s(p, f.parentNode, f, h, m);
23
- else if (n(p)) m.push(p._render(f.parentNode, f));
24
- else if (r(p)) {
25
- let e = a(), t = /* @__PURE__ */ new Map(), n = document.createTextNode("");
26
- f.parentNode.insertBefore(n, f), u({
27
- zoneStart: n,
28
- anchor: f,
29
- state: t,
30
- prevOrder: [],
31
- list: p,
32
- mount: l(e),
33
- ctxSnapshot: e,
34
- onDuplicateKey: (e) => {
35
- console.warn(`[elur] repeat(): duplicate key "${e}". Keys must be unique; the previous entry leaks (orphaned nodes + live effects).`);
36
- }
37
- }), m.push(() => {
38
- for (let e of t.values()) e.cleanup();
39
- t.clear();
40
- });
41
- } else if (Array.isArray(p)) for (let e of p) i(e) ? s(e, f.parentNode, f, h, m) : n(e) ? e._render(f.parentNode, f) : e != null && e !== !1 && f.parentNode.insertBefore(document.createTextNode(String(e)), f);
42
- else p != null && p !== !1 && f.parentNode.insertBefore(document.createTextNode(String(p)), f);
43
- return;
44
- }
45
- let g = null, _ = null, v = null, y = [], b = null, x = a(), S = l(x), C = !1, w = "", T = !0, E = e(() => {
46
- let e = p();
47
- if (typeof e == "string" || typeof e == "number") {
48
- w = String(e);
49
- let t = () => {
50
- C = !1, _ &&= (_(), null), g ? g.nodeValue = w : (g = document.createTextNode(w), f.parentNode.insertBefore(g, f));
51
- };
52
- T ? (T = !1, t()) : C || (C = !0, d(t));
53
- return;
54
- }
55
- if (C = !1, T = !1, g &&= (g.parentNode?.removeChild(g), null), _ &&= (_(), null), !(e == null || e === !1)) if (typeof e == "object" && e && e[t] != null) {
56
- let n = e[t];
57
- n.mountDom ? _ = n.mountDom({
58
- parent: f.parentNode,
59
- before: f
60
- }) ?? null : (g = document.createTextNode(String(e)), f.parentNode.insertBefore(g, f));
61
- } else if (n(e)) _ = e._render(f.parentNode, f);
62
- else if (i(e)) _ = c(e, f.parentNode, f, x);
63
- else if (r(e)) v || (v = /* @__PURE__ */ new Map(), b = document.createTextNode(""), f.parentNode.insertBefore(b, f)), u({
64
- zoneStart: b,
65
- anchor: f,
66
- state: v,
67
- prevOrder: y,
68
- list: e,
69
- mount: S,
70
- onDuplicateKey: (e) => {
71
- console.warn(`[elur] repeat(): duplicate key "${e}". Keys must be unique; the previous entry leaks (orphaned nodes + live effects).`);
72
- }
73
- });
74
- else if (Array.isArray(e)) {
75
- let t = [];
76
- for (let r of e) if (i(r)) t.push(o(r, f.parentNode, f));
77
- else if (n(r)) t.push(r._render(f.parentNode, f));
78
- else if (r != null && r !== !1) {
79
- let e = document.createTextNode(String(r));
80
- f.parentNode.insertBefore(e, f), t.push(() => e.parentNode?.removeChild(e));
81
- }
82
- _ = () => t.forEach((e) => e());
83
- } else g = document.createTextNode(String(e)), f.parentNode.insertBefore(g, f);
84
- });
85
- m.push(() => {
86
- if (E(), _ &&= (_(), null), g &&= (g.parentNode?.removeChild(g), null), v) {
87
- for (let e of v.values()) e.cleanup();
88
- v = null, b = null;
89
- }
90
- });
91
- }
92
- //#endregion
93
- export { f as activateNodeBinding };
94
-
95
- //# sourceMappingURL=node-binding.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"node-binding.js","names":[],"sources":["../../../../src/elur/template/node-binding.ts"],"sourcesContent":["import { effect } from \"../reactivity.js\";\nimport { isElurComponent } from \"../lifecycle.js\";\nimport { _captureContextSnapshot } from \"../context.js\";\nimport type { KEntry } from \"./types.js\";\nimport type { RepeatKey } from \"./keyed.js\";\nimport { isElurTemplate, isKeyedList, ELUR_RENDER_PROTOCOL } from \"./types.js\";\nimport {\n _mountComponent,\n _mountComponentWithCtx,\n _mountComponentDeferred,\n} from \"./mount-helpers.js\";\nimport { createKeyedMount, reconcileKeyedList } from \"./keyed-diff.js\";\nimport { queueDOMWrite } from \"./dom-write.js\";\n\n// =============================================================================\n// --- Reactive node binding ---\n// =============================================================================\n\n/**\n * Activates a reactive node binding at `anchor`.\n * Handles: text, ElurTemplate, ElurComponent, KeyedList, Array, and static values.\n * Pushes dispose functions into `disposes`.\n */\nexport function activateNodeBinding(\n anchor: Text,\n value: unknown,\n disposes: Array<() => void>,\n postMountHooks: Array<() => void>,\n): void {\n if (typeof value !== \"function\") {\n if (value != null && typeof value === \"object\" && (value as Record<PropertyKey, unknown>)[ELUR_RENDER_PROTOCOL] != null) {\n const proto = (value as Record<PropertyKey, unknown>)[ELUR_RENDER_PROTOCOL] as { mountDom?: (ctx: import(\"./types.js\").DomProtocolContext) => (() => void) | void };\n if (proto.mountDom) {\n const cleanup = proto.mountDom({\n parent: anchor.parentNode!,\n before: anchor,\n });\n if (cleanup) disposes.push(cleanup);\n return;\n }\n }\n if (isElurComponent(value)) {\n _mountComponentDeferred(value, anchor.parentNode!, anchor, postMountHooks, disposes);\n } else if (isElurTemplate(value)) {\n disposes.push(value._render(anchor.parentNode!, anchor));\n } else if (isKeyedList(value)) {\n // Static keyed list (`repeat(...)` directly, without a getter):\n // mirror the reactive path so a direct keyed value never falls\n // through to `String(value)`.\n const ctxSnapshot = _captureContextSnapshot();\n const keyedState = new Map<RepeatKey, KEntry>();\n const keyedZoneStart = document.createTextNode(\"\");\n anchor.parentNode!.insertBefore(keyedZoneStart, anchor);\n reconcileKeyedList({\n zoneStart: keyedZoneStart,\n anchor,\n state: keyedState,\n prevOrder: [],\n list: value,\n mount: createKeyedMount(ctxSnapshot),\n ctxSnapshot,\n onDuplicateKey: (key) => {\n console.warn(`[elur] repeat(): duplicate key \"${key}\". Keys must be unique; the previous entry leaks (orphaned nodes + live effects).`);\n },\n });\n disposes.push(() => {\n for (const entry of keyedState.values()) {\n entry.cleanup();\n }\n keyedState.clear();\n });\n } else if (Array.isArray(value)) {\n for (const item of value) {\n if (isElurComponent(item)) {\n _mountComponentDeferred(item, anchor.parentNode!, anchor, postMountHooks, disposes);\n } else if (isElurTemplate(item)) {\n item._render(anchor.parentNode!, anchor);\n } else if (item != null && item !== false) {\n anchor.parentNode!.insertBefore(\n document.createTextNode(String(item)),\n anchor\n );\n }\n }\n } else if (value != null && value !== false) {\n anchor.parentNode!.insertBefore(\n document.createTextNode(String(value)),\n anchor\n );\n }\n return;\n }\n\n // Reactive function path\n let textNode: Text | null = null;\n let innerCleanup: (() => void) | null = null;\n\n type Key = RepeatKey;\n let keyedState: Map<Key, KEntry> | null = null;\n let prevKeyOrder: Key[] = [];\n let keyedZoneStart: Node | null = null;\n\n const ctxSnapshot = _captureContextSnapshot();\n const keyedMount = createKeyedMount(ctxSnapshot);\n\n let _textQueued = false;\n let _pendingText = \"\";\n let _isFirstText = true;\n\n const dispose = effect(() => {\n const v = (value as () => unknown)();\n\n if (typeof v === \"string\" || typeof v === \"number\") {\n _pendingText = String(v);\n\n const update = () => {\n _textQueued = false;\n if (innerCleanup) {\n innerCleanup();\n innerCleanup = null;\n }\n if (!textNode) {\n textNode = document.createTextNode(_pendingText);\n anchor.parentNode!.insertBefore(textNode, anchor);\n } else {\n textNode.nodeValue = _pendingText;\n }\n };\n\n if (_isFirstText) {\n _isFirstText = false;\n update();\n } else if (!_textQueued) {\n _textQueued = true;\n queueDOMWrite(update);\n }\n return;\n }\n\n _textQueued = false;\n _isFirstText = false;\n\n if (textNode) {\n textNode.parentNode?.removeChild(textNode);\n textNode = null;\n }\n if (innerCleanup) {\n innerCleanup();\n innerCleanup = null;\n }\n\n if (v == null || v === false) {\n // Empty\n } else if (v != null && typeof v === \"object\" && (v as Record<PropertyKey, unknown>)[ELUR_RENDER_PROTOCOL] != null) {\n const proto = (v as Record<PropertyKey, unknown>)[ELUR_RENDER_PROTOCOL] as { mountDom?: (ctx: import(\"./types.js\").DomProtocolContext) => (() => void) | void };\n if (proto.mountDom) {\n innerCleanup = proto.mountDom({ parent: anchor.parentNode!, before: anchor }) ?? null;\n } else {\n textNode = document.createTextNode(String(v));\n anchor.parentNode!.insertBefore(textNode, anchor);\n }\n } else if (isElurTemplate(v)) {\n innerCleanup = v._render(anchor.parentNode!, anchor);\n } else if (isElurComponent(v)) {\n innerCleanup = _mountComponentWithCtx(v, anchor.parentNode!, anchor, ctxSnapshot);\n } else if (isKeyedList(v)) {\n\n if (!keyedState) {\n keyedState = new Map();\n keyedZoneStart = document.createTextNode(\"\");\n anchor.parentNode!.insertBefore(keyedZoneStart, anchor);\n }\n\n reconcileKeyedList({\n zoneStart: keyedZoneStart!,\n anchor,\n state: keyedState,\n prevOrder: prevKeyOrder,\n list: v,\n mount: keyedMount,\n onDuplicateKey: (key) => {\n console.warn(`[elur] repeat(): duplicate key \"${key}\". Keys must be unique; the previous entry leaks (orphaned nodes + live effects).`);\n },\n });\n } else if (Array.isArray(v)) {\n const cleanups: Array<() => void> = [];\n for (const item of v) {\n if (isElurComponent(item)) {\n cleanups.push(_mountComponent(item, anchor.parentNode!, anchor));\n } else if (isElurTemplate(item)) {\n cleanups.push(item._render(anchor.parentNode!, anchor));\n } else if (item != null && item !== false) {\n const t = document.createTextNode(String(item));\n anchor.parentNode!.insertBefore(t, anchor);\n cleanups.push(() => t.parentNode?.removeChild(t));\n }\n }\n innerCleanup = () => cleanups.forEach((c) => c());\n } else {\n textNode = document.createTextNode(String(v));\n anchor.parentNode!.insertBefore(textNode, anchor);\n }\n });\n\n disposes.push(() => {\n dispose();\n if (innerCleanup) {\n innerCleanup();\n innerCleanup = null;\n }\n if (textNode) {\n textNode.parentNode?.removeChild(textNode);\n textNode = null;\n }\n if (keyedState) {\n for (const entry of keyedState.values()) {\n entry.cleanup();\n }\n keyedState = null;\n keyedZoneStart = null;\n }\n });\n}\n"],"mappings":"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"}