kerfjs 5.0.0-beta.8 → 5.0.0-beta.80

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 (83) hide show
  1. package/CHANGELOG.md +2577 -117
  2. package/README.md +96 -37
  3. package/ai/cursorrules +110 -61
  4. package/ai/manifest.json +16 -7
  5. package/ai/skill.md +120 -75
  6. package/dist/actions.d.ts +1 -1
  7. package/dist/actions.js +10 -6
  8. package/dist/actions.js.map +1 -1
  9. package/dist/array-signal.js +1 -1
  10. package/dist/async.js +22 -19
  11. package/dist/async.js.map +1 -1
  12. package/dist/attach.js +1 -66
  13. package/dist/attach.js.map +1 -1
  14. package/dist/{chunk-HW7KSM2Y.js → chunk-3C6F6NM4.js} +1 -1
  15. package/dist/{chunk-HW7KSM2Y.js.map → chunk-3C6F6NM4.js.map} +1 -1
  16. package/dist/{chunk-GY4XV2UV.js → chunk-4TX6YJDM.js} +10 -3
  17. package/dist/chunk-4TX6YJDM.js.map +1 -0
  18. package/dist/{chunk-QIP723L4.js → chunk-5WRGJZV6.js} +3 -2
  19. package/dist/chunk-5WRGJZV6.js.map +1 -0
  20. package/dist/{chunk-KZJXHFIB.js → chunk-BI4HGICV.js} +3 -3
  21. package/dist/chunk-BI4HGICV.js.map +1 -0
  22. package/dist/chunk-FM6N2B4N.js +70 -0
  23. package/dist/chunk-FM6N2B4N.js.map +1 -0
  24. package/dist/{chunk-LVH3GC6B.js → chunk-H7WTRM6F.js} +3 -3
  25. package/dist/chunk-H7WTRM6F.js.map +1 -0
  26. package/dist/{chunk-U6FK33SG.js → chunk-IHMDBBUJ.js} +2 -2
  27. package/dist/chunk-IHMDBBUJ.js.map +1 -0
  28. package/dist/chunk-JN7EJM3B.js +86 -0
  29. package/dist/chunk-JN7EJM3B.js.map +1 -0
  30. package/dist/{chunk-UZJ6I4T6.js → chunk-MK42GLPV.js} +1 -1
  31. package/dist/chunk-MK42GLPV.js.map +1 -0
  32. package/dist/{chunk-SVATPF5R.js → chunk-TLL3KXT6.js} +249 -160
  33. package/dist/chunk-TLL3KXT6.js.map +1 -0
  34. package/dist/{chunk-ZDCJZCNO.js → chunk-UGNPDLNI.js} +78 -45
  35. package/dist/chunk-UGNPDLNI.js.map +1 -0
  36. package/dist/{chunk-V46JKE44.js → chunk-WKIPLNVO.js} +1 -1
  37. package/dist/chunk-WKIPLNVO.js.map +1 -0
  38. package/dist/{delegate-CL9VTZFb.d.ts → delegate--CrfgYtC.d.ts} +0 -34
  39. package/dist/dev.d.ts +31 -13
  40. package/dist/dev.js +101 -35
  41. package/dist/dev.js.map +1 -1
  42. package/dist/html.js +5 -4
  43. package/dist/html.js.map +1 -1
  44. package/dist/index.d.ts +14 -9
  45. package/dist/index.js +29 -20
  46. package/dist/index.js.map +1 -1
  47. package/dist/jsx-runtime.d.ts +13 -5
  48. package/dist/jsx-runtime.js +1 -1
  49. package/dist/list.d.ts +7 -3
  50. package/dist/list.js +126 -28
  51. package/dist/list.js.map +1 -1
  52. package/dist/overlay.d.ts +128 -129
  53. package/dist/overlay.js +675 -366
  54. package/dist/overlay.js.map +1 -1
  55. package/dist/remount.js +2 -2
  56. package/dist/router.d.ts +13 -4
  57. package/dist/router.js +37 -10
  58. package/dist/router.js.map +1 -1
  59. package/dist/scope.d.ts +35 -8
  60. package/dist/scope.js +61 -30
  61. package/dist/scope.js.map +1 -1
  62. package/dist/testing.js +1 -1
  63. package/dist/timing.d.ts +3 -2
  64. package/dist/timing.js +1 -1
  65. package/dist/timing.js.map +1 -1
  66. package/llms.txt +12 -5
  67. package/package.json +33 -8
  68. package/setup/cli.mjs +90 -0
  69. package/setup/index.d.mts +37 -0
  70. package/setup/index.mjs +1347 -0
  71. package/setup/jsonc.mjs +201 -0
  72. package/setup/state.schema.json +56 -0
  73. package/dist/chunk-GY4XV2UV.js.map +0 -1
  74. package/dist/chunk-KPXIOG2C.js +0 -54
  75. package/dist/chunk-KPXIOG2C.js.map +0 -1
  76. package/dist/chunk-KZJXHFIB.js.map +0 -1
  77. package/dist/chunk-LVH3GC6B.js.map +0 -1
  78. package/dist/chunk-QIP723L4.js.map +0 -1
  79. package/dist/chunk-SVATPF5R.js.map +0 -1
  80. package/dist/chunk-U6FK33SG.js.map +0 -1
  81. package/dist/chunk-UZJ6I4T6.js.map +0 -1
  82. package/dist/chunk-V46JKE44.js.map +0 -1
  83. package/dist/chunk-ZDCJZCNO.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/attr.ts"],"names":[],"mappings":"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","file":"chunk-MK42GLPV.js","sourcesContent":["/**\n * `attr(name, value)` — create a pre-computed attribute descriptor (static form).\n * `attr(name)` — create a per-render factory for dynamic attribute values (dynamic form).\n *\n * **Static form** — best for fixed action names, filter keys, role values, etc.\n * Escapes once at module-load time; produces a full {@link AttrSpec} with\n * `.name`, `.value`, `.selector`, and `.attrs`.\n *\n * const ACTIONS = {\n * toggle: attr('data-action', 'toggle'),\n * remove: attr('data-action', 'remove'),\n * } as const satisfies Record<string, AttrSpec<'data-action'>>;\n *\n * // In JSX — spread .attrs (rename-safe; no hardcoded attribute name):\n * <button {...ACTIONS.toggle.attrs}>Toggle</button>\n *\n * // In delegate — use the pre-computed selector:\n * delegate(root, 'click', ACTIONS.toggle.selector, handler);\n *\n * **Dynamic form** — best for per-row data like `data-id`, where the value\n * changes per item but the attribute name is constant.\n * The name is validated and pre-escaped at definition time; calling the\n * returned factory is cheap (it just freezes a one-key object — the value is\n * escaped later by the JSX attribute renderer when the result is spread).\n *\n * const ITEM = { id: attr('data-id') } as const;\n *\n * // In JSX — call the factory inline:\n * <li {...ITEM.id(String(item.id))}>…</li>\n *\n * For ad-hoc compound selectors, concatenate `.selector` strings:\n *\n * delegate(root, 'click',\n * ACTIONS.toggle.selector + attr('data-id', id).selector,\n * handler);\n *\n * Escaping:\n * - Attribute name: escaped as a CSS identifier via `cssEscapeIdent`, which is\n * an SSR-safe (no `CSS.escape`) adaptation of the Mathias Bynens polyfill\n * (https://github.com/mathiasbynens/CSS.escape, MIT licensed — see the\n * Acknowledgements section of LICENSE). Handles\n * control chars, leading digits, non-ASCII, and CSS metacharacters.\n * - Attribute value: embedded in double quotes as a CSS string. Backslashes and\n * double-quote characters are backslash-escaped; control characters are\n * hex-escaped per CSS Syntax Level 3 §3.4.\n *\n * Throws on an empty attribute name (not a valid CSS identifier).\n */\n\n/** Descriptor created by the static {@link attr} overload. */\nexport interface AttrSpec<\n N extends string = string,\n V extends string = string,\n> {\n /** The raw attribute name passed to `attr()`. */\n readonly name: N;\n /** The raw attribute value passed to `attr()`. */\n readonly value: V;\n /** Pre-computed `[name=\"value\"]` CSS selector string, safe to pass to `delegate()`. */\n readonly selector: string;\n /** Spreadable JSX object — `{ [name]: value }` — keeps the attribute name out of JSX literals. */\n readonly attrs: { readonly [K in N]: V };\n}\n\n/**\n * Escape `value` as a CSS identifier (for attribute names, id fragments, etc.).\n * Adapted from the CSS.escape polyfill by Mathias Bynens (MIT).\n */\nfunction cssEscapeIdent(value: string): string {\n if (value === '') {\n throw new Error('attr: attribute name must not be empty');\n }\n const str = String(value);\n let result = '';\n for (let i = 0; i < str.length; i++) {\n const cp = str.charCodeAt(i);\n const ch = str.charAt(i);\n\n // U+0000 NULL → replacement character\n if (cp === 0x0000) {\n result += '�';\n continue;\n }\n // Control characters and DEL: hex-escape\n if ((cp >= 0x0001 && cp <= 0x001f) || cp === 0x007f) {\n result += '\\\\' + cp.toString(16) + ' ';\n continue;\n }\n // Leading digit: hex-escape to avoid \"-NN\" / \"3px\"-style ambiguity\n if (i === 0 && cp >= 0x0030 && cp <= 0x0039) {\n result += '\\\\' + cp.toString(16) + ' ';\n continue;\n }\n // Second char is a digit when first is '-' (e.g. \"-3foo\"): hex-escape digit\n if (\n i === 1 &&\n cp >= 0x0030 &&\n cp <= 0x0039 &&\n str.charCodeAt(0) === 0x002d\n ) {\n result += '\\\\' + cp.toString(16) + ' ';\n continue;\n }\n // Non-ASCII, safe identifier chars (letters, digits, underscore, hyphen)\n if (\n cp >= 0x0080 ||\n cp === 0x002d || // `-`\n cp === 0x005f || // `_`\n (cp >= 0x0030 && cp <= 0x0039) || // 0-9\n (cp >= 0x0041 && cp <= 0x005a) || // A-Z\n (cp >= 0x0061 && cp <= 0x007a) // a-z\n ) {\n result += ch;\n continue;\n }\n // Everything else: backslash-escape\n result += '\\\\' + ch;\n }\n return result;\n}\n\n/**\n * Escape `value` as a CSS double-quoted string (for attribute values in\n * `[attr=\"value\"]` selectors).\n */\nfunction escapeCSSString(value: string): string {\n let result = '';\n for (let i = 0; i < value.length; i++) {\n const cp = value.charCodeAt(i);\n const ch = value.charAt(i);\n if (cp === 0x0000) {\n result += '�';\n } else if ((cp >= 0x0001 && cp <= 0x001f) || cp === 0x007f) {\n // Control chars: hex-escape\n result += '\\\\' + cp.toString(16) + ' ';\n } else if (cp === 0x005c) {\n // Backslash\n result += '\\\\\\\\';\n } else if (cp === 0x0022) {\n // Double quote (the string delimiter we use)\n result += '\\\\\"';\n } else {\n result += ch;\n }\n }\n return result;\n}\n\n/**\n * Static overload — pre-computes the full descriptor at definition time.\n * Returns an {@link AttrSpec} with `.name`, `.value`, `.selector`, and `.attrs`.\n */\nexport function attr<N extends string, V extends string>(\n name: N,\n value: V,\n): AttrSpec<N, V>;\n\n/**\n * Dynamic overload — pre-validates and pre-escapes the attribute name, returns a\n * factory that accepts a per-render value and produces a frozen spreadable object.\n * Use for per-row attributes like `data-id` where the value changes per item.\n * The optional `V` generic constrains which values the factory accepts:\n * `attr<'data-id', 'a'|'b'>('data-id')` → `(value: 'a'|'b') => { 'data-id': 'a'|'b' }`.\n * Leaving both generics off infers `N` from the argument and defaults `V` to `string`.\n */\nexport function attr<N extends string, V extends string = string>(\n name: N,\n): (value: V) => { readonly [K in N]: V };\n\nexport function attr<N extends string, V extends string>(\n name: N,\n value?: V,\n): AttrSpec<N, V> | ((value: string) => { readonly [K in N]: string }) {\n const escapedName = cssEscapeIdent(name); // validates + pre-escapes name in both paths\n if (value !== undefined) {\n const selector = `[${escapedName}=\"${escapeCSSString(value)}\"]`;\n return Object.freeze({\n name,\n value,\n selector,\n attrs: Object.freeze({ [name]: value }) as { readonly [K in N]: V },\n }) as AttrSpec<N, V>;\n }\n return (v: string): { readonly [K in N]: string } =>\n Object.freeze({ [name]: v }) as { readonly [K in N]: string };\n}\n"]}
@@ -1,9 +1,9 @@
1
- import { itemVersion } from './chunk-QIP723L4.js';
2
- import { parseRowTemplate, rowContractError, parseSingleRow, collectTemplateChildren } from './chunk-V46JKE44.js';
3
- import { captureRowBindings, listSafeHtml, boundTextNodeOf, syncFormProp, newBindingContext, disposeRowBindings, wireBindings, isSafeHtml, _setBindingContext, TEXT_MARKER_PREFIX, ROW_TEXT_PREFIX, wireRowBindings, carryOrRewireRowBindings, granularListSafeHtml } from './chunk-ZDCJZCNO.js';
4
- import { effect } from './chunk-U6FK33SG.js';
5
- import { LIST_MARKER_PREFIX, flattenWithoutListItems, collectLists, flatten } from './chunk-GY4XV2UV.js';
6
- import { devHooks } from './chunk-HW7KSM2Y.js';
1
+ import { itemVersion } from './chunk-5WRGJZV6.js';
2
+ import { parseRowTemplate, rowContractError, parseSingleRow, collectTemplateChildren } from './chunk-WKIPLNVO.js';
3
+ import { captureRowBindings, listSafeHtml, boundTextNodeOf, syncFormProp, newBindingContext, wireBindings, disposeRowBindings, isSafeHtml, _setBindingContext, TEXT_MARKER_PREFIX, ROW_TEXT_PREFIX, wireRowBindings, carryOrRewireRowBindings, granularListSafeHtml } from './chunk-UGNPDLNI.js';
4
+ import { effect } from './chunk-IHMDBBUJ.js';
5
+ import { LIST_MARKER_PREFIX, flattenWithoutListItems, collectLists, isOverlayHost, flatten } from './chunk-4TX6YJDM.js';
6
+ import { devHooks } from './chunk-3C6F6NM4.js';
7
7
 
8
8
  // src/list-render-state.ts
9
9
  function deriveListRenderState(bindingCount) {
@@ -18,7 +18,8 @@ function decideListPath(state, patches, snapshotLength, previousBindingCount) {
18
18
  for (const p of patches) {
19
19
  if (p.type === "insert") netDelta += 1;
20
20
  else if (p.type === "remove") netDelta -= 1;
21
- else if (p.type === "replace") return { path: "snapshot", reason: "replace" };
21
+ else if (p.type === "replace")
22
+ return { path: "snapshot", reason: "replace" };
22
23
  }
23
24
  const count = previousBindingCount ?? 0;
24
25
  if (count + netDelta !== snapshotLength) {
@@ -153,10 +154,12 @@ function eachGranular(sig, render, cacheKey, listKey) {
153
154
  return eachSnapshotById(snapshot, render, cacheKey, id, sig);
154
155
  }
155
156
  }
156
- const renderRow = (item, index) => captureRowBindings(() => inRowScope(() => {
157
- const out = render(item, index);
158
- return isSafeHtml(out) ? out.toString() : out;
159
- }));
157
+ const renderRow = (item, index) => captureRowBindings(
158
+ () => inRowScope(() => {
159
+ const out = render(item, index);
160
+ return isSafeHtml(out) ? out.toString() : out;
161
+ })
162
+ );
160
163
  const internalPatches = new Array(patches.length);
161
164
  const cache = ctx.caches.get(id);
162
165
  try {
@@ -223,13 +226,16 @@ function eachSnapshotById(items, render, cacheKey, id, source) {
223
226
  devHooks.staleIndex?.(id);
224
227
  }
225
228
  } else {
226
- const captured = captureRowBindings(() => inRowScope(() => {
227
- const out = render(item, i);
228
- return isSafeHtml(out) ? out.toString() : out;
229
- }));
229
+ const captured = captureRowBindings(
230
+ () => inRowScope(() => {
231
+ const out = render(item, i);
232
+ return isSafeHtml(out) ? out.toString() : out;
233
+ })
234
+ );
230
235
  html = captured.html;
231
236
  bindings = captured.bindings;
232
- if (cache !== null) cache.set(item, { cacheKey: k, html, bindings, version, index: i });
237
+ if (cache !== null)
238
+ cache.set(item, { cacheKey: k, html, bindings, version, index: i });
233
239
  }
234
240
  segItems[i] = { ref: item, cacheKey: k, html, bindings };
235
241
  }
@@ -281,16 +287,19 @@ function restoreFocus(snap) {
281
287
  if (domSelection === null) return;
282
288
  const [anchorNode, anchorOffset, focusNode, focusOffset] = domSelection;
283
289
  try {
284
- document.getSelection()?.setBaseAndExtent(
285
- anchorNode,
286
- anchorOffset,
287
- focusNode,
288
- focusOffset
289
- );
290
+ document.getSelection()?.setBaseAndExtent(anchorNode, anchorOffset, focusNode, focusOffset);
290
291
  } catch {
291
292
  }
292
293
  }
293
294
 
295
+ // src/utils/isUserAgentOwnedAttr.ts
296
+ function isUserAgentOwnedAttr(tagNameUpper, name) {
297
+ if (tagNameUpper.includes("-")) {
298
+ return name === "open" || name === "role" || name.startsWith("aria-");
299
+ }
300
+ return name === "open" && (tagNameUpper === "DETAILS" || tagNameUpper === "DIALOG");
301
+ }
302
+
294
303
  // src/utils/moveNode.ts
295
304
  function moveNode(parent, node, ref) {
296
305
  const move = parent.moveBefore;
@@ -343,7 +352,11 @@ function protectionTag(node) {
343
352
  const { dataset } = node;
344
353
  return (dataset.morphSkip !== void 0 ? "s" : "") + (dataset.morphSkipChildren !== void 0 ? "c" : "") + (dataset.morphPreserve !== void 0 ? "p" : "");
345
354
  }
346
- var MARKER_PREFIXES = [LIST_MARKER_PREFIX, TEXT_MARKER_PREFIX, ROW_TEXT_PREFIX];
355
+ var MARKER_PREFIXES = [
356
+ LIST_MARKER_PREFIX,
357
+ TEXT_MARKER_PREFIX,
358
+ ROW_TEXT_PREFIX
359
+ ];
347
360
  function isMarker(node) {
348
361
  if (node.nodeType !== COMMENT_NODE) return false;
349
362
  const { data } = node;
@@ -421,7 +434,8 @@ function morphChildren(fromParent, toParent, ownedItems) {
421
434
  if (matched === null && fromChild !== null && toChild.nodeType === COMMENT_NODE && toChild.data.startsWith(LIST_MARKER_PREFIX)) {
422
435
  const wantData = toChild.data;
423
436
  for (let scan = fromChild.nextSibling; scan !== null; scan = scan.nextSibling) {
424
- if (scan.nodeType !== COMMENT_NODE || scan.data !== wantData) continue;
437
+ if (scan.nodeType !== COMMENT_NODE || scan.data !== wantData)
438
+ continue;
425
439
  const regionEnd = afterListRegion(scan, ownedItems);
426
440
  const run = [];
427
441
  for (let r = scan; r !== null && r !== regionEnd; r = r.nextSibling) {
@@ -487,9 +501,6 @@ function morphElement(fromEl, toEl, ownedItems) {
487
501
  fromEl.value = toEl.textContent;
488
502
  }
489
503
  }
490
- function isUserAgentOwnedAttr(tagName, name) {
491
- return name === "open" && (tagName === "DETAILS" || tagName === "DIALOG");
492
- }
493
504
  function morphAttributes(fromEl, toEl) {
494
505
  const toAttrs = toEl.attributes;
495
506
  for (let i = 0; i < toAttrs.length; i++) {
@@ -534,7 +545,10 @@ function preserveTextEntryState(fromEl, toEl) {
534
545
  const toInput = toEl;
535
546
  toInput.value = fromInput.value;
536
547
  try {
537
- toInput.setSelectionRange(fromInput.selectionStart, fromInput.selectionEnd);
548
+ toInput.setSelectionRange(
549
+ fromInput.selectionStart,
550
+ fromInput.selectionEnd
551
+ );
538
552
  } catch {
539
553
  }
540
554
  }
@@ -567,7 +581,8 @@ function tryAttributeOnlyFastPath(liveNode, oldHtml, newHtml) {
567
581
  if (oldGt === -1 || newGt === -1) return false;
568
582
  if (oldHtml.length - oldGt !== newHtml.length - newGt) return false;
569
583
  if (oldHtml.slice(oldGt) !== newHtml.slice(newGt)) return false;
570
- if (containsDataMorphSkip(oldHtml) || containsDataMorphSkip(newHtml)) return false;
584
+ if (containsDataMorphSkip(oldHtml) || containsDataMorphSkip(newHtml))
585
+ return false;
571
586
  const oldTag = parseOpeningTag(oldHtml, oldGt);
572
587
  const newTag = parseOpeningTag(newHtml, newGt);
573
588
  if (oldTag === null || newTag === null) return false;
@@ -588,14 +603,15 @@ function tryAttributeOnlyFastPath(liveNode, oldHtml, newHtml) {
588
603
  }
589
604
  for (const name of oldTag.attrs.keys()) {
590
605
  if (newTag.attrs.has(name)) continue;
591
- if (isUserAgentOwnedAttr2(liveTagUpper, name)) continue;
606
+ if (isUserAgentOwnedAttr(liveTagUpper, name)) continue;
592
607
  liveNode.removeAttribute(name);
593
608
  syncFormProp(liveNode, name, "", false);
594
609
  }
595
610
  return true;
596
611
  }
597
612
  function tryTextContentFastPath(liveNode, oldHtml, newHtml) {
598
- if (containsDataMorphSkip(oldHtml) || containsDataMorphSkip(newHtml)) return false;
613
+ if (containsDataMorphSkip(oldHtml) || containsDataMorphSkip(newHtml))
614
+ return false;
599
615
  let p = 0;
600
616
  const minLen = Math.min(oldHtml.length, newHtml.length);
601
617
  while (p < minLen && oldHtml.charCodeAt(p) === newHtml.charCodeAt(p)) p++;
@@ -610,7 +626,8 @@ function tryTextContentFastPath(liveNode, oldHtml, newHtml) {
610
626
  if (!isPureTextWindow(newHtml, p, newWinEnd)) return false;
611
627
  if (p === 0) return false;
612
628
  const boundaryCc = oldHtml.charCodeAt(p - 1);
613
- if (boundaryCc === LT || boundaryCc === DQUOTE || boundaryCc === SQUOTE || boundaryCc === EQ || boundaryCc === AMP) return false;
629
+ if (boundaryCc === LT || boundaryCc === DQUOTE || boundaryCc === SQUOTE || boundaryCc === EQ || boundaryCc === AMP)
630
+ return false;
614
631
  const textStart = lastIndexOfChar(oldHtml, GT, p - 1);
615
632
  if (textStart === -1) return false;
616
633
  const textEnd = oldHtml.indexOf("<", p);
@@ -637,7 +654,8 @@ function containsDataMorphSkip(html) {
637
654
  function isPureTextWindow(html, start, end) {
638
655
  for (let i = start; i < end; i++) {
639
656
  const cc = html.charCodeAt(i);
640
- if (cc === LT || cc === GT || cc === DQUOTE || cc === SQUOTE || cc === AMP || cc === EQ) return false;
657
+ if (cc === LT || cc === GT || cc === DQUOTE || cc === SQUOTE || cc === AMP || cc === EQ)
658
+ return false;
641
659
  }
642
660
  return true;
643
661
  }
@@ -730,9 +748,6 @@ function unescapeAttrValue(s) {
730
748
  if (s.indexOf("&") === -1) return s;
731
749
  return s.replace(/&quot;/g, '"').replace(/&#39;/g, "'").replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&amp;/g, "&");
732
750
  }
733
- function isUserAgentOwnedAttr2(tagNameUpper, name) {
734
- return name === "open" && (tagNameUpper === "DETAILS" || tagNameUpper === "DIALOG");
735
- }
736
751
 
737
752
  // src/list-reconcile-granular.ts
738
753
  function reconcileGranular(binding, patches) {
@@ -769,7 +784,14 @@ function reconcileGranular(binding, patches) {
769
784
  if (runLen === 1) {
770
785
  applySingleInsert(liveParent, items, patch, endAnchor(binding));
771
786
  } else {
772
- applyBulkInsert(liveParent, items, patches, i, runEnd, endAnchor(binding));
787
+ applyBulkInsert(
788
+ liveParent,
789
+ items,
790
+ patches,
791
+ i,
792
+ runEnd,
793
+ endAnchor(binding)
794
+ );
773
795
  }
774
796
  i = runEnd;
775
797
  continue;
@@ -881,7 +903,10 @@ function applyBulkUpdate(liveParent, items, patches, start, end) {
881
903
  morphChanges.push({ patchIdx: k, html: p.html });
882
904
  }
883
905
  if (morphChanges.length === 0) return;
884
- const { content, count } = parseRowTemplate(morphChanges.map((c) => c.html).join(""), liveParent);
906
+ const { content, count } = parseRowTemplate(
907
+ morphChanges.map((c) => c.html).join(""),
908
+ liveParent
909
+ );
885
910
  if (count !== morphChanges.length) {
886
911
  throw findOffendingChange(patches, morphChanges, liveParent);
887
912
  }
@@ -924,18 +949,30 @@ function applyBulkInsert(liveParent, items, patches, start, end, tailAnchor) {
924
949
  function findOffendingInsert(patches, start, htmls, liveParent) {
925
950
  for (let i = 0; i < htmls.length; i++) {
926
951
  if (parseRowTemplate(htmls[i], liveParent).count !== 1) {
927
- return rowContractError(patches[start + i].index, htmls[i], liveParent);
952
+ return rowContractError(
953
+ patches[start + i].index,
954
+ htmls[i],
955
+ liveParent
956
+ );
928
957
  }
929
958
  }
930
- return new Error("each(): bulk-insert mismatch with no per-row offender (kerf bug).");
959
+ return new Error(
960
+ "each(): bulk-insert mismatch with no per-row offender (kerf bug)."
961
+ );
931
962
  }
932
963
  function findOffendingChange(patches, changes, liveParent) {
933
964
  for (const c of changes) {
934
965
  if (parseRowTemplate(c.html, liveParent).count !== 1) {
935
- return rowContractError(patches[c.patchIdx].index, c.html, liveParent);
966
+ return rowContractError(
967
+ patches[c.patchIdx].index,
968
+ c.html,
969
+ liveParent
970
+ );
936
971
  }
937
972
  }
938
- return new Error("each(): bulk-update mismatch with no per-row offender (kerf bug).");
973
+ return new Error(
974
+ "each(): bulk-update mismatch with no per-row offender (kerf bug)."
975
+ );
939
976
  }
940
977
 
941
978
  // src/list-reconcile-inplace.ts
@@ -960,7 +997,12 @@ function tryInPlaceContentUpdate(binding, listSeg) {
960
997
  }
961
998
  function updateRowInPlace(liveParent, old, ni, index) {
962
999
  if (old.html === ni.html || tryAttributeOnlyFastPath(old.node, old.html, ni.html) || tryTextContentFastPath(old.node, old.html, ni.html)) {
963
- const kept = carryOrRewireRowBindings(old.node, old.bindings, old.bindingDisposers, ni.bindings);
1000
+ const kept = carryOrRewireRowBindings(
1001
+ old.node,
1002
+ old.bindings,
1003
+ old.bindingDisposers,
1004
+ ni.bindings
1005
+ );
964
1006
  return {
965
1007
  ref: ni.ref,
966
1008
  cacheKey: ni.cacheKey,
@@ -973,7 +1015,12 @@ function updateRowInPlace(liveParent, old, ni, index) {
973
1015
  const newNode = parseSingleRow(ni.html, index, liveParent);
974
1016
  if (old.node.tagName === newNode.tagName) {
975
1017
  _morphElement(old.node, newNode);
976
- const kept = carryOrRewireRowBindings(old.node, old.bindings, old.bindingDisposers, ni.bindings);
1018
+ const kept = carryOrRewireRowBindings(
1019
+ old.node,
1020
+ old.bindings,
1021
+ old.bindingDisposers,
1022
+ ni.bindings
1023
+ );
977
1024
  return {
978
1025
  ref: ni.ref,
979
1026
  cacheKey: ni.cacheKey,
@@ -985,7 +1032,12 @@ function updateRowInPlace(liveParent, old, ni, index) {
985
1032
  }
986
1033
  disposeRowBindings(old.bindingDisposers);
987
1034
  liveParent.replaceChild(newNode, old.node);
988
- const fresh = carryOrRewireRowBindings(newNode, void 0, void 0, ni.bindings);
1035
+ const fresh = carryOrRewireRowBindings(
1036
+ newNode,
1037
+ void 0,
1038
+ void 0,
1039
+ ni.bindings
1040
+ );
989
1041
  return {
990
1042
  ref: ni.ref,
991
1043
  cacheKey: ni.cacheKey,
@@ -1070,15 +1122,22 @@ function buildFreshNodes(newRecord, freshIndices, freshHtmls, liveParent) {
1070
1122
  function findOffendingRow(newRecord, freshIndices, freshHtmls, liveParent) {
1071
1123
  for (let i = 0; i < freshHtmls.length; i++) {
1072
1124
  if (parseRowTemplate(freshHtmls[i], liveParent).count !== 1) {
1073
- return rowContractError(freshIndices[i], newRecord[freshIndices[i]].html, liveParent);
1125
+ return rowContractError(
1126
+ freshIndices[i],
1127
+ newRecord[freshIndices[i]].html,
1128
+ liveParent
1129
+ );
1074
1130
  }
1075
1131
  }
1076
- return new Error("each(): bulk-parse mismatch with no per-row offender (kerf bug).");
1132
+ return new Error(
1133
+ "each(): bulk-parse mismatch with no per-row offender (kerf bug)."
1134
+ );
1077
1135
  }
1078
1136
  function removeOldNodes(liveParent, removedItems) {
1079
1137
  for (const item of removedItems) {
1080
1138
  disposeRowBindings(item.bindingDisposers);
1081
- if (item.node.parentElement === liveParent) liveParent.removeChild(item.node);
1139
+ if (item.node.parentElement === liveParent)
1140
+ liveParent.removeChild(item.node);
1082
1141
  }
1083
1142
  }
1084
1143
  function applyMoves(liveParent, newRecord, prevIdx, stable, tailAnchor) {
@@ -1130,6 +1189,111 @@ function reconcileList(binding, listSeg) {
1130
1189
  reconcileSnapshot(binding, listSeg);
1131
1190
  }
1132
1191
 
1192
+ // src/mount-list-bindings.ts
1193
+ function anyRebuiltListIsGranular(segment, rebuilt) {
1194
+ if (!rebuilt.size) return false;
1195
+ const lists = collectLists(segment);
1196
+ for (const id of rebuilt) {
1197
+ if (lists.get(id)?.patches) return true;
1198
+ }
1199
+ return false;
1200
+ }
1201
+ function bindListsFromMarkers(rootEl, segment, bindings, inlinedItems, rebuiltLists) {
1202
+ const lists = collectLists(segment);
1203
+ const found = [];
1204
+ collectComments(rootEl, found);
1205
+ for (const marker of found) {
1206
+ if (!marker.data.startsWith(LIST_MARKER_PREFIX)) continue;
1207
+ const id = marker.data.slice(LIST_MARKER_PREFIX.length);
1208
+ const existing = bindings.get(id);
1209
+ if (existing) {
1210
+ if (existing.marker === marker && rootEl.contains(existing.marker))
1211
+ continue;
1212
+ for (const item of existing.items) {
1213
+ disposeRowBindings(item.bindingDisposers);
1214
+ if (rootEl.contains(item.node)) {
1215
+ item.node.parentElement?.removeChild(item.node);
1216
+ }
1217
+ }
1218
+ bindings.delete(id);
1219
+ rebuiltLists?.add(id);
1220
+ devHooks.listRebind?.(id, marker.parentElement);
1221
+ }
1222
+ const listSeg = lists.get(id);
1223
+ const liveParent = marker.parentElement;
1224
+ const items = [];
1225
+ if (inlinedItems) {
1226
+ let next = marker.nextElementSibling;
1227
+ for (let i = 0; i < listSeg.items.length && next !== null; i++) {
1228
+ validateInlinedRowMatch(listSeg.items[i].html, i, next, liveParent);
1229
+ items.push({
1230
+ ref: listSeg.items[i].ref,
1231
+ cacheKey: listSeg.items[i].cacheKey,
1232
+ html: listSeg.items[i].html,
1233
+ node: next,
1234
+ bindings: listSeg.items[i].bindings
1235
+ });
1236
+ next = next.nextElementSibling;
1237
+ }
1238
+ }
1239
+ const binding = { liveParent, items, marker };
1240
+ if (items.length > 0) {
1241
+ devHooks.missingRowKey?.(items[0].node, items[0].html, binding);
1242
+ }
1243
+ devHooks.eachInMorphSkip?.(id, liveParent, rootEl);
1244
+ bindings.set(id, binding);
1245
+ for (const bound of items) {
1246
+ if (bound.bindings?.length) {
1247
+ bound.bindingDisposers = wireRowBindings(bound.node, bound.bindings);
1248
+ }
1249
+ }
1250
+ }
1251
+ }
1252
+ function validateInlinedRowMatch(expectedHtml, index, boundEl, liveParent) {
1253
+ if (boundEl.outerHTML === expectedHtml) return;
1254
+ const { content, count } = parseRowTemplate(expectedHtml, liveParent);
1255
+ if (count !== 1) throw rowContractError(index, expectedHtml, liveParent);
1256
+ const expectedTag = content.firstElementChild.tagName;
1257
+ if (boundEl.tagName !== expectedTag)
1258
+ throw rowStructureError(index, boundEl.tagName, expectedTag);
1259
+ }
1260
+ function rowStructureError(index, gotTag, wantTag) {
1261
+ const got = gotTag.toLowerCase();
1262
+ const want = wantTag.toLowerCase();
1263
+ return new Error(
1264
+ `each(): row ${index} renders <${want}>, but the HTML parser wrapped the rows in <${got}> \u2014 so kerf cannot bind one row per element. This happens when an each() of <${want}> sits directly inside a table: the parser inserts <${got}> around the whole run. Put the each() inside an explicit <${got}> (e.g. <table><${got}>{each(...)}</${got}></table>) so the rows are the direct children kerf binds.`
1265
+ );
1266
+ }
1267
+ function collectOwnedItems(bindings) {
1268
+ const owned = /* @__PURE__ */ new Set();
1269
+ for (const b of bindings.values()) {
1270
+ for (const item of b.items) owned.add(item.node);
1271
+ }
1272
+ return owned;
1273
+ }
1274
+ function cleanupOrphanBindings(segment, bindings, renderCtx) {
1275
+ const liveIds = collectLists(segment);
1276
+ for (const [id, binding] of bindings) {
1277
+ if (liveIds.has(id)) continue;
1278
+ for (const item of binding.items) {
1279
+ disposeRowBindings(item.bindingDisposers);
1280
+ item.node.remove();
1281
+ }
1282
+ binding.marker.remove();
1283
+ bindings.delete(id);
1284
+ renderCtx.bindingCounts.delete(id);
1285
+ renderCtx.bindingSources.delete(id);
1286
+ renderCtx.caches.delete(id);
1287
+ }
1288
+ }
1289
+ function collectComments(node, out) {
1290
+ for (let c = node.firstChild; c; c = c.nextSibling) {
1291
+ if (c.nodeType === Node.COMMENT_NODE) out.push(c);
1292
+ else if (c.nodeType === Node.ELEMENT_NODE && !isOverlayHost(c))
1293
+ collectComments(c, out);
1294
+ }
1295
+ }
1296
+
1133
1297
  // src/mount.ts
1134
1298
  var MOUNTED_MARKER = /* @__PURE__ */ Symbol.for("kerfjs.mounted");
1135
1299
  var NESTED_MOUNT_MSG = "mount: rootEl is already inside (or contains) a mounted tree. kerf supports one mount per tree \u2014 compose with plain functions that return JSX instead of nesting mounts.";
@@ -1155,15 +1319,17 @@ function assertNotInsideMountedTree(rootEl) {
1155
1319
  );
1156
1320
  }
1157
1321
  let ancestor = rootEl.parentElement;
1158
- while (ancestor) {
1322
+ while (ancestor && !isOverlayHost(ancestor)) {
1159
1323
  if (isMounted(ancestor)) throw new Error(NESTED_MOUNT_MSG);
1160
1324
  ancestor = ancestor.parentElement;
1161
1325
  }
1162
1326
  const stack = [];
1163
- for (let i = 0; i < rootEl.children.length; i++) stack.push(rootEl.children[i]);
1327
+ for (let i = 0; i < rootEl.children.length; i++)
1328
+ stack.push(rootEl.children[i]);
1164
1329
  while (stack.length > 0) {
1165
1330
  const cur = stack.pop();
1166
1331
  if (isMounted(cur)) throw new Error(NESTED_MOUNT_MSG);
1332
+ if (isOverlayHost(cur)) continue;
1167
1333
  for (let i = 0; i < cur.children.length; i++) stack.push(cur.children[i]);
1168
1334
  }
1169
1335
  }
@@ -1241,7 +1407,8 @@ function mount(rootEl, render) {
1241
1407
  valueOnlyWarnCtx
1242
1408
  );
1243
1409
  if (anyRebuiltListIsGranular(segment, renderCtx.rebuiltLists)) {
1244
- for (const id of renderCtx.rebuiltLists) renderCtx.bindingCounts.delete(id);
1410
+ for (const id of renderCtx.rebuiltLists)
1411
+ renderCtx.bindingCounts.delete(id);
1245
1412
  result = runRenderPass();
1246
1413
  segment = resultToSegment(result);
1247
1414
  nextStaticHtml = runSubsequentRender(
@@ -1255,7 +1422,8 @@ function mount(rootEl, render) {
1255
1422
  }
1256
1423
  if (nextStaticHtml !== prevStaticHtml) {
1257
1424
  bindingDisposers = wireBindings(rootEl, bindingCtx, bindingDisposers);
1258
- if (devHooks.staleBindingEnabled?.()) prevWiredBindings = bindingCtx.list;
1425
+ if (devHooks.staleBindingEnabled?.())
1426
+ prevWiredBindings = bindingCtx.list;
1259
1427
  } else {
1260
1428
  devHooks.staleBinding?.(prevWiredBindings, bindingCtx.list);
1261
1429
  }
@@ -1283,11 +1451,7 @@ function mount(rootEl, render) {
1283
1451
  renderCtx.previousCallCount = renderCtx.counter;
1284
1452
  devHooks.listInvariants?.(rootEl, bindings, expectedCounts || void 0);
1285
1453
  }
1286
- const disposeEffect = effect(() => {
1287
- reconcileAndCommitListPhase(renderStaticPhase());
1288
- });
1289
- return () => {
1290
- disposeEffect();
1454
+ const releaseResources = () => {
1291
1455
  for (const d of bindingDisposers) d();
1292
1456
  bindingDisposers = [];
1293
1457
  for (const b of bindings.values()) {
@@ -1296,6 +1460,21 @@ function mount(rootEl, render) {
1296
1460
  listenerWarnObserver?.disconnect();
1297
1461
  setMounted(rootEl, false);
1298
1462
  };
1463
+ const priorChildren = rootEl.firstChild ? Array.from(rootEl.childNodes) : [];
1464
+ let disposeEffect;
1465
+ try {
1466
+ disposeEffect = effect(() => {
1467
+ reconcileAndCommitListPhase(renderStaticPhase());
1468
+ });
1469
+ } catch (err) {
1470
+ releaseResources();
1471
+ rootEl.replaceChildren(...priorChildren);
1472
+ throw err;
1473
+ }
1474
+ return () => {
1475
+ disposeEffect();
1476
+ releaseResources();
1477
+ };
1299
1478
  }
1300
1479
  function runFirstRender(rootEl, segment, bindings) {
1301
1480
  rootEl.innerHTML = flatten(segment, true);
@@ -1307,12 +1486,22 @@ function runSubsequentRender(rootEl, segment, bindings, renderCtx, prevStaticHtm
1307
1486
  if (currentStaticHtml === prevStaticHtml) {
1308
1487
  return prevStaticHtml;
1309
1488
  }
1310
- devHooks.valueOnlyRerender?.(prevStaticHtml, currentStaticHtml, valueOnlyWarnCtx);
1489
+ devHooks.valueOnlyRerender?.(
1490
+ prevStaticHtml,
1491
+ currentStaticHtml,
1492
+ valueOnlyWarnCtx
1493
+ );
1311
1494
  cleanupOrphanBindings(segment, bindings, renderCtx);
1312
1495
  const template = rootEl.cloneNode(false);
1313
1496
  template.innerHTML = currentStaticHtml;
1314
1497
  morph(rootEl, template, collectOwnedItems(bindings));
1315
- bindListsFromMarkers(rootEl, segment, bindings, false, renderCtx.rebuiltLists);
1498
+ bindListsFromMarkers(
1499
+ rootEl,
1500
+ segment,
1501
+ bindings,
1502
+ false,
1503
+ renderCtx.rebuiltLists
1504
+ );
1316
1505
  return currentStaticHtml;
1317
1506
  }
1318
1507
  function coerceRenderResult(result) {
@@ -1322,107 +1511,7 @@ function coerceRenderResult(result) {
1322
1511
  function resultToSegment(result) {
1323
1512
  return isSafeHtml(result) ? result.__segment ?? { kind: "static", html: result.__html } : { kind: "static", html: coerceRenderResult(result) };
1324
1513
  }
1325
- function anyRebuiltListIsGranular(segment, rebuilt) {
1326
- if (!rebuilt.size) return false;
1327
- const lists = collectLists(segment);
1328
- for (const id of rebuilt) {
1329
- if (lists.get(id)?.patches) return true;
1330
- }
1331
- return false;
1332
- }
1333
- function bindListsFromMarkers(rootEl, segment, bindings, inlinedItems, rebuiltLists) {
1334
- const lists = collectLists(segment);
1335
- const found = [];
1336
- collectComments(rootEl, found);
1337
- for (const marker of found) {
1338
- if (!marker.data.startsWith(LIST_MARKER_PREFIX)) continue;
1339
- const id = marker.data.slice(LIST_MARKER_PREFIX.length);
1340
- const existing = bindings.get(id);
1341
- if (existing) {
1342
- if (existing.marker === marker && rootEl.contains(existing.marker)) continue;
1343
- for (const item of existing.items) {
1344
- disposeRowBindings(item.bindingDisposers);
1345
- if (rootEl.contains(item.node)) {
1346
- item.node.parentElement?.removeChild(item.node);
1347
- }
1348
- }
1349
- bindings.delete(id);
1350
- rebuiltLists?.add(id);
1351
- devHooks.listRebind?.(id, marker.parentElement);
1352
- }
1353
- const listSeg = lists.get(id);
1354
- const liveParent = marker.parentElement;
1355
- const items = [];
1356
- if (inlinedItems) {
1357
- let next = marker.nextElementSibling;
1358
- for (let i = 0; i < listSeg.items.length && next !== null; i++) {
1359
- validateInlinedRowMatch(listSeg.items[i].html, i, next, liveParent);
1360
- const rowBindings = listSeg.items[i].bindings;
1361
- const bound = {
1362
- ref: listSeg.items[i].ref,
1363
- cacheKey: listSeg.items[i].cacheKey,
1364
- html: listSeg.items[i].html,
1365
- node: next,
1366
- bindings: rowBindings
1367
- };
1368
- if (rowBindings?.length) {
1369
- bound.bindingDisposers = wireRowBindings(next, rowBindings);
1370
- }
1371
- items.push(bound);
1372
- next = next.nextElementSibling;
1373
- }
1374
- }
1375
- const binding = { liveParent, items, marker };
1376
- if (items.length > 0) {
1377
- devHooks.missingRowKey?.(items[0].node, items[0].html, binding);
1378
- }
1379
- devHooks.eachInMorphSkip?.(id, liveParent, rootEl);
1380
- bindings.set(id, binding);
1381
- }
1382
- }
1383
- function validateInlinedRowMatch(expectedHtml, index, boundEl, liveParent) {
1384
- if (boundEl.outerHTML === expectedHtml) return;
1385
- const { content, count } = parseRowTemplate(expectedHtml, liveParent);
1386
- if (count !== 1) throw rowContractError(index, expectedHtml, liveParent);
1387
- const expectedTag = content.firstElementChild.tagName;
1388
- if (boundEl.tagName !== expectedTag) throw rowStructureError(index, boundEl.tagName, expectedTag);
1389
- }
1390
- function rowStructureError(index, gotTag, wantTag) {
1391
- const got = gotTag.toLowerCase();
1392
- const want = wantTag.toLowerCase();
1393
- return new Error(
1394
- `each(): row ${index} renders <${want}>, but the HTML parser wrapped the rows in <${got}> \u2014 so kerf cannot bind one row per element. This happens when an each() of <${want}> sits directly inside a table: the parser inserts <${got}> around the whole run. Put the each() inside an explicit <${got}> (e.g. <table><${got}>{each(...)}</${got}></table>) so the rows are the direct children kerf binds.`
1395
- );
1396
- }
1397
- function collectOwnedItems(bindings) {
1398
- const owned = /* @__PURE__ */ new Set();
1399
- for (const b of bindings.values()) {
1400
- for (const item of b.items) owned.add(item.node);
1401
- }
1402
- return owned;
1403
- }
1404
- function cleanupOrphanBindings(segment, bindings, renderCtx) {
1405
- const liveIds = collectLists(segment);
1406
- for (const [id, binding] of bindings) {
1407
- if (liveIds.has(id)) continue;
1408
- for (const item of binding.items) {
1409
- disposeRowBindings(item.bindingDisposers);
1410
- item.node.remove();
1411
- }
1412
- binding.marker.remove();
1413
- bindings.delete(id);
1414
- renderCtx.bindingCounts.delete(id);
1415
- renderCtx.bindingSources.delete(id);
1416
- renderCtx.caches.delete(id);
1417
- }
1418
- }
1419
- function collectComments(node, out) {
1420
- for (let c = node.firstChild; c; c = c.nextSibling) {
1421
- if (c.nodeType === Node.COMMENT_NODE) out.push(c);
1422
- else if (c.nodeType === Node.ELEMENT_NODE) collectComments(c, out);
1423
- }
1424
- }
1425
1514
 
1426
1515
  export { captureFocus, each, morph, mount, moveNode, restoreFocus };
1427
1516
 
1428
- //# sourceMappingURL=chunk-SVATPF5R.js.map
1517
+ //# sourceMappingURL=chunk-TLL3KXT6.js.map