kerfjs 4.4.0 → 4.5.0-beta.1

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 (84) hide show
  1. package/CHANGELOG.md +284 -104
  2. package/LICENSE +1 -1
  3. package/README.md +73 -54
  4. package/ai/cursorrules +130 -48
  5. package/ai/manifest.json +63 -5
  6. package/ai/skill.md +148 -65
  7. package/dist/actions.d.ts +1 -1
  8. package/dist/actions.js +4 -4
  9. package/dist/actions.js.map +1 -1
  10. package/dist/array-signal.js +5 -5
  11. package/dist/async.js +34 -24
  12. package/dist/async.js.map +1 -1
  13. package/dist/attach.d.ts +11 -8
  14. package/dist/attach.js +54 -4
  15. package/dist/attach.js.map +1 -1
  16. package/dist/{chunk-QIP723L4.js → chunk-5WRGJZV6.js} +4 -3
  17. package/dist/chunk-5WRGJZV6.js.map +1 -0
  18. package/dist/{chunk-GY4XV2UV.js → chunk-BDX3R4OM.js} +4 -3
  19. package/dist/chunk-BDX3R4OM.js.map +1 -0
  20. package/dist/{chunk-VVDJLWMP.js → chunk-CEQMZYLR.js} +2 -2
  21. package/dist/chunk-CEQMZYLR.js.map +1 -0
  22. package/dist/{chunk-KEZTD6H4.js → chunk-E5R5GNKE.js} +15 -5
  23. package/dist/chunk-E5R5GNKE.js.map +1 -0
  24. package/dist/{chunk-MRYM3O3V.js → chunk-ELXVRKY2.js} +12 -9
  25. package/dist/chunk-ELXVRKY2.js.map +1 -0
  26. package/dist/{chunk-U32TFTGZ.js → chunk-MK42GLPV.js} +3 -3
  27. package/dist/chunk-MK42GLPV.js.map +1 -0
  28. package/dist/{chunk-SUPUPSBE.js → chunk-QFUNWHKH.js} +42 -20
  29. package/dist/chunk-QFUNWHKH.js.map +1 -0
  30. package/dist/{chunk-SRWQKB33.js → chunk-V757BT6U.js} +206 -111
  31. package/dist/chunk-V757BT6U.js.map +1 -0
  32. package/dist/{chunk-YHH7OUFA.js → chunk-WKIPLNVO.js} +3 -3
  33. package/dist/chunk-WKIPLNVO.js.map +1 -0
  34. package/dist/{chunk-3APBEVHF.js → chunk-Y2FOYPBV.js} +3 -3
  35. package/dist/{chunk-3APBEVHF.js.map → chunk-Y2FOYPBV.js.map} +1 -1
  36. package/dist/{chunk-SAYPJ6XR.js → chunk-ZOIERTUW.js} +10 -6
  37. package/dist/chunk-ZOIERTUW.js.map +1 -0
  38. package/dist/dev.d.ts +9 -6
  39. package/dist/dev.js +66 -19
  40. package/dist/dev.js.map +1 -1
  41. package/dist/html.d.ts +1 -1
  42. package/dist/html.js +8 -7
  43. package/dist/html.js.map +1 -1
  44. package/dist/index.d.ts +1 -1
  45. package/dist/index.js +28 -19
  46. package/dist/index.js.map +1 -1
  47. package/dist/jsx-runtime.js +5 -5
  48. package/dist/list.d.ts +1 -1
  49. package/dist/list.js +304 -213
  50. package/dist/list.js.map +1 -1
  51. package/dist/overlay.d.ts +190 -280
  52. package/dist/overlay.js +471 -364
  53. package/dist/overlay.js.map +1 -1
  54. package/dist/remount.d.ts +5 -3
  55. package/dist/remount.js +29 -10
  56. package/dist/remount.js.map +1 -1
  57. package/dist/router.d.ts +1 -1
  58. package/dist/router.js +73 -28
  59. package/dist/router.js.map +1 -1
  60. package/dist/scope.d.ts +4 -3
  61. package/dist/scope.js +11 -10
  62. package/dist/scope.js.map +1 -1
  63. package/dist/testing.js +4 -4
  64. package/dist/timing.d.ts +3 -2
  65. package/dist/timing.js +5 -5
  66. package/dist/timing.js.map +1 -1
  67. package/llms.txt +13 -6
  68. package/package.json +35 -13
  69. package/setup/cli.mjs +90 -0
  70. package/setup/index.d.mts +37 -0
  71. package/setup/index.mjs +1347 -0
  72. package/setup/jsonc.mjs +201 -0
  73. package/setup/state.schema.json +56 -0
  74. package/dist/chunk-GY4XV2UV.js.map +0 -1
  75. package/dist/chunk-KEZTD6H4.js.map +0 -1
  76. package/dist/chunk-MRYM3O3V.js.map +0 -1
  77. package/dist/chunk-QIP723L4.js.map +0 -1
  78. package/dist/chunk-SAYPJ6XR.js.map +0 -1
  79. package/dist/chunk-SRWQKB33.js.map +0 -1
  80. package/dist/chunk-SUPUPSBE.js.map +0 -1
  81. package/dist/chunk-U32TFTGZ.js.map +0 -1
  82. package/dist/chunk-VVDJLWMP.js.map +0 -1
  83. package/dist/chunk-YHH7OUFA.js.map +0 -1
  84. /package/dist/{attrSelector-Cmu2ZoGO.d.ts → attr-Cmu2ZoGO.d.ts} +0 -0
@@ -1,9 +1,9 @@
1
- import { itemVersion } from './chunk-QIP723L4.js';
2
- import { parseRowTemplate, rowContractError, parseSingleRow, collectTemplateChildren } from './chunk-YHH7OUFA.js';
3
- import { captureRowBindings, listSafeHtml, boundTextNodeOf, syncFormProp, newBindingContext, wireBindings, disposeRowBindings, isSafeHtml, wireRowBindings, _setBindingContext, TEXT_MARKER_PREFIX, ROW_TEXT_PREFIX, carryOrRewireRowBindings, granularListSafeHtml } from './chunk-SUPUPSBE.js';
4
- import { effect } from './chunk-3APBEVHF.js';
5
- import { LIST_MARKER_PREFIX, flattenWithoutListItems, collectLists, flatten } from './chunk-GY4XV2UV.js';
6
- import { devHooks } from './chunk-VVDJLWMP.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, disposeRowBindings, wireBindings, isSafeHtml, _setBindingContext, TEXT_MARKER_PREFIX, ROW_TEXT_PREFIX, wireRowBindings, carryOrRewireRowBindings, granularListSafeHtml } from './chunk-QFUNWHKH.js';
4
+ import { effect } from './chunk-Y2FOYPBV.js';
5
+ import { LIST_MARKER_PREFIX, flattenWithoutListItems, collectLists, flatten } from './chunk-BDX3R4OM.js';
6
+ import { devHooks } from './chunk-CEQMZYLR.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) {
@@ -106,6 +107,28 @@ function assertObjectItem(item, index) {
106
107
  );
107
108
  }
108
109
  }
110
+ function _hasGranularIndexShift(previousBindingCount, patches) {
111
+ const rendered = [];
112
+ for (let i = 0; i < previousBindingCount; i++) rendered.push(i);
113
+ for (const patch of patches) {
114
+ if (patch.type === "insert") rendered.splice(patch.index, 0, patch.index);
115
+ else if (patch.type === "remove") rendered.splice(patch.index, 1);
116
+ else if (patch.type === "move") {
117
+ const [moved] = rendered.splice(patch.from, 1);
118
+ rendered.splice(patch.to, 0, moved);
119
+ }
120
+ }
121
+ return rendered.some((renderedAt, index) => renderedAt !== index);
122
+ }
123
+ function _hasGranularCacheKeyDrift(snapshot, cacheKey, cache) {
124
+ for (let i = 0; i < snapshot.length; i++) {
125
+ const item = snapshot[i];
126
+ const nextKey = cacheKey(item, i);
127
+ const cached = cache.get(item);
128
+ if (cached !== void 0 && cached.cacheKey !== nextKey) return true;
129
+ }
130
+ return false;
131
+ }
109
132
  function eachGranular(sig, render, cacheKey, listKey) {
110
133
  const ctx = context;
111
134
  const id = listKey !== void 0 ? claimKey(ctx, listKey) : String(ctx.counter++);
@@ -124,40 +147,19 @@ function eachGranular(sig, render, cacheKey, listKey) {
124
147
  if (decision.path === "snapshot") {
125
148
  return eachSnapshotById(snapshot, render, cacheKey, id, sig);
126
149
  }
127
- let staleIndexShift = false;
128
- if (render.length >= 2 && devHooks.staleIndexEnabled?.() === true) {
129
- const rendered = [];
130
- for (let i = 0; i < previousBindingCount; i++) rendered.push(i);
131
- for (const p of patches) {
132
- if (p.type === "insert") rendered.splice(p.index, 0, p.index);
133
- else if (p.type === "remove") rendered.splice(p.index, 1);
134
- else if (p.type === "move") {
135
- const [moved] = rendered.splice(p.from, 1);
136
- rendered.splice(p.to, 0, moved);
137
- }
138
- }
139
- for (let i = 0; i < rendered.length; i++) {
140
- if (rendered[i] !== i) {
141
- staleIndexShift = true;
142
- break;
143
- }
144
- }
145
- }
150
+ const staleIndexShift = render.length >= 2 && devHooks.staleIndexEnabled?.() === true && _hasGranularIndexShift(previousBindingCount, patches);
146
151
  if (cacheKey !== void 0) {
147
152
  const cache2 = ctx.caches.get(id);
148
- for (let i = 0; i < snapshot.length; i++) {
149
- const item = snapshot[i];
150
- const k = cacheKey(item, i);
151
- const cached = cache2.get(item);
152
- if (cached !== void 0 && cached.cacheKey !== k) {
153
- return eachSnapshotById(snapshot, render, cacheKey, id, sig);
154
- }
153
+ if (_hasGranularCacheKeyDrift(snapshot, cacheKey, cache2)) {
154
+ return eachSnapshotById(snapshot, render, cacheKey, id, sig);
155
155
  }
156
156
  }
157
- const renderRow = (item, index) => captureRowBindings(() => inRowScope(() => {
158
- const out = render(item, index);
159
- return isSafeHtml(out) ? out.toString() : out;
160
- }));
157
+ const renderRow = (item, index) => captureRowBindings(
158
+ () => inRowScope(() => {
159
+ const out = render(item, index);
160
+ return isSafeHtml(out) ? out.toString() : out;
161
+ })
162
+ );
161
163
  const internalPatches = new Array(patches.length);
162
164
  const cache = ctx.caches.get(id);
163
165
  try {
@@ -224,13 +226,16 @@ function eachSnapshotById(items, render, cacheKey, id, source) {
224
226
  devHooks.staleIndex?.(id);
225
227
  }
226
228
  } else {
227
- const captured = captureRowBindings(() => inRowScope(() => {
228
- const out = render(item, i);
229
- return isSafeHtml(out) ? out.toString() : out;
230
- }));
229
+ const captured = captureRowBindings(
230
+ () => inRowScope(() => {
231
+ const out = render(item, i);
232
+ return isSafeHtml(out) ? out.toString() : out;
233
+ })
234
+ );
231
235
  html = captured.html;
232
236
  bindings = captured.bindings;
233
- 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 });
234
239
  }
235
240
  segItems[i] = { ref: item, cacheKey: k, html, bindings };
236
241
  }
@@ -240,16 +245,6 @@ function eachSnapshotById(items, render, cacheKey, id, source) {
240
245
  return listSafeHtml(id, segItems, source);
241
246
  }
242
247
 
243
- // src/utils/moveNode.ts
244
- function moveNode(parent, node, ref) {
245
- const move = parent.moveBefore;
246
- if (move !== void 0 && node.isConnected) {
247
- move.call(parent, node, ref);
248
- } else {
249
- parent.insertBefore(node, ref);
250
- }
251
- }
252
-
253
248
  // src/list-reconcile-focus.ts
254
249
  function captureFocus(liveParent) {
255
250
  const active = document.activeElement;
@@ -258,6 +253,7 @@ function captureFocus(liveParent) {
258
253
  const el = active;
259
254
  let selStart = null;
260
255
  let selEnd = null;
256
+ let domSelection = null;
261
257
  if (el.tagName === "INPUT" || el.tagName === "TEXTAREA") {
262
258
  try {
263
259
  selStart = el.selectionStart;
@@ -265,18 +261,45 @@ function captureFocus(liveParent) {
265
261
  } catch {
266
262
  }
267
263
  }
268
- return { el, selStart, selEnd };
264
+ if (el.isContentEditable) {
265
+ const selection = document.getSelection();
266
+ if (selection !== null && selection.anchorNode !== null && selection.focusNode !== null) {
267
+ domSelection = [
268
+ selection.anchorNode,
269
+ selection.anchorOffset,
270
+ selection.focusNode,
271
+ selection.focusOffset
272
+ ];
273
+ }
274
+ }
275
+ return [el, selStart, selEnd, domSelection];
269
276
  }
270
277
  function restoreFocus(snap) {
271
- if (document.activeElement === snap.el) return;
272
- if (!snap.el.isConnected) return;
273
- snap.el.focus();
274
- if (snap.selStart !== null && snap.selEnd !== null) {
278
+ const [el, selStart, selEnd, domSelection] = snap;
279
+ if (!el.isConnected) return;
280
+ if (document.activeElement !== el) el.focus();
281
+ if (selStart !== null && selEnd !== null) {
275
282
  try {
276
- snap.el.setSelectionRange(snap.selStart, snap.selEnd);
283
+ el.setSelectionRange(selStart, selEnd);
277
284
  } catch {
278
285
  }
279
286
  }
287
+ if (domSelection === null) return;
288
+ const [anchorNode, anchorOffset, focusNode, focusOffset] = domSelection;
289
+ try {
290
+ document.getSelection()?.setBaseAndExtent(anchorNode, anchorOffset, focusNode, focusOffset);
291
+ } catch {
292
+ }
293
+ }
294
+
295
+ // src/utils/moveNode.ts
296
+ function moveNode(parent, node, ref) {
297
+ const move = parent.moveBefore;
298
+ if (move !== void 0 && node.isConnected) {
299
+ move.call(parent, node, ref);
300
+ } else {
301
+ parent.insertBefore(node, ref);
302
+ }
280
303
  }
281
304
 
282
305
  // src/morph.ts
@@ -321,7 +344,11 @@ function protectionTag(node) {
321
344
  const { dataset } = node;
322
345
  return (dataset.morphSkip !== void 0 ? "s" : "") + (dataset.morphSkipChildren !== void 0 ? "c" : "") + (dataset.morphPreserve !== void 0 ? "p" : "");
323
346
  }
324
- var MARKER_PREFIXES = [LIST_MARKER_PREFIX, TEXT_MARKER_PREFIX, ROW_TEXT_PREFIX];
347
+ var MARKER_PREFIXES = [
348
+ LIST_MARKER_PREFIX,
349
+ TEXT_MARKER_PREFIX,
350
+ ROW_TEXT_PREFIX
351
+ ];
325
352
  function isMarker(node) {
326
353
  if (node.nodeType !== COMMENT_NODE) return false;
327
354
  const { data } = node;
@@ -399,7 +426,8 @@ function morphChildren(fromParent, toParent, ownedItems) {
399
426
  if (matched === null && fromChild !== null && toChild.nodeType === COMMENT_NODE && toChild.data.startsWith(LIST_MARKER_PREFIX)) {
400
427
  const wantData = toChild.data;
401
428
  for (let scan = fromChild.nextSibling; scan !== null; scan = scan.nextSibling) {
402
- if (scan.nodeType !== COMMENT_NODE || scan.data !== wantData) continue;
429
+ if (scan.nodeType !== COMMENT_NODE || scan.data !== wantData)
430
+ continue;
403
431
  const regionEnd = afterListRegion(scan, ownedItems);
404
432
  const run = [];
405
433
  for (let r = scan; r !== null && r !== regionEnd; r = r.nextSibling) {
@@ -512,7 +540,10 @@ function preserveTextEntryState(fromEl, toEl) {
512
540
  const toInput = toEl;
513
541
  toInput.value = fromInput.value;
514
542
  try {
515
- toInput.setSelectionRange(fromInput.selectionStart, fromInput.selectionEnd);
543
+ toInput.setSelectionRange(
544
+ fromInput.selectionStart,
545
+ fromInput.selectionEnd
546
+ );
516
547
  } catch {
517
548
  }
518
549
  }
@@ -545,7 +576,8 @@ function tryAttributeOnlyFastPath(liveNode, oldHtml, newHtml) {
545
576
  if (oldGt === -1 || newGt === -1) return false;
546
577
  if (oldHtml.length - oldGt !== newHtml.length - newGt) return false;
547
578
  if (oldHtml.slice(oldGt) !== newHtml.slice(newGt)) return false;
548
- if (containsDataMorphSkip(oldHtml) || containsDataMorphSkip(newHtml)) return false;
579
+ if (containsDataMorphSkip(oldHtml) || containsDataMorphSkip(newHtml))
580
+ return false;
549
581
  const oldTag = parseOpeningTag(oldHtml, oldGt);
550
582
  const newTag = parseOpeningTag(newHtml, newGt);
551
583
  if (oldTag === null || newTag === null) return false;
@@ -573,7 +605,8 @@ function tryAttributeOnlyFastPath(liveNode, oldHtml, newHtml) {
573
605
  return true;
574
606
  }
575
607
  function tryTextContentFastPath(liveNode, oldHtml, newHtml) {
576
- if (containsDataMorphSkip(oldHtml) || containsDataMorphSkip(newHtml)) return false;
608
+ if (containsDataMorphSkip(oldHtml) || containsDataMorphSkip(newHtml))
609
+ return false;
577
610
  let p = 0;
578
611
  const minLen = Math.min(oldHtml.length, newHtml.length);
579
612
  while (p < minLen && oldHtml.charCodeAt(p) === newHtml.charCodeAt(p)) p++;
@@ -588,7 +621,8 @@ function tryTextContentFastPath(liveNode, oldHtml, newHtml) {
588
621
  if (!isPureTextWindow(newHtml, p, newWinEnd)) return false;
589
622
  if (p === 0) return false;
590
623
  const boundaryCc = oldHtml.charCodeAt(p - 1);
591
- if (boundaryCc === LT || boundaryCc === DQUOTE || boundaryCc === SQUOTE || boundaryCc === EQ || boundaryCc === AMP) return false;
624
+ if (boundaryCc === LT || boundaryCc === DQUOTE || boundaryCc === SQUOTE || boundaryCc === EQ || boundaryCc === AMP)
625
+ return false;
592
626
  const textStart = lastIndexOfChar(oldHtml, GT, p - 1);
593
627
  if (textStart === -1) return false;
594
628
  const textEnd = oldHtml.indexOf("<", p);
@@ -615,7 +649,8 @@ function containsDataMorphSkip(html) {
615
649
  function isPureTextWindow(html, start, end) {
616
650
  for (let i = start; i < end; i++) {
617
651
  const cc = html.charCodeAt(i);
618
- if (cc === LT || cc === GT || cc === DQUOTE || cc === SQUOTE || cc === AMP || cc === EQ) return false;
652
+ if (cc === LT || cc === GT || cc === DQUOTE || cc === SQUOTE || cc === AMP || cc === EQ)
653
+ return false;
619
654
  }
620
655
  return true;
621
656
  }
@@ -747,7 +782,14 @@ function reconcileGranular(binding, patches) {
747
782
  if (runLen === 1) {
748
783
  applySingleInsert(liveParent, items, patch, endAnchor(binding));
749
784
  } else {
750
- applyBulkInsert(liveParent, items, patches, i, runEnd, endAnchor(binding));
785
+ applyBulkInsert(
786
+ liveParent,
787
+ items,
788
+ patches,
789
+ i,
790
+ runEnd,
791
+ endAnchor(binding)
792
+ );
751
793
  }
752
794
  i = runEnd;
753
795
  continue;
@@ -859,7 +901,10 @@ function applyBulkUpdate(liveParent, items, patches, start, end) {
859
901
  morphChanges.push({ patchIdx: k, html: p.html });
860
902
  }
861
903
  if (morphChanges.length === 0) return;
862
- const { content, count } = parseRowTemplate(morphChanges.map((c) => c.html).join(""), liveParent);
904
+ const { content, count } = parseRowTemplate(
905
+ morphChanges.map((c) => c.html).join(""),
906
+ liveParent
907
+ );
863
908
  if (count !== morphChanges.length) {
864
909
  throw findOffendingChange(patches, morphChanges, liveParent);
865
910
  }
@@ -892,8 +937,9 @@ function applyBulkInsert(liveParent, items, patches, start, end, tailAnchor) {
892
937
  html: htmls[k],
893
938
  node: newNodes[k],
894
939
  bindings: p.bindings,
940
+ // Every fresh row needs its fine-grained holes wired to the newly parsed
941
+ // node; otherwise later signal writes would target no live DOM binding.
895
942
  bindingDisposers: wireRowIfBound(newNodes[k], p.bindings)
896
- // KF-294
897
943
  };
898
944
  }
899
945
  items.splice(startIdx, 0, ...newEntries);
@@ -901,18 +947,30 @@ function applyBulkInsert(liveParent, items, patches, start, end, tailAnchor) {
901
947
  function findOffendingInsert(patches, start, htmls, liveParent) {
902
948
  for (let i = 0; i < htmls.length; i++) {
903
949
  if (parseRowTemplate(htmls[i], liveParent).count !== 1) {
904
- return rowContractError(patches[start + i].index, htmls[i], liveParent);
950
+ return rowContractError(
951
+ patches[start + i].index,
952
+ htmls[i],
953
+ liveParent
954
+ );
905
955
  }
906
956
  }
907
- return new Error("each(): bulk-insert mismatch with no per-row offender (kerf bug).");
957
+ return new Error(
958
+ "each(): bulk-insert mismatch with no per-row offender (kerf bug)."
959
+ );
908
960
  }
909
961
  function findOffendingChange(patches, changes, liveParent) {
910
962
  for (const c of changes) {
911
963
  if (parseRowTemplate(c.html, liveParent).count !== 1) {
912
- return rowContractError(patches[c.patchIdx].index, c.html, liveParent);
964
+ return rowContractError(
965
+ patches[c.patchIdx].index,
966
+ c.html,
967
+ liveParent
968
+ );
913
969
  }
914
970
  }
915
- return new Error("each(): bulk-update mismatch with no per-row offender (kerf bug).");
971
+ return new Error(
972
+ "each(): bulk-update mismatch with no per-row offender (kerf bug)."
973
+ );
916
974
  }
917
975
 
918
976
  // src/list-reconcile-inplace.ts
@@ -937,7 +995,12 @@ function tryInPlaceContentUpdate(binding, listSeg) {
937
995
  }
938
996
  function updateRowInPlace(liveParent, old, ni, index) {
939
997
  if (old.html === ni.html || tryAttributeOnlyFastPath(old.node, old.html, ni.html) || tryTextContentFastPath(old.node, old.html, ni.html)) {
940
- const kept = carryOrRewireRowBindings(old.node, old.bindings, old.bindingDisposers, ni.bindings);
998
+ const kept = carryOrRewireRowBindings(
999
+ old.node,
1000
+ old.bindings,
1001
+ old.bindingDisposers,
1002
+ ni.bindings
1003
+ );
941
1004
  return {
942
1005
  ref: ni.ref,
943
1006
  cacheKey: ni.cacheKey,
@@ -950,7 +1013,12 @@ function updateRowInPlace(liveParent, old, ni, index) {
950
1013
  const newNode = parseSingleRow(ni.html, index, liveParent);
951
1014
  if (old.node.tagName === newNode.tagName) {
952
1015
  _morphElement(old.node, newNode);
953
- const kept = carryOrRewireRowBindings(old.node, old.bindings, old.bindingDisposers, ni.bindings);
1016
+ const kept = carryOrRewireRowBindings(
1017
+ old.node,
1018
+ old.bindings,
1019
+ old.bindingDisposers,
1020
+ ni.bindings
1021
+ );
954
1022
  return {
955
1023
  ref: ni.ref,
956
1024
  cacheKey: ni.cacheKey,
@@ -962,7 +1030,12 @@ function updateRowInPlace(liveParent, old, ni, index) {
962
1030
  }
963
1031
  disposeRowBindings(old.bindingDisposers);
964
1032
  liveParent.replaceChild(newNode, old.node);
965
- const fresh = carryOrRewireRowBindings(newNode, void 0, void 0, ni.bindings);
1033
+ const fresh = carryOrRewireRowBindings(
1034
+ newNode,
1035
+ void 0,
1036
+ void 0,
1037
+ ni.bindings
1038
+ );
966
1039
  return {
967
1040
  ref: ni.ref,
968
1041
  cacheKey: ni.cacheKey,
@@ -1047,15 +1120,22 @@ function buildFreshNodes(newRecord, freshIndices, freshHtmls, liveParent) {
1047
1120
  function findOffendingRow(newRecord, freshIndices, freshHtmls, liveParent) {
1048
1121
  for (let i = 0; i < freshHtmls.length; i++) {
1049
1122
  if (parseRowTemplate(freshHtmls[i], liveParent).count !== 1) {
1050
- return rowContractError(freshIndices[i], newRecord[freshIndices[i]].html, liveParent);
1123
+ return rowContractError(
1124
+ freshIndices[i],
1125
+ newRecord[freshIndices[i]].html,
1126
+ liveParent
1127
+ );
1051
1128
  }
1052
1129
  }
1053
- return new Error("each(): bulk-parse mismatch with no per-row offender (kerf bug).");
1130
+ return new Error(
1131
+ "each(): bulk-parse mismatch with no per-row offender (kerf bug)."
1132
+ );
1054
1133
  }
1055
1134
  function removeOldNodes(liveParent, removedItems) {
1056
1135
  for (const item of removedItems) {
1057
1136
  disposeRowBindings(item.bindingDisposers);
1058
- if (item.node.parentElement === liveParent) liveParent.removeChild(item.node);
1137
+ if (item.node.parentElement === liveParent)
1138
+ liveParent.removeChild(item.node);
1059
1139
  }
1060
1140
  }
1061
1141
  function applyMoves(liveParent, newRecord, prevIdx, stable, tailAnchor) {
@@ -1132,12 +1212,13 @@ function assertNotInsideMountedTree(rootEl) {
1132
1212
  );
1133
1213
  }
1134
1214
  let ancestor = rootEl.parentElement;
1135
- while (ancestor !== null) {
1215
+ while (ancestor) {
1136
1216
  if (isMounted(ancestor)) throw new Error(NESTED_MOUNT_MSG);
1137
1217
  ancestor = ancestor.parentElement;
1138
1218
  }
1139
1219
  const stack = [];
1140
- for (let i = 0; i < rootEl.children.length; i++) stack.push(rootEl.children[i]);
1220
+ for (let i = 0; i < rootEl.children.length; i++)
1221
+ stack.push(rootEl.children[i]);
1141
1222
  while (stack.length > 0) {
1142
1223
  const cur = stack.pop();
1143
1224
  if (isMounted(cur)) throw new Error(NESTED_MOUNT_MSG);
@@ -1152,7 +1233,7 @@ function mount(rootEl, render) {
1152
1233
  }
1153
1234
  const owner = rootEl.ownerDocument;
1154
1235
  if (owner !== document) {
1155
- if (owner.defaultView === null) document.adoptNode(rootEl);
1236
+ if (!owner.defaultView) document.adoptNode(rootEl);
1156
1237
  }
1157
1238
  assertNotInsideMountedTree(rootEl);
1158
1239
  setMounted(rootEl, true);
@@ -1189,10 +1270,9 @@ function mount(rootEl, render) {
1189
1270
  _setBindingContext(null);
1190
1271
  }
1191
1272
  };
1192
- const disposeEffect = effect(() => {
1273
+ function renderStaticPhase() {
1193
1274
  let result = runRenderPass();
1194
- const countChanged = renderCtx.previousCallCount !== void 0 && renderCtx.previousCallCount !== renderCtx.counter;
1195
- if (countChanged) {
1275
+ if (renderCtx.previousCallCount !== void 0 && renderCtx.previousCallCount !== renderCtx.counter) {
1196
1276
  for (const id of renderCtx.shiftCandidates) {
1197
1277
  if (renderCtx.warnedShiftIds.has(id)) continue;
1198
1278
  renderCtx.warnedShiftIds.add(id);
@@ -1207,7 +1287,7 @@ function mount(rootEl, render) {
1207
1287
  prevStaticHtml = flattenWithoutListItems(segment);
1208
1288
  devHooks.parserRepair?.(prevStaticHtml);
1209
1289
  bindingDisposers = wireBindings(rootEl, bindingCtx, bindingDisposers);
1210
- if (devHooks.staleBindingEnabled?.() === true) prevWiredBindings = bindingCtx.list;
1290
+ if (devHooks.staleBindingEnabled?.()) prevWiredBindings = bindingCtx.list;
1211
1291
  isFirst = false;
1212
1292
  } else {
1213
1293
  let nextStaticHtml = runSubsequentRender(
@@ -1219,7 +1299,8 @@ function mount(rootEl, render) {
1219
1299
  valueOnlyWarnCtx
1220
1300
  );
1221
1301
  if (anyRebuiltListIsGranular(segment, renderCtx.rebuiltLists)) {
1222
- for (const id of renderCtx.rebuiltLists) renderCtx.bindingCounts.delete(id);
1302
+ for (const id of renderCtx.rebuiltLists)
1303
+ renderCtx.bindingCounts.delete(id);
1223
1304
  result = runRenderPass();
1224
1305
  segment = resultToSegment(result);
1225
1306
  nextStaticHtml = runSubsequentRender(
@@ -1233,16 +1314,20 @@ function mount(rootEl, render) {
1233
1314
  }
1234
1315
  if (nextStaticHtml !== prevStaticHtml) {
1235
1316
  bindingDisposers = wireBindings(rootEl, bindingCtx, bindingDisposers);
1236
- if (devHooks.staleBindingEnabled?.() === true) prevWiredBindings = bindingCtx.list;
1317
+ if (devHooks.staleBindingEnabled?.())
1318
+ prevWiredBindings = bindingCtx.list;
1237
1319
  } else {
1238
1320
  devHooks.staleBinding?.(prevWiredBindings, bindingCtx.list);
1239
1321
  }
1240
1322
  prevStaticHtml = nextStaticHtml;
1241
1323
  }
1242
- const expectedCounts = devHooks.listInvariantsEnabled?.() === true ? /* @__PURE__ */ new Map() : null;
1324
+ return segment;
1325
+ }
1326
+ function reconcileAndCommitListPhase(segment) {
1327
+ const expectedCounts = devHooks.listInvariantsEnabled?.() ? /* @__PURE__ */ new Map() : null;
1243
1328
  for (const listSeg of collectLists(segment).values()) {
1244
1329
  const binding = bindings.get(listSeg.id);
1245
- if (binding === void 0) {
1330
+ if (!binding) {
1246
1331
  throw new Error(
1247
1332
  "mount: an each() list appeared in the render output but its marker never reached the live DOM. The most common cause is an each() introduced inside a data-morph-skip subtree on a re-render \u2014 the morph leaves that subtree untouched, so the list can never bind. Move the each() outside the skipped subtree, or remove data-morph-skip from its ancestor."
1248
1333
  );
@@ -1252,11 +1337,14 @@ function mount(rootEl, render) {
1252
1337
  renderCtx.bindingSources.set(listSeg.id, listSeg.source);
1253
1338
  expectedCounts?.set(
1254
1339
  listSeg.id,
1255
- listSeg.patches !== void 0 && listSeg.source !== void 0 ? listSeg.source.value.length : listSeg.items.length
1340
+ listSeg.patches && listSeg.source ? listSeg.source.value.length : listSeg.items.length
1256
1341
  );
1257
1342
  }
1258
1343
  renderCtx.previousCallCount = renderCtx.counter;
1259
- devHooks.listInvariants?.(rootEl, bindings, expectedCounts ?? void 0);
1344
+ devHooks.listInvariants?.(rootEl, bindings, expectedCounts || void 0);
1345
+ }
1346
+ const disposeEffect = effect(() => {
1347
+ reconcileAndCommitListPhase(renderStaticPhase());
1260
1348
  });
1261
1349
  return () => {
1262
1350
  disposeEffect();
@@ -1279,27 +1367,36 @@ function runSubsequentRender(rootEl, segment, bindings, renderCtx, prevStaticHtm
1279
1367
  if (currentStaticHtml === prevStaticHtml) {
1280
1368
  return prevStaticHtml;
1281
1369
  }
1282
- devHooks.valueOnlyRerender?.(prevStaticHtml, currentStaticHtml, valueOnlyWarnCtx);
1370
+ devHooks.valueOnlyRerender?.(
1371
+ prevStaticHtml,
1372
+ currentStaticHtml,
1373
+ valueOnlyWarnCtx
1374
+ );
1283
1375
  cleanupOrphanBindings(segment, bindings, renderCtx);
1284
1376
  const template = rootEl.cloneNode(false);
1285
1377
  template.innerHTML = currentStaticHtml;
1286
1378
  morph(rootEl, template, collectOwnedItems(bindings));
1287
- bindListsFromMarkers(rootEl, segment, bindings, false, renderCtx.rebuiltLists);
1379
+ bindListsFromMarkers(
1380
+ rootEl,
1381
+ segment,
1382
+ bindings,
1383
+ false,
1384
+ renderCtx.rebuiltLists
1385
+ );
1288
1386
  return currentStaticHtml;
1289
1387
  }
1290
1388
  function coerceRenderResult(result) {
1291
- if (result === null || result === void 0) return "";
1292
- if (result === false || result === true) return "";
1389
+ if (result == null || typeof result === "boolean") return "";
1293
1390
  return String(result);
1294
1391
  }
1295
1392
  function resultToSegment(result) {
1296
1393
  return isSafeHtml(result) ? result.__segment ?? { kind: "static", html: result.__html } : { kind: "static", html: coerceRenderResult(result) };
1297
1394
  }
1298
1395
  function anyRebuiltListIsGranular(segment, rebuilt) {
1299
- if (rebuilt.size === 0) return false;
1396
+ if (!rebuilt.size) return false;
1300
1397
  const lists = collectLists(segment);
1301
1398
  for (const id of rebuilt) {
1302
- if (lists.get(id)?.patches !== void 0) return true;
1399
+ if (lists.get(id)?.patches) return true;
1303
1400
  }
1304
1401
  return false;
1305
1402
  }
@@ -1311,8 +1408,9 @@ function bindListsFromMarkers(rootEl, segment, bindings, inlinedItems, rebuiltLi
1311
1408
  if (!marker.data.startsWith(LIST_MARKER_PREFIX)) continue;
1312
1409
  const id = marker.data.slice(LIST_MARKER_PREFIX.length);
1313
1410
  const existing = bindings.get(id);
1314
- if (existing !== void 0) {
1315
- if (existing.marker === marker && rootEl.contains(existing.marker)) continue;
1411
+ if (existing) {
1412
+ if (existing.marker === marker && rootEl.contains(existing.marker))
1413
+ continue;
1316
1414
  for (const item of existing.items) {
1317
1415
  disposeRowBindings(item.bindingDisposers);
1318
1416
  if (rootEl.contains(item.node)) {
@@ -1338,7 +1436,7 @@ function bindListsFromMarkers(rootEl, segment, bindings, inlinedItems, rebuiltLi
1338
1436
  node: next,
1339
1437
  bindings: rowBindings
1340
1438
  };
1341
- if (rowBindings !== void 0 && rowBindings.length > 0) {
1439
+ if (rowBindings?.length) {
1342
1440
  bound.bindingDisposers = wireRowBindings(next, rowBindings);
1343
1441
  }
1344
1442
  items.push(bound);
@@ -1358,7 +1456,8 @@ function validateInlinedRowMatch(expectedHtml, index, boundEl, liveParent) {
1358
1456
  const { content, count } = parseRowTemplate(expectedHtml, liveParent);
1359
1457
  if (count !== 1) throw rowContractError(index, expectedHtml, liveParent);
1360
1458
  const expectedTag = content.firstElementChild.tagName;
1361
- if (boundEl.tagName !== expectedTag) throw rowStructureError(index, boundEl.tagName, expectedTag);
1459
+ if (boundEl.tagName !== expectedTag)
1460
+ throw rowStructureError(index, boundEl.tagName, expectedTag);
1362
1461
  }
1363
1462
  function rowStructureError(index, gotTag, wantTag) {
1364
1463
  const got = gotTag.toLowerCase();
@@ -1380,13 +1479,9 @@ function cleanupOrphanBindings(segment, bindings, renderCtx) {
1380
1479
  if (liveIds.has(id)) continue;
1381
1480
  for (const item of binding.items) {
1382
1481
  disposeRowBindings(item.bindingDisposers);
1383
- if (item.node.parentElement !== null) {
1384
- item.node.parentElement.removeChild(item.node);
1385
- }
1386
- }
1387
- if (binding.marker.parentElement !== null) {
1388
- binding.marker.parentElement.removeChild(binding.marker);
1482
+ item.node.remove();
1389
1483
  }
1484
+ binding.marker.remove();
1390
1485
  bindings.delete(id);
1391
1486
  renderCtx.bindingCounts.delete(id);
1392
1487
  renderCtx.bindingSources.delete(id);
@@ -1394,12 +1489,12 @@ function cleanupOrphanBindings(segment, bindings, renderCtx) {
1394
1489
  }
1395
1490
  }
1396
1491
  function collectComments(node, out) {
1397
- for (let c = node.firstChild; c !== null; c = c.nextSibling) {
1492
+ for (let c = node.firstChild; c; c = c.nextSibling) {
1398
1493
  if (c.nodeType === Node.COMMENT_NODE) out.push(c);
1399
1494
  else if (c.nodeType === Node.ELEMENT_NODE) collectComments(c, out);
1400
1495
  }
1401
1496
  }
1402
1497
 
1403
- export { each, morph, mount, moveNode };
1404
- //# sourceMappingURL=chunk-SRWQKB33.js.map
1405
- //# sourceMappingURL=chunk-SRWQKB33.js.map
1498
+ export { captureFocus, each, morph, mount, moveNode, restoreFocus };
1499
+
1500
+ //# sourceMappingURL=chunk-V757BT6U.js.map