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.
- package/CHANGELOG.md +284 -104
- package/LICENSE +1 -1
- package/README.md +73 -54
- package/ai/cursorrules +130 -48
- package/ai/manifest.json +63 -5
- package/ai/skill.md +148 -65
- package/dist/actions.d.ts +1 -1
- package/dist/actions.js +4 -4
- package/dist/actions.js.map +1 -1
- package/dist/array-signal.js +5 -5
- package/dist/async.js +34 -24
- package/dist/async.js.map +1 -1
- package/dist/attach.d.ts +11 -8
- package/dist/attach.js +54 -4
- package/dist/attach.js.map +1 -1
- package/dist/{chunk-QIP723L4.js → chunk-5WRGJZV6.js} +4 -3
- package/dist/chunk-5WRGJZV6.js.map +1 -0
- package/dist/{chunk-GY4XV2UV.js → chunk-BDX3R4OM.js} +4 -3
- package/dist/chunk-BDX3R4OM.js.map +1 -0
- package/dist/{chunk-VVDJLWMP.js → chunk-CEQMZYLR.js} +2 -2
- package/dist/chunk-CEQMZYLR.js.map +1 -0
- package/dist/{chunk-KEZTD6H4.js → chunk-E5R5GNKE.js} +15 -5
- package/dist/chunk-E5R5GNKE.js.map +1 -0
- package/dist/{chunk-MRYM3O3V.js → chunk-ELXVRKY2.js} +12 -9
- package/dist/chunk-ELXVRKY2.js.map +1 -0
- package/dist/{chunk-U32TFTGZ.js → chunk-MK42GLPV.js} +3 -3
- package/dist/chunk-MK42GLPV.js.map +1 -0
- package/dist/{chunk-SUPUPSBE.js → chunk-QFUNWHKH.js} +42 -20
- package/dist/chunk-QFUNWHKH.js.map +1 -0
- package/dist/{chunk-SRWQKB33.js → chunk-V757BT6U.js} +206 -111
- package/dist/chunk-V757BT6U.js.map +1 -0
- package/dist/{chunk-YHH7OUFA.js → chunk-WKIPLNVO.js} +3 -3
- package/dist/chunk-WKIPLNVO.js.map +1 -0
- package/dist/{chunk-3APBEVHF.js → chunk-Y2FOYPBV.js} +3 -3
- package/dist/{chunk-3APBEVHF.js.map → chunk-Y2FOYPBV.js.map} +1 -1
- package/dist/{chunk-SAYPJ6XR.js → chunk-ZOIERTUW.js} +10 -6
- package/dist/chunk-ZOIERTUW.js.map +1 -0
- package/dist/dev.d.ts +9 -6
- package/dist/dev.js +66 -19
- package/dist/dev.js.map +1 -1
- package/dist/html.d.ts +1 -1
- package/dist/html.js +8 -7
- package/dist/html.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +28 -19
- package/dist/index.js.map +1 -1
- package/dist/jsx-runtime.js +5 -5
- package/dist/list.d.ts +1 -1
- package/dist/list.js +304 -213
- package/dist/list.js.map +1 -1
- package/dist/overlay.d.ts +190 -280
- package/dist/overlay.js +471 -364
- package/dist/overlay.js.map +1 -1
- package/dist/remount.d.ts +5 -3
- package/dist/remount.js +29 -10
- package/dist/remount.js.map +1 -1
- package/dist/router.d.ts +1 -1
- package/dist/router.js +73 -28
- package/dist/router.js.map +1 -1
- package/dist/scope.d.ts +4 -3
- package/dist/scope.js +11 -10
- package/dist/scope.js.map +1 -1
- package/dist/testing.js +4 -4
- package/dist/timing.d.ts +3 -2
- package/dist/timing.js +5 -5
- package/dist/timing.js.map +1 -1
- package/llms.txt +13 -6
- package/package.json +35 -13
- package/setup/cli.mjs +90 -0
- package/setup/index.d.mts +37 -0
- package/setup/index.mjs +1347 -0
- package/setup/jsonc.mjs +201 -0
- package/setup/state.schema.json +56 -0
- package/dist/chunk-GY4XV2UV.js.map +0 -1
- package/dist/chunk-KEZTD6H4.js.map +0 -1
- package/dist/chunk-MRYM3O3V.js.map +0 -1
- package/dist/chunk-QIP723L4.js.map +0 -1
- package/dist/chunk-SAYPJ6XR.js.map +0 -1
- package/dist/chunk-SRWQKB33.js.map +0 -1
- package/dist/chunk-SUPUPSBE.js.map +0 -1
- package/dist/chunk-U32TFTGZ.js.map +0 -1
- package/dist/chunk-VVDJLWMP.js.map +0 -1
- package/dist/chunk-YHH7OUFA.js.map +0 -1
- /package/dist/{attrSelector-Cmu2ZoGO.d.ts → attr-Cmu2ZoGO.d.ts} +0 -0
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { itemVersion } from './chunk-
|
|
2
|
-
import { parseRowTemplate, rowContractError, parseSingleRow, collectTemplateChildren } from './chunk-
|
|
3
|
-
import { captureRowBindings, listSafeHtml, boundTextNodeOf, syncFormProp, newBindingContext,
|
|
4
|
-
import { effect } from './chunk-
|
|
5
|
-
import { LIST_MARKER_PREFIX, flattenWithoutListItems, collectLists, flatten } from './chunk-
|
|
6
|
-
import { devHooks } from './chunk-
|
|
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")
|
|
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
|
-
|
|
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
|
-
|
|
149
|
-
|
|
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(
|
|
158
|
-
|
|
159
|
-
|
|
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(
|
|
228
|
-
|
|
229
|
-
|
|
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)
|
|
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
|
-
|
|
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
|
-
|
|
272
|
-
if (!
|
|
273
|
-
|
|
274
|
-
if (
|
|
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
|
-
|
|
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 = [
|
|
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)
|
|
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(
|
|
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))
|
|
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))
|
|
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)
|
|
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)
|
|
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(
|
|
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(
|
|
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(
|
|
950
|
+
return rowContractError(
|
|
951
|
+
patches[start + i].index,
|
|
952
|
+
htmls[i],
|
|
953
|
+
liveParent
|
|
954
|
+
);
|
|
905
955
|
}
|
|
906
956
|
}
|
|
907
|
-
return new Error(
|
|
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(
|
|
964
|
+
return rowContractError(
|
|
965
|
+
patches[c.patchIdx].index,
|
|
966
|
+
c.html,
|
|
967
|
+
liveParent
|
|
968
|
+
);
|
|
913
969
|
}
|
|
914
970
|
}
|
|
915
|
-
return new Error(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
1123
|
+
return rowContractError(
|
|
1124
|
+
freshIndices[i],
|
|
1125
|
+
newRecord[freshIndices[i]].html,
|
|
1126
|
+
liveParent
|
|
1127
|
+
);
|
|
1051
1128
|
}
|
|
1052
1129
|
}
|
|
1053
|
-
return new Error(
|
|
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)
|
|
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
|
|
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++)
|
|
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
|
|
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
|
-
|
|
1273
|
+
function renderStaticPhase() {
|
|
1193
1274
|
let result = runRenderPass();
|
|
1194
|
-
|
|
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?.()
|
|
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)
|
|
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?.()
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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?.(
|
|
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(
|
|
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
|
|
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
|
|
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
|
|
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
|
|
1315
|
-
if (existing.marker === marker && rootEl.contains(existing.marker))
|
|
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
|
|
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)
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
1405
|
-
//# sourceMappingURL=chunk-
|
|
1498
|
+
export { captureFocus, each, morph, mount, moveNode, restoreFocus };
|
|
1499
|
+
|
|
1500
|
+
//# sourceMappingURL=chunk-V757BT6U.js.map
|