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
package/dist/list.js
CHANGED
|
@@ -1,226 +1,224 @@
|
|
|
1
|
-
import { ARRAY_SIGNAL_BRAND } from './chunk-
|
|
2
|
-
import { moveNode, mount } from './chunk-
|
|
3
|
-
import './chunk-QIP723L4.js';
|
|
4
|
-
import './chunk-YHH7OUFA.js';
|
|
5
|
-
import './chunk-SUPUPSBE.js';
|
|
6
|
-
import { effect } from './chunk-3APBEVHF.js';
|
|
7
|
-
import './chunk-GY4XV2UV.js';
|
|
8
|
-
import './chunk-VVDJLWMP.js';
|
|
1
|
+
import { ARRAY_SIGNAL_BRAND } from './chunk-ELXVRKY2.js';
|
|
2
|
+
import { captureFocus, restoreFocus, moveNode, mount } from './chunk-V757BT6U.js';
|
|
9
3
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
import { effect } from './chunk-Y2FOYPBV.js';
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
// src/list-row-controller.ts
|
|
11
|
+
var NOOP = () => {
|
|
12
|
+
};
|
|
13
|
+
function createListRowController(options) {
|
|
14
|
+
const { container, key, render, tag, endAnchor } = options;
|
|
20
15
|
const rows = /* @__PURE__ */ new Map();
|
|
21
16
|
const order = [];
|
|
22
|
-
let items = [];
|
|
23
|
-
let disposed = false;
|
|
24
|
-
let rafPending = false;
|
|
25
|
-
let firstRender = true;
|
|
26
|
-
const patchSource = source;
|
|
27
|
-
const granularEligible = virtualize === void 0 && patchSource[ARRAY_SIGNAL_BRAND] === true;
|
|
28
|
-
const container = virtualize === void 0 ? parent : document.createElement("div");
|
|
29
|
-
if (virtualize !== void 0) {
|
|
30
|
-
if (virtualize.containerClass !== void 0) container.className = virtualize.containerClass;
|
|
31
|
-
if (virtualize.containerId !== void 0) container.id = virtualize.containerId;
|
|
32
|
-
parent.appendChild(container);
|
|
33
|
-
}
|
|
34
|
-
const NOOP = () => {
|
|
35
|
-
};
|
|
36
17
|
const asElementRow = (rendered) => {
|
|
37
18
|
if (rendered instanceof HTMLElement) return { el: rendered, dispose: NOOP };
|
|
38
19
|
if (rendered !== null && typeof rendered === "object" && "el" in rendered && rendered.el instanceof HTMLElement) {
|
|
39
|
-
const
|
|
40
|
-
return { el:
|
|
20
|
+
const row = rendered;
|
|
21
|
+
return { el: row.el, dispose: row.dispose ?? NOOP, update: row.update };
|
|
41
22
|
}
|
|
42
23
|
return null;
|
|
43
24
|
};
|
|
44
25
|
const makeRow = (item) => {
|
|
45
26
|
const elementRow = asElementRow(render(item));
|
|
46
27
|
if (elementRow !== null) {
|
|
47
|
-
return {
|
|
28
|
+
return {
|
|
29
|
+
el: elementRow.el,
|
|
30
|
+
item,
|
|
31
|
+
dispose: elementRow.dispose,
|
|
32
|
+
elementMode: true,
|
|
33
|
+
update: elementRow.update
|
|
34
|
+
};
|
|
48
35
|
}
|
|
49
36
|
const el = document.createElement(tag);
|
|
50
37
|
const dispose2 = mount(el, () => render(item));
|
|
51
38
|
return { el, item, dispose: dispose2, elementMode: false };
|
|
52
39
|
};
|
|
53
|
-
const reconcileItem = (row,
|
|
40
|
+
const reconcileItem = (row, item) => {
|
|
54
41
|
if (row.item === item) return row;
|
|
42
|
+
const oldKey = key(row.item);
|
|
43
|
+
const newKey = key(item);
|
|
55
44
|
if (row.elementMode) {
|
|
56
45
|
row.item = item;
|
|
46
|
+
if (newKey !== oldKey) {
|
|
47
|
+
rows.delete(oldKey);
|
|
48
|
+
rows.set(newKey, row);
|
|
49
|
+
}
|
|
57
50
|
row.update?.(item);
|
|
58
51
|
return row;
|
|
59
52
|
}
|
|
60
53
|
row.dispose();
|
|
61
54
|
row.el.remove();
|
|
62
|
-
rows.delete(
|
|
55
|
+
rows.delete(oldKey);
|
|
63
56
|
const fresh = makeRow(item);
|
|
64
|
-
rows.set(
|
|
57
|
+
rows.set(newKey, fresh);
|
|
65
58
|
return fresh;
|
|
66
59
|
};
|
|
67
|
-
const
|
|
68
|
-
const
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
row.el.remove();
|
|
74
|
-
rows.delete(k);
|
|
75
|
-
}
|
|
60
|
+
const preserveFocus = (operation) => {
|
|
61
|
+
const focus = captureFocus(container);
|
|
62
|
+
try {
|
|
63
|
+
operation();
|
|
64
|
+
} finally {
|
|
65
|
+
if (focus !== null) restoreFocus(focus);
|
|
76
66
|
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
const
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
67
|
+
};
|
|
68
|
+
const sync = (visible) => {
|
|
69
|
+
preserveFocus(() => {
|
|
70
|
+
const wanted = /* @__PURE__ */ new Set();
|
|
71
|
+
for (const item of visible) wanted.add(key(item));
|
|
72
|
+
for (const [rowKey, row] of rows) {
|
|
73
|
+
if (!wanted.has(rowKey)) {
|
|
74
|
+
row.dispose();
|
|
75
|
+
row.el.remove();
|
|
76
|
+
rows.delete(rowKey);
|
|
77
|
+
}
|
|
87
78
|
}
|
|
88
|
-
order.
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
79
|
+
order.length = 0;
|
|
80
|
+
for (const item of visible) {
|
|
81
|
+
const rowKey = key(item);
|
|
82
|
+
const existing = rows.get(rowKey);
|
|
83
|
+
const row = existing === void 0 ? makeRow(item) : reconcileItem(existing, item);
|
|
84
|
+
if (existing === void 0) rows.set(rowKey, row);
|
|
85
|
+
order.push(row);
|
|
95
86
|
}
|
|
96
|
-
ref =
|
|
97
|
-
|
|
87
|
+
let ref = endAnchor();
|
|
88
|
+
for (let index = order.length - 1; index >= 0; index--) {
|
|
89
|
+
const el = order[index].el;
|
|
90
|
+
if (el.parentNode !== container || el.nextSibling !== ref)
|
|
91
|
+
moveNode(container, el, ref);
|
|
92
|
+
ref = el;
|
|
93
|
+
}
|
|
94
|
+
});
|
|
98
95
|
};
|
|
99
96
|
const applyPatches = (patches) => {
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
rows.delete(oldKey);
|
|
124
|
-
rows.set(newKey, current);
|
|
125
|
-
}
|
|
126
|
-
current.update?.(patch.item);
|
|
127
|
-
} else {
|
|
128
|
-
current.dispose();
|
|
129
|
-
current.el.remove();
|
|
130
|
-
rows.delete(key(current.item));
|
|
131
|
-
const row = makeRow(patch.item);
|
|
132
|
-
rows.set(key(patch.item), row);
|
|
97
|
+
preserveFocus(() => {
|
|
98
|
+
for (const patch of patches) {
|
|
99
|
+
if (patch.type === "insert") {
|
|
100
|
+
const row = makeRow(patch.item);
|
|
101
|
+
rows.set(key(patch.item), row);
|
|
102
|
+
order.splice(patch.index, 0, row);
|
|
103
|
+
container.insertBefore(
|
|
104
|
+
row.el,
|
|
105
|
+
order[patch.index + 1]?.el ?? endAnchor()
|
|
106
|
+
);
|
|
107
|
+
} else if (patch.type === "remove") {
|
|
108
|
+
const [row] = order.splice(patch.index, 1);
|
|
109
|
+
row.dispose();
|
|
110
|
+
row.el.remove();
|
|
111
|
+
rows.delete(key(row.item));
|
|
112
|
+
} else if (patch.type === "move") {
|
|
113
|
+
const [row] = order.splice(patch.from, 1);
|
|
114
|
+
order.splice(patch.to, 0, row);
|
|
115
|
+
moveNode(container, row.el, order[patch.to + 1]?.el ?? endAnchor());
|
|
116
|
+
} else if (patch.type === "update") {
|
|
117
|
+
const current = order[patch.index];
|
|
118
|
+
const row = reconcileItem(current, patch.item);
|
|
119
|
+
if (row !== current) {
|
|
133
120
|
order[patch.index] = row;
|
|
134
|
-
container.insertBefore(
|
|
121
|
+
container.insertBefore(
|
|
122
|
+
row.el,
|
|
123
|
+
order[patch.index + 1]?.el ?? endAnchor()
|
|
124
|
+
);
|
|
135
125
|
}
|
|
136
126
|
}
|
|
137
127
|
}
|
|
128
|
+
});
|
|
129
|
+
};
|
|
130
|
+
const dispose = (removeElements) => {
|
|
131
|
+
for (const row of rows.values()) {
|
|
132
|
+
row.dispose();
|
|
133
|
+
if (removeElements) row.el.remove();
|
|
138
134
|
}
|
|
135
|
+
rows.clear();
|
|
136
|
+
order.length = 0;
|
|
139
137
|
};
|
|
140
|
-
|
|
138
|
+
return { order, sync, applyPatches, dispose };
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// src/list-virtualization-controller.ts
|
|
142
|
+
function createListVirtualizationController(options) {
|
|
143
|
+
const { parent, container, virtualize, key, rows } = options;
|
|
144
|
+
const overscan = virtualize.overscan ?? 3;
|
|
145
|
+
const { minRows, rowHeight } = virtualize;
|
|
146
|
+
const contentVisibility = virtualize.mode === "content-visibility";
|
|
141
147
|
const fixedHeight = typeof rowHeight === "number" ? rowHeight : null;
|
|
142
148
|
const measuring = typeof rowHeight === "object" && rowHeight !== null;
|
|
143
149
|
const measured = /* @__PURE__ */ new Map();
|
|
144
|
-
const
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
};
|
|
148
|
-
const variableHeightAt = fixedHeight !== null ? null : measuring ? (index) => {
|
|
149
|
-
const k = key(items[index]);
|
|
150
|
-
return measured.has(k) ? measured.get(k) : estimateAt(index);
|
|
151
|
-
} : (index) => rowHeight(items[index], index);
|
|
152
|
-
const intrinsicSizeAt = (index) => fixedHeight !== null ? fixedHeight : variableHeightAt(index);
|
|
150
|
+
const indexByKey = /* @__PURE__ */ new Map();
|
|
151
|
+
const renderSubscribers = /* @__PURE__ */ new Set();
|
|
152
|
+
let items = [];
|
|
153
153
|
let offsets = [0];
|
|
154
154
|
let heightsDirty = true;
|
|
155
|
-
const indexByKey = /* @__PURE__ */ new Map();
|
|
156
155
|
let pendingAnchorDelta = 0;
|
|
156
|
+
let rafPending = false;
|
|
157
|
+
let disposed = false;
|
|
158
|
+
const estimateAt = (index) => {
|
|
159
|
+
const estimate = rowHeight.estimate;
|
|
160
|
+
return typeof estimate === "function" ? estimate(items[index], index) : estimate;
|
|
161
|
+
};
|
|
162
|
+
const variableHeightAt = fixedHeight !== null ? null : measuring ? (index) => measured.get(key(items[index])) ?? estimateAt(index) : (index) => rowHeight(
|
|
163
|
+
items[index],
|
|
164
|
+
index
|
|
165
|
+
);
|
|
166
|
+
const intrinsicSizeAt = (index) => fixedHeight ?? variableHeightAt(index);
|
|
157
167
|
const rebuildOffsets = () => {
|
|
158
|
-
const
|
|
159
|
-
|
|
160
|
-
offsets = new Array(total + 1);
|
|
168
|
+
const heightAt = variableHeightAt;
|
|
169
|
+
offsets = new Array(items.length + 1);
|
|
161
170
|
offsets[0] = 0;
|
|
162
171
|
if (measuring) indexByKey.clear();
|
|
163
|
-
for (let
|
|
164
|
-
offsets[
|
|
165
|
-
if (measuring) indexByKey.set(key(items[
|
|
172
|
+
for (let index = 0; index < items.length; index++) {
|
|
173
|
+
offsets[index + 1] = offsets[index] + heightAt(index);
|
|
174
|
+
if (measuring) indexByKey.set(key(items[index]), index);
|
|
166
175
|
}
|
|
167
176
|
if (measuring) {
|
|
168
|
-
for (const
|
|
177
|
+
for (const rowKey of measured.keys()) {
|
|
178
|
+
if (!indexByKey.has(rowKey)) measured.delete(rowKey);
|
|
179
|
+
}
|
|
169
180
|
}
|
|
170
181
|
};
|
|
171
182
|
const findStart = (target, total) => {
|
|
172
|
-
let
|
|
173
|
-
let
|
|
174
|
-
while (
|
|
175
|
-
const
|
|
176
|
-
if (offsets[
|
|
177
|
-
else
|
|
183
|
+
let low = 0;
|
|
184
|
+
let high = total;
|
|
185
|
+
while (low < high) {
|
|
186
|
+
const middle = low + high + 1 >> 1;
|
|
187
|
+
if (offsets[middle] <= target) low = middle;
|
|
188
|
+
else high = middle - 1;
|
|
178
189
|
}
|
|
179
|
-
return
|
|
190
|
+
return low;
|
|
180
191
|
};
|
|
181
192
|
const findEnd = (target, total) => {
|
|
182
|
-
let
|
|
183
|
-
let
|
|
184
|
-
while (
|
|
185
|
-
const
|
|
186
|
-
if (offsets[
|
|
187
|
-
else
|
|
193
|
+
let low = 0;
|
|
194
|
+
let high = total;
|
|
195
|
+
while (low < high) {
|
|
196
|
+
const middle = low + high >> 1;
|
|
197
|
+
if (offsets[middle] >= target) high = middle;
|
|
198
|
+
else low = middle + 1;
|
|
188
199
|
}
|
|
189
|
-
return
|
|
200
|
+
return low;
|
|
190
201
|
};
|
|
191
|
-
const
|
|
202
|
+
const sizeRows = (start2) => {
|
|
192
203
|
if (measuring) return;
|
|
193
|
-
for (let
|
|
194
|
-
const
|
|
195
|
-
const
|
|
196
|
-
order[
|
|
204
|
+
for (let index = 0; index < rows.order.length; index++) {
|
|
205
|
+
const absoluteIndex = start2 + index;
|
|
206
|
+
const height = fixedHeight ?? offsets[absoluteIndex + 1] - offsets[absoluteIndex];
|
|
207
|
+
rows.order[index].el.style.height = `${height}px`;
|
|
197
208
|
}
|
|
198
209
|
};
|
|
199
|
-
const
|
|
200
|
-
const renderWindow = () => {
|
|
201
|
-
if (virtualize === void 0) {
|
|
202
|
-
if (granularEligible) {
|
|
203
|
-
const patches = patchSource._consumePatches();
|
|
204
|
-
if (!firstRender && patches.length > 0 && !patches.some((p) => p.type === "replace")) {
|
|
205
|
-
applyPatches(patches);
|
|
206
|
-
return;
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
syncRows(items);
|
|
210
|
-
firstRender = false;
|
|
211
|
-
return;
|
|
212
|
-
}
|
|
210
|
+
const renderCurrent = () => {
|
|
213
211
|
if (contentVisibility) {
|
|
214
|
-
|
|
215
|
-
for (let
|
|
216
|
-
const el = order[
|
|
212
|
+
rows.sync(items);
|
|
213
|
+
for (let index = 0; index < rows.order.length; index++) {
|
|
214
|
+
const el = rows.order[index].el;
|
|
217
215
|
el.style.contentVisibility = "auto";
|
|
218
|
-
el.style.containIntrinsicSize = `0 ${intrinsicSizeAt(
|
|
216
|
+
el.style.containIntrinsicSize = `0 ${intrinsicSizeAt(index)}px`;
|
|
219
217
|
}
|
|
220
218
|
return;
|
|
221
219
|
}
|
|
222
220
|
const total = items.length;
|
|
223
|
-
let
|
|
221
|
+
let start2;
|
|
224
222
|
let end;
|
|
225
223
|
let padTop;
|
|
226
224
|
let padBottom;
|
|
@@ -229,40 +227,41 @@ function bindList(parent, source, options) {
|
|
|
229
227
|
rebuildOffsets();
|
|
230
228
|
heightsDirty = false;
|
|
231
229
|
}
|
|
232
|
-
|
|
230
|
+
start2 = 0;
|
|
233
231
|
end = total;
|
|
234
232
|
padTop = 0;
|
|
235
233
|
padBottom = 0;
|
|
234
|
+
} else if (fixedHeight !== null) {
|
|
235
|
+
const viewportBottom = parent.scrollTop + parent.clientHeight;
|
|
236
|
+
start2 = Math.max(
|
|
237
|
+
0,
|
|
238
|
+
Math.floor(parent.scrollTop / fixedHeight) - overscan
|
|
239
|
+
);
|
|
240
|
+
end = Math.min(total, Math.ceil(viewportBottom / fixedHeight) + overscan);
|
|
241
|
+
padTop = start2 * fixedHeight;
|
|
242
|
+
padBottom = Math.max(0, total - end) * fixedHeight;
|
|
236
243
|
} else {
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
start = Math.max(0, Math.floor(scrollTop / fixedHeight) - overscan);
|
|
241
|
-
end = Math.min(total, Math.ceil(viewportBottom / fixedHeight) + overscan);
|
|
242
|
-
padTop = start * fixedHeight;
|
|
243
|
-
padBottom = Math.max(0, total - end) * fixedHeight;
|
|
244
|
-
} else {
|
|
245
|
-
if (heightsDirty) {
|
|
246
|
-
rebuildOffsets();
|
|
247
|
-
heightsDirty = false;
|
|
248
|
-
}
|
|
249
|
-
start = Math.max(0, findStart(scrollTop, total) - overscan);
|
|
250
|
-
end = Math.min(total, findEnd(viewportBottom, total) + overscan);
|
|
251
|
-
padTop = offsets[start];
|
|
252
|
-
padBottom = offsets[total] - offsets[end];
|
|
244
|
+
if (heightsDirty) {
|
|
245
|
+
rebuildOffsets();
|
|
246
|
+
heightsDirty = false;
|
|
253
247
|
}
|
|
248
|
+
const viewportBottom = parent.scrollTop + parent.clientHeight;
|
|
249
|
+
start2 = Math.max(0, findStart(parent.scrollTop, total) - overscan);
|
|
250
|
+
end = Math.min(total, findEnd(viewportBottom, total) + overscan);
|
|
251
|
+
padTop = offsets[start2];
|
|
252
|
+
padBottom = offsets[total] - offsets[end];
|
|
254
253
|
}
|
|
255
|
-
|
|
256
|
-
|
|
254
|
+
rows.sync(items.slice(start2, end));
|
|
255
|
+
sizeRows(start2);
|
|
257
256
|
container.style.paddingTop = `${padTop}px`;
|
|
258
257
|
container.style.paddingBottom = `${padBottom}px`;
|
|
259
|
-
for (const
|
|
258
|
+
for (const callback of renderSubscribers) callback();
|
|
260
259
|
};
|
|
261
|
-
const
|
|
262
|
-
items =
|
|
260
|
+
const render = (nextItems) => {
|
|
261
|
+
items = nextItems;
|
|
263
262
|
heightsDirty = true;
|
|
264
|
-
|
|
265
|
-
}
|
|
263
|
+
renderCurrent();
|
|
264
|
+
};
|
|
266
265
|
const scheduleRender = () => {
|
|
267
266
|
if (rafPending) return;
|
|
268
267
|
rafPending = true;
|
|
@@ -273,51 +272,143 @@ function bindList(parent, source, options) {
|
|
|
273
272
|
parent.scrollTop += pendingAnchorDelta;
|
|
274
273
|
pendingAnchorDelta = 0;
|
|
275
274
|
}
|
|
276
|
-
|
|
275
|
+
renderCurrent();
|
|
277
276
|
});
|
|
278
277
|
};
|
|
279
|
-
|
|
280
|
-
const
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
278
|
+
const resizeObserver = !contentVisibility && globalThis.ResizeObserver !== void 0 ? new globalThis.ResizeObserver(scheduleRender) : void 0;
|
|
279
|
+
const start = () => {
|
|
280
|
+
if (contentVisibility) return;
|
|
281
|
+
parent.addEventListener("scroll", scheduleRender);
|
|
282
|
+
resizeObserver?.observe(parent);
|
|
283
|
+
};
|
|
284
|
+
const setHeight = (rowKey, height) => {
|
|
284
285
|
if (!measuring || contentVisibility) return;
|
|
285
|
-
const
|
|
286
|
-
if (
|
|
287
|
-
const oldHeight = measured.
|
|
286
|
+
const index = indexByKey.get(rowKey);
|
|
287
|
+
if (index === void 0) return;
|
|
288
|
+
const oldHeight = measured.get(rowKey) ?? estimateAt(index);
|
|
288
289
|
if (height === oldHeight) return;
|
|
289
|
-
measured.set(
|
|
290
|
-
if (offsets[
|
|
290
|
+
measured.set(rowKey, height);
|
|
291
|
+
if (offsets[index + 1] <= parent.scrollTop)
|
|
292
|
+
pendingAnchorDelta += height - oldHeight;
|
|
291
293
|
heightsDirty = true;
|
|
292
294
|
scheduleRender();
|
|
293
295
|
};
|
|
294
|
-
const
|
|
296
|
+
const onRender = (callback) => {
|
|
297
|
+
renderSubscribers.add(callback);
|
|
298
|
+
return () => renderSubscribers.delete(callback);
|
|
299
|
+
};
|
|
300
|
+
const dispose = () => {
|
|
295
301
|
disposed = true;
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
row.dispose();
|
|
299
|
-
if (virtualize === void 0) row.el.remove();
|
|
300
|
-
}
|
|
301
|
-
rows.clear();
|
|
302
|
+
parent.removeEventListener("scroll", scheduleRender);
|
|
303
|
+
resizeObserver?.disconnect();
|
|
302
304
|
renderSubscribers.clear();
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
305
|
+
};
|
|
306
|
+
return { contentVisibility, render, start, setHeight, onRender, dispose };
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
// src/list.ts
|
|
310
|
+
var NOOP2 = () => {
|
|
311
|
+
};
|
|
312
|
+
function assertUniqueListKeys(items, key) {
|
|
313
|
+
const firstIndex = /* @__PURE__ */ new Map();
|
|
314
|
+
for (let index = 0; index < items.length; index++) {
|
|
315
|
+
const rowKey = key(items[index]);
|
|
316
|
+
const first = firstIndex.get(rowKey);
|
|
317
|
+
if (first !== void 0) {
|
|
318
|
+
const displayed = typeof rowKey === "string" ? JSON.stringify(rowKey) : String(rowKey);
|
|
319
|
+
throw new Error(
|
|
320
|
+
`bindList: duplicate key ${displayed} at indices ${first} and ${index} \u2014 every row key must be unique.`
|
|
321
|
+
);
|
|
322
|
+
}
|
|
323
|
+
firstIndex.set(rowKey, index);
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
function bindList(parent, source, options) {
|
|
327
|
+
const { key, render, tag = "div", virtualize, before } = options;
|
|
328
|
+
let firstRender = true;
|
|
329
|
+
let forceSnapshot = false;
|
|
330
|
+
const patchSource = source;
|
|
331
|
+
const granularEligible = virtualize === void 0 && patchSource[ARRAY_SIGNAL_BRAND] === true;
|
|
332
|
+
const container = virtualize === void 0 ? parent : document.createElement("div");
|
|
333
|
+
if (virtualize !== void 0) {
|
|
334
|
+
if (virtualize.containerClass !== void 0)
|
|
335
|
+
container.className = virtualize.containerClass;
|
|
336
|
+
if (virtualize.containerId !== void 0)
|
|
337
|
+
container.id = virtualize.containerId;
|
|
338
|
+
}
|
|
339
|
+
const endAnchor = () => {
|
|
340
|
+
if (virtualize !== void 0 || before === void 0) return null;
|
|
341
|
+
return (typeof before === "function" ? before() : before) ?? null;
|
|
342
|
+
};
|
|
343
|
+
const rows = createListRowController({
|
|
344
|
+
container,
|
|
345
|
+
key,
|
|
346
|
+
render,
|
|
347
|
+
tag,
|
|
348
|
+
endAnchor
|
|
349
|
+
});
|
|
350
|
+
const virtualization = virtualize === void 0 ? void 0 : createListVirtualizationController({
|
|
351
|
+
parent,
|
|
352
|
+
container,
|
|
353
|
+
virtualize,
|
|
354
|
+
key,
|
|
355
|
+
rows
|
|
356
|
+
});
|
|
357
|
+
const renderItems = (items) => {
|
|
358
|
+
if (virtualization !== void 0) {
|
|
359
|
+
virtualization.render(items);
|
|
360
|
+
return;
|
|
361
|
+
}
|
|
362
|
+
if (granularEligible) {
|
|
363
|
+
const patches = patchSource._consumePatches();
|
|
364
|
+
if (!firstRender && !forceSnapshot && patches.length > 0 && !patches.some((patch) => patch.type === "replace")) {
|
|
365
|
+
try {
|
|
366
|
+
rows.applyPatches(patches);
|
|
367
|
+
} catch (error) {
|
|
368
|
+
forceSnapshot = true;
|
|
369
|
+
throw error;
|
|
370
|
+
}
|
|
371
|
+
return;
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
rows.sync(items);
|
|
375
|
+
firstRender = false;
|
|
376
|
+
forceSnapshot = false;
|
|
377
|
+
};
|
|
378
|
+
const stopEffect = effect(() => {
|
|
379
|
+
const items = source.value;
|
|
380
|
+
try {
|
|
381
|
+
assertUniqueListKeys(items, key);
|
|
382
|
+
} catch (error) {
|
|
383
|
+
if (granularEligible) {
|
|
384
|
+
patchSource._consumePatches();
|
|
385
|
+
forceSnapshot = true;
|
|
386
|
+
}
|
|
387
|
+
throw error;
|
|
388
|
+
}
|
|
389
|
+
renderItems(items);
|
|
390
|
+
});
|
|
391
|
+
if (virtualization !== void 0) {
|
|
392
|
+
parent.appendChild(container);
|
|
393
|
+
virtualization.start();
|
|
394
|
+
}
|
|
395
|
+
const dispose = (() => {
|
|
396
|
+
stopEffect();
|
|
397
|
+
rows.dispose(virtualization === void 0);
|
|
398
|
+
if (virtualization !== void 0) {
|
|
399
|
+
virtualization.dispose();
|
|
306
400
|
container.remove();
|
|
307
401
|
VIRTUAL_INTERNALS.delete(handle);
|
|
308
402
|
}
|
|
309
403
|
});
|
|
310
404
|
const handle = dispose;
|
|
311
|
-
handle.setHeight = setHeight;
|
|
312
|
-
if (
|
|
405
|
+
handle.setHeight = virtualization?.setHeight ?? NOOP2;
|
|
406
|
+
if (virtualization !== void 0) {
|
|
313
407
|
handle.container = container;
|
|
314
|
-
if (!contentVisibility) {
|
|
408
|
+
if (!virtualization.contentVisibility) {
|
|
315
409
|
VIRTUAL_INTERNALS.set(handle, {
|
|
316
|
-
visibleRows: () => order.map((row) => ({ key: key(row.item), el: row.el })),
|
|
317
|
-
onRender:
|
|
318
|
-
renderSubscribers.add(cb);
|
|
319
|
-
return () => renderSubscribers.delete(cb);
|
|
320
|
-
}
|
|
410
|
+
visibleRows: () => rows.order.map((row) => ({ key: key(row.item), el: row.el })),
|
|
411
|
+
onRender: virtualization.onRender
|
|
321
412
|
});
|
|
322
413
|
}
|
|
323
414
|
}
|
|
@@ -327,13 +418,13 @@ var VIRTUAL_INTERNALS = /* @__PURE__ */ new WeakMap();
|
|
|
327
418
|
function observeRowHeights(handle) {
|
|
328
419
|
const internals = VIRTUAL_INTERNALS.get(handle);
|
|
329
420
|
const RO = globalThis.ResizeObserver;
|
|
330
|
-
if (internals === void 0 || RO === void 0) return
|
|
331
|
-
};
|
|
421
|
+
if (internals === void 0 || RO === void 0) return NOOP2;
|
|
332
422
|
const keyByEl = /* @__PURE__ */ new WeakMap();
|
|
333
423
|
const observer = new RO((entries) => {
|
|
334
424
|
for (const entry of entries) {
|
|
335
425
|
const k = keyByEl.get(entry.target);
|
|
336
|
-
if (k !== void 0)
|
|
426
|
+
if (k !== void 0)
|
|
427
|
+
handle.setHeight(k, entry.target.offsetHeight);
|
|
337
428
|
}
|
|
338
429
|
});
|
|
339
430
|
const resync = () => {
|
|
@@ -352,5 +443,5 @@ function observeRowHeights(handle) {
|
|
|
352
443
|
}
|
|
353
444
|
|
|
354
445
|
export { bindList, observeRowHeights };
|
|
355
|
-
|
|
446
|
+
|
|
356
447
|
//# sourceMappingURL=list.js.map
|