kerfjs 5.0.0-beta.7 → 5.0.0-beta.71
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 +2488 -117
- package/README.md +96 -37
- package/ai/cursorrules +110 -61
- package/ai/manifest.json +16 -7
- package/ai/skill.md +120 -75
- package/dist/actions.d.ts +1 -1
- package/dist/actions.js +10 -6
- package/dist/actions.js.map +1 -1
- package/dist/array-signal.js +1 -1
- package/dist/async.js +22 -19
- package/dist/async.js.map +1 -1
- package/dist/attach.js +1 -66
- package/dist/attach.js.map +1 -1
- package/dist/{chunk-HW7KSM2Y.js → chunk-3C6F6NM4.js} +1 -1
- package/dist/{chunk-HW7KSM2Y.js.map → chunk-3C6F6NM4.js.map} +1 -1
- package/dist/{chunk-GY4XV2UV.js → chunk-4TX6YJDM.js} +10 -3
- package/dist/chunk-4TX6YJDM.js.map +1 -0
- package/dist/{chunk-QIP723L4.js → chunk-5WRGJZV6.js} +3 -2
- package/dist/chunk-5WRGJZV6.js.map +1 -0
- package/dist/{chunk-KZJXHFIB.js → chunk-BI4HGICV.js} +3 -3
- package/dist/chunk-BI4HGICV.js.map +1 -0
- package/dist/chunk-FM6N2B4N.js +70 -0
- package/dist/chunk-FM6N2B4N.js.map +1 -0
- package/dist/{chunk-LVH3GC6B.js → chunk-H7WTRM6F.js} +3 -3
- package/dist/chunk-H7WTRM6F.js.map +1 -0
- package/dist/{chunk-U6FK33SG.js → chunk-IHMDBBUJ.js} +2 -2
- package/dist/chunk-IHMDBBUJ.js.map +1 -0
- package/dist/chunk-JN7EJM3B.js +86 -0
- package/dist/chunk-JN7EJM3B.js.map +1 -0
- package/dist/{chunk-UZJ6I4T6.js → chunk-MK42GLPV.js} +1 -1
- package/dist/chunk-MK42GLPV.js.map +1 -0
- package/dist/{chunk-SVATPF5R.js → chunk-TLL3KXT6.js} +249 -160
- package/dist/chunk-TLL3KXT6.js.map +1 -0
- package/dist/{chunk-ZDCJZCNO.js → chunk-UGNPDLNI.js} +78 -45
- package/dist/chunk-UGNPDLNI.js.map +1 -0
- package/dist/{chunk-V46JKE44.js → chunk-WKIPLNVO.js} +1 -1
- package/dist/chunk-WKIPLNVO.js.map +1 -0
- package/dist/{delegate-CL9VTZFb.d.ts → delegate--CrfgYtC.d.ts} +0 -34
- package/dist/dev.d.ts +31 -13
- package/dist/dev.js +101 -35
- package/dist/dev.js.map +1 -1
- package/dist/html.js +5 -4
- package/dist/html.js.map +1 -1
- package/dist/index.d.ts +14 -9
- package/dist/index.js +29 -20
- package/dist/index.js.map +1 -1
- package/dist/jsx-runtime.d.ts +13 -5
- package/dist/jsx-runtime.js +1 -1
- package/dist/list.d.ts +7 -3
- package/dist/list.js +126 -28
- package/dist/list.js.map +1 -1
- package/dist/overlay.d.ts +25 -28
- package/dist/overlay.js +580 -275
- package/dist/overlay.js.map +1 -1
- package/dist/remount.js +2 -2
- package/dist/router.d.ts +13 -4
- package/dist/router.js +37 -10
- package/dist/router.js.map +1 -1
- package/dist/scope.d.ts +35 -8
- package/dist/scope.js +61 -30
- package/dist/scope.js.map +1 -1
- package/dist/testing.js +1 -1
- package/dist/timing.d.ts +3 -2
- package/dist/timing.js +1 -1
- package/dist/timing.js.map +1 -1
- package/llms.txt +11 -4
- package/package.json +32 -7
- 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-KPXIOG2C.js +0 -54
- package/dist/chunk-KPXIOG2C.js.map +0 -1
- package/dist/chunk-KZJXHFIB.js.map +0 -1
- package/dist/chunk-LVH3GC6B.js.map +0 -1
- package/dist/chunk-QIP723L4.js.map +0 -1
- package/dist/chunk-SVATPF5R.js.map +0 -1
- package/dist/chunk-U6FK33SG.js.map +0 -1
- package/dist/chunk-UZJ6I4T6.js.map +0 -1
- package/dist/chunk-V46JKE44.js.map +0 -1
- package/dist/chunk-ZDCJZCNO.js.map +0 -1
package/dist/list.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { ARRAY_SIGNAL_BRAND } from './chunk-
|
|
2
|
-
import { captureFocus, restoreFocus, moveNode, mount } from './chunk-
|
|
1
|
+
import { ARRAY_SIGNAL_BRAND } from './chunk-H7WTRM6F.js';
|
|
2
|
+
import { captureFocus, restoreFocus, moveNode, mount } from './chunk-TLL3KXT6.js';
|
|
3
3
|
|
|
4
4
|
|
|
5
5
|
|
|
6
|
-
import { effect } from './chunk-
|
|
6
|
+
import { effect } from './chunk-IHMDBBUJ.js';
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
|
|
@@ -87,7 +87,8 @@ function createListRowController(options) {
|
|
|
87
87
|
let ref = endAnchor();
|
|
88
88
|
for (let index = order.length - 1; index >= 0; index--) {
|
|
89
89
|
const el = order[index].el;
|
|
90
|
-
if (el.parentNode !== container || el.nextSibling !== ref)
|
|
90
|
+
if (el.parentNode !== container || el.nextSibling !== ref)
|
|
91
|
+
moveNode(container, el, ref);
|
|
91
92
|
ref = el;
|
|
92
93
|
}
|
|
93
94
|
});
|
|
@@ -99,7 +100,10 @@ function createListRowController(options) {
|
|
|
99
100
|
const row = makeRow(patch.item);
|
|
100
101
|
rows.set(key(patch.item), row);
|
|
101
102
|
order.splice(patch.index, 0, row);
|
|
102
|
-
container.insertBefore(
|
|
103
|
+
container.insertBefore(
|
|
104
|
+
row.el,
|
|
105
|
+
order[patch.index + 1]?.el ?? endAnchor()
|
|
106
|
+
);
|
|
103
107
|
} else if (patch.type === "remove") {
|
|
104
108
|
const [row] = order.splice(patch.index, 1);
|
|
105
109
|
row.dispose();
|
|
@@ -114,7 +118,10 @@ function createListRowController(options) {
|
|
|
114
118
|
const row = reconcileItem(current, patch.item);
|
|
115
119
|
if (row !== current) {
|
|
116
120
|
order[patch.index] = row;
|
|
117
|
-
container.insertBefore(
|
|
121
|
+
container.insertBefore(
|
|
122
|
+
row.el,
|
|
123
|
+
order[patch.index + 1]?.el ?? endAnchor()
|
|
124
|
+
);
|
|
118
125
|
}
|
|
119
126
|
}
|
|
120
127
|
}
|
|
@@ -132,8 +139,38 @@ function createListRowController(options) {
|
|
|
132
139
|
}
|
|
133
140
|
|
|
134
141
|
// src/list-virtualization-controller.ts
|
|
142
|
+
function assertHeight(value, what) {
|
|
143
|
+
if (!(typeof value === "number" && value >= 0 && value < Infinity))
|
|
144
|
+
throw new RangeError(
|
|
145
|
+
`bindList: ${what} must be a finite height >= 0 (got ${String(value)})`
|
|
146
|
+
);
|
|
147
|
+
return value;
|
|
148
|
+
}
|
|
149
|
+
function validateVirtualize(virtualize) {
|
|
150
|
+
const { rowHeight, overscan, minRows } = virtualize;
|
|
151
|
+
for (const [name, count] of [
|
|
152
|
+
["overscan", overscan],
|
|
153
|
+
["minRows", minRows]
|
|
154
|
+
]) {
|
|
155
|
+
if (count !== void 0 && !(Number.isInteger(count) && count >= 0))
|
|
156
|
+
throw new RangeError(
|
|
157
|
+
`bindList: virtualize.${name} must be an integer >= 0 (got ${count})`
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
if (typeof rowHeight === "number") {
|
|
161
|
+
if (assertHeight(rowHeight, "rowHeight") === 0 && virtualize.mode !== "content-visibility")
|
|
162
|
+
throw new RangeError(
|
|
163
|
+
"bindList: a fixed rowHeight must be > 0 in window mode"
|
|
164
|
+
);
|
|
165
|
+
} else if (typeof rowHeight !== "function") {
|
|
166
|
+
const estimate = rowHeight?.estimate;
|
|
167
|
+
if (typeof estimate !== "function")
|
|
168
|
+
assertHeight(estimate, "rowHeight.estimate");
|
|
169
|
+
}
|
|
170
|
+
}
|
|
135
171
|
function createListVirtualizationController(options) {
|
|
136
172
|
const { parent, container, virtualize, key, rows } = options;
|
|
173
|
+
validateVirtualize(virtualize);
|
|
137
174
|
const overscan = virtualize.overscan ?? 3;
|
|
138
175
|
const { minRows, rowHeight } = virtualize;
|
|
139
176
|
const contentVisibility = virtualize.mode === "content-visibility";
|
|
@@ -145,14 +182,23 @@ function createListVirtualizationController(options) {
|
|
|
145
182
|
let items = [];
|
|
146
183
|
let offsets = [0];
|
|
147
184
|
let heightsDirty = true;
|
|
148
|
-
|
|
185
|
+
const pendingAnchorBaselines = /* @__PURE__ */ new Map();
|
|
149
186
|
let rafPending = false;
|
|
150
187
|
let disposed = false;
|
|
151
188
|
const estimateAt = (index) => {
|
|
152
189
|
const estimate = rowHeight.estimate;
|
|
153
|
-
return typeof estimate === "function" ?
|
|
190
|
+
return typeof estimate === "function" ? assertHeight(
|
|
191
|
+
estimate(items[index], index),
|
|
192
|
+
`rowHeight.estimate(item, ${index})`
|
|
193
|
+
) : estimate;
|
|
154
194
|
};
|
|
155
|
-
const variableHeightAt = fixedHeight !== null ? null : measuring ? (index) => measured.get(key(items[index])) ?? estimateAt(index) : (index) =>
|
|
195
|
+
const variableHeightAt = fixedHeight !== null ? null : measuring ? (index) => measured.get(key(items[index])) ?? estimateAt(index) : (index) => assertHeight(
|
|
196
|
+
rowHeight(
|
|
197
|
+
items[index],
|
|
198
|
+
index
|
|
199
|
+
),
|
|
200
|
+
`rowHeight(item, ${index})`
|
|
201
|
+
);
|
|
156
202
|
const intrinsicSizeAt = (index) => fixedHeight ?? variableHeightAt(index);
|
|
157
203
|
const rebuildOffsets = () => {
|
|
158
204
|
const heightAt = variableHeightAt;
|
|
@@ -167,6 +213,9 @@ function createListVirtualizationController(options) {
|
|
|
167
213
|
for (const rowKey of measured.keys()) {
|
|
168
214
|
if (!indexByKey.has(rowKey)) measured.delete(rowKey);
|
|
169
215
|
}
|
|
216
|
+
for (const rowKey of pendingAnchorBaselines.keys()) {
|
|
217
|
+
if (!indexByKey.has(rowKey)) pendingAnchorBaselines.delete(rowKey);
|
|
218
|
+
}
|
|
170
219
|
}
|
|
171
220
|
};
|
|
172
221
|
const findStart = (target, total) => {
|
|
@@ -223,7 +272,10 @@ function createListVirtualizationController(options) {
|
|
|
223
272
|
padBottom = 0;
|
|
224
273
|
} else if (fixedHeight !== null) {
|
|
225
274
|
const viewportBottom = parent.scrollTop + parent.clientHeight;
|
|
226
|
-
start2 = Math.
|
|
275
|
+
start2 = Math.min(
|
|
276
|
+
total,
|
|
277
|
+
Math.max(0, Math.floor(parent.scrollTop / fixedHeight) - overscan)
|
|
278
|
+
);
|
|
227
279
|
end = Math.min(total, Math.ceil(viewportBottom / fixedHeight) + overscan);
|
|
228
280
|
padTop = start2 * fixedHeight;
|
|
229
281
|
padBottom = Math.max(0, total - end) * fixedHeight;
|
|
@@ -249,16 +301,27 @@ function createListVirtualizationController(options) {
|
|
|
249
301
|
heightsDirty = true;
|
|
250
302
|
renderCurrent();
|
|
251
303
|
};
|
|
304
|
+
const applyAnchorCorrection = () => {
|
|
305
|
+
if (heightsDirty) {
|
|
306
|
+
rebuildOffsets();
|
|
307
|
+
heightsDirty = false;
|
|
308
|
+
}
|
|
309
|
+
let delta = 0;
|
|
310
|
+
for (const [rowKey, baseline] of pendingAnchorBaselines) {
|
|
311
|
+
const index = indexByKey.get(rowKey);
|
|
312
|
+
if (offsets[index] + baseline <= parent.scrollTop)
|
|
313
|
+
delta += offsets[index + 1] - offsets[index] - baseline;
|
|
314
|
+
}
|
|
315
|
+
pendingAnchorBaselines.clear();
|
|
316
|
+
if (delta !== 0) parent.scrollTop += delta;
|
|
317
|
+
};
|
|
252
318
|
const scheduleRender = () => {
|
|
253
319
|
if (rafPending) return;
|
|
254
320
|
rafPending = true;
|
|
255
321
|
globalThis.requestAnimationFrame(() => {
|
|
256
322
|
rafPending = false;
|
|
257
323
|
if (disposed) return;
|
|
258
|
-
if (
|
|
259
|
-
parent.scrollTop += pendingAnchorDelta;
|
|
260
|
-
pendingAnchorDelta = 0;
|
|
261
|
-
}
|
|
324
|
+
if (pendingAnchorBaselines.size > 0) applyAnchorCorrection();
|
|
262
325
|
renderCurrent();
|
|
263
326
|
});
|
|
264
327
|
};
|
|
@@ -269,13 +332,15 @@ function createListVirtualizationController(options) {
|
|
|
269
332
|
resizeObserver?.observe(parent);
|
|
270
333
|
};
|
|
271
334
|
const setHeight = (rowKey, height) => {
|
|
335
|
+
assertHeight(height, "setHeight()");
|
|
272
336
|
if (!measuring || contentVisibility) return;
|
|
273
337
|
const index = indexByKey.get(rowKey);
|
|
274
338
|
if (index === void 0) return;
|
|
275
339
|
const oldHeight = measured.get(rowKey) ?? estimateAt(index);
|
|
276
340
|
if (height === oldHeight) return;
|
|
277
341
|
measured.set(rowKey, height);
|
|
278
|
-
if (
|
|
342
|
+
if (!pendingAnchorBaselines.has(rowKey))
|
|
343
|
+
pendingAnchorBaselines.set(rowKey, oldHeight);
|
|
279
344
|
heightsDirty = true;
|
|
280
345
|
scheduleRender();
|
|
281
346
|
};
|
|
@@ -309,30 +374,54 @@ function assertUniqueListKeys(items, key) {
|
|
|
309
374
|
firstIndex.set(rowKey, index);
|
|
310
375
|
}
|
|
311
376
|
}
|
|
377
|
+
function resolvePatchConsumer(source) {
|
|
378
|
+
const branded = source;
|
|
379
|
+
if (branded[ARRAY_SIGNAL_BRAND] !== true) return void 0;
|
|
380
|
+
const consume = branded._consumePatches;
|
|
381
|
+
if (typeof consume !== "function") {
|
|
382
|
+
throw new TypeError(
|
|
383
|
+
"bindList: source carries the arraySignal brand but has no _consumePatches() queue"
|
|
384
|
+
);
|
|
385
|
+
}
|
|
386
|
+
return consume.bind(source);
|
|
387
|
+
}
|
|
312
388
|
function bindList(parent, source, options) {
|
|
313
389
|
const { key, render, tag = "div", virtualize, before } = options;
|
|
314
390
|
let firstRender = true;
|
|
315
391
|
let forceSnapshot = false;
|
|
316
|
-
const
|
|
317
|
-
const granularEligible = virtualize === void 0 && patchSource[ARRAY_SIGNAL_BRAND] === true;
|
|
392
|
+
const consumePatches = virtualize === void 0 ? resolvePatchConsumer(source) : void 0;
|
|
318
393
|
const container = virtualize === void 0 ? parent : document.createElement("div");
|
|
319
394
|
if (virtualize !== void 0) {
|
|
320
|
-
if (virtualize.containerClass !== void 0)
|
|
321
|
-
|
|
395
|
+
if (virtualize.containerClass !== void 0)
|
|
396
|
+
container.className = virtualize.containerClass;
|
|
397
|
+
if (virtualize.containerId !== void 0)
|
|
398
|
+
container.id = virtualize.containerId;
|
|
322
399
|
}
|
|
323
400
|
const endAnchor = () => {
|
|
324
401
|
if (virtualize !== void 0 || before === void 0) return null;
|
|
325
402
|
return (typeof before === "function" ? before() : before) ?? null;
|
|
326
403
|
};
|
|
327
|
-
const rows = createListRowController({
|
|
328
|
-
|
|
404
|
+
const rows = createListRowController({
|
|
405
|
+
container,
|
|
406
|
+
key,
|
|
407
|
+
render,
|
|
408
|
+
tag,
|
|
409
|
+
endAnchor
|
|
410
|
+
});
|
|
411
|
+
const virtualization = virtualize === void 0 ? void 0 : createListVirtualizationController({
|
|
412
|
+
parent,
|
|
413
|
+
container,
|
|
414
|
+
virtualize,
|
|
415
|
+
key,
|
|
416
|
+
rows
|
|
417
|
+
});
|
|
329
418
|
const renderItems = (items) => {
|
|
330
419
|
if (virtualization !== void 0) {
|
|
331
420
|
virtualization.render(items);
|
|
332
421
|
return;
|
|
333
422
|
}
|
|
334
|
-
if (
|
|
335
|
-
const patches =
|
|
423
|
+
if (consumePatches !== void 0) {
|
|
424
|
+
const patches = consumePatches();
|
|
336
425
|
if (!firstRender && !forceSnapshot && patches.length > 0 && !patches.some((patch) => patch.type === "replace")) {
|
|
337
426
|
try {
|
|
338
427
|
rows.applyPatches(patches);
|
|
@@ -347,19 +436,27 @@ function bindList(parent, source, options) {
|
|
|
347
436
|
firstRender = false;
|
|
348
437
|
forceSnapshot = false;
|
|
349
438
|
};
|
|
350
|
-
const
|
|
439
|
+
const track = () => {
|
|
351
440
|
const items = source.value;
|
|
352
441
|
try {
|
|
353
442
|
assertUniqueListKeys(items, key);
|
|
354
443
|
} catch (error) {
|
|
355
|
-
if (
|
|
356
|
-
|
|
444
|
+
if (consumePatches !== void 0) {
|
|
445
|
+
consumePatches();
|
|
357
446
|
forceSnapshot = true;
|
|
358
447
|
}
|
|
359
448
|
throw error;
|
|
360
449
|
}
|
|
361
450
|
renderItems(items);
|
|
362
|
-
}
|
|
451
|
+
};
|
|
452
|
+
let stopEffect;
|
|
453
|
+
try {
|
|
454
|
+
stopEffect = effect(track);
|
|
455
|
+
} catch (error) {
|
|
456
|
+
rows.dispose(true);
|
|
457
|
+
virtualization?.dispose();
|
|
458
|
+
throw error;
|
|
459
|
+
}
|
|
363
460
|
if (virtualization !== void 0) {
|
|
364
461
|
parent.appendChild(container);
|
|
365
462
|
virtualization.start();
|
|
@@ -395,7 +492,8 @@ function observeRowHeights(handle) {
|
|
|
395
492
|
const observer = new RO((entries) => {
|
|
396
493
|
for (const entry of entries) {
|
|
397
494
|
const k = keyByEl.get(entry.target);
|
|
398
|
-
if (k !== void 0)
|
|
495
|
+
if (k !== void 0)
|
|
496
|
+
handle.setHeight(k, entry.target.offsetHeight);
|
|
399
497
|
}
|
|
400
498
|
});
|
|
401
499
|
const resync = () => {
|
package/dist/list.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/list-row-controller.ts","../src/list-virtualization-controller.ts","../src/list.ts"],"names":["dispose","start","NOOP"],"mappings":"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","file":"list.js","sourcesContent":["import type { ArrayPatch } from './array-signal.js';\nimport type { BindListOptions,ListKey,RowElement } from './list.js';\nimport { captureFocus,restoreFocus } from './list-reconcile-focus.js';\nimport { mount,type MountResult } from './mount.js';\nimport { moveNode } from './utils/moveNode.js';\n\ninterface ListRow<T> {\n el: HTMLElement;\n item: T;\n dispose: () => void;\n elementMode: boolean;\n update?: (item: T) => void;\n}\n\nexport interface ListRowController<T> {\n readonly order: Array<ListRow<T>>;\n sync: (visible: readonly T[]) => void;\n applyPatches: (patches: readonly ArrayPatch<T>[]) => void;\n dispose: (removeElements: boolean) => void;\n}\n\ninterface ListRowControllerOptions<T> {\n container: HTMLElement;\n key: (item: T) => ListKey;\n render: BindListOptions<T>['render'];\n tag: string;\n endAnchor: () => Node | null;\n}\n\nconst NOOP = (): void => { /* element-mode rows with no caller teardown */ };\n\n/** Own the keyed row map, DOM order, row lifecycles, and both reconcile paths. */\nexport function createListRowController<T>(\n options: ListRowControllerOptions<T>,\n): ListRowController<T> {\n const { container,key,render,tag,endAnchor } = options;\n const rows = new Map<ListKey,ListRow<T>>();\n const order: Array<ListRow<T>> = [];\n\n const asElementRow = (\n rendered: MountResult | RowElement<T>,\n ): { el: HTMLElement; dispose: () => void; update?: (item: T) => void } | null => {\n if (rendered instanceof HTMLElement) return { el: rendered,dispose: NOOP };\n if (\n rendered !== null\n && typeof rendered === 'object'\n && 'el' in rendered\n && (rendered as { el: unknown }).el instanceof HTMLElement\n ) {\n const row = rendered as { el: HTMLElement; update?: (item: T) => void; dispose?: () => void };\n return { el: row.el,dispose: row.dispose ?? NOOP,update: row.update };\n }\n return null;\n };\n\n const makeRow = (item: T): ListRow<T> => {\n const elementRow = asElementRow(render(item));\n if (elementRow !== null) {\n return {\n el: elementRow.el,\n item,\n dispose: elementRow.dispose,\n elementMode: true,\n update: elementRow.update,\n };\n }\n const el = document.createElement(tag);\n const dispose = mount(el,() => render(item) as MountResult);\n return { el,item,dispose,elementMode: false };\n };\n\n // The single item-replacement contract used by snapshot and granular paths.\n // Element-mode rows keep their caller-owned element and are re-keyed; content\n // rows replace their mount. DOM placement remains the caller's responsibility.\n const reconcileItem = (row: ListRow<T>,item: T): ListRow<T> => {\n if (row.item === item) return row;\n const oldKey = key(row.item);\n const newKey = key(item);\n if (row.elementMode) {\n row.item = item;\n if (newKey !== oldKey) {\n rows.delete(oldKey);\n rows.set(newKey,row);\n }\n row.update?.(item);\n return row;\n }\n row.dispose();\n row.el.remove();\n rows.delete(oldKey);\n const fresh = makeRow(item);\n rows.set(newKey,fresh);\n return fresh;\n };\n\n const preserveFocus = (operation: () => void): void => {\n const focus = captureFocus(container);\n try {\n operation();\n } finally {\n if (focus !== null) restoreFocus(focus);\n }\n };\n\n const sync = (visible: readonly T[]): void => {\n preserveFocus(() => {\n const wanted = new Set<ListKey>();\n for (const item of visible) wanted.add(key(item));\n\n for (const [rowKey,row] of rows) {\n if (!wanted.has(rowKey)) {\n row.dispose();\n row.el.remove();\n rows.delete(rowKey);\n }\n }\n\n order.length = 0;\n for (const item of visible) {\n const rowKey = key(item);\n const existing = rows.get(rowKey);\n const row = existing === undefined ? makeRow(item) : reconcileItem(existing,item);\n if (existing === undefined) rows.set(rowKey,row);\n order.push(row);\n }\n\n let ref: Node | null = endAnchor();\n for (let index = order.length - 1; index >= 0; index--) {\n const el = order[index].el;\n if (el.parentNode !== container || el.nextSibling !== ref) moveNode(container,el,ref);\n ref = el;\n }\n });\n };\n\n const applyPatches = (patches: readonly ArrayPatch<T>[]): void => {\n preserveFocus(() => {\n for (const patch of patches) {\n if (patch.type === 'insert') {\n const row = makeRow(patch.item);\n rows.set(key(patch.item),row);\n order.splice(patch.index,0,row);\n container.insertBefore(row.el,order[patch.index + 1]?.el ?? endAnchor());\n } else if (patch.type === 'remove') {\n const [row] = order.splice(patch.index,1);\n row.dispose();\n row.el.remove();\n rows.delete(key(row.item));\n } else if (patch.type === 'move') {\n const [row] = order.splice(patch.from,1);\n order.splice(patch.to,0,row);\n moveNode(container,row.el,order[patch.to + 1]?.el ?? endAnchor());\n } else if (patch.type === 'update') {\n const current = order[patch.index];\n const row = reconcileItem(current,patch.item);\n if (row !== current) {\n order[patch.index] = row;\n container.insertBefore(row.el,order[patch.index + 1]?.el ?? endAnchor());\n }\n }\n }\n });\n };\n\n const dispose = (removeElements: boolean): void => {\n for (const row of rows.values()) {\n row.dispose();\n if (removeElements) row.el.remove();\n }\n rows.clear();\n order.length = 0;\n };\n\n return { order,sync,applyPatches,dispose };\n}\n","import type { BindListOptions,ListKey } from './list.js';\nimport type { ListRowController } from './list-row-controller.js';\n\ninterface ListVirtualizationController<T> {\n readonly contentVisibility: boolean;\n render: (items: readonly T[]) => void;\n start: () => void;\n setHeight: (key: ListKey,height: number) => void;\n onRender: (callback: () => void) => () => void;\n dispose: () => void;\n}\n\ninterface ListVirtualizationControllerOptions<T> {\n parent: HTMLElement;\n container: HTMLElement;\n virtualize: NonNullable<BindListOptions<T>['virtualize']>;\n key: (item: T) => ListKey;\n rows: ListRowController<T>;\n}\n\n/** Own window calculation, height models, scheduling, observers, and CSS strategy. */\nexport function createListVirtualizationController<T>(\n options: ListVirtualizationControllerOptions<T>,\n): ListVirtualizationController<T> {\n const { parent,container,virtualize,key,rows } = options;\n const overscan = virtualize.overscan ?? 3;\n const { minRows,rowHeight } = virtualize;\n const contentVisibility = virtualize.mode === 'content-visibility';\n const fixedHeight = typeof rowHeight === 'number' ? rowHeight : null;\n const measuring = typeof rowHeight === 'object' && rowHeight !== null;\n const measured = new Map<ListKey,number>();\n const indexByKey = new Map<ListKey,number>();\n const renderSubscribers = new Set<() => void>();\n let items: readonly T[] = [];\n let offsets: number[] = [0];\n let heightsDirty = true;\n let pendingAnchorDelta = 0;\n let rafPending = false;\n let disposed = false;\n\n const estimateAt = (index: number): number => {\n const estimate = (rowHeight as { estimate: number | ((item: T,index: number) => number) }).estimate;\n return typeof estimate === 'function' ? estimate(items[index],index) : estimate;\n };\n const variableHeightAt: ((index: number) => number) | null =\n fixedHeight !== null\n ? null\n : measuring\n ? (index): number => measured.get(key(items[index])) ?? estimateAt(index)\n : (index): number => (rowHeight as (item: T,index: number) => number)(items[index],index);\n const intrinsicSizeAt = (index: number): number =>\n fixedHeight ?? (variableHeightAt as (index: number) => number)(index);\n\n const rebuildOffsets = (): void => {\n const heightAt = variableHeightAt as (index: number) => number;\n offsets = new Array<number>(items.length + 1);\n offsets[0] = 0;\n if (measuring) indexByKey.clear();\n for (let index = 0; index < items.length; index++) {\n offsets[index + 1] = offsets[index] + heightAt(index);\n if (measuring) indexByKey.set(key(items[index]),index);\n }\n if (measuring) {\n for (const rowKey of measured.keys()) {\n if (!indexByKey.has(rowKey)) measured.delete(rowKey);\n }\n }\n };\n\n const findStart = (target: number,total: number): number => {\n let low = 0;\n let high = total;\n while (low < high) {\n const middle = (low + high + 1) >> 1;\n if (offsets[middle] <= target) low = middle;\n else high = middle - 1;\n }\n return low;\n };\n\n const findEnd = (target: number,total: number): number => {\n let low = 0;\n let high = total;\n while (low < high) {\n const middle = (low + high) >> 1;\n if (offsets[middle] >= target) high = middle;\n else low = middle + 1;\n }\n return low;\n };\n\n const sizeRows = (start: number): void => {\n if (measuring) return;\n for (let index = 0; index < rows.order.length; index++) {\n const absoluteIndex = start + index;\n const height = fixedHeight ?? offsets[absoluteIndex + 1] - offsets[absoluteIndex];\n rows.order[index].el.style.height = `${height}px`;\n }\n };\n\n const renderCurrent = (): void => {\n if (contentVisibility) {\n rows.sync(items);\n for (let index = 0; index < rows.order.length; index++) {\n const el = rows.order[index].el;\n el.style.contentVisibility = 'auto';\n el.style.containIntrinsicSize = `0 ${intrinsicSizeAt(index)}px`;\n }\n return;\n }\n\n const total = items.length;\n let start: number;\n let end: number;\n let padTop: number;\n let padBottom: number;\n if (minRows !== undefined && total < minRows) {\n if (fixedHeight === null && heightsDirty) {\n rebuildOffsets();\n heightsDirty = false;\n }\n start = 0;\n end = total;\n padTop = 0;\n padBottom = 0;\n } else if (fixedHeight !== null) {\n const viewportBottom = parent.scrollTop + parent.clientHeight;\n start = Math.max(0,Math.floor(parent.scrollTop / fixedHeight) - overscan);\n end = Math.min(total,Math.ceil(viewportBottom / fixedHeight) + overscan);\n padTop = start * fixedHeight;\n padBottom = Math.max(0,total - end) * fixedHeight;\n } else {\n if (heightsDirty) {\n rebuildOffsets();\n heightsDirty = false;\n }\n const viewportBottom = parent.scrollTop + parent.clientHeight;\n start = Math.max(0,findStart(parent.scrollTop,total) - overscan);\n end = Math.min(total,findEnd(viewportBottom,total) + overscan);\n padTop = offsets[start];\n padBottom = offsets[total] - offsets[end];\n }\n rows.sync(items.slice(start,end));\n sizeRows(start);\n container.style.paddingTop = `${padTop}px`;\n container.style.paddingBottom = `${padBottom}px`;\n for (const callback of renderSubscribers) callback();\n };\n\n const render = (nextItems: readonly T[]): void => {\n items = nextItems;\n heightsDirty = true;\n renderCurrent();\n };\n\n const scheduleRender = (): void => {\n if (rafPending) return;\n rafPending = true;\n globalThis.requestAnimationFrame(() => {\n rafPending = false;\n if (disposed) return;\n if (pendingAnchorDelta !== 0) {\n parent.scrollTop += pendingAnchorDelta;\n pendingAnchorDelta = 0;\n }\n renderCurrent();\n });\n };\n\n const resizeObserver = !contentVisibility && globalThis.ResizeObserver !== undefined\n ? new globalThis.ResizeObserver(scheduleRender)\n : undefined;\n\n const start = (): void => {\n if (contentVisibility) return;\n parent.addEventListener('scroll',scheduleRender);\n resizeObserver?.observe(parent);\n };\n\n const setHeight = (rowKey: ListKey,height: number): void => {\n if (!measuring || contentVisibility) return;\n const index = indexByKey.get(rowKey);\n if (index === undefined) return;\n const oldHeight = measured.get(rowKey) ?? estimateAt(index);\n if (height === oldHeight) return;\n measured.set(rowKey,height);\n if (offsets[index + 1] <= parent.scrollTop) pendingAnchorDelta += height - oldHeight;\n heightsDirty = true;\n scheduleRender();\n };\n\n const onRender = (callback: () => void): (() => void) => {\n renderSubscribers.add(callback);\n return () => renderSubscribers.delete(callback);\n };\n\n const dispose = (): void => {\n disposed = true;\n parent.removeEventListener('scroll',scheduleRender);\n resizeObserver?.disconnect();\n renderSubscribers.clear();\n };\n\n return { contentVisibility,render,start,setHeight,onRender,dispose };\n}\n","/**\n * `kerfjs/list` — `bindList`, a keyed list with a live per-row mount and\n * optional viewport virtualization.\n *\n * This is a DELIBERATE second list API, distinct from `each()`. It does two\n * things `each()` structurally cannot:\n * 1. **Per-row reactivity.** Every row is individually `mount()`ed, so a signal\n * the row's `render` reads updates just that row (fine-grained binding or a\n * one-row morph) without touching its siblings — no full-list pass.\n * 2. **Virtualization.** With `{ virtualize: { rowHeight } }` only the rows in\n * the scroll viewport are rendered; padding on the scroll container keeps\n * `scrollHeight` honest. `rowHeight` is a fixed `number` (O(1) windowing), a\n * `(item, index) => number` for **app-declared variable** heights (a prefix\n * sum + binary-search window), or `{ estimate }` for **measured** heights —\n * the app reports real heights via the returned handle's `setHeight` (or the\n * `observeRowHeights` helper) and kerf anchor-corrects `scrollTop`. See\n * `docs/17-list-virtualization.md`.\n *\n * `each()` stays the choice for item-owned-state lists rendered to HTML strings;\n * reach for `bindList` when you need surgical per-row updates or windowing.\n *\n * import { bindList } from 'kerfjs/list';\n *\n * const dispose = bindList(listEl, itemsSignal, {\n * key: (row) => row.id,\n * render: (row) => <span class={selected} data-id={row.id}>{row.label}</span>,\n * tag: 'li',\n * virtualize: { rowHeight: 32 },\n * });\n *\n * `render` reads signals for reactivity (external state like a `selectedId`, or\n * signals the item carries) — keep the item OBJECTS stable across renders and\n * drive structure (add/remove/move) through `itemsSignal`. A row whose item\n * object identity changes is rebuilt (same rule as `each()`'s memo). `bindList`\n * OWNS `parent`'s children by default (append/move to the end) — to share\n * `parent` with fixed trailing siblings (an \"add\" button, an indicator), pass\n * `before` so the rows end just before that node. It reads `itemsSignal.value`,\n * so a plain `signal<T[]>` or an `arraySignal<T>` both work.\n */\nimport { ARRAY_SIGNAL_BRAND, type ArrayPatch } from './array-signal.js';\nimport { createListRowController } from './list-row-controller.js';\nimport { createListVirtualizationController } from './list-virtualization-controller.js';\nimport type { MountResult } from './mount.js';\nimport { effect } from './reactive.js';\n\nconst NOOP = (): void => { /* intentional no-op */ };\n\n/** A row's stable key. */\nexport type ListKey = string | number;\n\n/** Anything with a tracking `.value` array read — a `signal<readonly T[]>` or an `arraySignal<T>`. */\nexport interface ListSource<T> {\n readonly value: readonly T[];\n}\n\n/**\n * A row built imperatively by `render`: return the row **element** itself (kerf\n * keys/moves/reuses it and owns nothing inside it), or `{ el, update?, dispose? }`\n * to also hand back an `update(item)` — called on the SAME element when the row's\n * key persists but its item changes — and a `dispose` that runs only when the row\n * is removed.\n */\nexport type RowElement<T> =\n | HTMLElement\n | { el: HTMLElement; update?: (item: T) => void; dispose?: () => void };\n\n/**\n * The virtualization height model:\n * - **`number`** — every row is this fixed pixel height (O(1) windowing).\n * - **`(item, index) => number`** — app-declared **variable** heights, derived\n * purely from the item and its index.\n * - **`{ estimate }`** — **measured** heights: kerf uses `estimate` for a row\n * until the app reports its real height through {@link BindListHandle.setHeight}\n * (or the `observeRowHeights` helper). See `docs/17-list-virtualization.md`.\n */\nexport type RowHeight<T> =\n | number\n | ((item: T, index: number) => number)\n | { estimate: number | ((item: T, index: number) => number) };\n\n/**\n * The value {@link bindList} returns: a disposer you call to tear the list down,\n * augmented with `setHeight` for the **measured** virtualization mode.\n */\nexport type BindListHandle = (() => void) & {\n /**\n * Report a row's real pixel height (measured after layout) for\n * `virtualize: { rowHeight: { estimate } }` lists. Keyed by the list `key`, so\n * a report survives reorders. kerf recomputes the window and, if the row sits\n * ABOVE the viewport, anchor-corrects `scrollTop` so content doesn't jump.\n * A no-op for fixed / declared-height lists and for unknown keys.\n */\n setHeight: (key: ListKey, height: number) => void;\n /**\n * The inner container element kerf creates to hold the rows in a **virtualized**\n * list (the \"sizer\"). `undefined` for a non-virtualized list (there the rows\n * live directly in `parent`). Use it to style, id, or otherwise reach the row\n * block without guessing at `parent.lastElementChild` — though `containerClass`\n * / `containerId` on `virtualize` set those declaratively.\n */\n container?: HTMLElement;\n};\n\n/** Options for {@link bindList}. */\nexport interface BindListOptions<T> {\n /** Stable, unique per-row key. Duplicate keys are rejected before DOM mutation. */\n key: (item: T) => ListKey;\n /**\n * Build a row. Two modes, chosen per call by what you return:\n * - **Content mode** (a `MountResult` — JSX / `SafeHtml`): kerf creates the\n * row element (`tag`) and `mount()`s your content inside it, so signals your\n * content reads drive per-row reactivity.\n * - **Element mode** (an `HTMLElement`, or `{ el, update?, dispose? }`): the\n * element you return IS the row, so you own its tag, class, `data-*`, and\n * listeners. kerf **keys/moves/reuses** it — the SAME element survives an\n * append/remove/reorder or a fresh item object at the same key. Refresh its\n * content by reading signals inside it, or by returning an `update(item)`\n * that kerf calls on the existing element when the item changes. `dispose`\n * runs only when the row is genuinely removed.\n */\n render: (item: T) => MountResult | RowElement<T>;\n /** Row element tag for **content mode**. Default `'div'` (use `'li'` inside a `<ul>`, `'tr'` inside a `<tbody>`, …). Ignored in element mode. */\n tag?: string;\n /**\n * Keep the rows as a contiguous block that ENDS just before this node, instead\n * of at the very end of `parent`. Use it when `parent` also holds non-row\n * siblings that must stay put — a trailing \"add\" button, a sliding indicator:\n * `before: () => addButton`. The node (a function is re-read each reconcile, or\n * pass the node directly) must be a child of `parent`. Without it, bindList\n * assumes exclusive ownership and appends rows to the end. Ignored when\n * virtualized (the rows own bindList's inner sizer exclusively).\n */\n before?: Node | (() => Node | null);\n /**\n * Turn on viewport virtualization. `parent` must be a scroll container (your\n * CSS: a fixed height + `overflow: auto`). `overscan` (default 3) is how many\n * extra rows to render above and below the viewport.\n *\n * `rowHeight` (a {@link RowHeight}) is the height model:\n * - **`number`** — every row is this fixed pixel height. O(1) windowing, no\n * cumulative model built.\n * - **`(item, index) => number`** — app-declared **variable** heights, derived\n * purely from the item and its index. kerf builds a prefix sum of the\n * heights (rebuilt when the source array changes, not per scroll frame) and\n * binary-searches it to find the visible window. Return a non-negative\n * number of pixels.\n * - **`{ estimate }`** — **measured** heights for rows whose height is only\n * known after layout. kerf sizes an unmeasured row by `estimate` (a number\n * or an `(item, index) => number`), and the app reports each row's real\n * height via {@link BindListHandle.setHeight} (or the `observeRowHeights`\n * helper). kerf anchor-corrects `scrollTop` when an above-viewport row is\n * remeasured, so content doesn't jump.\n *\n * `minRows` renders **every** row (no windowing, zero padding) while the list\n * is shorter than it, and windows only at or above it — the DOM structure (the\n * inner container) is the same either way, so the call site never branches. A\n * fully-rendered short list is friendlier to find-in-page, screen readers, and\n * DOM-count assertions, which only see rows actually in the DOM.\n *\n * `containerClass` / `containerId` are set on the inner container kerf creates\n * to hold the rows, so it's reachable from CSS and tests without guessing at\n * `parent.lastElementChild` (it's also on the handle as `handle.container`).\n *\n * kerf re-windows on `parent`'s `scroll` and, where `ResizeObserver` exists, on\n * `parent` resizing — so a list that mounts before layout (a hidden tab,\n * `clientHeight` 0) fills in once it's sized, and a resized container re-windows.\n *\n * `mode` (default `'window'`) picks the virtualization STRATEGY:\n * - **`'window'`** — the JS windowing above: only the visible rows are in the\n * DOM, bounded node count, works on every engine. Off-window rows are removed\n * (see the findability tradeoff below).\n * - **`'content-visibility'`** — **every** row stays in the DOM and kerf sets\n * `content-visibility: auto` + `contain-intrinsic-size: 0 <rowHeight>px` on\n * each one, so a supporting engine (Chromium, Safari 18) skips the *layout /\n * paint* of off-screen rows while keeping them findable. `rowHeight` here is\n * used **only** as the `contain-intrinsic-size` placeholder (scrollbar\n * accuracy before a row is first rendered) — there is no windowing math, no\n * padding, no scroll listener, no anchor correction, and `setHeight` /\n * `observeRowHeights` are **no-ops** (the browser owns real measurement).\n * `minRows` is ignored (all rows already render). On an engine without\n * `content-visibility` the CSS is simply inert — all rows render, correct and\n * fully findable, only without the skip optimization. Choose this mode for\n * medium lists where find-in-page / a11y / anchor links matter more than the\n * node ceiling; keep `'window'` for very large (100k-row) lists.\n *\n * **Findability tradeoff (`'window'` mode).** Off-window rows are removed from\n * the DOM (not merely hidden), so with `mode: 'window'`: **find-in-page\n * (Cmd/Ctrl+F)**, **screen readers / the a11y tree**, and **anchor links /\n * `scrollIntoView`** only reach the visible window — a match, an announced row,\n * or a linked element that has been windowed out isn't in the DOM to find.\n * Convey the true total via ARIA (`aria-rowcount` / `aria-setsize`) if it\n * matters, and use a non-virtualized list — `minRows` above the list length, or\n * `mode: 'content-visibility'` — when full findability matters more than the DOM\n * node ceiling. See `docs/17-list-virtualization.md` §17.10 / §17.11.\n */\n virtualize?: {\n rowHeight: RowHeight<T>;\n overscan?: number;\n minRows?: number;\n containerClass?: string;\n containerId?: string;\n /**\n * Virtualization strategy. `'window'` (default) removes off-window rows from\n * the DOM; `'content-visibility'` keeps every row in the DOM and lets the\n * browser skip off-screen layout/paint (full find-in-page / a11y, at the cost\n * of an unbounded node count). See the option JSDoc above.\n */\n mode?: 'window' | 'content-visibility';\n };\n}\n\n/** Reject a keyed snapshot before reconciliation can alias two rows in the DOM. */\nfunction assertUniqueListKeys<T>(items: readonly T[], key: (item: T) => ListKey): void {\n const firstIndex = new Map<ListKey,number>();\n for (let index = 0; index < items.length; index++) {\n const rowKey = key(items[index]);\n const first = firstIndex.get(rowKey);\n if (first !== undefined) {\n const displayed = typeof rowKey === 'string' ? JSON.stringify(rowKey) : String(rowKey);\n throw new Error(\n `bindList: duplicate key ${displayed} at indices ${first} and ${index} — every row key must be unique.`,\n );\n }\n firstIndex.set(rowKey,index);\n }\n}\n\n/**\n * Bind a keyed, per-row-reactive list to `parent`, driven by `source` (a\n * `signal<readonly T[]>` or an `arraySignal<T>`). Returns a disposer that tears\n * down every row mount, the scroll listener (if virtualized), and the source\n * subscription.\n */\nexport function bindList<T>(\n parent: HTMLElement,\n source: ListSource<T>,\n options: BindListOptions<T>,\n): BindListHandle {\n const { key,render,tag = 'div',virtualize,before } = options;\n let firstRender = true;\n let forceSnapshot = false;\n\n const patchSource = source as {\n [ARRAY_SIGNAL_BRAND]?: boolean;\n _consumePatches?: () => ArrayPatch<T>[];\n };\n const granularEligible = virtualize === undefined && patchSource[ARRAY_SIGNAL_BRAND] === true;\n\n const container = virtualize === undefined ? parent : document.createElement('div');\n if (virtualize !== undefined) {\n if (virtualize.containerClass !== undefined) container.className = virtualize.containerClass;\n if (virtualize.containerId !== undefined) container.id = virtualize.containerId;\n }\n const endAnchor = (): Node | null => {\n if (virtualize !== undefined || before === undefined) return null;\n return (typeof before === 'function' ? before() : before) ?? null;\n };\n\n const rows = createListRowController({ container,key,render,tag,endAnchor });\n const virtualization = virtualize === undefined\n ? undefined\n : createListVirtualizationController({ parent,container,virtualize,key,rows });\n\n const renderItems = (items: readonly T[]): void => {\n if (virtualization !== undefined) {\n virtualization.render(items);\n return;\n }\n if (granularEligible) {\n const patches = patchSource._consumePatches!();\n if (\n !firstRender\n && !forceSnapshot\n && patches.length > 0\n && !patches.some((patch) => patch.type === 'replace')\n ) {\n try {\n rows.applyPatches(patches);\n } catch (error) {\n forceSnapshot = true;\n throw error;\n }\n return;\n }\n }\n rows.sync(items);\n firstRender = false;\n forceSnapshot = false;\n };\n\n const stopEffect = effect(() => {\n const items = source.value;\n try {\n assertUniqueListKeys(items,key);\n } catch (error) {\n if (granularEligible) {\n patchSource._consumePatches!();\n forceSnapshot = true;\n }\n throw error;\n }\n renderItems(items);\n });\n\n if (virtualization !== undefined) {\n parent.appendChild(container);\n virtualization.start();\n }\n\n const dispose = ((): void => {\n stopEffect();\n rows.dispose(virtualization === undefined);\n if (virtualization !== undefined) {\n virtualization.dispose();\n container.remove();\n VIRTUAL_INTERNALS.delete(handle);\n }\n }) as BindListHandle;\n const handle = dispose;\n handle.setHeight = virtualization?.setHeight ?? NOOP;\n\n if (virtualization !== undefined) {\n handle.container = container;\n if (!virtualization.contentVisibility) {\n VIRTUAL_INTERNALS.set(handle,{\n visibleRows: () => rows.order.map((row) => ({ key: key(row.item),el: row.el })),\n onRender: virtualization.onRender,\n });\n }\n }\n\n return handle;\n}\n\n/** Internal coordination surface between {@link bindList} and {@link observeRowHeights}. */\ninterface VirtualInternals {\n /** The current visible rows, in order, with their keys. */\n visibleRows: () => Array<{ key: ListKey; el: HTMLElement }>;\n /** Subscribe to each window render; returns an unsubscribe. */\n onRender: (cb: () => void) => () => void;\n}\n\n// GC-tied (WeakMap) coordination store — a pure cache, not counted against\n// Design rule 5 (same class as `bindings.ts:insertedTextNodes`).\nconst VIRTUAL_INTERNALS = new WeakMap<object, VirtualInternals>();\n\n/**\n * Drive a **measured** virtualized `bindList` (`virtualize: { rowHeight: {\n * estimate } }`) from real layout: install ONE `ResizeObserver` over the visible\n * rows and forward each row's `offsetHeight` to `handle.setHeight`, re-observing\n * as the window shifts. Returns a disposer.\n *\n * This is the batteries-included measurement path; it is deliberately separate\n * from `bindList` (which never depends on `ResizeObserver`) — you can measure\n * however you like and call `handle.setHeight` yourself instead. A no-op for a\n * non-virtualized handle or where `ResizeObserver` is unavailable (SSR).\n *\n * const list = bindList(scrollEl, source, { key, render, virtualize: { rowHeight: { estimate: 64 } } });\n * const stopMeasuring = observeRowHeights(list);\n */\nexport function observeRowHeights(handle: BindListHandle): () => void {\n const internals = VIRTUAL_INTERNALS.get(handle);\n const RO = globalThis.ResizeObserver;\n if (internals === undefined || RO === undefined) return NOOP;\n\n const keyByEl = new WeakMap<Element, ListKey>();\n const observer = new RO((entries) => {\n for (const entry of entries) {\n const k = keyByEl.get(entry.target);\n if (k !== undefined) handle.setHeight(k, (entry.target as HTMLElement).offsetHeight);\n }\n });\n\n const resync = (): void => {\n observer.disconnect();\n for (const { key: k, el } of internals.visibleRows()) {\n keyByEl.set(el, k);\n observer.observe(el);\n }\n };\n\n const unsubscribe = internals.onRender(resync);\n resync(); // observe the initial window\n\n return () => {\n observer.disconnect();\n unsubscribe();\n };\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/list-row-controller.ts","../src/list-virtualization-controller.ts","../src/list.ts"],"names":["dispose","start","NOOP"],"mappings":"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","file":"list.js","sourcesContent":["import type { ArrayPatch } from './array-signal.js';\nimport type { BindListOptions, ListKey, RowElement } from './list.js';\nimport { captureFocus, restoreFocus } from './list-reconcile-focus.js';\nimport { mount, type MountResult } from './mount.js';\nimport { moveNode } from './utils/moveNode.js';\n\ninterface ListRow<T> {\n el: HTMLElement;\n item: T;\n dispose: () => void;\n elementMode: boolean;\n update?: (item: T) => void;\n}\n\nexport interface ListRowController<T> {\n readonly order: Array<ListRow<T>>;\n sync: (visible: readonly T[]) => void;\n applyPatches: (patches: readonly ArrayPatch<T>[]) => void;\n dispose: (removeElements: boolean) => void;\n}\n\ninterface ListRowControllerOptions<T> {\n container: HTMLElement;\n key: (item: T) => ListKey;\n render: BindListOptions<T>['render'];\n tag: string;\n endAnchor: () => Node | null;\n}\n\nconst NOOP = (): void => {\n /* element-mode rows with no caller teardown */\n};\n\n/** Own the keyed row map, DOM order, row lifecycles, and both reconcile paths. */\nexport function createListRowController<T>(\n options: ListRowControllerOptions<T>,\n): ListRowController<T> {\n const { container, key, render, tag, endAnchor } = options;\n const rows = new Map<ListKey, ListRow<T>>();\n const order: Array<ListRow<T>> = [];\n\n const asElementRow = (\n rendered: MountResult | RowElement<T>,\n ): {\n el: HTMLElement;\n dispose: () => void;\n update?: (item: T) => void;\n } | null => {\n if (rendered instanceof HTMLElement) return { el: rendered, dispose: NOOP };\n if (\n rendered !== null &&\n typeof rendered === 'object' &&\n 'el' in rendered &&\n (rendered as { el: unknown }).el instanceof HTMLElement\n ) {\n const row = rendered as {\n el: HTMLElement;\n update?: (item: T) => void;\n dispose?: () => void;\n };\n return { el: row.el, dispose: row.dispose ?? NOOP, update: row.update };\n }\n return null;\n };\n\n const makeRow = (item: T): ListRow<T> => {\n const elementRow = asElementRow(render(item));\n if (elementRow !== null) {\n return {\n el: elementRow.el,\n item,\n dispose: elementRow.dispose,\n elementMode: true,\n update: elementRow.update,\n };\n }\n const el = document.createElement(tag);\n const dispose = mount(el, () => render(item) as MountResult);\n return { el, item, dispose, elementMode: false };\n };\n\n // The single item-replacement contract used by snapshot and granular paths.\n // Element-mode rows keep their caller-owned element and are re-keyed; content\n // rows replace their mount. DOM placement remains the caller's responsibility.\n const reconcileItem = (row: ListRow<T>, item: T): ListRow<T> => {\n if (row.item === item) return row;\n const oldKey = key(row.item);\n const newKey = key(item);\n if (row.elementMode) {\n row.item = item;\n if (newKey !== oldKey) {\n rows.delete(oldKey);\n rows.set(newKey, row);\n }\n row.update?.(item);\n return row;\n }\n row.dispose();\n row.el.remove();\n rows.delete(oldKey);\n const fresh = makeRow(item);\n rows.set(newKey, fresh);\n return fresh;\n };\n\n const preserveFocus = (operation: () => void): void => {\n const focus = captureFocus(container);\n try {\n operation();\n } finally {\n if (focus !== null) restoreFocus(focus);\n }\n };\n\n const sync = (visible: readonly T[]): void => {\n preserveFocus(() => {\n const wanted = new Set<ListKey>();\n for (const item of visible) wanted.add(key(item));\n\n for (const [rowKey, row] of rows) {\n if (!wanted.has(rowKey)) {\n row.dispose();\n row.el.remove();\n rows.delete(rowKey);\n }\n }\n\n order.length = 0;\n for (const item of visible) {\n const rowKey = key(item);\n const existing = rows.get(rowKey);\n const row =\n existing === undefined\n ? makeRow(item)\n : reconcileItem(existing, item);\n if (existing === undefined) rows.set(rowKey, row);\n order.push(row);\n }\n\n let ref: Node | null = endAnchor();\n for (let index = order.length - 1; index >= 0; index--) {\n const el = order[index].el;\n if (el.parentNode !== container || el.nextSibling !== ref)\n moveNode(container, el, ref);\n ref = el;\n }\n });\n };\n\n const applyPatches = (patches: readonly ArrayPatch<T>[]): void => {\n preserveFocus(() => {\n for (const patch of patches) {\n if (patch.type === 'insert') {\n const row = makeRow(patch.item);\n rows.set(key(patch.item), row);\n order.splice(patch.index, 0, row);\n container.insertBefore(\n row.el,\n order[patch.index + 1]?.el ?? endAnchor(),\n );\n } else if (patch.type === 'remove') {\n const [row] = order.splice(patch.index, 1);\n row.dispose();\n row.el.remove();\n rows.delete(key(row.item));\n } else if (patch.type === 'move') {\n const [row] = order.splice(patch.from, 1);\n order.splice(patch.to, 0, row);\n moveNode(container, row.el, order[patch.to + 1]?.el ?? endAnchor());\n } else if (patch.type === 'update') {\n const current = order[patch.index];\n const row = reconcileItem(current, patch.item);\n if (row !== current) {\n order[patch.index] = row;\n container.insertBefore(\n row.el,\n order[patch.index + 1]?.el ?? endAnchor(),\n );\n }\n }\n }\n });\n };\n\n const dispose = (removeElements: boolean): void => {\n for (const row of rows.values()) {\n row.dispose();\n if (removeElements) row.el.remove();\n }\n rows.clear();\n order.length = 0;\n };\n\n return { order, sync, applyPatches, dispose };\n}\n","import type { BindListOptions, ListKey } from './list.js';\nimport type { ListRowController } from './list-row-controller.js';\n\ninterface ListVirtualizationController<T> {\n readonly contentVisibility: boolean;\n render: (items: readonly T[]) => void;\n start: () => void;\n setHeight: (key: ListKey, height: number) => void;\n onRender: (callback: () => void) => () => void;\n dispose: () => void;\n}\n\ninterface ListVirtualizationControllerOptions<T> {\n parent: HTMLElement;\n container: HTMLElement;\n virtualize: NonNullable<BindListOptions<T>['virtualize']>;\n key: (item: T) => ListKey;\n rows: ListRowController<T>;\n}\n\n/** A pixel height: a finite number >= 0 (zero-height rows are allowed). */\nfunction assertHeight(value: unknown, what: string): number {\n if (!(typeof value === 'number' && value >= 0 && value < Infinity))\n throw new RangeError(\n `bindList: ${what} must be a finite height >= 0 (got ${String(value)})`,\n );\n return value;\n}\n\n/** Reject an invalid `virtualize` configuration before any DOM is touched. */\nfunction validateVirtualize<T>(\n virtualize: NonNullable<BindListOptions<T>['virtualize']>,\n): void {\n const { rowHeight, overscan, minRows } = virtualize;\n for (const [name, count] of [\n ['overscan', overscan],\n ['minRows', minRows],\n ] as const) {\n if (count !== undefined && !(Number.isInteger(count) && count >= 0))\n throw new RangeError(\n `bindList: virtualize.${name} must be an integer >= 0 (got ${count})`,\n );\n }\n if (typeof rowHeight === 'number') {\n // Window mode divides by a fixed height; content-visibility only uses it as\n // a placeholder size, where zero is harmless.\n if (\n assertHeight(rowHeight, 'rowHeight') === 0 &&\n virtualize.mode !== 'content-visibility'\n )\n throw new RangeError(\n 'bindList: a fixed rowHeight must be > 0 in window mode',\n );\n } else if (typeof rowHeight !== 'function') {\n const estimate = (rowHeight as { estimate?: unknown } | null)?.estimate;\n if (typeof estimate !== 'function')\n assertHeight(estimate, 'rowHeight.estimate');\n }\n}\n\n/** Own window calculation, height models, scheduling, observers, and CSS strategy. */\nexport function createListVirtualizationController<T>(\n options: ListVirtualizationControllerOptions<T>,\n): ListVirtualizationController<T> {\n const { parent, container, virtualize, key, rows } = options;\n validateVirtualize(virtualize);\n const overscan = virtualize.overscan ?? 3;\n const { minRows, rowHeight } = virtualize;\n const contentVisibility = virtualize.mode === 'content-visibility';\n const fixedHeight = typeof rowHeight === 'number' ? rowHeight : null;\n const measuring = typeof rowHeight === 'object' && rowHeight !== null;\n const measured = new Map<ListKey, number>();\n const indexByKey = new Map<ListKey, number>();\n const renderSubscribers = new Set<() => void>();\n let items: readonly T[] = [];\n let offsets: number[] = [0];\n let heightsDirty = true;\n // Measured-mode anchor correction is resolved at frame time, not at\n // setHeight() time: each key remembers the height it had before its first\n // report this frame, and the frame applies the net change only for keys\n // still in the source AND still above the viewport top. A delta summed at\n // report time went stale when the source removed or reordered the key, or\n // the user scrolled, before the frame ran (KF-FJ40AE).\n const pendingAnchorBaselines = new Map<ListKey, number>();\n let rafPending = false;\n let disposed = false;\n\n const estimateAt = (index: number): number => {\n const estimate = (\n rowHeight as { estimate: number | ((item: T, index: number) => number) }\n ).estimate;\n return typeof estimate === 'function'\n ? assertHeight(\n estimate(items[index], index),\n `rowHeight.estimate(item, ${index})`,\n )\n : estimate;\n };\n const variableHeightAt: ((index: number) => number) | null =\n fixedHeight !== null\n ? null\n : measuring\n ? (index): number =>\n measured.get(key(items[index])) ?? estimateAt(index)\n : (index): number =>\n assertHeight(\n (rowHeight as (item: T, index: number) => number)(\n items[index],\n index,\n ),\n `rowHeight(item, ${index})`,\n );\n const intrinsicSizeAt = (index: number): number =>\n fixedHeight ?? (variableHeightAt as (index: number) => number)(index);\n\n const rebuildOffsets = (): void => {\n const heightAt = variableHeightAt as (index: number) => number;\n offsets = new Array<number>(items.length + 1);\n offsets[0] = 0;\n if (measuring) indexByKey.clear();\n for (let index = 0; index < items.length; index++) {\n offsets[index + 1] = offsets[index] + heightAt(index);\n if (measuring) indexByKey.set(key(items[index]), index);\n }\n if (measuring) {\n for (const rowKey of measured.keys()) {\n if (!indexByKey.has(rowKey)) measured.delete(rowKey);\n }\n for (const rowKey of pendingAnchorBaselines.keys()) {\n if (!indexByKey.has(rowKey)) pendingAnchorBaselines.delete(rowKey);\n }\n }\n };\n\n const findStart = (target: number, total: number): number => {\n let low = 0;\n let high = total;\n while (low < high) {\n const middle = (low + high + 1) >> 1;\n if (offsets[middle] <= target) low = middle;\n else high = middle - 1;\n }\n return low;\n };\n\n const findEnd = (target: number, total: number): number => {\n let low = 0;\n let high = total;\n while (low < high) {\n const middle = (low + high) >> 1;\n if (offsets[middle] >= target) high = middle;\n else low = middle + 1;\n }\n return low;\n };\n\n const sizeRows = (start: number): void => {\n if (measuring) return;\n for (let index = 0; index < rows.order.length; index++) {\n const absoluteIndex = start + index;\n const height =\n fixedHeight ?? offsets[absoluteIndex + 1] - offsets[absoluteIndex];\n rows.order[index].el.style.height = `${height}px`;\n }\n };\n\n const renderCurrent = (): void => {\n if (contentVisibility) {\n rows.sync(items);\n for (let index = 0; index < rows.order.length; index++) {\n const el = rows.order[index].el;\n el.style.contentVisibility = 'auto';\n el.style.containIntrinsicSize = `0 ${intrinsicSizeAt(index)}px`;\n }\n return;\n }\n\n const total = items.length;\n let start: number;\n let end: number;\n let padTop: number;\n let padBottom: number;\n if (minRows !== undefined && total < minRows) {\n if (fixedHeight === null && heightsDirty) {\n rebuildOffsets();\n heightsDirty = false;\n }\n start = 0;\n end = total;\n padTop = 0;\n padBottom = 0;\n } else if (fixedHeight !== null) {\n const viewportBottom = parent.scrollTop + parent.clientHeight;\n // Clamp to `total`: a source that shrinks while scrolled deep (before the\n // browser clamps scrollTop) must not pad past the content (KF-FJ40AE).\n start = Math.min(\n total,\n Math.max(0, Math.floor(parent.scrollTop / fixedHeight) - overscan),\n );\n end = Math.min(total, Math.ceil(viewportBottom / fixedHeight) + overscan);\n padTop = start * fixedHeight;\n padBottom = Math.max(0, total - end) * fixedHeight;\n } else {\n if (heightsDirty) {\n rebuildOffsets();\n heightsDirty = false;\n }\n const viewportBottom = parent.scrollTop + parent.clientHeight;\n start = Math.max(0, findStart(parent.scrollTop, total) - overscan);\n end = Math.min(total, findEnd(viewportBottom, total) + overscan);\n padTop = offsets[start];\n padBottom = offsets[total] - offsets[end];\n }\n rows.sync(items.slice(start, end));\n sizeRows(start);\n container.style.paddingTop = `${padTop}px`;\n container.style.paddingBottom = `${padBottom}px`;\n for (const callback of renderSubscribers) callback();\n };\n\n const render = (nextItems: readonly T[]): void => {\n items = nextItems;\n heightsDirty = true;\n renderCurrent();\n };\n\n const applyAnchorCorrection = (): void => {\n if (heightsDirty) {\n rebuildOffsets();\n heightsDirty = false;\n }\n let delta = 0;\n for (const [rowKey, baseline] of pendingAnchorBaselines) {\n // rebuildOffsets() just pruned every key that left the source.\n const index = indexByKey.get(rowKey) as number;\n if (offsets[index] + baseline <= parent.scrollTop)\n delta += offsets[index + 1] - offsets[index] - baseline;\n }\n pendingAnchorBaselines.clear();\n if (delta !== 0) parent.scrollTop += delta;\n };\n\n const scheduleRender = (): void => {\n if (rafPending) return;\n rafPending = true;\n globalThis.requestAnimationFrame(() => {\n rafPending = false;\n if (disposed) return;\n if (pendingAnchorBaselines.size > 0) applyAnchorCorrection();\n renderCurrent();\n });\n };\n\n const resizeObserver =\n !contentVisibility && globalThis.ResizeObserver !== undefined\n ? new globalThis.ResizeObserver(scheduleRender)\n : undefined;\n\n const start = (): void => {\n if (contentVisibility) return;\n parent.addEventListener('scroll', scheduleRender);\n resizeObserver?.observe(parent);\n };\n\n const setHeight = (rowKey: ListKey, height: number): void => {\n assertHeight(height, 'setHeight()');\n if (!measuring || contentVisibility) return;\n const index = indexByKey.get(rowKey);\n if (index === undefined) return;\n const oldHeight = measured.get(rowKey) ?? estimateAt(index);\n if (height === oldHeight) return;\n measured.set(rowKey, height);\n if (!pendingAnchorBaselines.has(rowKey))\n pendingAnchorBaselines.set(rowKey, oldHeight);\n heightsDirty = true;\n scheduleRender();\n };\n\n const onRender = (callback: () => void): (() => void) => {\n renderSubscribers.add(callback);\n return () => renderSubscribers.delete(callback);\n };\n\n const dispose = (): void => {\n disposed = true;\n parent.removeEventListener('scroll', scheduleRender);\n resizeObserver?.disconnect();\n renderSubscribers.clear();\n };\n\n return { contentVisibility, render, start, setHeight, onRender, dispose };\n}\n","/**\n * `kerfjs/list` — `bindList`, a keyed list with a live per-row mount and\n * optional viewport virtualization.\n *\n * This is a DELIBERATE second list API, distinct from `each()`. It does two\n * things `each()` structurally cannot:\n * 1. **Per-row reactivity.** Every row is individually `mount()`ed, so a signal\n * the row's `render` reads updates just that row (fine-grained binding or a\n * one-row morph) without touching its siblings — no full-list pass.\n * 2. **Virtualization.** With `{ virtualize: { rowHeight } }` only the rows in\n * the scroll viewport are rendered; padding on the scroll container keeps\n * `scrollHeight` honest. `rowHeight` is a fixed `number` (O(1) windowing), a\n * `(item, index) => number` for **app-declared variable** heights (a prefix\n * sum + binary-search window), or `{ estimate }` for **measured** heights —\n * the app reports real heights via the returned handle's `setHeight` (or the\n * `observeRowHeights` helper) and kerf anchor-corrects `scrollTop`. See\n * `docs/17-list-virtualization.md`.\n *\n * `each()` stays the choice for item-owned-state lists rendered to HTML strings;\n * reach for `bindList` when you need surgical per-row updates or windowing.\n *\n * import { bindList } from 'kerfjs/list';\n *\n * const dispose = bindList(listEl, itemsSignal, {\n * key: (row) => row.id,\n * render: (row) => <span class={selected} data-id={row.id}>{row.label}</span>,\n * tag: 'li',\n * virtualize: { rowHeight: 32 },\n * });\n *\n * `render` reads signals for reactivity (external state like a `selectedId`, or\n * signals the item carries) — keep the item OBJECTS stable across renders and\n * drive structure (add/remove/move) through `itemsSignal`. A row whose item\n * object identity changes is rebuilt (same rule as `each()`'s memo). `bindList`\n * OWNS `parent`'s children by default (append/move to the end) — to share\n * `parent` with fixed trailing siblings (an \"add\" button, an indicator), pass\n * `before` so the rows end just before that node. It reads `itemsSignal.value`,\n * so a plain `signal<T[]>` or an `arraySignal<T>` both work.\n */\nimport { ARRAY_SIGNAL_BRAND, type ArrayPatch } from './array-signal.js';\nimport { createListRowController } from './list-row-controller.js';\nimport { createListVirtualizationController } from './list-virtualization-controller.js';\nimport type { MountResult } from './mount.js';\nimport { effect } from './reactive.js';\n\nconst NOOP = (): void => {\n /* intentional no-op */\n};\n\n/** A row's stable key. */\nexport type ListKey = string | number;\n\n/** Anything with a tracking `.value` array read — a `signal<readonly T[]>` or an `arraySignal<T>`. */\nexport interface ListSource<T> {\n readonly value: readonly T[];\n}\n\n/**\n * A row built imperatively by `render`: return the row **element** itself (kerf\n * keys/moves/reuses it and owns nothing inside it), or `{ el, update?, dispose? }`\n * to also hand back an `update(item)` — called on the SAME element when the row's\n * key persists but its item changes — and a `dispose` that runs only when the row\n * is removed.\n */\nexport type RowElement<T> =\n | HTMLElement\n | { el: HTMLElement; update?: (item: T) => void; dispose?: () => void };\n\n/**\n * The virtualization height model:\n * - **`number`** — every row is this fixed pixel height (O(1) windowing).\n * - **`(item, index) => number`** — app-declared **variable** heights, derived\n * purely from the item and its index.\n * - **`{ estimate }`** — **measured** heights: kerf uses `estimate` for a row\n * until the app reports its real height through {@link BindListHandle.setHeight}\n * (or the `observeRowHeights` helper). See `docs/17-list-virtualization.md`.\n */\nexport type RowHeight<T> =\n | number\n | ((item: T, index: number) => number)\n | { estimate: number | ((item: T, index: number) => number) };\n\n/**\n * The value {@link bindList} returns: a disposer you call to tear the list down,\n * augmented with `setHeight` for the **measured** virtualization mode.\n */\nexport type BindListHandle = (() => void) & {\n /**\n * Report a row's real pixel height (measured after layout) for\n * `virtualize: { rowHeight: { estimate } }` lists. Keyed by the list `key`, so\n * a report survives reorders. kerf recomputes the window and, if the row sits\n * ABOVE the viewport, anchor-corrects `scrollTop` so content doesn't jump.\n * A no-op for fixed / declared-height lists and for unknown keys.\n */\n setHeight: (key: ListKey, height: number) => void;\n /**\n * The inner container element kerf creates to hold the rows in a **virtualized**\n * list (the \"sizer\"). `undefined` for a non-virtualized list (there the rows\n * live directly in `parent`). Use it to style, id, or otherwise reach the row\n * block without guessing at `parent.lastElementChild` — though `containerClass`\n * / `containerId` on `virtualize` set those declaratively.\n */\n container?: HTMLElement;\n};\n\n/** Options for {@link bindList}. */\nexport interface BindListOptions<T> {\n /** Stable, unique per-row key. Duplicate keys are rejected before DOM mutation. */\n key: (item: T) => ListKey;\n /**\n * Build a row. Two modes, chosen per call by what you return:\n * - **Content mode** (a `MountResult` — JSX / `SafeHtml`): kerf creates the\n * row element (`tag`) and `mount()`s your content inside it, so signals your\n * content reads drive per-row reactivity.\n * - **Element mode** (an `HTMLElement`, or `{ el, update?, dispose? }`): the\n * element you return IS the row, so you own its tag, class, `data-*`, and\n * listeners. kerf **keys/moves/reuses** it — the SAME element survives an\n * append/remove/reorder or a fresh item object at the same key. Refresh its\n * content by reading signals inside it, or by returning an `update(item)`\n * that kerf calls on the existing element when the item changes. `dispose`\n * runs only when the row is genuinely removed.\n */\n render: (item: T) => MountResult | RowElement<T>;\n /** Row element tag for **content mode**. Default `'div'` (use `'li'` inside a `<ul>`, `'tr'` inside a `<tbody>`, …). Ignored in element mode. */\n tag?: string;\n /**\n * Keep the rows as a contiguous block that ENDS just before this node, instead\n * of at the very end of `parent`. Use it when `parent` also holds non-row\n * siblings that must stay put — a trailing \"add\" button, a sliding indicator:\n * `before: () => addButton`. The node (a function is re-read each reconcile, or\n * pass the node directly) must be a child of `parent`. Without it, bindList\n * assumes exclusive ownership and appends rows to the end. Ignored when\n * virtualized (the rows own bindList's inner sizer exclusively).\n */\n before?: Node | (() => Node | null);\n /**\n * Turn on viewport virtualization. `parent` must be a scroll container (your\n * CSS: a fixed height + `overflow: auto`). `overscan` (default 3) is how many\n * extra rows to render above and below the viewport. Every height must be a\n * finite, non-negative number of pixels (a fixed `rowHeight` must be > 0 in\n * `'window'` mode), and `overscan` / `minRows` non-negative integers; invalid\n * values throw a descriptive `bindList:` error.\n *\n * `rowHeight` (a {@link RowHeight}) is the height model:\n * - **`number`** — every row is this fixed pixel height. O(1) windowing, no\n * cumulative model built.\n * - **`(item, index) => number`** — app-declared **variable** heights, derived\n * purely from the item and its index. kerf builds a prefix sum of the\n * heights (rebuilt when the source array changes, not per scroll frame) and\n * binary-searches it to find the visible window. Return a non-negative\n * number of pixels.\n * - **`{ estimate }`** — **measured** heights for rows whose height is only\n * known after layout. kerf sizes an unmeasured row by `estimate` (a number\n * or an `(item, index) => number`), and the app reports each row's real\n * height via {@link BindListHandle.setHeight} (or the `observeRowHeights`\n * helper). kerf anchor-corrects `scrollTop` when an above-viewport row is\n * remeasured, so content doesn't jump.\n *\n * `minRows` renders **every** row (no windowing, zero padding) while the list\n * is shorter than it, and windows only at or above it — the DOM structure (the\n * inner container) is the same either way, so the call site never branches. A\n * fully-rendered short list is friendlier to find-in-page, screen readers, and\n * DOM-count assertions, which only see rows actually in the DOM.\n *\n * `containerClass` / `containerId` are set on the inner container kerf creates\n * to hold the rows, so it's reachable from CSS and tests without guessing at\n * `parent.lastElementChild` (it's also on the handle as `handle.container`).\n *\n * kerf re-windows on `parent`'s `scroll` and, where `ResizeObserver` exists, on\n * `parent` resizing — so a list that mounts before layout (a hidden tab,\n * `clientHeight` 0) fills in once it's sized, and a resized container re-windows.\n *\n * `mode` (default `'window'`) picks the virtualization STRATEGY:\n * - **`'window'`** — the JS windowing above: only the visible rows are in the\n * DOM, bounded node count, works on every engine. Off-window rows are removed\n * (see the findability tradeoff below).\n * - **`'content-visibility'`** — **every** row stays in the DOM and kerf sets\n * `content-visibility: auto` + `contain-intrinsic-size: 0 <rowHeight>px` on\n * each one, so a supporting engine (Chromium, Safari 18) skips the *layout /\n * paint* of off-screen rows while keeping them findable. `rowHeight` here is\n * used **only** as the `contain-intrinsic-size` placeholder (scrollbar\n * accuracy before a row is first rendered) — there is no windowing math, no\n * padding, no scroll listener, no anchor correction, and `setHeight` /\n * `observeRowHeights` are **no-ops** (the browser owns real measurement).\n * `minRows` is ignored (all rows already render). On an engine without\n * `content-visibility` the CSS is simply inert — all rows render, correct and\n * fully findable, only without the skip optimization. Choose this mode for\n * medium lists where find-in-page / a11y / anchor links matter more than the\n * node ceiling; keep `'window'` for very large (100k-row) lists.\n *\n * **Findability tradeoff (`'window'` mode).** Off-window rows are removed from\n * the DOM (not merely hidden), so with `mode: 'window'`: **find-in-page\n * (Cmd/Ctrl+F)**, **screen readers / the a11y tree**, and **anchor links /\n * `scrollIntoView`** only reach the visible window — a match, an announced row,\n * or a linked element that has been windowed out isn't in the DOM to find.\n * Convey the true total via ARIA (`aria-rowcount` / `aria-setsize`) if it\n * matters, and use a non-virtualized list — `minRows` above the list length, or\n * `mode: 'content-visibility'` — when full findability matters more than the DOM\n * node ceiling. See `docs/17-list-virtualization.md` §17.10 / §17.11.\n */\n virtualize?: {\n rowHeight: RowHeight<T>;\n overscan?: number;\n minRows?: number;\n containerClass?: string;\n containerId?: string;\n /**\n * Virtualization strategy. `'window'` (default) removes off-window rows from\n * the DOM; `'content-visibility'` keeps every row in the DOM and lets the\n * browser skip off-screen layout/paint (full find-in-page / a11y, at the cost\n * of an unbounded node count). See the option JSDoc above.\n */\n mode?: 'window' | 'content-visibility';\n };\n}\n\n/** Reject a keyed snapshot before reconciliation can alias two rows in the DOM. */\nfunction assertUniqueListKeys<T>(\n items: readonly T[],\n key: (item: T) => ListKey,\n): void {\n const firstIndex = new Map<ListKey, number>();\n for (let index = 0; index < items.length; index++) {\n const rowKey = key(items[index]);\n const first = firstIndex.get(rowKey);\n if (first !== undefined) {\n const displayed =\n typeof rowKey === 'string' ? JSON.stringify(rowKey) : String(rowKey);\n throw new Error(\n `bindList: duplicate key ${displayed} at indices ${first} and ${index} — every row key must be unique.`,\n );\n }\n firstIndex.set(rowKey, index);\n }\n}\n\n/**\n * The bound patch-queue consumer of an `arraySignal` source, or `undefined` for\n * a plain signal. A source that carries the `arraySignal` brand but no callable\n * queue (a hand-rolled or mismatched copy) is rejected with an informative error.\n */\nfunction resolvePatchConsumer<T>(\n source: ListSource<T>,\n): (() => ArrayPatch<T>[]) | undefined {\n const branded = source as {\n [ARRAY_SIGNAL_BRAND]?: unknown;\n _consumePatches?: unknown;\n };\n if (branded[ARRAY_SIGNAL_BRAND] !== true) return undefined;\n const consume = branded._consumePatches;\n if (typeof consume !== 'function') {\n throw new TypeError(\n 'bindList: source carries the arraySignal brand but has no _consumePatches() queue',\n );\n }\n return (consume as () => ArrayPatch<T>[]).bind(source);\n}\n\n/**\n * Bind a keyed, per-row-reactive list to `parent`, driven by `source` (a\n * `signal<readonly T[]>` or an `arraySignal<T>`). Returns a disposer that tears\n * down every row mount, the scroll listener (if virtualized), and the source\n * subscription.\n */\nexport function bindList<T>(\n parent: HTMLElement,\n source: ListSource<T>,\n options: BindListOptions<T>,\n): BindListHandle {\n const { key, render, tag = 'div', virtualize, before } = options;\n let firstRender = true;\n let forceSnapshot = false;\n\n // The granular path needs the arraySignal patch queue. Resolve it once, as a\n // bound function, so a branded source without one fails here with a clear\n // message instead of as a generic TypeError on the first render.\n const consumePatches =\n virtualize === undefined ? resolvePatchConsumer(source) : undefined;\n\n const container =\n virtualize === undefined ? parent : document.createElement('div');\n if (virtualize !== undefined) {\n if (virtualize.containerClass !== undefined)\n container.className = virtualize.containerClass;\n if (virtualize.containerId !== undefined)\n container.id = virtualize.containerId;\n }\n const endAnchor = (): Node | null => {\n if (virtualize !== undefined || before === undefined) return null;\n return (typeof before === 'function' ? before() : before) ?? null;\n };\n\n const rows = createListRowController({\n container,\n key,\n render,\n tag,\n endAnchor,\n });\n const virtualization =\n virtualize === undefined\n ? undefined\n : createListVirtualizationController({\n parent,\n container,\n virtualize,\n key,\n rows,\n });\n\n const renderItems = (items: readonly T[]): void => {\n if (virtualization !== undefined) {\n virtualization.render(items);\n return;\n }\n if (consumePatches !== undefined) {\n const patches = consumePatches();\n if (\n !firstRender &&\n !forceSnapshot &&\n patches.length > 0 &&\n !patches.some((patch) => patch.type === 'replace')\n ) {\n try {\n rows.applyPatches(patches);\n } catch (error) {\n forceSnapshot = true;\n throw error;\n }\n return;\n }\n }\n rows.sync(items);\n firstRender = false;\n forceSnapshot = false;\n };\n\n const track = (): void => {\n const items = source.value;\n try {\n assertUniqueListKeys(items, key);\n } catch (error) {\n if (consumePatches !== undefined) {\n consumePatches();\n forceSnapshot = true;\n }\n throw error;\n }\n renderItems(items);\n };\n\n // The first render runs synchronously inside effect(). If it throws, no\n // handle ever reaches the caller, so release every row that pass already\n // created (content mounts, element-mode dispose callbacks, DOM) here — the\n // effect itself is already disposed by effect() — and rethrow the original.\n let stopEffect: () => void;\n try {\n stopEffect = effect(track);\n } catch (error) {\n rows.dispose(true);\n virtualization?.dispose();\n throw error;\n }\n\n if (virtualization !== undefined) {\n parent.appendChild(container);\n virtualization.start();\n }\n\n const dispose = ((): void => {\n stopEffect();\n rows.dispose(virtualization === undefined);\n if (virtualization !== undefined) {\n virtualization.dispose();\n container.remove();\n VIRTUAL_INTERNALS.delete(handle);\n }\n }) as BindListHandle;\n const handle = dispose;\n handle.setHeight = virtualization?.setHeight ?? NOOP;\n\n if (virtualization !== undefined) {\n handle.container = container;\n if (!virtualization.contentVisibility) {\n VIRTUAL_INTERNALS.set(handle, {\n visibleRows: () =>\n rows.order.map((row) => ({ key: key(row.item), el: row.el })),\n onRender: virtualization.onRender,\n });\n }\n }\n\n return handle;\n}\n\n/** Internal coordination surface between {@link bindList} and {@link observeRowHeights}. */\ninterface VirtualInternals {\n /** The current visible rows, in order, with their keys. */\n visibleRows: () => Array<{ key: ListKey; el: HTMLElement }>;\n /** Subscribe to each window render; returns an unsubscribe. */\n onRender: (cb: () => void) => () => void;\n}\n\n// GC-tied (WeakMap) coordination store — a pure cache, not counted against\n// Design rule 5 (same class as `bindings.ts:insertedTextNodes`).\nconst VIRTUAL_INTERNALS = new WeakMap<object, VirtualInternals>();\n\n/**\n * Drive a **measured** virtualized `bindList` (`virtualize: { rowHeight: {\n * estimate } }`) from real layout: install ONE `ResizeObserver` over the visible\n * rows and forward each row's `offsetHeight` to `handle.setHeight`, re-observing\n * as the window shifts. Returns a disposer.\n *\n * This is the batteries-included measurement path; it is deliberately separate\n * from `bindList` (which never observes rows; its only `ResizeObserver` use is\n * an optional observer on the scroll parent that re-windows on resize) — you\n * can measure however you like and call `handle.setHeight` yourself instead. A no-op for a\n * non-virtualized handle or where `ResizeObserver` is unavailable (SSR).\n *\n * const list = bindList(scrollEl, source, { key, render, virtualize: { rowHeight: { estimate: 64 } } });\n * const stopMeasuring = observeRowHeights(list);\n */\nexport function observeRowHeights(handle: BindListHandle): () => void {\n const internals = VIRTUAL_INTERNALS.get(handle);\n const RO = globalThis.ResizeObserver;\n if (internals === undefined || RO === undefined) return NOOP;\n\n const keyByEl = new WeakMap<Element, ListKey>();\n const observer = new RO((entries) => {\n for (const entry of entries) {\n const k = keyByEl.get(entry.target);\n if (k !== undefined)\n handle.setHeight(k, (entry.target as HTMLElement).offsetHeight);\n }\n });\n\n const resync = (): void => {\n observer.disconnect();\n for (const { key: k, el } of internals.visibleRows()) {\n keyByEl.set(el, k);\n observer.observe(el);\n }\n };\n\n const unsubscribe = internals.onRender(resync);\n resync(); // observe the initial window\n\n return () => {\n observer.disconnect();\n unsubscribe();\n };\n}\n"]}
|
package/dist/overlay.d.ts
CHANGED
|
@@ -26,7 +26,11 @@ interface AnchorPositionOptions {
|
|
|
26
26
|
* One-shot: position `el` relative to `anchor` — below by default, flipping above
|
|
27
27
|
* if it would overflow the viewport, aligned to a horizontal edge and clamped into
|
|
28
28
|
* view. Sets `el.style` `position: fixed`, `margin: 0`, `left`, and `top` (fixed so
|
|
29
|
-
* `left`/`top` are viewport coordinates, matching `getBoundingClientRect`).
|
|
29
|
+
* `left`/`top` are viewport coordinates, matching `getBoundingClientRect`). When an
|
|
30
|
+
* ancestor makes itself the containing block for fixed descendants (a
|
|
31
|
+
* `transform`, `filter`, `perspective`, or `contain` on a wrapping `<dialog>`),
|
|
32
|
+
* `left`/`top` are translated (and unscaled) into that box's coordinates so `el`
|
|
33
|
+
* still lands next to the anchor. This is
|
|
30
34
|
* `popover()`'s placement core, usable on any element (an inline hint, a tooltip) —
|
|
31
35
|
* no overlay lifecycle. Pair with {@link autoReposition} to keep it glued while open.
|
|
32
36
|
*/
|
|
@@ -39,28 +43,6 @@ declare function positionAnchored(el: HTMLElement, anchor: Element, options?: An
|
|
|
39
43
|
*/
|
|
40
44
|
declare function autoReposition(el: HTMLElement, anchor: Element, options?: AnchorPositionOptions): () => void;
|
|
41
45
|
|
|
42
|
-
/**
|
|
43
|
-
* Internal overlay / popover / tooltip lifecycle implementation.
|
|
44
|
-
*
|
|
45
|
-
* Every real kerf app hand-rolls this: `toElement → body.appendChild → mount →
|
|
46
|
-
* wire dismissal → remove`, plus the fiddly parts (Escape, backdrop / outside
|
|
47
|
-
* click, focus trap, restoring focus on close). `window.confirm` is a no-op in
|
|
48
|
-
* Tauri WKWebViews, so a hand-built overlay is mandatory there. This subpath
|
|
49
|
-
* blesses the pattern as three functions over `mount()` — `overlay()`, and the
|
|
50
|
-
* `confirm()` / `toast()` conveniences built on it. No per-instance framework
|
|
51
|
-
* state: each call owns its DOM + listeners in a closure and returns a handle.
|
|
52
|
-
*
|
|
53
|
-
* import { overlay, confirm, toast } from 'kerfjs/overlay';
|
|
54
|
-
*
|
|
55
|
-
* const ok = await confirm('Delete this file?', { danger: true });
|
|
56
|
-
* toast('Saved');
|
|
57
|
-
* const dialog = overlay(<Settings />, { dismiss: ['escape', 'backdrop'] });
|
|
58
|
-
* // …later: dialog.close(); or await dialog.result;
|
|
59
|
-
*
|
|
60
|
-
* Structural only — kerf ships no CSS. The wrapper gets your `className`; style
|
|
61
|
-
* the backdrop / centering / animation yourself.
|
|
62
|
-
*/
|
|
63
|
-
|
|
64
46
|
/** A user-initiated dismissal trigger. */
|
|
65
47
|
type DismissTrigger = 'escape' | 'backdrop' | 'outside';
|
|
66
48
|
/** Content for an overlay: static `SafeHtml`, or a render function `mount()` drives reactively. */
|
|
@@ -127,12 +109,23 @@ interface OverlayHandle {
|
|
|
127
109
|
* it, wire the requested dismissals + (optionally) a focus trap, and return a
|
|
128
110
|
* handle. Concurrent fallback overlays dismiss from the top down. See
|
|
129
111
|
* {@link OverlayOptions}.
|
|
112
|
+
*
|
|
113
|
+
* Construction is transactional: a malformed `initialFocus` selector throws a
|
|
114
|
+
* descriptive error before anything is touched, and if a later setup phase
|
|
115
|
+
* throws (the content's first render, `showModal()` / `showPopover()`), every
|
|
116
|
+
* piece already installed — wrapper node, mount, listeners, fallback-stack
|
|
117
|
+
* entry, top-layer state, moved focus — is rolled back before the original
|
|
118
|
+
* error is rethrown.
|
|
130
119
|
*/
|
|
131
120
|
declare function overlay(content: OverlayContent, options?: OverlayOptions): OverlayHandle;
|
|
132
|
-
|
|
133
121
|
/** Options for {@link popover}. */
|
|
134
122
|
interface PopoverOptions {
|
|
135
|
-
/**
|
|
123
|
+
/**
|
|
124
|
+
* Where to append the popover wrapper. Default: when `anchor` sits inside an
|
|
125
|
+
* open modal `<dialog>`, that dialog's `[data-kerf-overlay-host]` element (a
|
|
126
|
+
* dialog kerf opened gets one automatically), so the popover is part of the
|
|
127
|
+
* modal subtree and stays interactive; otherwise `document.body`.
|
|
128
|
+
*/
|
|
136
129
|
container?: Element;
|
|
137
130
|
/** Class on the wrapper. Default `'kerf-popover'`. */
|
|
138
131
|
className?: string;
|
|
@@ -176,7 +169,7 @@ declare function popover(anchor: Element, content: OverlayContent, options?: Pop
|
|
|
176
169
|
type TooltipContent = string | SafeHtml | (() => MountResult);
|
|
177
170
|
/** Options for {@link tooltip}. */
|
|
178
171
|
interface TooltipOptions extends AnchorPositionOptions {
|
|
179
|
-
/** Where to append the tooltip wrapper. Default `document.body`. */
|
|
172
|
+
/** Where to append the tooltip wrapper. Default: the anchor's modal-dialog host slot (see {@link PopoverOptions.container}), else `document.body`. */
|
|
180
173
|
container?: Element;
|
|
181
174
|
/** Class on the wrapper. Default `'kerf-tooltip'`. */
|
|
182
175
|
className?: string;
|
|
@@ -252,9 +245,13 @@ interface ConfirmOptions {
|
|
|
252
245
|
/** A promise-based `window.confirm` replacement. */
|
|
253
246
|
declare function confirm(message: string, options?: ConfirmOptions): Promise<boolean>;
|
|
254
247
|
|
|
255
|
-
/**
|
|
248
|
+
/**
|
|
249
|
+
* Validate a single field's value, synchronously: return a non-empty message
|
|
250
|
+
* to block OK, anything else to accept. A validator that throws is treated as
|
|
251
|
+
* a programming error — the dialog closes and the returned promise rejects
|
|
252
|
+
* with that error.
|
|
253
|
+
*/
|
|
256
254
|
type FieldValidator = (value: string) => string | null | undefined | void;
|
|
257
|
-
/** Options for {@link prompt}. */
|
|
258
255
|
interface PromptOptions {
|
|
259
256
|
container?: Element;
|
|
260
257
|
className?: string;
|