@elurjs/core 3.6.2 → 3.7.0-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (211) 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 +1 -1
  116. package/dist/lib/elur/router.cjs.map +1 -1
  117. package/dist/lib/elur/router.js +1 -1
  118. package/dist/lib/elur/server/index.cjs +1 -1
  119. package/dist/lib/elur/server/index.cjs.map +1 -1
  120. package/dist/lib/elur/server/index.js +175 -107
  121. package/dist/lib/elur/server/index.js.map +1 -1
  122. package/dist/lib/elur/store.cjs +1 -1
  123. package/dist/lib/elur/store.cjs.map +1 -1
  124. package/dist/lib/elur/store.js +1 -1
  125. package/dist/lib/elur/template/bindings.cjs +1 -1
  126. package/dist/lib/elur/template/bindings.cjs.map +1 -1
  127. package/dist/lib/elur/template/bindings.js +98 -84
  128. package/dist/lib/elur/template/bindings.js.map +1 -1
  129. package/dist/lib/elur/template/dom-write.d.cts +1 -5
  130. package/dist/lib/elur/template/dom-write.d.ts +1 -5
  131. package/dist/lib/elur/template/error-boundary.cjs +1 -1
  132. package/dist/lib/elur/template/error-boundary.cjs.map +1 -1
  133. package/dist/lib/elur/template/error-boundary.js +56 -50
  134. package/dist/lib/elur/template/error-boundary.js.map +1 -1
  135. package/dist/lib/elur/template/html.cjs +1 -1
  136. package/dist/lib/elur/template/html.cjs.map +1 -1
  137. package/dist/lib/elur/template/html.js +40 -37
  138. package/dist/lib/elur/template/html.js.map +1 -1
  139. package/dist/lib/elur/template/index.cjs +1 -1
  140. package/dist/lib/elur/template/index.d.cts +2 -1
  141. package/dist/lib/elur/template/index.d.ts +2 -1
  142. package/dist/lib/elur/template/index.js +13 -12
  143. package/dist/lib/elur/template/keyed-diff.d.cts +1 -32
  144. package/dist/lib/elur/template/keyed-diff.d.ts +1 -32
  145. package/dist/lib/elur/template/keyed.cjs +1 -1
  146. package/dist/lib/elur/template/keyed.cjs.map +1 -1
  147. package/dist/lib/elur/template/keyed.d.cts +10 -2
  148. package/dist/lib/elur/template/keyed.d.ts +10 -2
  149. package/dist/lib/elur/template/keyed.js +12 -1
  150. package/dist/lib/elur/template/keyed.js.map +1 -1
  151. package/dist/lib/elur/template/mount-helpers.d.cts +1 -29
  152. package/dist/lib/elur/template/mount-helpers.d.ts +1 -29
  153. package/dist/lib/elur/template/node-binding.d.cts +1 -6
  154. package/dist/lib/elur/template/node-binding.d.ts +1 -6
  155. package/dist/lib/elur/template/portal.cjs +1 -1
  156. package/dist/lib/elur/template/portal.cjs.map +1 -1
  157. package/dist/lib/elur/template/portal.js +1 -1
  158. package/dist/lib/elur/template/transitions.cjs +1 -1
  159. package/dist/lib/elur/template/transitions.cjs.map +1 -1
  160. package/dist/lib/elur/template/transitions.js +2 -2
  161. package/dist/lib/elur/template/types.cjs +1 -1
  162. package/dist/lib/elur/template/types.cjs.map +1 -1
  163. package/dist/lib/elur/template/types.d.cts +55 -0
  164. package/dist/lib/elur/template/types.d.ts +55 -0
  165. package/dist/lib/elur/template/types.js +5 -1
  166. package/dist/lib/elur/template/types.js.map +1 -1
  167. package/dist/lib/elur.cjs +1 -1
  168. package/dist/lib/elur.js +2 -2
  169. package/dist/lib/form.cjs +1 -1
  170. package/dist/lib/form.js +1 -1
  171. package/dist/lib/hydrate.cjs +1 -2
  172. package/dist/lib/hydrate.js +2 -410
  173. package/dist/lib/index.cjs +1 -1
  174. package/dist/lib/index.js +2 -2
  175. package/dist/lib/lifecycle.cjs +1 -1
  176. package/dist/lib/lifecycle.js +4 -0
  177. package/dist/lib/plugins.cjs +1 -1
  178. package/dist/lib/plugins.js +1 -1
  179. package/dist/lib/router.cjs +1 -1
  180. package/dist/lib/router.js +1 -1
  181. package/dist/lib/server.cjs +1 -1
  182. package/dist/lib/server.js +175 -107
  183. package/dist/lib/signals.cjs +1 -2
  184. package/dist/lib/signals.js +2 -218
  185. package/dist/lib/store.cjs +1 -1
  186. package/dist/lib/store.js +1 -1
  187. package/dist/lib/template.cjs +1 -1
  188. package/dist/lib/template.js +13 -12
  189. package/package.json +7 -9
  190. package/dist/lib/elur/component.cjs.map +0 -1
  191. package/dist/lib/elur/component.js.map +0 -1
  192. package/dist/lib/elur/hydrate/index.cjs.map +0 -1
  193. package/dist/lib/elur/hydrate/index.js.map +0 -1
  194. package/dist/lib/elur/reactivity.cjs.map +0 -1
  195. package/dist/lib/elur/reactivity.js.map +0 -1
  196. package/dist/lib/elur/template/dom-write.cjs +0 -2
  197. package/dist/lib/elur/template/dom-write.cjs.map +0 -1
  198. package/dist/lib/elur/template/dom-write.js +0 -16
  199. package/dist/lib/elur/template/dom-write.js.map +0 -1
  200. package/dist/lib/elur/template/keyed-diff.cjs +0 -2
  201. package/dist/lib/elur/template/keyed-diff.cjs.map +0 -1
  202. package/dist/lib/elur/template/keyed-diff.js +0 -100
  203. package/dist/lib/elur/template/keyed-diff.js.map +0 -1
  204. package/dist/lib/elur/template/mount-helpers.cjs +0 -2
  205. package/dist/lib/elur/template/mount-helpers.cjs.map +0 -1
  206. package/dist/lib/elur/template/mount-helpers.js +0 -132
  207. package/dist/lib/elur/template/mount-helpers.js.map +0 -1
  208. package/dist/lib/elur/template/node-binding.cjs +0 -2
  209. package/dist/lib/elur/template/node-binding.cjs.map +0 -1
  210. package/dist/lib/elur/template/node-binding.js +0 -95
  211. package/dist/lib/elur/template/node-binding.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"devtools.cjs","names":[],"sources":["../../src/elur/devtools.ts"],"sourcesContent":["import { _debugGetRouterInternal } from \"./router.js\";\nimport {\n _setComponentDebugHooks,\n type ElurComponent,\n} from \"./lifecycle.js\";\nimport {\n _setSignalDebugHooks,\n type Signal,\n} from \"./reactivity.js\";\n\nexport interface DevToolsOptions {\n refreshMs?: number;\n historyLimit?: number;\n initiallyOpen?: boolean;\n position?: \"bottom-right\" | \"bottom-left\";\n}\n\ntype _DevToolsTab = \"signals\" | \"components\" | \"router\";\n\ninterface _DevToolsState {\n enabled: boolean;\n activeTab: _DevToolsTab;\n renderedTab: _DevToolsTab | null;\n refreshId: ReturnType<typeof setInterval> | null;\n root: HTMLDivElement | null;\n panel: HTMLDivElement | null;\n content: HTMLDivElement | null;\n dispose: (() => void) | null;\n renderKeys: Record<_DevToolsTab, string>;\n scrollMemo: Record<_DevToolsTab, { top: number; left: number }>;\n}\n\nconst _state: _DevToolsState = {\n enabled: false,\n activeTab: \"signals\",\n renderedTab: null,\n refreshId: null,\n root: null,\n panel: null,\n content: null,\n dispose: null,\n renderKeys: { signals: \"\", components: \"\", router: \"\" },\n scrollMemo: {\n signals: { top: 0, left: 0 },\n components: { top: 0, left: 0 },\n router: { top: 0, left: 0 },\n },\n};\n\ntype _SignalRef = { deref(): Signal<any> | undefined };\n\ninterface _SignalMeta {\n id: number;\n createdAt: number;\n lastUpdated: number;\n history: Array<{ at: number; value: unknown }>;\n}\n\ninterface _SignalSnapshot {\n id: number;\n value: unknown;\n subscriberCount: number;\n createdAt: number;\n lastUpdated: number;\n history: Array<{ at: number; value: unknown }>;\n}\n\ninterface _ComponentSnapshot {\n id: number;\n parentId: number | null;\n debugName: string;\n mountedAt: number;\n hasDefaultSlot: boolean;\n slotNames: string[];\n props: Record<string, unknown>;\n}\n\ninterface _ComponentRecord extends _ComponentSnapshot {\n ref: _ComponentRef;\n}\n\ntype _ComponentRef = { deref(): ElurComponent | undefined };\n\nconst _signalRefs = new Set<_SignalRef>();\nlet _signalMeta = new WeakMap<Signal<any>, _SignalMeta>();\nlet _signalSeq = 1;\nlet _signalHistoryLimit = 50;\n\nlet _componentIds = new WeakMap<ElurComponent, number>();\nconst _componentMounted = new Map<number, _ComponentRecord>();\nconst _componentMountStack: number[] = [];\nlet _componentSeq = 1;\n\nfunction _makeSignalRef<T>(s: Signal<T>): _SignalRef {\n if (typeof WeakRef !== \"undefined\") return new WeakRef(s) as _SignalRef;\n return { deref: () => s };\n}\n\nfunction _makeComponentRef(inst: ElurComponent): _ComponentRef {\n if (typeof WeakRef !== \"undefined\") return new WeakRef(inst) as _ComponentRef;\n return { deref: () => inst };\n}\n\nfunction _trimSignalHistory(meta: _SignalMeta): void {\n if (meta.history.length > _signalHistoryLimit) {\n meta.history.splice(0, meta.history.length - _signalHistoryLimit);\n }\n}\n\nfunction _ensureSignalMeta<T>(s: Signal<T>, initialValue: T): _SignalMeta {\n const existing = _signalMeta.get(s);\n if (existing) {\n _trimSignalHistory(existing);\n return existing;\n }\n\n const now = Date.now();\n const meta: _SignalMeta = {\n id: _signalSeq++,\n createdAt: now,\n lastUpdated: now,\n history: [{ at: now, value: initialValue }],\n };\n _signalMeta.set(s, meta);\n _signalRefs.add(_makeSignalRef(s));\n return meta;\n}\n\n/** @internal Exported for testing. */\nexport function _listSignals(): _SignalSnapshot[] {\n const out: _SignalSnapshot[] = [];\n\n for (const ref of Array.from(_signalRefs)) {\n const s = ref.deref();\n if (!s) {\n _signalRefs.delete(ref);\n continue;\n }\n\n const meta = _signalMeta.get(s);\n if (!meta) continue;\n\n const subCount = (s as unknown as { _subs?: Set<() => void> })._subs?.size ?? 0;\n\n out.push({\n id: meta.id,\n value: s.peek(),\n subscriberCount: subCount,\n createdAt: meta.createdAt,\n lastUpdated: meta.lastUpdated,\n history: meta.history.slice(),\n });\n }\n\n out.sort((a, b) => b.lastUpdated - a.lastUpdated);\n return out;\n}\n\nfunction _componentName(inst: ElurComponent): string {\n const maybeDebugName = (inst as { _debugName?: string })._debugName;\n if (maybeDebugName && maybeDebugName.trim()) return maybeDebugName;\n const ctor = (inst as { constructor?: { name?: string } }).constructor;\n return ctor?.name && ctor.name.trim() ? ctor.name : \"AnonymousComponent\";\n}\n\nfunction _componentSlotNames(inst: ElurComponent): string[] {\n const slots = (inst as unknown as { _slots?: unknown })._slots;\n if (!(slots instanceof Map)) return [];\n return Array.from(slots.keys()).map((k) => String(k));\n}\n\nfunction _componentProps(inst: ElurComponent): Record<string, unknown> {\n const out: Record<string, unknown> = {};\n for (const key of Object.keys(inst as unknown as Record<string, unknown>)) {\n if (\n key === \"__isElurComponent\" ||\n key === \"children\" ||\n key === \"_debugName\" ||\n key.startsWith(\"_\")\n ) {\n continue;\n }\n const value = (inst as unknown as Record<string, unknown>)[key];\n if (typeof value === \"function\") continue;\n out[key] = value;\n }\n return out;\n}\n\nfunction _mountPathChain(fullPath: string | null): string[] {\n if (!fullPath) return [];\n if (fullPath === \"*\") return [\"*\"];\n\n const parts = fullPath.split(\"/\").filter(Boolean);\n const out: string[] = [];\n let cur = \"\";\n for (const part of parts) {\n cur += \"/\" + part;\n out.push(cur);\n }\n return out.length > 0 ? out : [\"/\"];\n}\n\nfunction _listMountedComponents(): _ComponentSnapshot[] {\n const out: _ComponentSnapshot[] = [];\n\n for (const [id, item] of _componentMounted) {\n const inst = item.ref.deref();\n if (!inst) {\n _componentMounted.delete(id);\n continue;\n }\n\n // Keep rows fresh while panel is open (debug name/props can change after mount).\n item.debugName = _componentName(inst);\n item.hasDefaultSlot = inst.children != null;\n item.slotNames = _componentSlotNames(inst);\n item.props = _componentProps(inst);\n\n out.push({\n id: item.id,\n parentId: item.parentId,\n debugName: item.debugName,\n mountedAt: item.mountedAt,\n hasDefaultSlot: item.hasDefaultSlot,\n slotNames: [...item.slotNames],\n props: { ...item.props },\n });\n }\n\n out.sort((a, b) => a.id - b.id);\n return out;\n}\n\nfunction _removeMountedComponentSubtree(rootId: number): void {\n const pending = [rootId];\n while (pending.length > 0) {\n const current = pending.pop()!;\n for (const [id, record] of _componentMounted) {\n if (record.parentId === current) pending.push(id);\n }\n _componentMounted.delete(current);\n }\n}\n\nfunction _resetDevtoolsStores(): void {\n _signalRefs.clear();\n _signalMeta = new WeakMap<Signal<any>, _SignalMeta>();\n _signalSeq = 1;\n\n _componentIds = new WeakMap<ElurComponent, number>();\n _componentMounted.clear();\n _componentMountStack.length = 0;\n _componentSeq = 1;\n}\n\nfunction _safeStringify(value: unknown): string {\n if (typeof value === \"string\") return value;\n if (typeof value === \"number\" || typeof value === \"boolean\" || value == null) {\n return String(value);\n }\n try {\n return JSON.stringify(value);\n } catch {\n return Object.prototype.toString.call(value);\n }\n}\n\nfunction _escapeHtml(value: string): string {\n return value\n .replace(/&/g, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\")\n .replace(/\\\"/g, \"&quot;\")\n .replace(/'/g, \"&#39;\");\n}\n\nfunction _valuePreview(value: unknown, max = 90): string {\n const raw = _safeStringify(value);\n if (raw.length <= max) return raw;\n return raw.slice(0, max - 1) + \"…\";\n}\n\nfunction _relativeTime(ts: number): string {\n if (!ts) return \"-\";\n const diff = Date.now() - ts;\n if (diff < 1000) return `${diff}ms ago`;\n if (diff < 60_000) return `${Math.floor(diff / 1000)}s ago`;\n return `${Math.floor(diff / 60_000)}m ago`;\n}\n\nfunction _renderSignals(target: HTMLDivElement): void {\n const signals = _listSignals();\n const key = `${signals.length}:${signals.map((s) => `${s.id}-${s.lastUpdated}-${s.subscriberCount}`).join(\"|\")}`;\n if (_state.renderedTab === \"signals\" && _state.renderKeys.signals === key) return;\n _state.renderKeys.signals = key;\n _state.renderedTab = \"signals\";\n\n const rows = signals\n .map((s) => {\n const fullValue = _safeStringify(s.value);\n const preview = _valuePreview(s.value, 120);\n return `<tr data-elur-devtools-signal-id=\"${s.id}\">\n <td style=\"padding:6px 8px;white-space:nowrap;\">${s.id}</td>\n <td style=\"padding:6px 8px;max-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-family:ui-monospace, SFMono-Regular, Menlo, monospace;\" title=\"${_escapeHtml(fullValue)}\">${_escapeHtml(preview)}</td>\n <td>${s.subscriberCount}</td>\n <td data-elur-devtools-history-count=\"${s.history.length}\">${s.history.length}</td>\n <td>${_relativeTime(s.lastUpdated)}</td>\n </tr>`;\n })\n .join(\"\");\n\n target.innerHTML = `\n <div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:8px;\">\n <strong>Signals</strong>\n <span style=\"opacity:.8\">${signals.length} active</span>\n </div>\n <div data-elur-devtools-scroll=\"signals\" style=\"max-height:260px;overflow:auto;overscroll-behavior:contain;border:1px solid #2f2f35;border-radius:8px;\">\n <table style=\"width:100%;border-collapse:collapse;font-size:12px;table-layout:fixed;\">\n <thead>\n <tr style=\"background:#1f1f24;\">\n <th style=\"text-align:left;padding:6px 8px;width:42px;\">ID</th>\n <th style=\"text-align:left;padding:6px 8px;\">Value</th>\n <th style=\"text-align:left;padding:6px 8px;width:50px;\">Subs</th>\n <th style=\"text-align:left;padding:6px 8px;width:50px;\">History</th>\n <th style=\"text-align:left;padding:6px 8px;width:84px;\">Updated</th>\n </tr>\n </thead>\n <tbody>${rows}</tbody>\n </table>\n </div>\n <p style=\"margin:8px 0 0 0;font-size:11px;opacity:.75;\">Click a row to log full history in console.</p>\n `;\n\n for (const row of target.querySelectorAll<HTMLTableRowElement>(\"tr[data-elur-devtools-signal-id]\")) {\n row.style.cursor = \"pointer\";\n row.addEventListener(\"click\", () => {\n const id = Number(row.dataset.elurDevtoolsSignalId);\n const signal = signals.find((s) => s.id === id);\n if (!signal) return;\n console.group(`[Elur DevTools] Signal #${signal.id}`);\n console.log(\"Current value:\", signal.value);\n console.log(\"Subscribers:\", signal.subscriberCount);\n console.table(signal.history.map((h) => ({ at: new Date(h.at).toISOString(), value: h.value })));\n console.groupEnd();\n });\n }\n}\n\ninterface _TreeNode extends _ComponentSnapshot {\n children: _TreeNode[];\n}\n\nfunction _buildComponentTree(rows: _ComponentSnapshot[]): _TreeNode[] {\n const byId = new Map<number, _TreeNode>();\n const roots: _TreeNode[] = [];\n\n for (const row of rows) {\n byId.set(row.id, { ...row, children: [] });\n }\n\n for (const node of byId.values()) {\n if (node.parentId == null) {\n roots.push(node);\n continue;\n }\n const parent = byId.get(node.parentId);\n if (!parent) {\n roots.push(node);\n continue;\n }\n parent.children.push(node);\n }\n\n return roots;\n}\n\nfunction _renderTreeNode(node: _TreeNode, depth: number): string {\n const pad = 10 + depth * 14;\n const props = Object.keys(node.props).length > 0 ? _safeStringify(node.props) : \"{}\";\n const slots = node.slotNames.length > 0 ? node.slotNames.join(\", \") : \"none\";\n\n const header = `<div style=\"padding:6px 8px 6px ${pad}px;border-bottom:1px solid #24242b;\">\n <div><strong>${_escapeHtml(node.debugName)}</strong> <span style=\"opacity:.7\">#${node.id}</span></div>\n <div style=\"font-size:11px;opacity:.8;\">slots: ${slots} | default-slot: ${node.hasDefaultSlot ? \"yes\" : \"no\"}</div>\n <div style=\"font-size:11px;opacity:.8;\">props: ${_escapeHtml(_valuePreview(props, 180))}</div>\n </div>`;\n\n return header + node.children.map((c) => _renderTreeNode(c, depth + 1)).join(\"\");\n}\n\nfunction _renderComponents(target: HTMLDivElement): void {\n const rows = _listMountedComponents();\n const router = _debugGetRouterInternal();\n const routeKey = router ? `${router.currentPath}|${router.matchedPath ?? \"\"}` : \"no-router\";\n const key = `${routeKey}:${rows.length}:${rows.map((r) => `${r.id}-${r.parentId}-${r.debugName}-${r.hasDefaultSlot}-${r.slotNames.join(\",\")}-${_safeStringify(r.props)}`).join(\"|\")}`;\n if (_state.renderedTab === \"components\" && _state.renderKeys.components === key) return;\n _state.renderKeys.components = key;\n _state.renderedTab = \"components\";\n\n const roots = _buildComponentTree(rows);\n\n target.innerHTML = `\n <div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:8px;\">\n <strong>Component Tree</strong>\n <span style=\"opacity:.8\">${rows.length} mounted</span>\n </div>\n <div style=\"font-size:11px;opacity:.82;margin-bottom:8px;display:flex;gap:8px;flex-wrap:wrap;\">\n <span><b>current:</b> ${_escapeHtml(router?.currentPath ?? \"-\")}</span>\n <span><b>matched:</b> ${_escapeHtml(router?.matchedPath ?? \"none\")}</span>\n </div>\n <div data-elur-devtools-scroll=\"components\" style=\"max-height:280px;overflow:auto;overscroll-behavior:contain;border:1px solid #2f2f35;border-radius:8px;\">\n ${roots.length > 0\n ? roots.map((r) => _renderTreeNode(r, 0)).join(\"\")\n : \"<div style='padding:10px;opacity:.75'>No mounted components tracked. Enable devtools before your first mount() to capture initial tree.</div>\"}\n </div>\n `;\n}\n\nfunction _renderRouter(target: HTMLDivElement): void {\n const router = _debugGetRouterInternal();\n const key = router\n ? `${router.mode}|${router.base}|${router.currentPath}|${JSON.stringify(router.params)}|${JSON.stringify(router.query)}|${router.matchedPath}|${router.activeGuards.names.join(\",\")}`\n : \"none\";\n if (_state.renderedTab === \"router\" && _state.renderKeys.router === key) return;\n _state.renderKeys.router = key;\n _state.renderedTab = \"router\";\n\n if (!router) {\n target.innerHTML = `\n <strong>Router State</strong>\n <div style=\"margin-top:8px;opacity:.75\">No active Elur router instance. Ensure your app uses createRouter()/RouterView from @elurjs/core/router.</div>\n `;\n return;\n }\n\n const chain = _mountPathChain(router.matchedPath);\n target.innerHTML = `\n <strong>Router State</strong>\n <div data-elur-devtools-scroll=\"router\" style=\"margin-top:8px;font-size:12px;line-height:1.55;max-height:280px;overflow:auto;overscroll-behavior:contain;border:1px solid #2f2f35;border-radius:8px;padding:8px;\">\n <div><b>mode</b>: ${router.mode}</div>\n <div><b>base</b>: ${router.base}</div>\n <div><b>current</b>: ${_escapeHtml(router.currentPath)}</div>\n <div><b>params</b>: ${_escapeHtml(_safeStringify(router.params))}</div>\n <div><b>query</b>: ${_escapeHtml(_safeStringify(router.query))}</div>\n <div><b>matched</b>: ${_escapeHtml(router.matchedPath ?? \"none\")}</div>\n <div><b>matched chain</b>: ${chain.length > 0 ? _escapeHtml(chain.join(\" -> \")) : \"none\"}</div>\n <div><b>guards</b>: ${router.activeGuards.names.length > 0 ? _escapeHtml(router.activeGuards.names.join(\", \")) : \"none\"}</div>\n </div>\n `;\n}\n\nfunction _rememberScroll(tab: _DevToolsTab): void {\n if (!_state.content) return;\n const box = _state.content.querySelector<HTMLElement>(`[data-elur-devtools-scroll='${tab}']`);\n if (!box) return;\n _state.scrollMemo[tab] = { top: box.scrollTop, left: box.scrollLeft };\n}\n\nfunction _restoreScroll(tab: _DevToolsTab): void {\n if (!_state.content) return;\n const box = _state.content.querySelector<HTMLElement>(`[data-elur-devtools-scroll='${tab}']`);\n if (!box) return;\n const memo = _state.scrollMemo[tab];\n box.scrollTop = memo.top;\n box.scrollLeft = memo.left;\n if (box.dataset.elurDevtoolsScrollBound !== \"1\") {\n box.addEventListener(\"scroll\", () => {\n _state.scrollMemo[tab] = { top: box.scrollTop, left: box.scrollLeft };\n }, { passive: true });\n box.dataset.elurDevtoolsScrollBound = \"1\";\n }\n}\n\nfunction _refreshPanel(force = false): void {\n if (!_state.content) return;\n\n const tab = _state.activeTab;\n if (!force) _rememberScroll(tab);\n\n if (_state.activeTab === \"signals\") {\n _renderSignals(_state.content);\n _restoreScroll(\"signals\");\n return;\n }\n if (_state.activeTab === \"components\") {\n _renderComponents(_state.content);\n _restoreScroll(\"components\");\n return;\n }\n _renderRouter(_state.content);\n _restoreScroll(\"router\");\n}\n\nfunction _syncTabButtons(): void {\n if (!_state.panel) return;\n for (const btn of _state.panel.querySelectorAll<HTMLButtonElement>(\"button[data-elur-devtools-tab]\")) {\n const isActive = btn.dataset.elurDevtoolsTab === _state.activeTab;\n btn.style.background = isActive ? \"#2d4c7a\" : \"#1f1f24\";\n }\n}\n\nfunction _createOverlay(options: Required<Pick<DevToolsOptions, \"position\">>): void {\n const root = document.createElement(\"div\");\n root.setAttribute(\"data-elur-devtools-root\", \"\");\n root.style.position = \"fixed\";\n root.style.zIndex = \"2147483647\";\n root.style.bottom = \"16px\";\n root.style.right = options.position === \"bottom-right\" ? \"16px\" : \"auto\";\n root.style.left = options.position === \"bottom-left\" ? \"16px\" : \"auto\";\n root.style.fontFamily = \"ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, sans-serif\";\n\n const button = document.createElement(\"button\");\n button.type = \"button\";\n button.textContent = \"Elur DevTools\";\n button.setAttribute(\"data-elur-devtools-button\", \"\");\n button.style.background = \"#111827\";\n button.style.color = \"#f9fafb\";\n button.style.border = \"1px solid #374151\";\n button.style.borderRadius = \"999px\";\n button.style.padding = \"8px 12px\";\n button.style.cursor = \"pointer\";\n button.style.boxShadow = \"0 6px 18px rgba(0,0,0,.3)\";\n\n const panel = document.createElement(\"div\");\n panel.setAttribute(\"data-elur-devtools-panel\", \"\");\n panel.style.marginTop = \"8px\";\n panel.style.width = \"460px\";\n panel.style.maxWidth = \"min(92vw, 460px)\";\n panel.style.background = \"#15151b\";\n panel.style.color = \"#e5e7eb\";\n panel.style.border = \"1px solid #2f2f35\";\n panel.style.borderRadius = \"12px\";\n panel.style.padding = \"10px\";\n panel.style.display = \"none\";\n panel.style.boxShadow = \"0 14px 28px rgba(0,0,0,.35)\";\n\n const tabs = document.createElement(\"div\");\n tabs.style.display = \"flex\";\n tabs.style.gap = \"6px\";\n tabs.style.marginBottom = \"10px\";\n\n const content = document.createElement(\"div\");\n content.setAttribute(\"data-elur-devtools-content\", \"\");\n\n const makeTab = (name: _DevToolsTab, label: string): HTMLButtonElement => {\n const t = document.createElement(\"button\");\n t.type = \"button\";\n t.textContent = label;\n t.setAttribute(\"data-elur-devtools-tab\", name);\n t.style.border = \"1px solid #353543\";\n t.style.borderRadius = \"8px\";\n t.style.padding = \"6px 9px\";\n t.style.background = \"#1f1f24\";\n t.style.color = \"#d1d5db\";\n t.style.cursor = \"pointer\";\n t.addEventListener(\"click\", () => {\n _state.activeTab = name;\n _syncTabButtons();\n _refreshPanel(true);\n });\n return t;\n };\n\n tabs.appendChild(makeTab(\"signals\", \"Signals\"));\n tabs.appendChild(makeTab(\"components\", \"Components\"));\n tabs.appendChild(makeTab(\"router\", \"Router\"));\n\n button.addEventListener(\"click\", () => {\n panel.style.display = panel.style.display === \"none\" ? \"block\" : \"none\";\n if (panel.style.display === \"block\") {\n _syncTabButtons();\n _refreshPanel(true);\n }\n });\n\n panel.appendChild(tabs);\n panel.appendChild(content);\n root.appendChild(button);\n root.appendChild(panel);\n document.body.appendChild(root);\n\n _state.root = root;\n _state.panel = panel;\n _state.content = content;\n}\n\nexport function disableDevTools(): void {\n if (!_state.enabled) return;\n _state.enabled = false;\n\n if (_state.refreshId != null) {\n clearInterval(_state.refreshId);\n _state.refreshId = null;\n }\n\n _setSignalDebugHooks(null);\n _setComponentDebugHooks(null);\n _resetDevtoolsStores();\n\n if (_state.root?.parentNode) {\n _state.root.parentNode.removeChild(_state.root);\n }\n\n _state.root = null;\n _state.panel = null;\n _state.content = null;\n _state.dispose = null;\n _state.renderedTab = null;\n _state.renderKeys = { signals: \"\", components: \"\", router: \"\" };\n _state.scrollMemo = {\n signals: { top: 0, left: 0 },\n components: { top: 0, left: 0 },\n router: { top: 0, left: 0 },\n };\n}\n\nexport function enableDevTools(options: DevToolsOptions = {}): { disable: () => void } {\n if (typeof document === \"undefined\") {\n return { disable: () => undefined };\n }\n\n if (_state.enabled && _state.dispose) {\n return { disable: _state.dispose };\n }\n\n const refreshMs = Math.max(100, options.refreshMs ?? 350);\n _signalHistoryLimit = Math.max(1, options.historyLimit ?? 50);\n const position = options.position ?? \"bottom-right\";\n\n _state.enabled = true;\n _state.activeTab = \"signals\";\n\n // Apply the new limit to histories that were already created before enableDevTools.\n for (const ref of Array.from(_signalRefs)) {\n const s = ref.deref();\n if (!s) {\n _signalRefs.delete(ref);\n continue;\n }\n const meta = _signalMeta.get(s);\n if (meta) _trimSignalHistory(meta);\n }\n\n _setSignalDebugHooks({\n onCreate(signal, initialValue) {\n _ensureSignalMeta(signal, initialValue);\n },\n onWrite(signal, value) {\n const meta = _ensureSignalMeta(signal, value);\n const now = Date.now();\n meta.lastUpdated = now;\n meta.history.push({ at: now, value });\n _trimSignalHistory(meta);\n },\n });\n\n _setComponentDebugHooks({\n onMountStart(inst) {\n let id = _componentIds.get(inst);\n if (id == null) {\n id = _componentSeq++;\n _componentIds.set(inst, id);\n }\n\n const parentId = _componentMountStack.length > 0\n ? _componentMountStack[_componentMountStack.length - 1]\n : null;\n\n _componentMounted.set(id, {\n id,\n parentId,\n debugName: _componentName(inst),\n mountedAt: Date.now(),\n hasDefaultSlot: inst.children != null,\n slotNames: _componentSlotNames(inst),\n props: _componentProps(inst),\n ref: _makeComponentRef(inst),\n });\n\n _componentMountStack.push(id);\n },\n onMountEnd(inst) {\n const id = _componentIds.get(inst);\n if (id == null) return;\n\n const entry = _componentMounted.get(id);\n if (entry) {\n entry.debugName = _componentName(inst);\n entry.hasDefaultSlot = inst.children != null;\n entry.slotNames = _componentSlotNames(inst);\n entry.props = _componentProps(inst);\n }\n\n if (_componentMountStack[_componentMountStack.length - 1] === id) {\n _componentMountStack.pop();\n return;\n }\n\n const idx = _componentMountStack.lastIndexOf(id);\n if (idx >= 0) _componentMountStack.splice(idx, 1);\n },\n onUnmount(inst) {\n const id = _componentIds.get(inst);\n if (id == null) return;\n\n _removeMountedComponentSubtree(id);\n\n const idx = _componentMountStack.lastIndexOf(id);\n if (idx >= 0) _componentMountStack.splice(idx, 1);\n },\n });\n\n _createOverlay({ position });\n\n _state.refreshId = setInterval(() => {\n if (_state.panel?.style.display === \"block\") {\n _refreshPanel();\n }\n }, refreshMs);\n\n if (options.initiallyOpen && _state.panel) {\n _state.panel.style.display = \"block\";\n _syncTabButtons();\n _refreshPanel(true);\n }\n\n const dispose = () => disableDevTools();\n _state.dispose = dispose;\n return { disable: dispose };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"devtools.cjs","names":[],"sources":["../../src/elur/devtools.ts"],"sourcesContent":["import { _debugGetRouterInternal } from \"./router.js\";\nimport {\n _setComponentDebugHooks,\n type ElurComponent,\n} from \"./lifecycle.js\";\nimport {\n _setSignalDebugHooks,\n type Signal,\n} from \"./reactivity.js\";\n\nexport interface DevToolsOptions {\n refreshMs?: number;\n historyLimit?: number;\n initiallyOpen?: boolean;\n position?: \"bottom-right\" | \"bottom-left\";\n}\n\ntype _DevToolsTab = \"signals\" | \"components\" | \"router\";\n\ninterface _DevToolsState {\n enabled: boolean;\n activeTab: _DevToolsTab;\n renderedTab: _DevToolsTab | null;\n refreshId: ReturnType<typeof setInterval> | null;\n root: HTMLDivElement | null;\n panel: HTMLDivElement | null;\n content: HTMLDivElement | null;\n dispose: (() => void) | null;\n renderKeys: Record<_DevToolsTab, string>;\n scrollMemo: Record<_DevToolsTab, { top: number; left: number }>;\n}\n\nconst _state: _DevToolsState = {\n enabled: false,\n activeTab: \"signals\",\n renderedTab: null,\n refreshId: null,\n root: null,\n panel: null,\n content: null,\n dispose: null,\n renderKeys: { signals: \"\", components: \"\", router: \"\" },\n scrollMemo: {\n signals: { top: 0, left: 0 },\n components: { top: 0, left: 0 },\n router: { top: 0, left: 0 },\n },\n};\n\ntype _SignalRef = { deref(): Signal<any> | undefined };\n\ninterface _SignalMeta {\n id: number;\n createdAt: number;\n lastUpdated: number;\n history: Array<{ at: number; value: unknown }>;\n}\n\ninterface _SignalSnapshot {\n id: number;\n value: unknown;\n subscriberCount: number;\n createdAt: number;\n lastUpdated: number;\n history: Array<{ at: number; value: unknown }>;\n}\n\ninterface _ComponentSnapshot {\n id: number;\n parentId: number | null;\n debugName: string;\n mountedAt: number;\n hasDefaultSlot: boolean;\n slotNames: string[];\n props: Record<string, unknown>;\n}\n\ninterface _ComponentRecord extends _ComponentSnapshot {\n ref: _ComponentRef;\n}\n\ntype _ComponentRef = { deref(): ElurComponent | undefined };\n\nconst _signalRefs = new Set<_SignalRef>();\nlet _signalMeta = new WeakMap<Signal<any>, _SignalMeta>();\nlet _signalSeq = 1;\nlet _signalHistoryLimit = 50;\n\nlet _componentIds = new WeakMap<ElurComponent, number>();\nconst _componentMounted = new Map<number, _ComponentRecord>();\nconst _componentMountStack: number[] = [];\nlet _componentSeq = 1;\n\nfunction _makeSignalRef<T>(s: Signal<T>): _SignalRef {\n if (typeof WeakRef !== \"undefined\") return new WeakRef(s) as _SignalRef;\n return { deref: () => s };\n}\n\nfunction _makeComponentRef(inst: ElurComponent): _ComponentRef {\n if (typeof WeakRef !== \"undefined\") return new WeakRef(inst) as _ComponentRef;\n return { deref: () => inst };\n}\n\nfunction _trimSignalHistory(meta: _SignalMeta): void {\n if (meta.history.length > _signalHistoryLimit) {\n meta.history.splice(0, meta.history.length - _signalHistoryLimit);\n }\n}\n\nfunction _ensureSignalMeta<T>(s: Signal<T>, initialValue: T): _SignalMeta {\n const existing = _signalMeta.get(s);\n if (existing) {\n _trimSignalHistory(existing);\n return existing;\n }\n\n const now = Date.now();\n const meta: _SignalMeta = {\n id: _signalSeq++,\n createdAt: now,\n lastUpdated: now,\n history: [{ at: now, value: initialValue }],\n };\n _signalMeta.set(s, meta);\n _signalRefs.add(_makeSignalRef(s));\n return meta;\n}\n\n/** @internal Exported for testing. */\nexport function _listSignals(): _SignalSnapshot[] {\n const out: _SignalSnapshot[] = [];\n\n for (const ref of Array.from(_signalRefs)) {\n const s = ref.deref();\n if (!s) {\n _signalRefs.delete(ref);\n continue;\n }\n\n const meta = _signalMeta.get(s);\n if (!meta) continue;\n\n const subCount = (s as unknown as { _subs?: Set<() => void> })._subs?.size ?? 0;\n\n out.push({\n id: meta.id,\n value: s.peek(),\n subscriberCount: subCount,\n createdAt: meta.createdAt,\n lastUpdated: meta.lastUpdated,\n history: meta.history.slice(),\n });\n }\n\n out.sort((a, b) => b.lastUpdated - a.lastUpdated);\n return out;\n}\n\nfunction _componentName(inst: ElurComponent): string {\n const maybeDebugName = (inst as { _debugName?: string })._debugName;\n if (maybeDebugName && maybeDebugName.trim()) return maybeDebugName;\n const ctor = (inst as { constructor?: { name?: string } }).constructor;\n return ctor?.name && ctor.name.trim() ? ctor.name : \"AnonymousComponent\";\n}\n\nfunction _componentSlotNames(inst: ElurComponent): string[] {\n const slots = (inst as unknown as { _slots?: unknown })._slots;\n if (!(slots instanceof Map)) return [];\n return Array.from(slots.keys()).map((k) => String(k));\n}\n\nfunction _componentProps(inst: ElurComponent): Record<string, unknown> {\n const out: Record<string, unknown> = {};\n for (const key of Object.keys(inst as unknown as Record<string, unknown>)) {\n if (\n key === \"__isElurComponent\" ||\n key === \"children\" ||\n key === \"_debugName\" ||\n key.startsWith(\"_\")\n ) {\n continue;\n }\n const value = (inst as unknown as Record<string, unknown>)[key];\n if (typeof value === \"function\") continue;\n out[key] = value;\n }\n return out;\n}\n\nfunction _mountPathChain(fullPath: string | null): string[] {\n if (!fullPath) return [];\n if (fullPath === \"*\") return [\"*\"];\n\n const parts = fullPath.split(\"/\").filter(Boolean);\n const out: string[] = [];\n let cur = \"\";\n for (const part of parts) {\n cur += \"/\" + part;\n out.push(cur);\n }\n return out.length > 0 ? out : [\"/\"];\n}\n\nfunction _listMountedComponents(): _ComponentSnapshot[] {\n const out: _ComponentSnapshot[] = [];\n\n for (const [id, item] of _componentMounted) {\n const inst = item.ref.deref();\n if (!inst) {\n _componentMounted.delete(id);\n continue;\n }\n\n // Keep rows fresh while panel is open (debug name/props can change after mount).\n item.debugName = _componentName(inst);\n item.hasDefaultSlot = inst.children != null;\n item.slotNames = _componentSlotNames(inst);\n item.props = _componentProps(inst);\n\n out.push({\n id: item.id,\n parentId: item.parentId,\n debugName: item.debugName,\n mountedAt: item.mountedAt,\n hasDefaultSlot: item.hasDefaultSlot,\n slotNames: [...item.slotNames],\n props: { ...item.props },\n });\n }\n\n out.sort((a, b) => a.id - b.id);\n return out;\n}\n\nfunction _removeMountedComponentSubtree(rootId: number): void {\n const pending = [rootId];\n while (pending.length > 0) {\n const current = pending.pop()!;\n for (const [id, record] of _componentMounted) {\n if (record.parentId === current) pending.push(id);\n }\n _componentMounted.delete(current);\n }\n}\n\nfunction _resetDevtoolsStores(): void {\n _signalRefs.clear();\n _signalMeta = new WeakMap<Signal<any>, _SignalMeta>();\n _signalSeq = 1;\n\n _componentIds = new WeakMap<ElurComponent, number>();\n _componentMounted.clear();\n _componentMountStack.length = 0;\n _componentSeq = 1;\n}\n\nfunction _safeStringify(value: unknown): string {\n if (typeof value === \"string\") return value;\n if (typeof value === \"number\" || typeof value === \"boolean\" || value == null) {\n return String(value);\n }\n try {\n return JSON.stringify(value);\n } catch {\n return Object.prototype.toString.call(value);\n }\n}\n\nfunction _escapeHtml(value: string): string {\n return value\n .replace(/&/g, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\")\n .replace(/\\\"/g, \"&quot;\")\n .replace(/'/g, \"&#39;\");\n}\n\nfunction _valuePreview(value: unknown, max = 90): string {\n const raw = _safeStringify(value);\n if (raw.length <= max) return raw;\n return raw.slice(0, max - 1) + \"…\";\n}\n\nfunction _relativeTime(ts: number): string {\n if (!ts) return \"-\";\n const diff = Date.now() - ts;\n if (diff < 1000) return `${diff}ms ago`;\n if (diff < 60_000) return `${Math.floor(diff / 1000)}s ago`;\n return `${Math.floor(diff / 60_000)}m ago`;\n}\n\nfunction _renderSignals(target: HTMLDivElement): void {\n const signals = _listSignals();\n const key = `${signals.length}:${signals.map((s) => `${s.id}-${s.lastUpdated}-${s.subscriberCount}`).join(\"|\")}`;\n if (_state.renderedTab === \"signals\" && _state.renderKeys.signals === key) return;\n _state.renderKeys.signals = key;\n _state.renderedTab = \"signals\";\n\n const rows = signals\n .map((s) => {\n const fullValue = _safeStringify(s.value);\n const preview = _valuePreview(s.value, 120);\n return `<tr data-elur-devtools-signal-id=\"${s.id}\">\n <td style=\"padding:6px 8px;white-space:nowrap;\">${s.id}</td>\n <td style=\"padding:6px 8px;max-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-family:ui-monospace, SFMono-Regular, Menlo, monospace;\" title=\"${_escapeHtml(fullValue)}\">${_escapeHtml(preview)}</td>\n <td>${s.subscriberCount}</td>\n <td data-elur-devtools-history-count=\"${s.history.length}\">${s.history.length}</td>\n <td>${_relativeTime(s.lastUpdated)}</td>\n </tr>`;\n })\n .join(\"\");\n\n target.innerHTML = `\n <div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:8px;\">\n <strong>Signals</strong>\n <span style=\"opacity:.8\">${signals.length} active</span>\n </div>\n <div data-elur-devtools-scroll=\"signals\" style=\"max-height:260px;overflow:auto;overscroll-behavior:contain;border:1px solid #2f2f35;border-radius:8px;\">\n <table style=\"width:100%;border-collapse:collapse;font-size:12px;table-layout:fixed;\">\n <thead>\n <tr style=\"background:#1f1f24;\">\n <th style=\"text-align:left;padding:6px 8px;width:42px;\">ID</th>\n <th style=\"text-align:left;padding:6px 8px;\">Value</th>\n <th style=\"text-align:left;padding:6px 8px;width:50px;\">Subs</th>\n <th style=\"text-align:left;padding:6px 8px;width:50px;\">History</th>\n <th style=\"text-align:left;padding:6px 8px;width:84px;\">Updated</th>\n </tr>\n </thead>\n <tbody>${rows}</tbody>\n </table>\n </div>\n <p style=\"margin:8px 0 0 0;font-size:11px;opacity:.75;\">Click a row to log full history in console.</p>\n `;\n\n for (const row of target.querySelectorAll<HTMLTableRowElement>(\"tr[data-elur-devtools-signal-id]\")) {\n row.style.cursor = \"pointer\";\n row.addEventListener(\"click\", () => {\n const id = Number(row.dataset.elurDevtoolsSignalId);\n const signal = signals.find((s) => s.id === id);\n if (!signal) return;\n console.group(`[Elur DevTools] Signal #${signal.id}`);\n console.log(\"Current value:\", signal.value);\n console.log(\"Subscribers:\", signal.subscriberCount);\n console.table(signal.history.map((h) => ({ at: new Date(h.at).toISOString(), value: h.value })));\n console.groupEnd();\n });\n }\n}\n\ninterface _TreeNode extends _ComponentSnapshot {\n children: _TreeNode[];\n}\n\nfunction _buildComponentTree(rows: _ComponentSnapshot[]): _TreeNode[] {\n const byId = new Map<number, _TreeNode>();\n const roots: _TreeNode[] = [];\n\n for (const row of rows) {\n byId.set(row.id, { ...row, children: [] });\n }\n\n for (const node of byId.values()) {\n if (node.parentId == null) {\n roots.push(node);\n continue;\n }\n const parent = byId.get(node.parentId);\n if (!parent) {\n roots.push(node);\n continue;\n }\n parent.children.push(node);\n }\n\n return roots;\n}\n\nfunction _renderTreeNode(node: _TreeNode, depth: number): string {\n const pad = 10 + depth * 14;\n const props = Object.keys(node.props).length > 0 ? _safeStringify(node.props) : \"{}\";\n const slots = node.slotNames.length > 0 ? node.slotNames.join(\", \") : \"none\";\n\n const header = `<div style=\"padding:6px 8px 6px ${pad}px;border-bottom:1px solid #24242b;\">\n <div><strong>${_escapeHtml(node.debugName)}</strong> <span style=\"opacity:.7\">#${node.id}</span></div>\n <div style=\"font-size:11px;opacity:.8;\">slots: ${slots} | default-slot: ${node.hasDefaultSlot ? \"yes\" : \"no\"}</div>\n <div style=\"font-size:11px;opacity:.8;\">props: ${_escapeHtml(_valuePreview(props, 180))}</div>\n </div>`;\n\n return header + node.children.map((c) => _renderTreeNode(c, depth + 1)).join(\"\");\n}\n\nfunction _renderComponents(target: HTMLDivElement): void {\n const rows = _listMountedComponents();\n const router = _debugGetRouterInternal();\n const routeKey = router ? `${router.currentPath}|${router.matchedPath ?? \"\"}` : \"no-router\";\n const key = `${routeKey}:${rows.length}:${rows.map((r) => `${r.id}-${r.parentId}-${r.debugName}-${r.hasDefaultSlot}-${r.slotNames.join(\",\")}-${_safeStringify(r.props)}`).join(\"|\")}`;\n if (_state.renderedTab === \"components\" && _state.renderKeys.components === key) return;\n _state.renderKeys.components = key;\n _state.renderedTab = \"components\";\n\n const roots = _buildComponentTree(rows);\n\n target.innerHTML = `\n <div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:8px;\">\n <strong>Component Tree</strong>\n <span style=\"opacity:.8\">${rows.length} mounted</span>\n </div>\n <div style=\"font-size:11px;opacity:.82;margin-bottom:8px;display:flex;gap:8px;flex-wrap:wrap;\">\n <span><b>current:</b> ${_escapeHtml(router?.currentPath ?? \"-\")}</span>\n <span><b>matched:</b> ${_escapeHtml(router?.matchedPath ?? \"none\")}</span>\n </div>\n <div data-elur-devtools-scroll=\"components\" style=\"max-height:280px;overflow:auto;overscroll-behavior:contain;border:1px solid #2f2f35;border-radius:8px;\">\n ${roots.length > 0\n ? roots.map((r) => _renderTreeNode(r, 0)).join(\"\")\n : \"<div style='padding:10px;opacity:.75'>No mounted components tracked. Enable devtools before your first mount() to capture initial tree.</div>\"}\n </div>\n `;\n}\n\nfunction _renderRouter(target: HTMLDivElement): void {\n const router = _debugGetRouterInternal();\n const key = router\n ? `${router.mode}|${router.base}|${router.currentPath}|${JSON.stringify(router.params)}|${JSON.stringify(router.query)}|${router.matchedPath}|${router.activeGuards.names.join(\",\")}`\n : \"none\";\n if (_state.renderedTab === \"router\" && _state.renderKeys.router === key) return;\n _state.renderKeys.router = key;\n _state.renderedTab = \"router\";\n\n if (!router) {\n target.innerHTML = `\n <strong>Router State</strong>\n <div style=\"margin-top:8px;opacity:.75\">No active Elur router instance. Ensure your app uses createRouter()/RouterView from @elurjs/core/router.</div>\n `;\n return;\n }\n\n const chain = _mountPathChain(router.matchedPath);\n target.innerHTML = `\n <strong>Router State</strong>\n <div data-elur-devtools-scroll=\"router\" style=\"margin-top:8px;font-size:12px;line-height:1.55;max-height:280px;overflow:auto;overscroll-behavior:contain;border:1px solid #2f2f35;border-radius:8px;padding:8px;\">\n <div><b>mode</b>: ${router.mode}</div>\n <div><b>base</b>: ${router.base}</div>\n <div><b>current</b>: ${_escapeHtml(router.currentPath)}</div>\n <div><b>params</b>: ${_escapeHtml(_safeStringify(router.params))}</div>\n <div><b>query</b>: ${_escapeHtml(_safeStringify(router.query))}</div>\n <div><b>matched</b>: ${_escapeHtml(router.matchedPath ?? \"none\")}</div>\n <div><b>matched chain</b>: ${chain.length > 0 ? _escapeHtml(chain.join(\" -> \")) : \"none\"}</div>\n <div><b>guards</b>: ${router.activeGuards.names.length > 0 ? _escapeHtml(router.activeGuards.names.join(\", \")) : \"none\"}</div>\n </div>\n `;\n}\n\nfunction _rememberScroll(tab: _DevToolsTab): void {\n if (!_state.content) return;\n const box = _state.content.querySelector<HTMLElement>(`[data-elur-devtools-scroll='${tab}']`);\n if (!box) return;\n _state.scrollMemo[tab] = { top: box.scrollTop, left: box.scrollLeft };\n}\n\nfunction _restoreScroll(tab: _DevToolsTab): void {\n if (!_state.content) return;\n const box = _state.content.querySelector<HTMLElement>(`[data-elur-devtools-scroll='${tab}']`);\n if (!box) return;\n const memo = _state.scrollMemo[tab];\n box.scrollTop = memo.top;\n box.scrollLeft = memo.left;\n if (box.dataset.elurDevtoolsScrollBound !== \"1\") {\n box.addEventListener(\"scroll\", () => {\n _state.scrollMemo[tab] = { top: box.scrollTop, left: box.scrollLeft };\n }, { passive: true });\n box.dataset.elurDevtoolsScrollBound = \"1\";\n }\n}\n\nfunction _refreshPanel(force = false): void {\n if (!_state.content) return;\n\n const tab = _state.activeTab;\n if (!force) _rememberScroll(tab);\n\n if (_state.activeTab === \"signals\") {\n _renderSignals(_state.content);\n _restoreScroll(\"signals\");\n return;\n }\n if (_state.activeTab === \"components\") {\n _renderComponents(_state.content);\n _restoreScroll(\"components\");\n return;\n }\n _renderRouter(_state.content);\n _restoreScroll(\"router\");\n}\n\nfunction _syncTabButtons(): void {\n if (!_state.panel) return;\n for (const btn of _state.panel.querySelectorAll<HTMLButtonElement>(\"button[data-elur-devtools-tab]\")) {\n const isActive = btn.dataset.elurDevtoolsTab === _state.activeTab;\n btn.style.background = isActive ? \"#2d4c7a\" : \"#1f1f24\";\n }\n}\n\nfunction _createOverlay(options: Required<Pick<DevToolsOptions, \"position\">>): void {\n const root = document.createElement(\"div\");\n root.setAttribute(\"data-elur-devtools-root\", \"\");\n root.style.position = \"fixed\";\n root.style.zIndex = \"2147483647\";\n root.style.bottom = \"16px\";\n root.style.right = options.position === \"bottom-right\" ? \"16px\" : \"auto\";\n root.style.left = options.position === \"bottom-left\" ? \"16px\" : \"auto\";\n root.style.fontFamily = \"ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, sans-serif\";\n\n const button = document.createElement(\"button\");\n button.type = \"button\";\n button.textContent = \"Elur DevTools\";\n button.setAttribute(\"data-elur-devtools-button\", \"\");\n button.style.background = \"#111827\";\n button.style.color = \"#f9fafb\";\n button.style.border = \"1px solid #374151\";\n button.style.borderRadius = \"999px\";\n button.style.padding = \"8px 12px\";\n button.style.cursor = \"pointer\";\n button.style.boxShadow = \"0 6px 18px rgba(0,0,0,.3)\";\n\n const panel = document.createElement(\"div\");\n panel.setAttribute(\"data-elur-devtools-panel\", \"\");\n panel.style.marginTop = \"8px\";\n panel.style.width = \"460px\";\n panel.style.maxWidth = \"min(92vw, 460px)\";\n panel.style.background = \"#15151b\";\n panel.style.color = \"#e5e7eb\";\n panel.style.border = \"1px solid #2f2f35\";\n panel.style.borderRadius = \"12px\";\n panel.style.padding = \"10px\";\n panel.style.display = \"none\";\n panel.style.boxShadow = \"0 14px 28px rgba(0,0,0,.35)\";\n\n const tabs = document.createElement(\"div\");\n tabs.style.display = \"flex\";\n tabs.style.gap = \"6px\";\n tabs.style.marginBottom = \"10px\";\n\n const content = document.createElement(\"div\");\n content.setAttribute(\"data-elur-devtools-content\", \"\");\n\n const makeTab = (name: _DevToolsTab, label: string): HTMLButtonElement => {\n const t = document.createElement(\"button\");\n t.type = \"button\";\n t.textContent = label;\n t.setAttribute(\"data-elur-devtools-tab\", name);\n t.style.border = \"1px solid #353543\";\n t.style.borderRadius = \"8px\";\n t.style.padding = \"6px 9px\";\n t.style.background = \"#1f1f24\";\n t.style.color = \"#d1d5db\";\n t.style.cursor = \"pointer\";\n t.addEventListener(\"click\", () => {\n _state.activeTab = name;\n _syncTabButtons();\n _refreshPanel(true);\n });\n return t;\n };\n\n tabs.appendChild(makeTab(\"signals\", \"Signals\"));\n tabs.appendChild(makeTab(\"components\", \"Components\"));\n tabs.appendChild(makeTab(\"router\", \"Router\"));\n\n button.addEventListener(\"click\", () => {\n panel.style.display = panel.style.display === \"none\" ? \"block\" : \"none\";\n if (panel.style.display === \"block\") {\n _syncTabButtons();\n _refreshPanel(true);\n }\n });\n\n panel.appendChild(tabs);\n panel.appendChild(content);\n root.appendChild(button);\n root.appendChild(panel);\n document.body.appendChild(root);\n\n _state.root = root;\n _state.panel = panel;\n _state.content = content;\n}\n\nexport function disableDevTools(): void {\n if (!_state.enabled) return;\n _state.enabled = false;\n\n if (_state.refreshId != null) {\n clearInterval(_state.refreshId);\n _state.refreshId = null;\n }\n\n _setSignalDebugHooks(null);\n _setComponentDebugHooks(null);\n _resetDevtoolsStores();\n\n if (_state.root?.parentNode) {\n _state.root.parentNode.removeChild(_state.root);\n }\n\n _state.root = null;\n _state.panel = null;\n _state.content = null;\n _state.dispose = null;\n _state.renderedTab = null;\n _state.renderKeys = { signals: \"\", components: \"\", router: \"\" };\n _state.scrollMemo = {\n signals: { top: 0, left: 0 },\n components: { top: 0, left: 0 },\n router: { top: 0, left: 0 },\n };\n}\n\nexport function enableDevTools(options: DevToolsOptions = {}): { disable: () => void } {\n if (typeof document === \"undefined\") {\n return { disable: () => undefined };\n }\n\n if (_state.enabled && _state.dispose) {\n return { disable: _state.dispose };\n }\n\n const refreshMs = Math.max(100, options.refreshMs ?? 350);\n _signalHistoryLimit = Math.max(1, options.historyLimit ?? 50);\n const position = options.position ?? \"bottom-right\";\n\n _state.enabled = true;\n _state.activeTab = \"signals\";\n\n // Apply the new limit to histories that were already created before enableDevTools.\n for (const ref of Array.from(_signalRefs)) {\n const s = ref.deref();\n if (!s) {\n _signalRefs.delete(ref);\n continue;\n }\n const meta = _signalMeta.get(s);\n if (meta) _trimSignalHistory(meta);\n }\n\n _setSignalDebugHooks({\n onCreate(signal, initialValue) {\n _ensureSignalMeta(signal, initialValue);\n },\n onWrite(signal, value) {\n const meta = _ensureSignalMeta(signal, value);\n const now = Date.now();\n meta.lastUpdated = now;\n meta.history.push({ at: now, value });\n _trimSignalHistory(meta);\n },\n });\n\n _setComponentDebugHooks({\n onMountStart(inst) {\n let id = _componentIds.get(inst);\n if (id == null) {\n id = _componentSeq++;\n _componentIds.set(inst, id);\n }\n\n const parentId = _componentMountStack.length > 0\n ? _componentMountStack[_componentMountStack.length - 1]\n : null;\n\n _componentMounted.set(id, {\n id,\n parentId,\n debugName: _componentName(inst),\n mountedAt: Date.now(),\n hasDefaultSlot: inst.children != null,\n slotNames: _componentSlotNames(inst),\n props: _componentProps(inst),\n ref: _makeComponentRef(inst),\n });\n\n _componentMountStack.push(id);\n },\n onMountEnd(inst) {\n const id = _componentIds.get(inst);\n if (id == null) return;\n\n const entry = _componentMounted.get(id);\n if (entry) {\n entry.debugName = _componentName(inst);\n entry.hasDefaultSlot = inst.children != null;\n entry.slotNames = _componentSlotNames(inst);\n entry.props = _componentProps(inst);\n }\n\n if (_componentMountStack[_componentMountStack.length - 1] === id) {\n _componentMountStack.pop();\n return;\n }\n\n const idx = _componentMountStack.lastIndexOf(id);\n if (idx >= 0) _componentMountStack.splice(idx, 1);\n },\n onUnmount(inst) {\n const id = _componentIds.get(inst);\n if (id == null) return;\n\n _removeMountedComponentSubtree(id);\n\n const idx = _componentMountStack.lastIndexOf(id);\n if (idx >= 0) _componentMountStack.splice(idx, 1);\n },\n });\n\n _createOverlay({ position });\n\n _state.refreshId = setInterval(() => {\n if (_state.panel?.style.display === \"block\") {\n _refreshPanel();\n }\n }, refreshMs);\n\n if (options.initiallyOpen && _state.panel) {\n _state.panel.style.display = \"block\";\n _syncTabButtons();\n _refreshPanel(true);\n }\n\n const dispose = () => disableDevTools();\n _state.dispose = dispose;\n return { disable: dispose };\n}\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { _setSignalDebugHooks as e } from "./signals.js";
1
+ import { _setSignalDebugHooks as e } from "./elur/next-2/reactivity.js";
2
2
  import { _setComponentDebugHooks as t } from "./lifecycle.js";
3
3
  import { _debugGetRouterInternal as n } from "./router.js";
4
4
  //#region src/elur/devtools.ts
@@ -1,2 +1,2 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`./signals.cjs`);function t(e=`Required`){return t=>t==null||t===``||Array.isArray(t)&&t.length===0?e:null}function n(e,t){return n=>typeof n==`string`&&n.length<e?t??`Minimum ${e} characters`:null}function r(e,t){return n=>typeof n==`string`&&n.length>e?t??`Maximum ${e} characters`:null}function i(e,t=`Invalid format`){return n=>typeof n==`string`&&!e.test(n)?t:null}function a(e=`Invalid email`){return i(/^[^\s@]+@[^\s@]+\.[^\s@]+$/,e)}function o(e,t){return n=>typeof n==`number`&&n<e?t??`Minimum value is ${e}`:null}function s(e,t){return n=>typeof n==`number`&&n>e?t??`Maximum value is ${e}`:null}function c(e){return e}var l={required:t,minLength:n,maxLength:r,email:a,pattern:i,min:o,max:s};function u(e,t){return{...e,...t}}function d(t,n=[],r=`blur`,i){let a=e.signal(t),o=e.signal(!1),s=e.signal(!1),c=e.signal(null),l=e.signal(!1),u=t,d=!0,f=e.effect(()=>{if(a.value,d){d=!1;return}c.peek()!==null&&(c.value=null)}),p=e.computed(()=>{if(c.value)return c.value;let e=i?.();for(let t of n){let n=t(a.value,e);if(n)return n}return null}),m=e.computed(()=>(r===`input`?s.value||o.value:r===`submit`?l.value:o.value)?p.value:null);function h(e){return e.type===`checkbox`||e.type===`radio`}function g(e){if(!e||!(`value`in e))return t;let n=e,r=n.value;return typeof t==`boolean`?n.checked===!0?!0:h(n)?!1:r===`true`||r===`1`?!0:r===`false`||r===`0`||r===``?!1:t:typeof t==`number`?r===``?NaN:Number(r):r}let _=e=>{a.value=g(e.target),s.value=!0},v=()=>{o.value=!0};function y(){e.batch(()=>{a.value=u,o.value=!1,s.value=!1,c.value=null,l.value=!1})}function b(t,n={}){let{shouldTouch:r=!1,shouldDirty:i=!0,shouldValidate:c=!0}=n;e.batch(()=>{a.value=t,i&&(s.value=!0),r&&(o.value=!0),c&&(l.value=!0)})}function x(e){c.value=e,e&&(o.value=!0)}function S(){o.value=!0,l.value=!0}function C(e){u=e}function w(){f(),m.dispose(),p.dispose()}return{value:a,error:m,rawError:p,touched:o,dirty:s,onInput:_,onBlur:v,reset:y,setValue:b,_setExternalError:x,_forceVisible:S,_setInitialValue:C,_dispose:w}}function f(t,n={},r=`blur`){function i(e){let t={};for(let i in e){let a=n[i]??[];t[i]=d(e[i],a,r)}return t}let a=e.signal(t.map(i)),o=t,s=e.computed(()=>a.value.length);function c(e){a.value=[...a.value,i(e)]}function l(e){let t=a.value;if(!(e<0||e>=t.length)){for(let n in t[e])t[e][n]._dispose();a.value=t.filter((t,n)=>n!==e)}}function u(e,t){let n=[...a.value];if(e<0||e>=n.length||t<0||t>=n.length||e===t)return;let[r]=n.splice(e,1);n.splice(t,0,r),a.value=n}function f(e,t){let n=[...a.value];if(!(e<0||e>=n.length)){for(let t in n[e])n[e][t]._dispose();n[e]=i(t),a.value=n}}function p(e){for(let e of a.value)for(let t in e)e[t]._dispose();a.value=e.map(i)}function m(e){let t=[...a.value];for(let n=0;n<e.length;n++){let r=e[n];if(n>=t.length){t.push(i(r));continue}let a=t[n];for(let[e,t]of Object.entries(r))a[e]&&a[e].setValue(t,{shouldDirty:!1,shouldTouch:!1,shouldValidate:!1})}a.value=t}function h(e){e&&(o=e);for(let e of a.value)for(let t in e)e[t]._dispose();a.value=o.map(i)}function g(){for(let e of a.value)for(let t in e)e[t]._dispose();s.dispose()}return{fields:a,append:c,remove:l,move:u,replace:f,length:s,setValues:p,patchValues:m,reset:h,_dispose:g}}function p(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function m(e,t=``,n=[]){for(let[r,i]of Object.entries(e)){let e=t?`${t}.${r}`:r;if(p(i)&&Object.keys(i).length>0){m(i,e,n);continue}n.push([e,i])}return n}function h(e,t,n){let r=t.split(`.`),i=e;for(let e=0;e<r.length-1;e++){let t=r[e],n=i[t];p(n)||(i[t]={}),i=i[t]}i[r[r.length-1]]=n}function g(t,n={}){let r=n.validateOn??`blur`,i={},a=n.validators;function o(){let e={};for(let t in i)h(e,t,i[t].value.value);return e}for(let[e,n]of m(t))i[e]=d(n,a?.[e]??[],r,o);let s=e.signal(!1),c=e.signal(0),l=e.computed(()=>o()),u=e.computed(()=>{let e={};for(let t in i){let n=i[t].error.value;n&&(e[t]=n)}return e}),f=e.computed(()=>{for(let e in i)if(i[e].rawError.value)return!1;return!0}),p=e.computed(()=>{for(let e in i)if(i[e].error.value)return!1;return!0}),g=e.computed(()=>{for(let e in i)if(i[e].dirty.value)return!0;return!1}),_=e.computed(()=>{for(let e in i)if(i[e].touched.value)return!0;return!1});function v(e){for(let t in e)i[t]?._setExternalError(e[t]??null)}function y(e,t,n={}){let r=i[e];r&&r.setValue(t,n)}function b(t,n={}){let{keepDirty:r=!1,keepTouched:a=!1,keepErrors:o=!0}=n;e.batch(()=>{for(let[e,n]of m(t)){let t=i[e];t&&(t.setValue(n,{shouldDirty:!r,shouldTouch:!1,shouldValidate:!o}),a||(t.touched.value=!1))}})}function x(e){if(e)for(let[t,n]of m(e)){let e=i[t];e&&e._setInitialValue(n)}for(let e in i)i[e].reset();s.value=!1,c.value=0}function S(){l.dispose(),u.dispose(),f.dispose(),p.dispose(),g.dispose(),_.dispose();for(let e in i)i[e]._dispose()}function C(e){return t=>{t.preventDefault(),c.value++;for(let e in i)i[e]._forceVisible();let r=l.value;if(n.validate){let e=n.validate(r);if(e){let t={},n=!1;for(let r in e){let i=e[r],a=Array.isArray(i)?i[0]??null:i??null;a&&(t[r]=a,n=!0)}if(n){v(t);return}}}for(let e in i)if(i[e].rawError.value)return;let a=e(r);a instanceof Promise&&(s.value=!0,a.finally(()=>{s.value=!1}).catch(()=>{}))}}return{fields:i,values:l,errors:u,canSubmit:f,valid:p,dirty:g,touched:_,isSubmitting:s,submitCount:c,handleSubmit:C,reset:x,setValue:y,setValues:b,setErrors:v,dispose:S}}exports.createForm=g,exports.createValidator=c,exports.elurField=d,exports.elurFieldArray=f,exports.email=a,exports.extendValidators=u,exports.max=s,exports.maxLength=r,exports.min=o,exports.minLength=n,exports.pattern=i,exports.required=t,exports.validators=l;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`./elur/next-2/reactivity.cjs`);function t(e=`Required`){return t=>t==null||t===``||Array.isArray(t)&&t.length===0?e:null}function n(e,t){return n=>typeof n==`string`&&n.length<e?t??`Minimum ${e} characters`:null}function r(e,t){return n=>typeof n==`string`&&n.length>e?t??`Maximum ${e} characters`:null}function i(e,t=`Invalid format`){return n=>typeof n==`string`&&!e.test(n)?t:null}function a(e=`Invalid email`){return i(/^[^\s@]+@[^\s@]+\.[^\s@]+$/,e)}function o(e,t){return n=>typeof n==`number`&&n<e?t??`Minimum value is ${e}`:null}function s(e,t){return n=>typeof n==`number`&&n>e?t??`Maximum value is ${e}`:null}function c(e){return e}var l={required:t,minLength:n,maxLength:r,email:a,pattern:i,min:o,max:s};function u(e,t){return{...e,...t}}function d(t,n=[],r=`blur`,i){let a=e.signal(t),o=e.signal(!1),s=e.signal(!1),c=e.signal(null),l=e.signal(!1),u=t,d=!0,f=e.effect(()=>{if(a.value,d){d=!1;return}c.peek()!==null&&(c.value=null)}),p=e.computed(()=>{if(c.value)return c.value;let e=i?.();for(let t of n){let n=t(a.value,e);if(n)return n}return null}),m=e.computed(()=>(r===`input`?s.value||o.value:r===`submit`?l.value:o.value)?p.value:null);function h(e){return e.type===`checkbox`||e.type===`radio`}function g(e){if(!e||!(`value`in e))return t;let n=e,r=n.value;return typeof t==`boolean`?n.checked===!0?!0:h(n)?!1:r===`true`||r===`1`?!0:r===`false`||r===`0`||r===``?!1:t:typeof t==`number`?r===``?NaN:Number(r):r}let _=e=>{a.value=g(e.target),s.value=!0},v=()=>{o.value=!0};function y(){e.batch(()=>{a.value=u,o.value=!1,s.value=!1,c.value=null,l.value=!1})}function b(t,n={}){let{shouldTouch:r=!1,shouldDirty:i=!0,shouldValidate:c=!0}=n;e.batch(()=>{a.value=t,i&&(s.value=!0),r&&(o.value=!0),c&&(l.value=!0)})}function x(e){c.value=e,e&&(o.value=!0)}function S(){o.value=!0,l.value=!0}function C(e){u=e}function w(){f(),m.dispose(),p.dispose()}return{value:a,error:m,rawError:p,touched:o,dirty:s,onInput:_,onBlur:v,reset:y,setValue:b,_setExternalError:x,_forceVisible:S,_setInitialValue:C,_dispose:w}}function f(t,n={},r=`blur`){function i(e){let t={};for(let i in e){let a=n[i]??[];t[i]=d(e[i],a,r)}return t}let a=e.signal(t.map(i)),o=t,s=e.computed(()=>a.value.length);function c(e){a.value=[...a.value,i(e)]}function l(e){let t=a.value;if(!(e<0||e>=t.length)){for(let n in t[e])t[e][n]._dispose();a.value=t.filter((t,n)=>n!==e)}}function u(e,t){let n=[...a.value];if(e<0||e>=n.length||t<0||t>=n.length||e===t)return;let[r]=n.splice(e,1);n.splice(t,0,r),a.value=n}function f(e,t){let n=[...a.value];if(!(e<0||e>=n.length)){for(let t in n[e])n[e][t]._dispose();n[e]=i(t),a.value=n}}function p(e){for(let e of a.value)for(let t in e)e[t]._dispose();a.value=e.map(i)}function m(e){let t=[...a.value];for(let n=0;n<e.length;n++){let r=e[n];if(n>=t.length){t.push(i(r));continue}let a=t[n];for(let[e,t]of Object.entries(r))a[e]&&a[e].setValue(t,{shouldDirty:!1,shouldTouch:!1,shouldValidate:!1})}a.value=t}function h(e){e&&(o=e);for(let e of a.value)for(let t in e)e[t]._dispose();a.value=o.map(i)}function g(){for(let e of a.value)for(let t in e)e[t]._dispose();s.dispose()}return{fields:a,append:c,remove:l,move:u,replace:f,length:s,setValues:p,patchValues:m,reset:h,_dispose:g}}function p(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function m(e,t=``,n=[]){for(let[r,i]of Object.entries(e)){let e=t?`${t}.${r}`:r;if(p(i)&&Object.keys(i).length>0){m(i,e,n);continue}n.push([e,i])}return n}function h(e,t,n){let r=t.split(`.`),i=e;for(let e=0;e<r.length-1;e++){let t=r[e],n=i[t];p(n)||(i[t]={}),i=i[t]}i[r[r.length-1]]=n}function g(t,n={}){let r=n.validateOn??`blur`,i={},a=n.validators;function o(){let e={};for(let t in i)h(e,t,i[t].value.value);return e}for(let[e,n]of m(t))i[e]=d(n,a?.[e]??[],r,o);let s=e.signal(!1),c=e.signal(0),l=e.computed(()=>o()),u=e.computed(()=>{let e={};for(let t in i){let n=i[t].error.value;n&&(e[t]=n)}return e}),f=e.computed(()=>{for(let e in i)if(i[e].rawError.value)return!1;return!0}),p=e.computed(()=>{for(let e in i)if(i[e].error.value)return!1;return!0}),g=e.computed(()=>{for(let e in i)if(i[e].dirty.value)return!0;return!1}),_=e.computed(()=>{for(let e in i)if(i[e].touched.value)return!0;return!1});function v(e){for(let t in e)i[t]?._setExternalError(e[t]??null)}function y(e,t,n={}){let r=i[e];r&&r.setValue(t,n)}function b(t,n={}){let{keepDirty:r=!1,keepTouched:a=!1,keepErrors:o=!0}=n;e.batch(()=>{for(let[e,n]of m(t)){let t=i[e];t&&(t.setValue(n,{shouldDirty:!r,shouldTouch:!1,shouldValidate:!o}),a||(t.touched.value=!1))}})}function x(e){if(e)for(let[t,n]of m(e)){let e=i[t];e&&e._setInitialValue(n)}for(let e in i)i[e].reset();s.value=!1,c.value=0}function S(){l.dispose(),u.dispose(),f.dispose(),p.dispose(),g.dispose(),_.dispose();for(let e in i)i[e]._dispose()}function C(e){return t=>{t.preventDefault(),c.value++;for(let e in i)i[e]._forceVisible();let r=l.value;if(n.validate){let e=n.validate(r);if(e){let t={},n=!1;for(let r in e){let i=e[r],a=Array.isArray(i)?i[0]??null:i??null;a&&(t[r]=a,n=!0)}if(n){v(t);return}}}for(let e in i)if(i[e].rawError.value)return;let a=e(r);a instanceof Promise&&(s.value=!0,a.finally(()=>{s.value=!1}).catch(()=>{}))}}return{fields:i,values:l,errors:u,canSubmit:f,valid:p,dirty:g,touched:_,isSubmitting:s,submitCount:c,handleSubmit:C,reset:x,setValue:y,setValues:b,setErrors:v,dispose:S}}exports.createForm=g,exports.createValidator=c,exports.elurField=d,exports.elurFieldArray=f,exports.email=a,exports.extendValidators=u,exports.max=s,exports.maxLength=r,exports.min=o,exports.minLength=n,exports.pattern=i,exports.required=t,exports.validators=l;
2
2
  //# sourceMappingURL=form.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"form.cjs","names":[],"sources":["../../src/elur/form.ts"],"sourcesContent":["import { signal, computed, effect, batch } from \"./reactivity.js\";\nimport type { Signal } from \"./reactivity.js\";\n\n// --- Validator ---\n\n/**\n * A validator function. Return an error string when invalid, or `null` /\n * `undefined` when valid.\n *\n * `allValues` is provided when the validator runs inside `createForm`, enabling\n * cross-field validation (e.g., \"confirm password matches password\").\n *\n * **Validators must be pure.** They are invoked reactively whenever the field\n * value changes — potentially many times per keystroke in forms with\n * cross-field rules — and may run inside computed signals that assume\n * deterministic output. Do not perform I/O, mutate external state, or rely on\n * `Date.now()` / `Math.random()` inside a validator. For asynchronous checks\n * (uniqueness, server-side rules), submit the form and inject the result via\n * {@link FormState.setErrors}.\n */\nexport type Validator<T, AllValues = unknown> = (\n value: T,\n allValues?: AllValues,\n) => string | null | undefined;\n\n// --- Built-in validators ---\n\nexport function required(message = \"Required\"): Validator<unknown> {\n return (v) =>\n v == null || v === \"\" || (Array.isArray(v) && v.length === 0)\n ? message\n : null;\n}\n\nexport function minLength(n: number, message?: string): Validator<string> {\n return (v) =>\n typeof v === \"string\" && v.length < n\n ? (message ?? `Minimum ${n} characters`)\n : null;\n}\n\nexport function maxLength(n: number, message?: string): Validator<string> {\n return (v) =>\n typeof v === \"string\" && v.length > n\n ? (message ?? `Maximum ${n} characters`)\n : null;\n}\n\nexport function pattern(regex: RegExp, message = \"Invalid format\"): Validator<string> {\n return (v) => (typeof v === \"string\" && !regex.test(v) ? message : null);\n}\n\nexport function email(message = \"Invalid email\"): Validator<string> {\n return pattern(/^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/, message);\n}\n\nexport function min(n: number, message?: string): Validator<number> {\n return (v) =>\n typeof v === \"number\" && v < n\n ? (message ?? `Minimum value is ${n}`)\n : null;\n}\n\nexport function max(n: number, message?: string): Validator<number> {\n return (v) =>\n typeof v === \"number\" && v > n\n ? (message ?? `Maximum value is ${n}`)\n : null;\n}\n\n// --- Custom validator API ---\n\n/** Creates a typed custom validator compatible with `elurField` and `createForm`. */\nexport function createValidator<T, AllValues = unknown>(\n fn: (value: T, allValues?: AllValues) => string | null | undefined\n): Validator<T, AllValues> {\n return fn;\n}\n\n/** All built-in validators grouped as a namespace. Extensible via `extendValidators`. */\nexport const validators = {\n required,\n minLength,\n maxLength,\n email,\n pattern,\n min,\n max,\n} as const;\n\n/** Shape of the built-in `validators` namespace. Used as the base type for `extendValidators`. */\nexport type ValidatorsBase = typeof validators;\n\n/**\n * Merges custom validator factories into the built-in namespace.\n * Returns a new object — the original is never mutated.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function extendValidators<E extends Record<string, (...args: any[]) => Validator<any>>>(\n base: ValidatorsBase,\n extensions: E\n): ValidatorsBase & E {\n return { ...base, ...extensions };\n}\n\n// --- validateOn ---\n\n/**\n * Controls when validation errors become visible.\n * - `\"blur\"` — after the field loses focus (default)\n * - `\"input\"` — as soon as the user types\n * - `\"submit\"` — only after the first submit attempt\n */\nexport type ValidateOn = \"blur\" | \"input\" | \"submit\";\n\n// --- FieldState ---\n\n/** Public state of a single form field. */\nexport interface FieldState<T> {\n /** Current value — read/write signal. */\n value: Signal<T>;\n /** Error visible según validateOn. Para UI. */\n readonly error: Signal<string | null>;\n /**\n * Error real, ignorando validateOn/touched/dirty.\n * Para lógica de habilitación de botones, validez global, etc.\n */\n readonly rawError: Signal<string | null>;\n /** True after the input has lost focus at least once. */\n touched: Signal<boolean>;\n /** True after the user has typed at least once. */\n dirty: Signal<boolean>;\n /** Attach to `@input` on any `<input>`, `<select>`, `<textarea>`. */\n readonly onInput: (e: Event) => void;\n /** Attach to `@blur`. */\n readonly onBlur: () => void;\n /** Reset to initial value and clear touched/dirty/error state. */\n reset(): void;\n /**\n * Set the field value programmatically.\n *\n * @param value — new value for the field.\n * @param options — control whether to touch/dirty the field and whether to force\n * validation visibility.\n */\n setValue(\n value: T,\n options?: { shouldTouch?: boolean; shouldDirty?: boolean; shouldValidate?: boolean },\n ): void;\n /**\n * @internal — inject an external error message (server / schema validator).\n * The error clears automatically when the user next edits the field.\n */\n _setExternalError(msg: string | null): void;\n /** @internal — force error visibility (e.g., on submit). */\n _forceVisible(): void;\n /** @internal — update the stored initial value so a later reset() returns here. */\n _setInitialValue(value: T): void;\n /** @internal — dispose computed signals. */\n _dispose(): void;\n}\n\n// --- elurField ---\n\n/** Creates a standalone reactive form field with optional validators. */\nexport function elurField<T, AllValues = unknown>(\n initialValue: T,\n fieldValidators: Validator<T, AllValues>[] = [],\n validateOn: ValidateOn = \"blur\",\n getAllValues?: () => AllValues,\n): FieldState<T> {\n const value = signal(initialValue);\n const touched = signal(false);\n const dirty = signal(false);\n const _ext = signal<string | null>(null);\n // Tracks whether the form has been submitted at least once (injected externally)\n const _submitted = signal(false);\n // Mutable reference so that reset() can be redirected by createForm.reset(newValues).\n let currentInitialValue = initialValue;\n\n let _skipFirstClear = true;\n const _disposeExtCleanup = effect(() => {\n value.value; // subscribe to value changes\n if (_skipFirstClear) {\n _skipFirstClear = false;\n return;\n }\n if (_ext.peek() !== null) {\n _ext.value = null;\n }\n });\n\n const rawError = computed<string | null>(() => {\n if (_ext.value) return _ext.value;\n const allValues = getAllValues?.();\n for (const v of fieldValidators) {\n const e = v(value.value, allValues);\n if (e) return e;\n }\n return null;\n });\n\n const error = computed<string | null>(() => {\n const isVisible =\n validateOn === \"input\" ? dirty.value || touched.value :\n validateOn === \"submit\" ? _submitted.value :\n touched.value;\n if (!isVisible) return null;\n return rawError.value;\n });\n\n function isCheckable(input: HTMLInputElement): boolean {\n return input.type === \"checkbox\" || input.type === \"radio\";\n }\n\n function coerce(target: EventTarget | null): T {\n if (!target || !(\"value\" in target)) return initialValue;\n const t = target as HTMLInputElement;\n const value = t.value;\n\n if (typeof initialValue === \"boolean\") {\n const checked = t.checked;\n if (checked === true) return true as unknown as T;\n if (isCheckable(t)) return false as unknown as T;\n if (value === \"true\" || value === \"1\") return true as unknown as T;\n if (value === \"false\" || value === \"0\" || value === \"\") return false as unknown as T;\n return initialValue;\n }\n\n if (typeof initialValue === \"number\") {\n if (value === \"\") return NaN as unknown as T;\n return Number(value) as unknown as T;\n }\n\n return value as unknown as T;\n }\n\n const onInput = (e: Event): void => {\n value.value = coerce(e.target);\n dirty.value = true;\n };\n\n const onBlur = (): void => { touched.value = true; };\n\n function reset(): void {\n batch(() => {\n value.value = currentInitialValue;\n touched.value = false;\n dirty.value = false;\n _ext.value = null;\n _submitted.value = false;\n });\n }\n\n function setValue(\n next: T,\n options: { shouldTouch?: boolean; shouldDirty?: boolean; shouldValidate?: boolean } = {},\n ): void {\n const { shouldTouch = false, shouldDirty = true, shouldValidate = true } = options;\n batch(() => {\n value.value = next;\n if (shouldDirty) dirty.value = true;\n if (shouldTouch) touched.value = true;\n if (shouldValidate) _submitted.value = true;\n });\n }\n\n function _setExternalError(msg: string | null): void {\n _ext.value = msg;\n if (msg) touched.value = true;\n }\n\n function _forceVisible(): void {\n touched.value = true;\n _submitted.value = true;\n }\n\n function _setInitialValue(next: T): void {\n currentInitialValue = next;\n }\n\n function _dispose(): void {\n _disposeExtCleanup();\n error.dispose();\n rawError.dispose();\n }\n\n return { value, error, rawError, touched, dirty, onInput, onBlur, reset, setValue, _setExternalError, _forceVisible, _setInitialValue, _dispose };\n}\n\n// --- FieldArrayState ---\n\n/** Public state of a field array (dynamic list of field groups). */\nexport interface FieldArrayState<T extends Record<string, unknown>> {\n /** Reactive list of field group states. */\n readonly fields: Signal<Array<{ [K in keyof T]: FieldState<T[K]> }>>;\n /** Appends a new item to the end of the array. */\n append(value: T): void;\n /** Removes the item at the given index. */\n remove(index: number): void;\n /**\n * Moves an item from `from` to `to` index.\n * Items between the two positions shift to fill the gap.\n */\n move(from: number, to: number): void;\n /** Replaces the item at the given index with new values. */\n replace(index: number, value: T): void;\n /** Number of items in the array. Reactive. */\n readonly length: Signal<number>;\n /** Replaces the whole array with a new list of items. */\n setValues(items: T[]): void;\n /** Patches existing items and appends any extras without touching untouched items. */\n patchValues(items: Partial<T>[]): void;\n /** Resets the array to its initial value, optionally updating that initial value. */\n reset(items?: T[]): void;\n /** @internal */\n _dispose(): void;\n}\n\n/**\n * Creates a reactive array of field groups for dynamic list forms.\n *\n * @example\n * const items = elurFieldArray([{ name: \"\" }], {\n * name: [required()],\n * });\n * items.append({ name: \"nuevo\" });\n * items.remove(0);\n */\nexport function elurFieldArray<T extends Record<string, unknown>>(\n initialItems: T[],\n fieldValidators: { [K in keyof T]?: Validator<T[K], unknown>[] } = {},\n validateOn: ValidateOn = \"blur\",\n): FieldArrayState<T> {\n function makeGroup(item: T): { [K in keyof T]: FieldState<T[K]> } {\n const group = {} as { [K in keyof T]: FieldState<T[K]> };\n for (const key in item) {\n const vs = (fieldValidators[key] ?? []) as Validator<T[typeof key], unknown>[];\n (group as Record<string, unknown>)[key] = elurField(item[key], vs, validateOn);\n }\n return group;\n }\n\n const fields = signal<Array<{ [K in keyof T]: FieldState<T[K]> }>>(\n initialItems.map(makeGroup)\n );\n // Mutable so that reset(newItems) can redirect the baseline.\n let currentInitialItems = initialItems;\n\n const length = computed(() => fields.value.length);\n\n function append(value: T): void {\n fields.value = [...fields.value, makeGroup(value)];\n }\n\n function remove(index: number): void {\n const current = fields.value;\n if (index < 0 || index >= current.length) return;\n // Dispose computed signals of the removed group before discarding\n for (const key in current[index]) {\n current[index][key]._dispose();\n }\n fields.value = current.filter((_, i) => i !== index);\n }\n\n function move(from: number, to: number): void {\n const current = [...fields.value];\n if (\n from < 0 || from >= current.length ||\n to < 0 || to >= current.length ||\n from === to\n ) return;\n const [item] = current.splice(from, 1);\n current.splice(to, 0, item);\n fields.value = current;\n }\n\n function replace(index: number, value: T): void {\n const current = [...fields.value];\n if (index < 0 || index >= current.length) return;\n // Dispose old group before replacing\n for (const key in current[index]) {\n current[index][key]._dispose();\n }\n current[index] = makeGroup(value);\n fields.value = current;\n }\n\n function setValues(items: T[]): void {\n for (const group of fields.value) {\n for (const key in group) group[key]._dispose();\n }\n fields.value = items.map(makeGroup);\n }\n\n function patchValues(items: Partial<T>[]): void {\n const current = [...fields.value];\n for (let i = 0; i < items.length; i++) {\n const patch = items[i] as Record<string, unknown>;\n if (i >= current.length) {\n current.push(makeGroup(patch as T));\n continue;\n }\n const group = current[i] as Record<string, FieldState<unknown>>;\n for (const [key, val] of Object.entries(patch)) {\n if (group[key]) {\n group[key].setValue(val, { shouldDirty: false, shouldTouch: false, shouldValidate: false });\n }\n }\n }\n fields.value = current;\n }\n\n function reset(items?: T[]): void {\n if (items) currentInitialItems = items;\n for (const group of fields.value) {\n for (const key in group) group[key]._dispose();\n }\n fields.value = currentInitialItems.map(makeGroup);\n }\n\n function _dispose(): void {\n for (const group of fields.value) {\n for (const key in group) group[key]._dispose();\n }\n length.dispose();\n }\n\n return { fields, append, remove, move, replace, length, setValues, patchValues, reset, _dispose };\n}\n\n// --- FormState ---\n\n/** Field-name map that supports top-level keys and dot-path nested keys. */\nexport type FormFields<T extends Record<string, unknown>> =\n { [K in keyof T]: FieldState<T[K]> } & Record<string, FieldState<unknown>>;\n\n/** Map of field-name → error message for external validation results. */\nexport type FieldErrors<T extends Record<string, unknown>> =\n { [K in keyof T]?: string | null } & Record<string, string | null | undefined>;\n\n/** Validators map supporting both top-level and dot-path keys. */\nexport type FormValidators<T extends Record<string, unknown>> =\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n { [K in keyof T]?: Validator<T[K], T>[] } & Record<string, Validator<any, any>[] | undefined>;\n\n// Utility used by setValues so callers can patch nested objects (e.g. { address: { city: \"Lima\" } }).\nexport type DeepPartial<T> = T extends object ? { [P in keyof T]?: DeepPartial<T[P]> } : T;\n\nexport interface FormState<T extends Record<string, unknown>> {\n /** Individual field states — access value, error, event handlers. */\n fields: FormFields<T>;\n /** Computed snapshot of all current field values. */\n readonly values: Signal<T>;\n /** Computed map of all currently visible field errors. */\n readonly errors: Signal<FieldErrors<T>>;\n /**\n * True when no field has a *visible* error.\n *\n * Visibility follows `validateOn`, so this signal reflects what the user\n * currently sees in the UI — not the underlying validity of the data.\n * Use it to drive error summaries, banners, or any UI that should only\n * react to errors the user has been shown.\n *\n * For enabling or disabling submit buttons, use {@link canSubmit} instead.\n */\n readonly valid: Signal<boolean>;\n /**\n * True when every per-field validator passes against the current values,\n * regardless of `touched`, `dirty`, or `validateOn`.\n *\n * This is the signal to bind to submit buttons:\n *\n * ```ts\n * <button disabled=${() => !form.canSubmit.value || form.isSubmitting.value}>\n * Save\n * </button>\n * ```\n *\n * Unlike {@link valid}, `canSubmit` does not depend on whether errors are\n * currently visible — a pristine form with empty required fields starts\n * as `false` and flips to `true` the moment all validators pass.\n *\n * External errors injected via {@link setErrors} also flip `canSubmit` to\n * `false` until the user edits the affected field.\n *\n * **Note:** `canSubmit` does not execute `options.validate` (schema-level\n * validators such as Zod). Schema validation runs only on submit, by design,\n * to keep per-keystroke cost predictable. If you need a schema rule to\n * affect `canSubmit` reactively, express it as a per-field validator in\n * `options.validators` instead.\n */\n readonly canSubmit: Signal<boolean>;\n /** True when at least one field has been modified. */\n readonly dirty: Signal<boolean>;\n /** True when at least one field has been touched (lost focus). */\n readonly touched: Signal<boolean>;\n /** True while the submit callback is executing (async-safe). */\n readonly isSubmitting: Signal<boolean>;\n /** Number of times the form has been submitted (including failed validations). */\n readonly submitCount: Signal<number>;\n /**\n * Wraps a submit callback. Returned handler:\n * 1. Calls `e.preventDefault()`\n * 2. Increments `submitCount` and marks all fields as visible\n * 3. Runs `options.validate` if provided (Zod, etc.)\n * 4. Only calls `fn(values)` if all validations pass\n * 5. Manages `isSubmitting` across async callbacks\n */\n handleSubmit(fn: (values: T) => void | Promise<void>): (e: Event) => void;\n /**\n * Reset all fields to their initial values. If `newInitialValues` is provided,\n * it becomes the new baseline and subsequent reset() calls will use it.\n */\n reset(newInitialValues?: T): void;\n /**\n * Set a single field value by its path (top-level or nested dot-path).\n */\n setValue(\n path: string,\n value: unknown,\n options?: { shouldTouch?: boolean; shouldDirty?: boolean; shouldValidate?: boolean },\n ): void;\n /**\n * Set multiple field values at once.\n *\n * @param values — partial object with top-level and/or nested values.\n * @param options — control whether to preserve existing touched/dirty/error state.\n */\n setValues(\n values: DeepPartial<T>,\n options?: { keepDirty?: boolean; keepTouched?: boolean; keepErrors?: boolean },\n ): void;\n /**\n * Inject external errors (e.g., from a server response) into specific fields.\n * Each field's error clears automatically the next time the user edits it.\n */\n setErrors(errors: FieldErrors<T>): void;\n /**\n * Disposes all internal computed signals.\n * Call in `onUnmount` when the form lives inside a component.\n */\n dispose(): void;\n}\n\nexport interface FormOptions<T extends Record<string, unknown>> {\n /** Per-field validators. Each validator receives `(value, allValues?)`. */\n validators?: FormValidators<T>;\n /**\n * Controls when validation errors become visible.\n * - `\"blur\"` — after the field loses focus (default)\n * - `\"input\"` — as soon as the user types\n * - `\"submit\"` — only after the first submit attempt\n */\n validateOn?: ValidateOn;\n /**\n * Optional schema-level validator — runs on submit after built-in validators pass.\n * Return `null` / `undefined` if valid, or a field→error map if not.\n * String arrays are accepted (first element shown per field).\n *\n * @example Zod interop\n * ```typescript\n * validate(values) {\n * const r = schema.safeParse(values);\n * if (r.success) return null;\n * return Object.fromEntries(\n * Object.entries(r.error.flatten().fieldErrors)\n * .map(([k, v]) => [k, v?.[0]])\n * );\n * }\n * ```\n */\n validate?: (\n values: T\n ) => Record<string, string | string[] | null | undefined> | null | undefined;\n}\n\nfunction isPlainRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction flattenValuePaths(\n value: Record<string, unknown>,\n prefix = \"\",\n out: Array<[string, unknown]> = [],\n): Array<[string, unknown]> {\n for (const [key, next] of Object.entries(value)) {\n const path = prefix ? `${prefix}.${key}` : key;\n if (isPlainRecord(next) && Object.keys(next).length > 0) {\n flattenValuePaths(next, path, out);\n continue;\n }\n out.push([path, next]);\n }\n return out;\n}\n\nfunction setAtPath(target: Record<string, unknown>, path: string, value: unknown): void {\n const parts = path.split(\".\");\n let current: Record<string, unknown> = target;\n\n for (let i = 0; i < parts.length - 1; i++) {\n const part = parts[i];\n const child = current[part];\n if (!isPlainRecord(child)) {\n current[part] = {};\n }\n current = current[part] as Record<string, unknown>;\n }\n\n current[parts[parts.length - 1]] = value;\n}\n\n// --- createForm ---\n\n/**\n * Creates a managed form with reactive fields, built-in validation,\n * schema-level validation (Zod/Valibot/Yup/custom), and submit handling.\n */\nexport function createForm<T extends Record<string, unknown>>(\n initialValues: T,\n options: FormOptions<T> = {}\n): FormState<T> {\n const validateOn: ValidateOn = options.validateOn ?? \"blur\";\n\n const fields = {} as Record<string, FieldState<unknown>>;\n const validatorsByPath = options.validators as\n | Record<string, Validator<unknown, T>[] | undefined>\n | undefined;\n\n function snapshotValues(): T {\n const r: Record<string, unknown> = {};\n for (const k in fields) setAtPath(r, k, fields[k].value.value);\n return r as T;\n }\n\n for (const [path, initialValue] of flattenValuePaths(initialValues)) {\n const vs = validatorsByPath?.[path] ?? [];\n fields[path] = elurField<unknown, T>(initialValue, vs, validateOn, snapshotValues);\n }\n\n const isSubmitting = signal(false);\n const submitCount = signal(0);\n\n const values = computed<T>(() => {\n return snapshotValues();\n });\n\n const errors = computed<FieldErrors<T>>(() => {\n const r: FieldErrors<T> = {};\n for (const k in fields) {\n const e = fields[k].error.value;\n if (e) (r as Record<string, unknown>)[k] = e;\n }\n return r;\n });\n\n const canSubmit = computed<boolean>(() => {\n for (const k in fields) {\n if (fields[k].rawError.value) return false;\n }\n return true;\n });\n\n const valid = computed<boolean>(() => {\n for (const k in fields) if (fields[k].error.value) return false;\n return true;\n });\n\n const dirty = computed<boolean>(() => {\n for (const k in fields) if (fields[k].dirty.value) return true;\n return false;\n });\n\n const touched = computed<boolean>(() => {\n for (const k in fields) if (fields[k].touched.value) return true;\n return false;\n });\n\n function setErrors(errs: FieldErrors<T>): void {\n for (const k in errs) fields[k]?._setExternalError(errs[k] ?? null);\n }\n\n function setValue(\n path: string,\n value: unknown,\n options: { shouldTouch?: boolean; shouldDirty?: boolean; shouldValidate?: boolean } = {},\n ): void {\n const field = fields[path];\n if (!field) return;\n field.setValue(value, options);\n }\n\n function setValues(\n values: DeepPartial<T>,\n options: { keepDirty?: boolean; keepTouched?: boolean; keepErrors?: boolean } = {},\n ): void {\n const { keepDirty = false, keepTouched = false, keepErrors = true } = options;\n batch(() => {\n for (const [path, v] of flattenValuePaths(values as Record<string, unknown>)) {\n const field = fields[path];\n if (!field) continue;\n field.setValue(v, {\n shouldDirty: !keepDirty,\n shouldTouch: false,\n shouldValidate: !keepErrors,\n });\n if (!keepTouched) field.touched.value = false;\n }\n });\n }\n\n function reset(newInitialValues?: T): void {\n if (newInitialValues) {\n for (const [path, v] of flattenValuePaths(newInitialValues)) {\n const field = fields[path];\n if (field) field._setInitialValue(v);\n }\n }\n for (const k in fields) fields[k].reset();\n isSubmitting.value = false;\n submitCount.value = 0;\n }\n\n function dispose(): void {\n values.dispose();\n errors.dispose();\n canSubmit.dispose();\n valid.dispose();\n dirty.dispose();\n touched.dispose();\n for (const k in fields) fields[k]._dispose();\n }\n\n function handleSubmit(fn: (values: T) => void | Promise<void>) {\n return (e: Event): void => {\n e.preventDefault();\n\n submitCount.value++;\n\n for (const k in fields) fields[k]._forceVisible();\n\n const currentValues = values.value;\n\n // Run schema-level validator (Zod, Valibot, etc.)\n if (options.validate) {\n const ext = options.validate(currentValues);\n if (ext) {\n const mapped: FieldErrors<T> = {};\n let hasAny = false;\n for (const k in ext) {\n const v = ext[k];\n const msg = Array.isArray(v) ? (v[0] ?? null) : (v ?? null);\n if (msg) {\n (mapped as Record<string, unknown>)[k] = msg;\n hasAny = true;\n }\n }\n if (hasAny) { setErrors(mapped); return; }\n }\n }\n\n // Check built-in validators\n for (const k in fields) if (fields[k].rawError.value) return;\n\n const result = fn(currentValues);\n\n if (result instanceof Promise) {\n isSubmitting.value = true;\n\n result\n .finally(() => {\n isSubmitting.value = false;\n })\n .catch(() => { });\n }\n };\n }\n\n return {\n fields: fields as FormFields<T>,\n values,\n errors,\n canSubmit,\n valid,\n dirty,\n touched,\n isSubmitting,\n submitCount,\n handleSubmit,\n reset,\n setValue,\n setValues,\n setErrors,\n dispose,\n };\n}"],"mappings":"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"}
1
+ {"version":3,"file":"form.cjs","names":[],"sources":["../../src/elur/form.ts"],"sourcesContent":["import { signal, computed, effect, batch } from \"./reactivity.js\";\nimport type { Signal } from \"./reactivity.js\";\n\n// --- Validator ---\n\n/**\n * A validator function. Return an error string when invalid, or `null` /\n * `undefined` when valid.\n *\n * `allValues` is provided when the validator runs inside `createForm`, enabling\n * cross-field validation (e.g., \"confirm password matches password\").\n *\n * **Validators must be pure.** They are invoked reactively whenever the field\n * value changes — potentially many times per keystroke in forms with\n * cross-field rules — and may run inside computed signals that assume\n * deterministic output. Do not perform I/O, mutate external state, or rely on\n * `Date.now()` / `Math.random()` inside a validator. For asynchronous checks\n * (uniqueness, server-side rules), submit the form and inject the result via\n * {@link FormState.setErrors}.\n */\nexport type Validator<T, AllValues = unknown> = (\n value: T,\n allValues?: AllValues,\n) => string | null | undefined;\n\n// --- Built-in validators ---\n\nexport function required(message = \"Required\"): Validator<unknown> {\n return (v) =>\n v == null || v === \"\" || (Array.isArray(v) && v.length === 0)\n ? message\n : null;\n}\n\nexport function minLength(n: number, message?: string): Validator<string> {\n return (v) =>\n typeof v === \"string\" && v.length < n\n ? (message ?? `Minimum ${n} characters`)\n : null;\n}\n\nexport function maxLength(n: number, message?: string): Validator<string> {\n return (v) =>\n typeof v === \"string\" && v.length > n\n ? (message ?? `Maximum ${n} characters`)\n : null;\n}\n\nexport function pattern(regex: RegExp, message = \"Invalid format\"): Validator<string> {\n return (v) => (typeof v === \"string\" && !regex.test(v) ? message : null);\n}\n\nexport function email(message = \"Invalid email\"): Validator<string> {\n return pattern(/^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/, message);\n}\n\nexport function min(n: number, message?: string): Validator<number> {\n return (v) =>\n typeof v === \"number\" && v < n\n ? (message ?? `Minimum value is ${n}`)\n : null;\n}\n\nexport function max(n: number, message?: string): Validator<number> {\n return (v) =>\n typeof v === \"number\" && v > n\n ? (message ?? `Maximum value is ${n}`)\n : null;\n}\n\n// --- Custom validator API ---\n\n/** Creates a typed custom validator compatible with `elurField` and `createForm`. */\nexport function createValidator<T, AllValues = unknown>(\n fn: (value: T, allValues?: AllValues) => string | null | undefined\n): Validator<T, AllValues> {\n return fn;\n}\n\n/** All built-in validators grouped as a namespace. Extensible via `extendValidators`. */\nexport const validators = {\n required,\n minLength,\n maxLength,\n email,\n pattern,\n min,\n max,\n} as const;\n\n/** Shape of the built-in `validators` namespace. Used as the base type for `extendValidators`. */\nexport type ValidatorsBase = typeof validators;\n\n/**\n * Merges custom validator factories into the built-in namespace.\n * Returns a new object — the original is never mutated.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function extendValidators<E extends Record<string, (...args: any[]) => Validator<any>>>(\n base: ValidatorsBase,\n extensions: E\n): ValidatorsBase & E {\n return { ...base, ...extensions };\n}\n\n// --- validateOn ---\n\n/**\n * Controls when validation errors become visible.\n * - `\"blur\"` — after the field loses focus (default)\n * - `\"input\"` — as soon as the user types\n * - `\"submit\"` — only after the first submit attempt\n */\nexport type ValidateOn = \"blur\" | \"input\" | \"submit\";\n\n// --- FieldState ---\n\n/** Public state of a single form field. */\nexport interface FieldState<T> {\n /** Current value — read/write signal. */\n value: Signal<T>;\n /** Error visible según validateOn. Para UI. */\n readonly error: Signal<string | null>;\n /**\n * Error real, ignorando validateOn/touched/dirty.\n * Para lógica de habilitación de botones, validez global, etc.\n */\n readonly rawError: Signal<string | null>;\n /** True after the input has lost focus at least once. */\n touched: Signal<boolean>;\n /** True after the user has typed at least once. */\n dirty: Signal<boolean>;\n /** Attach to `@input` on any `<input>`, `<select>`, `<textarea>`. */\n readonly onInput: (e: Event) => void;\n /** Attach to `@blur`. */\n readonly onBlur: () => void;\n /** Reset to initial value and clear touched/dirty/error state. */\n reset(): void;\n /**\n * Set the field value programmatically.\n *\n * @param value — new value for the field.\n * @param options — control whether to touch/dirty the field and whether to force\n * validation visibility.\n */\n setValue(\n value: T,\n options?: { shouldTouch?: boolean; shouldDirty?: boolean; shouldValidate?: boolean },\n ): void;\n /**\n * @internal — inject an external error message (server / schema validator).\n * The error clears automatically when the user next edits the field.\n */\n _setExternalError(msg: string | null): void;\n /** @internal — force error visibility (e.g., on submit). */\n _forceVisible(): void;\n /** @internal — update the stored initial value so a later reset() returns here. */\n _setInitialValue(value: T): void;\n /** @internal — dispose computed signals. */\n _dispose(): void;\n}\n\n// --- elurField ---\n\n/** Creates a standalone reactive form field with optional validators. */\nexport function elurField<T, AllValues = unknown>(\n initialValue: T,\n fieldValidators: Validator<T, AllValues>[] = [],\n validateOn: ValidateOn = \"blur\",\n getAllValues?: () => AllValues,\n): FieldState<T> {\n const value = signal(initialValue);\n const touched = signal(false);\n const dirty = signal(false);\n const _ext = signal<string | null>(null);\n // Tracks whether the form has been submitted at least once (injected externally)\n const _submitted = signal(false);\n // Mutable reference so that reset() can be redirected by createForm.reset(newValues).\n let currentInitialValue = initialValue;\n\n let _skipFirstClear = true;\n const _disposeExtCleanup = effect(() => {\n value.value; // subscribe to value changes\n if (_skipFirstClear) {\n _skipFirstClear = false;\n return;\n }\n if (_ext.peek() !== null) {\n _ext.value = null;\n }\n });\n\n const rawError = computed<string | null>(() => {\n if (_ext.value) return _ext.value;\n const allValues = getAllValues?.();\n for (const v of fieldValidators) {\n const e = v(value.value, allValues);\n if (e) return e;\n }\n return null;\n });\n\n const error = computed<string | null>(() => {\n const isVisible =\n validateOn === \"input\" ? dirty.value || touched.value :\n validateOn === \"submit\" ? _submitted.value :\n touched.value;\n if (!isVisible) return null;\n return rawError.value;\n });\n\n function isCheckable(input: HTMLInputElement): boolean {\n return input.type === \"checkbox\" || input.type === \"radio\";\n }\n\n function coerce(target: EventTarget | null): T {\n if (!target || !(\"value\" in target)) return initialValue;\n const t = target as HTMLInputElement;\n const value = t.value;\n\n if (typeof initialValue === \"boolean\") {\n const checked = t.checked;\n if (checked === true) return true as unknown as T;\n if (isCheckable(t)) return false as unknown as T;\n if (value === \"true\" || value === \"1\") return true as unknown as T;\n if (value === \"false\" || value === \"0\" || value === \"\") return false as unknown as T;\n return initialValue;\n }\n\n if (typeof initialValue === \"number\") {\n if (value === \"\") return NaN as unknown as T;\n return Number(value) as unknown as T;\n }\n\n return value as unknown as T;\n }\n\n const onInput = (e: Event): void => {\n value.value = coerce(e.target);\n dirty.value = true;\n };\n\n const onBlur = (): void => { touched.value = true; };\n\n function reset(): void {\n batch(() => {\n value.value = currentInitialValue;\n touched.value = false;\n dirty.value = false;\n _ext.value = null;\n _submitted.value = false;\n });\n }\n\n function setValue(\n next: T,\n options: { shouldTouch?: boolean; shouldDirty?: boolean; shouldValidate?: boolean } = {},\n ): void {\n const { shouldTouch = false, shouldDirty = true, shouldValidate = true } = options;\n batch(() => {\n value.value = next;\n if (shouldDirty) dirty.value = true;\n if (shouldTouch) touched.value = true;\n if (shouldValidate) _submitted.value = true;\n });\n }\n\n function _setExternalError(msg: string | null): void {\n _ext.value = msg;\n if (msg) touched.value = true;\n }\n\n function _forceVisible(): void {\n touched.value = true;\n _submitted.value = true;\n }\n\n function _setInitialValue(next: T): void {\n currentInitialValue = next;\n }\n\n function _dispose(): void {\n _disposeExtCleanup();\n error.dispose();\n rawError.dispose();\n }\n\n return { value, error, rawError, touched, dirty, onInput, onBlur, reset, setValue, _setExternalError, _forceVisible, _setInitialValue, _dispose };\n}\n\n// --- FieldArrayState ---\n\n/** Public state of a field array (dynamic list of field groups). */\nexport interface FieldArrayState<T extends Record<string, unknown>> {\n /** Reactive list of field group states. */\n readonly fields: Signal<Array<{ [K in keyof T]: FieldState<T[K]> }>>;\n /** Appends a new item to the end of the array. */\n append(value: T): void;\n /** Removes the item at the given index. */\n remove(index: number): void;\n /**\n * Moves an item from `from` to `to` index.\n * Items between the two positions shift to fill the gap.\n */\n move(from: number, to: number): void;\n /** Replaces the item at the given index with new values. */\n replace(index: number, value: T): void;\n /** Number of items in the array. Reactive. */\n readonly length: Signal<number>;\n /** Replaces the whole array with a new list of items. */\n setValues(items: T[]): void;\n /** Patches existing items and appends any extras without touching untouched items. */\n patchValues(items: Partial<T>[]): void;\n /** Resets the array to its initial value, optionally updating that initial value. */\n reset(items?: T[]): void;\n /** @internal */\n _dispose(): void;\n}\n\n/**\n * Creates a reactive array of field groups for dynamic list forms.\n *\n * @example\n * const items = elurFieldArray([{ name: \"\" }], {\n * name: [required()],\n * });\n * items.append({ name: \"nuevo\" });\n * items.remove(0);\n */\nexport function elurFieldArray<T extends Record<string, unknown>>(\n initialItems: T[],\n fieldValidators: { [K in keyof T]?: Validator<T[K], unknown>[] } = {},\n validateOn: ValidateOn = \"blur\",\n): FieldArrayState<T> {\n function makeGroup(item: T): { [K in keyof T]: FieldState<T[K]> } {\n const group = {} as { [K in keyof T]: FieldState<T[K]> };\n for (const key in item) {\n const vs = (fieldValidators[key] ?? []) as Validator<T[typeof key], unknown>[];\n (group as Record<string, unknown>)[key] = elurField(item[key], vs, validateOn);\n }\n return group;\n }\n\n const fields = signal<Array<{ [K in keyof T]: FieldState<T[K]> }>>(\n initialItems.map(makeGroup)\n );\n // Mutable so that reset(newItems) can redirect the baseline.\n let currentInitialItems = initialItems;\n\n const length = computed(() => fields.value.length);\n\n function append(value: T): void {\n fields.value = [...fields.value, makeGroup(value)];\n }\n\n function remove(index: number): void {\n const current = fields.value;\n if (index < 0 || index >= current.length) return;\n // Dispose computed signals of the removed group before discarding\n for (const key in current[index]) {\n current[index][key]._dispose();\n }\n fields.value = current.filter((_, i) => i !== index);\n }\n\n function move(from: number, to: number): void {\n const current = [...fields.value];\n if (\n from < 0 || from >= current.length ||\n to < 0 || to >= current.length ||\n from === to\n ) return;\n const [item] = current.splice(from, 1);\n current.splice(to, 0, item);\n fields.value = current;\n }\n\n function replace(index: number, value: T): void {\n const current = [...fields.value];\n if (index < 0 || index >= current.length) return;\n // Dispose old group before replacing\n for (const key in current[index]) {\n current[index][key]._dispose();\n }\n current[index] = makeGroup(value);\n fields.value = current;\n }\n\n function setValues(items: T[]): void {\n for (const group of fields.value) {\n for (const key in group) group[key]._dispose();\n }\n fields.value = items.map(makeGroup);\n }\n\n function patchValues(items: Partial<T>[]): void {\n const current = [...fields.value];\n for (let i = 0; i < items.length; i++) {\n const patch = items[i] as Record<string, unknown>;\n if (i >= current.length) {\n current.push(makeGroup(patch as T));\n continue;\n }\n const group = current[i] as Record<string, FieldState<unknown>>;\n for (const [key, val] of Object.entries(patch)) {\n if (group[key]) {\n group[key].setValue(val, { shouldDirty: false, shouldTouch: false, shouldValidate: false });\n }\n }\n }\n fields.value = current;\n }\n\n function reset(items?: T[]): void {\n if (items) currentInitialItems = items;\n for (const group of fields.value) {\n for (const key in group) group[key]._dispose();\n }\n fields.value = currentInitialItems.map(makeGroup);\n }\n\n function _dispose(): void {\n for (const group of fields.value) {\n for (const key in group) group[key]._dispose();\n }\n length.dispose();\n }\n\n return { fields, append, remove, move, replace, length, setValues, patchValues, reset, _dispose };\n}\n\n// --- FormState ---\n\n/** Field-name map that supports top-level keys and dot-path nested keys. */\nexport type FormFields<T extends Record<string, unknown>> =\n { [K in keyof T]: FieldState<T[K]> } & Record<string, FieldState<unknown>>;\n\n/** Map of field-name → error message for external validation results. */\nexport type FieldErrors<T extends Record<string, unknown>> =\n { [K in keyof T]?: string | null } & Record<string, string | null | undefined>;\n\n/** Validators map supporting both top-level and dot-path keys. */\nexport type FormValidators<T extends Record<string, unknown>> =\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n { [K in keyof T]?: Validator<T[K], T>[] } & Record<string, Validator<any, any>[] | undefined>;\n\n// Utility used by setValues so callers can patch nested objects (e.g. { address: { city: \"Lima\" } }).\nexport type DeepPartial<T> = T extends object ? { [P in keyof T]?: DeepPartial<T[P]> } : T;\n\nexport interface FormState<T extends Record<string, unknown>> {\n /** Individual field states — access value, error, event handlers. */\n fields: FormFields<T>;\n /** Computed snapshot of all current field values. */\n readonly values: Signal<T>;\n /** Computed map of all currently visible field errors. */\n readonly errors: Signal<FieldErrors<T>>;\n /**\n * True when no field has a *visible* error.\n *\n * Visibility follows `validateOn`, so this signal reflects what the user\n * currently sees in the UI — not the underlying validity of the data.\n * Use it to drive error summaries, banners, or any UI that should only\n * react to errors the user has been shown.\n *\n * For enabling or disabling submit buttons, use {@link canSubmit} instead.\n */\n readonly valid: Signal<boolean>;\n /**\n * True when every per-field validator passes against the current values,\n * regardless of `touched`, `dirty`, or `validateOn`.\n *\n * This is the signal to bind to submit buttons:\n *\n * ```ts\n * <button disabled=${() => !form.canSubmit.value || form.isSubmitting.value}>\n * Save\n * </button>\n * ```\n *\n * Unlike {@link valid}, `canSubmit` does not depend on whether errors are\n * currently visible — a pristine form with empty required fields starts\n * as `false` and flips to `true` the moment all validators pass.\n *\n * External errors injected via {@link setErrors} also flip `canSubmit` to\n * `false` until the user edits the affected field.\n *\n * **Note:** `canSubmit` does not execute `options.validate` (schema-level\n * validators such as Zod). Schema validation runs only on submit, by design,\n * to keep per-keystroke cost predictable. If you need a schema rule to\n * affect `canSubmit` reactively, express it as a per-field validator in\n * `options.validators` instead.\n */\n readonly canSubmit: Signal<boolean>;\n /** True when at least one field has been modified. */\n readonly dirty: Signal<boolean>;\n /** True when at least one field has been touched (lost focus). */\n readonly touched: Signal<boolean>;\n /** True while the submit callback is executing (async-safe). */\n readonly isSubmitting: Signal<boolean>;\n /** Number of times the form has been submitted (including failed validations). */\n readonly submitCount: Signal<number>;\n /**\n * Wraps a submit callback. Returned handler:\n * 1. Calls `e.preventDefault()`\n * 2. Increments `submitCount` and marks all fields as visible\n * 3. Runs `options.validate` if provided (Zod, etc.)\n * 4. Only calls `fn(values)` if all validations pass\n * 5. Manages `isSubmitting` across async callbacks\n */\n handleSubmit(fn: (values: T) => void | Promise<void>): (e: Event) => void;\n /**\n * Reset all fields to their initial values. If `newInitialValues` is provided,\n * it becomes the new baseline and subsequent reset() calls will use it.\n */\n reset(newInitialValues?: T): void;\n /**\n * Set a single field value by its path (top-level or nested dot-path).\n */\n setValue(\n path: string,\n value: unknown,\n options?: { shouldTouch?: boolean; shouldDirty?: boolean; shouldValidate?: boolean },\n ): void;\n /**\n * Set multiple field values at once.\n *\n * @param values — partial object with top-level and/or nested values.\n * @param options — control whether to preserve existing touched/dirty/error state.\n */\n setValues(\n values: DeepPartial<T>,\n options?: { keepDirty?: boolean; keepTouched?: boolean; keepErrors?: boolean },\n ): void;\n /**\n * Inject external errors (e.g., from a server response) into specific fields.\n * Each field's error clears automatically the next time the user edits it.\n */\n setErrors(errors: FieldErrors<T>): void;\n /**\n * Disposes all internal computed signals.\n * Call in `onUnmount` when the form lives inside a component.\n */\n dispose(): void;\n}\n\nexport interface FormOptions<T extends Record<string, unknown>> {\n /** Per-field validators. Each validator receives `(value, allValues?)`. */\n validators?: FormValidators<T>;\n /**\n * Controls when validation errors become visible.\n * - `\"blur\"` — after the field loses focus (default)\n * - `\"input\"` — as soon as the user types\n * - `\"submit\"` — only after the first submit attempt\n */\n validateOn?: ValidateOn;\n /**\n * Optional schema-level validator — runs on submit after built-in validators pass.\n * Return `null` / `undefined` if valid, or a field→error map if not.\n * String arrays are accepted (first element shown per field).\n *\n * @example Zod interop\n * ```typescript\n * validate(values) {\n * const r = schema.safeParse(values);\n * if (r.success) return null;\n * return Object.fromEntries(\n * Object.entries(r.error.flatten().fieldErrors)\n * .map(([k, v]) => [k, v?.[0]])\n * );\n * }\n * ```\n */\n validate?: (\n values: T\n ) => Record<string, string | string[] | null | undefined> | null | undefined;\n}\n\nfunction isPlainRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction flattenValuePaths(\n value: Record<string, unknown>,\n prefix = \"\",\n out: Array<[string, unknown]> = [],\n): Array<[string, unknown]> {\n for (const [key, next] of Object.entries(value)) {\n const path = prefix ? `${prefix}.${key}` : key;\n if (isPlainRecord(next) && Object.keys(next).length > 0) {\n flattenValuePaths(next, path, out);\n continue;\n }\n out.push([path, next]);\n }\n return out;\n}\n\nfunction setAtPath(target: Record<string, unknown>, path: string, value: unknown): void {\n const parts = path.split(\".\");\n let current: Record<string, unknown> = target;\n\n for (let i = 0; i < parts.length - 1; i++) {\n const part = parts[i];\n const child = current[part];\n if (!isPlainRecord(child)) {\n current[part] = {};\n }\n current = current[part] as Record<string, unknown>;\n }\n\n current[parts[parts.length - 1]] = value;\n}\n\n// --- createForm ---\n\n/**\n * Creates a managed form with reactive fields, built-in validation,\n * schema-level validation (Zod/Valibot/Yup/custom), and submit handling.\n */\nexport function createForm<T extends Record<string, unknown>>(\n initialValues: T,\n options: FormOptions<T> = {}\n): FormState<T> {\n const validateOn: ValidateOn = options.validateOn ?? \"blur\";\n\n const fields = {} as Record<string, FieldState<unknown>>;\n const validatorsByPath = options.validators as\n | Record<string, Validator<unknown, T>[] | undefined>\n | undefined;\n\n function snapshotValues(): T {\n const r: Record<string, unknown> = {};\n for (const k in fields) setAtPath(r, k, fields[k].value.value);\n return r as T;\n }\n\n for (const [path, initialValue] of flattenValuePaths(initialValues)) {\n const vs = validatorsByPath?.[path] ?? [];\n fields[path] = elurField<unknown, T>(initialValue, vs, validateOn, snapshotValues);\n }\n\n const isSubmitting = signal(false);\n const submitCount = signal(0);\n\n const values = computed<T>(() => {\n return snapshotValues();\n });\n\n const errors = computed<FieldErrors<T>>(() => {\n const r: FieldErrors<T> = {};\n for (const k in fields) {\n const e = fields[k].error.value;\n if (e) (r as Record<string, unknown>)[k] = e;\n }\n return r;\n });\n\n const canSubmit = computed<boolean>(() => {\n for (const k in fields) {\n if (fields[k].rawError.value) return false;\n }\n return true;\n });\n\n const valid = computed<boolean>(() => {\n for (const k in fields) if (fields[k].error.value) return false;\n return true;\n });\n\n const dirty = computed<boolean>(() => {\n for (const k in fields) if (fields[k].dirty.value) return true;\n return false;\n });\n\n const touched = computed<boolean>(() => {\n for (const k in fields) if (fields[k].touched.value) return true;\n return false;\n });\n\n function setErrors(errs: FieldErrors<T>): void {\n for (const k in errs) fields[k]?._setExternalError(errs[k] ?? null);\n }\n\n function setValue(\n path: string,\n value: unknown,\n options: { shouldTouch?: boolean; shouldDirty?: boolean; shouldValidate?: boolean } = {},\n ): void {\n const field = fields[path];\n if (!field) return;\n field.setValue(value, options);\n }\n\n function setValues(\n values: DeepPartial<T>,\n options: { keepDirty?: boolean; keepTouched?: boolean; keepErrors?: boolean } = {},\n ): void {\n const { keepDirty = false, keepTouched = false, keepErrors = true } = options;\n batch(() => {\n for (const [path, v] of flattenValuePaths(values as Record<string, unknown>)) {\n const field = fields[path];\n if (!field) continue;\n field.setValue(v, {\n shouldDirty: !keepDirty,\n shouldTouch: false,\n shouldValidate: !keepErrors,\n });\n if (!keepTouched) field.touched.value = false;\n }\n });\n }\n\n function reset(newInitialValues?: T): void {\n if (newInitialValues) {\n for (const [path, v] of flattenValuePaths(newInitialValues)) {\n const field = fields[path];\n if (field) field._setInitialValue(v);\n }\n }\n for (const k in fields) fields[k].reset();\n isSubmitting.value = false;\n submitCount.value = 0;\n }\n\n function dispose(): void {\n values.dispose();\n errors.dispose();\n canSubmit.dispose();\n valid.dispose();\n dirty.dispose();\n touched.dispose();\n for (const k in fields) fields[k]._dispose();\n }\n\n function handleSubmit(fn: (values: T) => void | Promise<void>) {\n return (e: Event): void => {\n e.preventDefault();\n\n submitCount.value++;\n\n for (const k in fields) fields[k]._forceVisible();\n\n const currentValues = values.value;\n\n // Run schema-level validator (Zod, Valibot, etc.)\n if (options.validate) {\n const ext = options.validate(currentValues);\n if (ext) {\n const mapped: FieldErrors<T> = {};\n let hasAny = false;\n for (const k in ext) {\n const v = ext[k];\n const msg = Array.isArray(v) ? (v[0] ?? null) : (v ?? null);\n if (msg) {\n (mapped as Record<string, unknown>)[k] = msg;\n hasAny = true;\n }\n }\n if (hasAny) { setErrors(mapped); return; }\n }\n }\n\n // Check built-in validators\n for (const k in fields) if (fields[k].rawError.value) return;\n\n const result = fn(currentValues);\n\n if (result instanceof Promise) {\n isSubmitting.value = true;\n\n result\n .finally(() => {\n isSubmitting.value = false;\n })\n .catch(() => { });\n }\n };\n }\n\n return {\n fields: fields as FormFields<T>,\n values,\n errors,\n canSubmit,\n valid,\n dirty,\n touched,\n isSubmitting,\n submitCount,\n handleSubmit,\n reset,\n setValue,\n setValues,\n setErrors,\n dispose,\n };\n}"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { batch as e, computed as t, effect as n, signal as r } from "./signals.js";
1
+ import { batch as e, computed as t, effect as n, signal as r } from "./elur/next-2/reactivity.js";
2
2
  //#region src/elur/form.ts
3
3
  function i(e = "Required") {
4
4
  return (t) => t == null || t === "" || Array.isArray(t) && t.length === 0 ? e : null;
@@ -1,2 +1 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`./signals.cjs`),t=require(`./elur/template/types.cjs`),n=require(`./lifecycle.cjs`),r=require(`./context.cjs`),i=require(`./elur/template/keyed.cjs`),a=require(`./elur/template/keyed-diff.cjs`),o=require(`./elur/template/sanitize.cjs`),s=require(`./elur/template/bindings.cjs`);function c(e,r,i={}){try{if(n.isElurComponent(e))return l(e,r,i);let a=e[t.ELUR_TEMPLATE_DESCRIPTOR];return a||S(i,-1,`descriptor`,`Template has no hydration descriptor`),{unmount:u(a,r,i)}}catch(t){if(i.mismatch===`throw`)throw t;return i.mismatch!==`remount`&&console.warn(`[elur] Hydration mismatch; remounting root:`,t),r.replaceChildren(),{unmount:n.isElurComponent(e)?e.render()._render(r,null):e._render(r,null)}}}function l(e,n,i){r._pushComponentContext();let a=()=>{};try{try{e.onInit?.()}catch(t){if(e.onError)e.onError(t);else throw t}let r=e.render()[t.ELUR_TEMPLATE_DESCRIPTOR];r||S(i,-1,`descriptor`,`Component template has no hydration descriptor`),a=u(r,n,i)}finally{r._popComponentContext()}let o=e.onMount?.();return{unmount(){e.onUnmount?.(),typeof o==`function`&&o(),a()}}}function u(e,t,n,r){let i=d(t,r),a=[];for(let t=0;t<e.contexts.length;t++){let r=e.contexts[t],o=e.values[t];if(r.type===`event`){let e=i.events.get(t);e||S(n,t,`event`,`Missing event marker ${t}`),e.removeAttribute(`data-elur-e-${t}`),a.push(p(e,r.eventName,r.modifiers,o));continue}if(r.type===`attr`){let e=i.attributes.get(t);e||S(n,t,`attribute`,`Missing attribute marker ${t}`),e.removeAttribute(`data-elur-a-${t}`),a.push(m(e,r.attrName,r.url===!0,o));continue}let s=i.nodes.get(t);s||S(n,t,`node`,`Missing node marker ${t}`);let c=h(s,o,n,i.keyed.get(t),i.arrayItems.get(t));c&&a.push(c)}return()=>{for(let e=a.length-1;e>=0;e--)a[e]()}}function d(e,t){let n=new Map,r=new Map,i=new Map,a=new Map,o=new Map,s=new Map,c=[],l=[],u=[],d=document.createTreeWalker(e,NodeFilter.SHOW_ELEMENT|NodeFilter.SHOW_COMMENT),p;for(;p=d.nextNode();){if(t&&!f(p,t))continue;if(p.nodeType===Node.COMMENT_NODE){let e=p,t=/^elur-(\d+)$/.exec(e.data);if(t){let n=Number(t[1]);c.length===0&&r.set(n,e),c.push(n);continue}let i=/^elur-end-(\d+)$/.exec(e.data);if(i){let t=Number(i[1]);if(c.pop()===t&&c.length===0){let i=r.get(t);i&&n.set(t,{start:i,end:e})}continue}let a=/^elur-ki:(.+)$/.exec(e.data);if(a){let t=a[1];l.length===0&&c.length===1?l.push({start:e,serializedKey:t,parentIndex:c[c.length-1]}):l.push({start:e,serializedKey:t,parentIndex:-1});continue}if(e.data===`elur-ke`){let t=l.pop();if(t){if(t.parentIndex>=0){let n=o.get(t.parentIndex)??[];n.push({start:t.start,end:e,serializedKey:t.serializedKey}),o.set(t.parentIndex,n)}}else throw Error(`[elur] Hydration marker mismatch: orphan keyed end marker (elur-ke)`);continue}if(e.data===`elur-ai`){u.length===0&&c.length===1?u.push({start:e,parentIndex:c[c.length-1]}):u.push({start:e,parentIndex:-1});continue}if(e.data===`elur-aiend`){let t=u.pop();if(t&&t.parentIndex>=0){let n=s.get(t.parentIndex)??[];n.push({start:t.start,end:e}),s.set(t.parentIndex,n)}continue}continue}if(c.length>0)continue;let e=p;for(let t of Array.from(e.attributes)){let n=/^data-elur-e-(\d+)$/.exec(t.name);n&&a.set(Number(n[1]),e);let r=/^data-elur-a-(\d+)$/.exec(t.name);r&&i.set(Number(r[1]),e)}}return{nodes:n,attributes:i,events:a,keyed:o,arrayItems:s}}function f(e,t){let n=document.createRange();return n.setStartAfter(t.start),n.setEndBefore(t.end),n.intersectsNode(e)}function p(e,t,n,r){if(typeof r!=`function`)throw TypeError(`Event "${t}" requires a function`);let i=r;if(s.isDelegableEvent(t)&&!n.includes(`capture`)&&!n.includes(`once`)&&document.body.contains(e))return s.activateDelegatedEvent(e,t,n,i);let a={once:n.includes(`once`),capture:n.includes(`capture`),passive:n.includes(`passive`)},o=e=>{n.includes(`prevent`)&&e.preventDefault(),n.includes(`stop`)&&e.stopPropagation(),!(n.includes(`self`)&&e.target!==e.currentTarget)&&i(e)};return e.addEventListener(t,o,a),()=>e.removeEventListener(t,o,a)}function m(t,n,r,i){if(n===`ref`){let e=i;return e.el=t,()=>{e.el=null}}let a=(n===`value`||n===`checked`||n===`selected`)&&n in t,s=!0,c=!1,l=e=>{if(a)if(!s)t[n]=e??``;else{let r=t[n];if(String(r)!==String(e??``)&&!c){c=!0;let e=n===`checked`||n===`selected`?`change`:`input`;queueMicrotask(()=>{c=!1,t.dispatchEvent(new Event(e,{bubbles:!0}))})}}else if(e==null||e===!1)t.removeAttribute(n);else{let i=r?o.sanitizeUrl(String(e)):String(e);t.setAttribute(n,i)}s=!1};return typeof i==`function`?e.effect(()=>l(i())):(l(i),()=>{})}function h(n,i,o,s,c){if(typeof i!=`function`)return g(n,i,o,s,c);let l=!0,u,d=b(n),f=null,p=r._captureContextSnapshot(),m=a.createKeyedMount(p),h=e=>{console.warn(`[elur] repeat(): duplicate key "${e}". Keys must be unique; the previous entry leaks (orphaned nodes + live effects).`)},v=e.effect(()=>{let e=i();if(t.isKeyedList(e)){if(l&&!f){let t=_(e,s,o);f={state:t.state,prevOrder:t.prevOrder},u=t.cleanup,a.reconcileKeyedList({zoneStart:n.start,anchor:n.end,state:f.state,prevOrder:f.prevOrder,list:e,mount:m,ctxSnapshot:p,onDuplicateKey:h}),d=null,l=!1;return}f||(u?.(),x(n),f={state:new Map,prevOrder:[]},u=()=>{for(let e of f.state.values())e.cleanup()}),a.reconcileKeyedList({zoneStart:n.start,anchor:n.end,state:f.state,prevOrder:f.prevOrder,list:e,mount:m,ctxSnapshot:p,onDuplicateKey:h}),d=null,l=!1;return}f&&(u?.(),x(n),f=null,u=void 0),typeof e==`string`||typeof e==`number`||typeof e==`bigint`?d?d.nodeValue!==String(e)&&(d.nodeValue=String(e)):(d=document.createTextNode(String(e)),n.end.parentNode.insertBefore(d,n.end)):l?u=g(n,e,o,s,c):(u?.(),x(n),u=y(n,e),d=b(n)),l=!1});return()=>{v(),u?.()}}function g(e,i,o,s,c){if(t.isKeyedList(i)){let t=r._captureContextSnapshot(),n=_(i,s,o);return a.reconcileKeyedList({zoneStart:e.start,anchor:e.end,state:n.state,prevOrder:n.prevOrder,list:i,mount:a.createKeyedMount(t),ctxSnapshot:t,onDuplicateKey:e=>{console.warn(`[elur] repeat(): duplicate key "${e}". Keys must be unique; the previous entry leaks (orphaned nodes + live effects).`)}}),n.cleanup}if(Array.isArray(i)){let t=[],n=c!==void 0&&c.length>0;for(let r=0;r<i.length;r++){let a=i[r],s=c?.[r];if(n&&s){let e=g(s,a,o);e&&t.push(e)}else if(n){let n=y(e,a);n&&t.push(n)}else{let n=g(e,a,o);n&&t.push(n)}}return t.length?()=>{for(let e=t.length-1;e>=0;e--)t[e]()}:void 0}if(t.isElurTemplate(i)){let n=i[t.ELUR_TEMPLATE_DESCRIPTOR];return n||S(o,-1,`descriptor`,`Nested template has no hydration descriptor`),u(n,e.start.parentNode,o,e)}if(n.isElurComponent(i)){r._pushComponentContext();let n;try{try{i.onInit?.()}catch(e){if(i.onError)i.onError(e);else throw e}let r=i.render()[t.ELUR_TEMPLATE_DESCRIPTOR];r||S(o,-1,`descriptor`,`Nested component has no hydration descriptor`);let a=u(r,e.start.parentNode,o,e),s=i.onMount?.();n=()=>{i.onUnmount?.(),typeof s==`function`&&s(),a()}}finally{r._popComponentContext()}return n}if(typeof i==`object`&&i){let n=i[t.ELUR_RENDER_PROTOCOL];if(n?.hydrateDom)return n.hydrateDom({parent:e.start.parentNode,bounds:e,context:o.context,render:t=>g(e,t,o)})??void 0}}function _(e,t,n){let r=new Map,a=[];if(!t||t.length===0)return{state:r,prevOrder:a,cleanup:()=>{}};let o=new Map;for(let t=0;t<e.items.length;t++){let n=i.normalizeRepeatKey(e.keyFn(e.items[t],t),t),r=i.serializeRepeatKey(n);o.has(r)&&console.warn(`[elur] repeat(): duplicate client key "${n}" during hydration. Keys must be unique; entries after the first leak.`),o.set(r,t)}for(let s of t){let t=o.get(s.serializedKey);if(t===void 0){v(s);continue}let c=e.items[t],l=i.normalizeRepeatKey(e.keyFn(c,t),t);if(i.serializeRepeatKey(l)!==s.serializedKey&&console.warn(`[elur] repeat(): hydration key mismatch at index ${t} (${i.deserializeRepeatKey(s.serializedKey)} != ${l}). The SSR item is adopted by position.`),r.has(l)){console.warn(`[elur] repeat(): duplicate key "${l}" during hydration; removing duplicate SSR node.`),v(s);continue}let u=e.renderFn(c,t),d=g({start:s.start,end:s.end},u,n);r.set(l,{start:s.start,end:s.end,cleanup:d??(()=>{})}),a.push(l)}return{state:r,prevOrder:a,cleanup:()=>{for(let e of r.values())e.cleanup()}}}function v(e){let t=e.start.nextSibling;for(;t&&t!==e.end;){let e=t.nextSibling;t.parentNode?.removeChild(t),t=e}e.start.parentNode?.removeChild(e.start),e.end.parentNode?.removeChild(e.end)}function y(e,r){if(r==null||r===!1||r===!0)return;if(Array.isArray(r)){let t=[];for(let n of r){let r=y(e,n);r&&t.push(r)}return t.length?()=>{for(let e=t.length-1;e>=0;e--)t[e]()}:void 0}if(t.isElurTemplate(r))return r._render(e.end.parentNode,e.end);if(n.isElurComponent(r))return r.render()._render(e.end.parentNode,e.end);let i=document.createTextNode(String(r));return e.end.parentNode.insertBefore(i,e.end),()=>i.parentNode?.removeChild(i)}function b(e){let t=e.start.nextSibling;for(;t&&t!==e.end;){if(t.nodeType===Node.TEXT_NODE)return t;t=t.nextSibling}return null}function x(e){let t=e.start.nextSibling;for(;t&&t!==e.end;){let e=t.nextSibling;t.parentNode?.removeChild(t),t=e}}function S(e,t,n,r){let i={index:t,kind:n,message:r};e.onMismatch?.(i);let a=Error(`[elur] Hydration marker mismatch: ${r}`);throw Object.assign(a,{mismatch:i}),a}exports.hydrate=c;
2
- //# sourceMappingURL=hydrate.cjs.map
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`./elur/next-2/hydrate.cjs`);exports._hydrateNodeRange=e._hydrateNodeRange,exports.hydrate=e.hydrate;
@@ -1,13 +1 @@
1
- import { type ElurComponent } from "../lifecycle.js";
2
- import { type ElurMountHandle, type ElurTemplate } from "../template/types.js";
3
- export interface HydrateOptions {
4
- mismatch?: "throw" | "warn-remount" | "remount";
5
- onMismatch?: (error: HydrationMismatch) => void;
6
- context?: unknown;
7
- }
8
- export interface HydrationMismatch {
9
- index: number;
10
- kind: "node" | "attribute" | "event" | "descriptor" | "keyed";
11
- message: string;
12
- }
13
- export declare function hydrate(value: ElurTemplate | ElurComponent, container: Element, options?: HydrateOptions): ElurMountHandle;
1
+ export * from "../next-2/hydrate.js";
@@ -1,13 +1 @@
1
- import { type ElurComponent } from "../lifecycle.js";
2
- import { type ElurMountHandle, type ElurTemplate } from "../template/types.js";
3
- export interface HydrateOptions {
4
- mismatch?: "throw" | "warn-remount" | "remount";
5
- onMismatch?: (error: HydrationMismatch) => void;
6
- context?: unknown;
7
- }
8
- export interface HydrationMismatch {
9
- index: number;
10
- kind: "node" | "attribute" | "event" | "descriptor" | "keyed";
11
- message: string;
12
- }
13
- export declare function hydrate(value: ElurTemplate | ElurComponent, container: Element, options?: HydrateOptions): ElurMountHandle;
1
+ export * from "../next-2/hydrate.js";