vlist 2.0.0 → 2.0.2
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/README.github.md +2 -2
- package/README.md +2 -2
- package/dist/core/dom.d.ts +1 -1
- package/dist/core/index.d.ts +1 -1
- package/dist/core/pipeline.d.ts +2 -2
- package/dist/core/scroll.d.ts +1 -1
- package/dist/core/types.d.ts +7 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -28
- package/dist/internals.js +1 -60
- package/dist/plugins/scrollbar/controller.d.ts +3 -3
- package/dist/plugins/scrollbar/scrollbar.d.ts +2 -2
- package/dist/rendering/renderer.d.ts +2 -2
- package/dist/rendering/viewport.d.ts +1 -1
- package/dist/size.json +1 -1
- package/dist/types.d.ts +1 -1
- package/package.json +1 -1
- package/dist/constants.js +0 -83
- package/dist/core/create.js +0 -740
- package/dist/core/dom.js +0 -47
- package/dist/core/hooks.js +0 -67
- package/dist/core/index.js +0 -13
- package/dist/core/pipeline.js +0 -307
- package/dist/core/pool.js +0 -42
- package/dist/core/scroll.js +0 -137
- package/dist/core/sizes.js +0 -6
- package/dist/core/state.js +0 -56
- package/dist/core/types.js +0 -7
- package/dist/core/velocity.js +0 -33
- package/dist/events/emitter.js +0 -60
- package/dist/events/index.js +0 -6
- package/dist/plugins/a11y/index.js +0 -1
- package/dist/plugins/a11y/plugin.js +0 -259
- package/dist/plugins/async/index.js +0 -12
- package/dist/plugins/async/manager.js +0 -568
- package/dist/plugins/async/placeholder.js +0 -154
- package/dist/plugins/async/plugin.js +0 -311
- package/dist/plugins/async/sparse.js +0 -540
- package/dist/plugins/autosize/index.js +0 -4
- package/dist/plugins/autosize/plugin.js +0 -185
- package/dist/plugins/grid/index.js +0 -5
- package/dist/plugins/grid/layout.js +0 -275
- package/dist/plugins/grid/plugin.js +0 -347
- package/dist/plugins/grid/renderer.js +0 -525
- package/dist/plugins/grid/types.js +0 -11
- package/dist/plugins/groups/async-bridge.js +0 -246
- package/dist/plugins/groups/index.js +0 -13
- package/dist/plugins/groups/layout.js +0 -294
- package/dist/plugins/groups/plugin.js +0 -571
- package/dist/plugins/groups/sticky.js +0 -255
- package/dist/plugins/groups/types.js +0 -12
- package/dist/plugins/masonry/index.js +0 -6
- package/dist/plugins/masonry/layout.js +0 -261
- package/dist/plugins/masonry/plugin.js +0 -381
- package/dist/plugins/masonry/renderer.js +0 -354
- package/dist/plugins/masonry/types.js +0 -9
- package/dist/plugins/page/index.js +0 -5
- package/dist/plugins/page/plugin.js +0 -166
- package/dist/plugins/scale/index.js +0 -4
- package/dist/plugins/scale/plugin.js +0 -507
- package/dist/plugins/scrollbar/controller.js +0 -574
- package/dist/plugins/scrollbar/index.js +0 -6
- package/dist/plugins/scrollbar/plugin.js +0 -93
- package/dist/plugins/scrollbar/scrollbar.js +0 -556
- package/dist/plugins/selection/index.js +0 -7
- package/dist/plugins/selection/plugin.js +0 -601
- package/dist/plugins/selection/state.js +0 -332
- package/dist/plugins/snapshots/index.js +0 -5
- package/dist/plugins/snapshots/plugin.js +0 -301
- package/dist/plugins/sortable/index.js +0 -6
- package/dist/plugins/sortable/plugin.js +0 -753
- package/dist/plugins/table/header.js +0 -501
- package/dist/plugins/table/index.js +0 -12
- package/dist/plugins/table/layout.js +0 -211
- package/dist/plugins/table/plugin.js +0 -391
- package/dist/plugins/table/renderer.js +0 -625
- package/dist/plugins/table/types.js +0 -12
- package/dist/plugins/transition/index.js +0 -5
- package/dist/plugins/transition/plugin.js +0 -405
- package/dist/rendering/aria.js +0 -23
- package/dist/rendering/index.js +0 -18
- package/dist/rendering/measured.js +0 -98
- package/dist/rendering/renderer.js +0 -586
- package/dist/rendering/scale.js +0 -267
- package/dist/rendering/scroll.js +0 -71
- package/dist/rendering/sizes.js +0 -193
- package/dist/rendering/sort.js +0 -65
- package/dist/rendering/viewport.js +0 -268
- package/dist/types.js +0 -5
- package/dist/utils/padding.js +0 -49
- package/dist/utils/stats.js +0 -124
package/dist/core/types.js
DELETED
package/dist/core/velocity.js
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* vlist v2 — Velocity Tracking
|
|
3
|
-
* Lightweight 2-sample velocity tracker for scroll momentum detection.
|
|
4
|
-
*/
|
|
5
|
-
export const MIN_RELIABLE_SAMPLES = 2;
|
|
6
|
-
/** Create a velocity tracker. */
|
|
7
|
-
export const createVelocityTracker = (_initialPosition = 0) => ({
|
|
8
|
-
velocity: 0,
|
|
9
|
-
sampleCount: 0,
|
|
10
|
-
});
|
|
11
|
-
/** Update velocity from new scroll position. Mutates tracker in place. */
|
|
12
|
-
export const updateVelocityTracker = (tracker, newPosition) => {
|
|
13
|
-
const now = performance.now();
|
|
14
|
-
const lastTime = tracker._lt ?? now;
|
|
15
|
-
const lastPos = tracker._lp ?? newPosition;
|
|
16
|
-
const dt = now - lastTime;
|
|
17
|
-
tracker._lp = newPosition;
|
|
18
|
-
tracker._lt = now;
|
|
19
|
-
// Zero time delta — record position but can't compute velocity
|
|
20
|
-
if (dt === 0) {
|
|
21
|
-
tracker.sampleCount = Math.min(tracker.sampleCount + 1, 5);
|
|
22
|
-
return tracker;
|
|
23
|
-
}
|
|
24
|
-
// Stale gap — reset
|
|
25
|
-
if (dt > 100) {
|
|
26
|
-
tracker.velocity = 0;
|
|
27
|
-
tracker.sampleCount = 1;
|
|
28
|
-
return tracker;
|
|
29
|
-
}
|
|
30
|
-
tracker.velocity = Math.abs(newPosition - lastPos) / dt;
|
|
31
|
-
tracker.sampleCount = Math.min(tracker.sampleCount + 1, 5);
|
|
32
|
-
return tracker;
|
|
33
|
-
};
|
package/dist/events/emitter.js
DELETED
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* vlist - Event Emitter
|
|
3
|
-
* Lightweight, type-safe event system
|
|
4
|
-
*/
|
|
5
|
-
// =============================================================================
|
|
6
|
-
// Event Emitter
|
|
7
|
-
// =============================================================================
|
|
8
|
-
/**
|
|
9
|
-
* Create a type-safe event emitter
|
|
10
|
-
* Functional approach - returns an object with methods
|
|
11
|
-
*/
|
|
12
|
-
export const createEmitter = () => {
|
|
13
|
-
const listeners = {};
|
|
14
|
-
/**
|
|
15
|
-
* Subscribe to an event
|
|
16
|
-
*/
|
|
17
|
-
const on = (event, handler) => {
|
|
18
|
-
if (!listeners[event]) {
|
|
19
|
-
listeners[event] = new Set();
|
|
20
|
-
}
|
|
21
|
-
listeners[event].add(handler);
|
|
22
|
-
// Return unsubscribe function
|
|
23
|
-
return () => off(event, handler);
|
|
24
|
-
};
|
|
25
|
-
/**
|
|
26
|
-
* Unsubscribe from an event
|
|
27
|
-
*/
|
|
28
|
-
const off = (event, handler) => {
|
|
29
|
-
listeners[event]?.delete(handler);
|
|
30
|
-
};
|
|
31
|
-
/**
|
|
32
|
-
* Emit an event to all subscribers
|
|
33
|
-
*/
|
|
34
|
-
const emit = (event, payload) => {
|
|
35
|
-
listeners[event]?.forEach((handler) => {
|
|
36
|
-
try {
|
|
37
|
-
handler(payload);
|
|
38
|
-
}
|
|
39
|
-
catch (error) {
|
|
40
|
-
if (process.env.NODE_ENV !== "production") {
|
|
41
|
-
console.error(`[vlist] Error in event handler for "${String(event)}":`, error);
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
});
|
|
45
|
-
};
|
|
46
|
-
/**
|
|
47
|
-
* Remove all listeners for an event (or all events if no event specified)
|
|
48
|
-
*/
|
|
49
|
-
const clear = (event) => {
|
|
50
|
-
if (event) {
|
|
51
|
-
delete listeners[event];
|
|
52
|
-
}
|
|
53
|
-
else {
|
|
54
|
-
for (const key in listeners) {
|
|
55
|
-
delete listeners[key];
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
};
|
|
59
|
-
return { on, off, emit, clear };
|
|
60
|
-
};
|
package/dist/events/index.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { a11y } from "./plugin";
|
|
@@ -1,259 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* vlist v2 — A11y Plugin
|
|
3
|
-
*
|
|
4
|
-
* Baseline keyboard navigation, single-select, focus management, and ARIA.
|
|
5
|
-
* Extracted from createVList() so it tree-shakes when selection() is used.
|
|
6
|
-
*
|
|
7
|
-
* Priority 55 — runs after selection (50). If selection already set
|
|
8
|
-
* itemStateFn, this plugin becomes a no-op.
|
|
9
|
-
*/
|
|
10
|
-
export function a11y() {
|
|
11
|
-
return {
|
|
12
|
-
name: "a11y",
|
|
13
|
-
priority: 55,
|
|
14
|
-
setup(ctx) {
|
|
15
|
-
if (ctx.getItemStateFn())
|
|
16
|
-
return;
|
|
17
|
-
const dom = ctx.dom;
|
|
18
|
-
const config = ctx.config;
|
|
19
|
-
const sizeCache = ctx.sizeCache;
|
|
20
|
-
const engineState = ctx.getState();
|
|
21
|
-
const emitter = ctx.emitter;
|
|
22
|
-
const classPrefix = config.classPrefix;
|
|
23
|
-
const liveRegion = dom.liveRegion;
|
|
24
|
-
let focusIdx = -1;
|
|
25
|
-
let focusVis = false;
|
|
26
|
-
let selId;
|
|
27
|
-
let selIdx = -1;
|
|
28
|
-
const getItem = (i) => ctx.getItem(i);
|
|
29
|
-
const getTotal = () => engineState.totalItems;
|
|
30
|
-
const _focusEvt = { id: 0, index: 0 };
|
|
31
|
-
const _selEvt = { selected: [], items: [] };
|
|
32
|
-
ctx.setItemStateFn((_i, is) => {
|
|
33
|
-
is.selected = selIdx === _i;
|
|
34
|
-
is.focused = focusVis && focusIdx === _i;
|
|
35
|
-
});
|
|
36
|
-
function announce(message) {
|
|
37
|
-
liveRegion.textContent = "";
|
|
38
|
-
liveRegion.textContent = message;
|
|
39
|
-
}
|
|
40
|
-
const skip = (from, dir, total) => {
|
|
41
|
-
let i = from;
|
|
42
|
-
while (i >= 0 && i < total) {
|
|
43
|
-
const it = getItem(i);
|
|
44
|
-
if (!it || !it.__groupHeader)
|
|
45
|
-
return i;
|
|
46
|
-
i += dir;
|
|
47
|
-
}
|
|
48
|
-
i = from - dir;
|
|
49
|
-
while (i >= 0 && i < total) {
|
|
50
|
-
const it = getItem(i);
|
|
51
|
-
if (!it || !it.__groupHeader)
|
|
52
|
-
return i;
|
|
53
|
-
i -= dir;
|
|
54
|
-
}
|
|
55
|
-
return from;
|
|
56
|
-
};
|
|
57
|
-
const scrollIntoView = (idx) => {
|
|
58
|
-
const nav = ctx.getNavConfig();
|
|
59
|
-
const ci = nav.scrollIndex ? nav.scrollIndex(idx) : idx;
|
|
60
|
-
const off = sizeCache.getOffset(ci);
|
|
61
|
-
const sz = sizeCache.getSize(ci);
|
|
62
|
-
const sp = engineState.scrollPosition;
|
|
63
|
-
const cs = engineState.containerSize;
|
|
64
|
-
const sP = config.startPadding;
|
|
65
|
-
const eP = config.endPadding;
|
|
66
|
-
const adjTop = off + sP;
|
|
67
|
-
const adjBot = adjTop + sz;
|
|
68
|
-
let pos = sp;
|
|
69
|
-
if (adjTop < sp)
|
|
70
|
-
pos = Math.max(0, off);
|
|
71
|
-
else if (adjBot > sp + cs)
|
|
72
|
-
pos = adjBot + eP - cs;
|
|
73
|
-
if (pos !== sp) {
|
|
74
|
-
engineState.scrollPosition = pos;
|
|
75
|
-
ctx.scrollTo(pos);
|
|
76
|
-
}
|
|
77
|
-
};
|
|
78
|
-
const commit = (idx, scroll) => {
|
|
79
|
-
dom.content.setAttribute("aria-activedescendant", `${classPrefix}-item-${idx}`);
|
|
80
|
-
if (scroll)
|
|
81
|
-
scrollIntoView(idx);
|
|
82
|
-
ctx.forceRender();
|
|
83
|
-
};
|
|
84
|
-
const move = (next) => {
|
|
85
|
-
focusIdx = next;
|
|
86
|
-
focusVis = true;
|
|
87
|
-
commit(next, true);
|
|
88
|
-
const it = getItem(next);
|
|
89
|
-
if (it) {
|
|
90
|
-
_focusEvt.id = it.id;
|
|
91
|
-
_focusEvt.index = next;
|
|
92
|
-
emitter.emit("focus:change", _focusEvt);
|
|
93
|
-
announce(`Item ${next + 1} of ${getTotal()}`);
|
|
94
|
-
}
|
|
95
|
-
};
|
|
96
|
-
const select = (idx, kbd) => {
|
|
97
|
-
focusIdx = idx;
|
|
98
|
-
if (kbd)
|
|
99
|
-
focusVis = true;
|
|
100
|
-
const it = getItem(idx);
|
|
101
|
-
if (it && selId === it.id) {
|
|
102
|
-
selId = undefined;
|
|
103
|
-
selIdx = -1;
|
|
104
|
-
}
|
|
105
|
-
else {
|
|
106
|
-
selId = it?.id;
|
|
107
|
-
selIdx = it ? idx : -1;
|
|
108
|
-
}
|
|
109
|
-
commit(idx, kbd);
|
|
110
|
-
if (selId !== undefined && it && selId === it.id) {
|
|
111
|
-
_selEvt.selected[0] = selId;
|
|
112
|
-
_selEvt.selected.length = 1;
|
|
113
|
-
_selEvt.items[0] = it;
|
|
114
|
-
_selEvt.items.length = 1;
|
|
115
|
-
announce(`Selected, item ${idx + 1} of ${getTotal()}`);
|
|
116
|
-
}
|
|
117
|
-
else {
|
|
118
|
-
_selEvt.selected.length = 0;
|
|
119
|
-
_selEvt.items.length = 0;
|
|
120
|
-
announce(`Deselected`);
|
|
121
|
-
}
|
|
122
|
-
emitter.emit("selection:change", _selEvt);
|
|
123
|
-
};
|
|
124
|
-
// ── Focus handlers ──────────────────────────────────────────
|
|
125
|
-
const onFocusIn = () => {
|
|
126
|
-
if (engineState.destroyed)
|
|
127
|
-
return;
|
|
128
|
-
if (!dom.content.matches(":focus-visible"))
|
|
129
|
-
return;
|
|
130
|
-
const t = getTotal();
|
|
131
|
-
if (t === 0)
|
|
132
|
-
return;
|
|
133
|
-
let tgt = focusIdx >= 0 ? Math.min(focusIdx, t - 1) : 0;
|
|
134
|
-
tgt = skip(tgt, 1, t);
|
|
135
|
-
move(tgt);
|
|
136
|
-
};
|
|
137
|
-
const onFocusOut = (e) => {
|
|
138
|
-
if (engineState.destroyed)
|
|
139
|
-
return;
|
|
140
|
-
const rel = e.relatedTarget;
|
|
141
|
-
if (rel && dom.root.contains(rel))
|
|
142
|
-
return;
|
|
143
|
-
focusVis = false;
|
|
144
|
-
dom.content.removeAttribute("aria-activedescendant");
|
|
145
|
-
ctx.forceRender();
|
|
146
|
-
};
|
|
147
|
-
dom.content.addEventListener("focusin", onFocusIn);
|
|
148
|
-
dom.content.addEventListener("focusout", onFocusOut);
|
|
149
|
-
// ── Keyboard handler ────────────────────────────────────────
|
|
150
|
-
ctx.registerKeydownHandler((e) => {
|
|
151
|
-
if (engineState.destroyed)
|
|
152
|
-
return;
|
|
153
|
-
const total = getTotal();
|
|
154
|
-
if (total === 0)
|
|
155
|
-
return;
|
|
156
|
-
const p = focusIdx;
|
|
157
|
-
let n = p;
|
|
158
|
-
if (e.key === " " || e.key === "Enter") {
|
|
159
|
-
if (p >= 0) {
|
|
160
|
-
const it = getItem(p);
|
|
161
|
-
if (it && !it.__groupHeader) {
|
|
162
|
-
select(p, true);
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
e.preventDefault();
|
|
166
|
-
return;
|
|
167
|
-
}
|
|
168
|
-
const nav = ctx.getNavConfig();
|
|
169
|
-
if (nav.navigate) {
|
|
170
|
-
switch (e.key) {
|
|
171
|
-
case "ArrowUp":
|
|
172
|
-
case "ArrowDown":
|
|
173
|
-
case "ArrowLeft":
|
|
174
|
-
case "ArrowRight":
|
|
175
|
-
case "PageUp":
|
|
176
|
-
case "PageDown":
|
|
177
|
-
case "Home":
|
|
178
|
-
case "End":
|
|
179
|
-
n = nav.navigate(p, e.key, total);
|
|
180
|
-
break;
|
|
181
|
-
default: return;
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
else {
|
|
185
|
-
const ud = nav.ud || 1;
|
|
186
|
-
const lr = nav.lr;
|
|
187
|
-
const hz = config.horizontal;
|
|
188
|
-
switch (e.key) {
|
|
189
|
-
case "ArrowUp":
|
|
190
|
-
if (hz && !lr)
|
|
191
|
-
return;
|
|
192
|
-
n = p - (hz ? lr : ud);
|
|
193
|
-
break;
|
|
194
|
-
case "ArrowDown":
|
|
195
|
-
if (hz && !lr)
|
|
196
|
-
return;
|
|
197
|
-
n = p + (hz ? lr : ud);
|
|
198
|
-
break;
|
|
199
|
-
case "ArrowLeft":
|
|
200
|
-
if (!hz && !lr)
|
|
201
|
-
return;
|
|
202
|
-
n = p - (hz ? ud : lr);
|
|
203
|
-
break;
|
|
204
|
-
case "ArrowRight":
|
|
205
|
-
if (!hz && !lr)
|
|
206
|
-
return;
|
|
207
|
-
n = p + (hz ? ud : lr);
|
|
208
|
-
break;
|
|
209
|
-
case "PageUp":
|
|
210
|
-
case "PageDown": {
|
|
211
|
-
const sz = sizeCache.getSize(Math.max(0, nav.scrollIndex ? nav.scrollIndex(p) : p));
|
|
212
|
-
const visRows = Math.max(1, Math.floor(engineState.containerSize / sz));
|
|
213
|
-
const delta = visRows * ud;
|
|
214
|
-
n = e.key === "PageUp" ? p - delta : p + delta;
|
|
215
|
-
break;
|
|
216
|
-
}
|
|
217
|
-
case "Home":
|
|
218
|
-
n = 0;
|
|
219
|
-
break;
|
|
220
|
-
case "End":
|
|
221
|
-
n = total - 1;
|
|
222
|
-
break;
|
|
223
|
-
default: return;
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
if (n < 0)
|
|
227
|
-
n = 0;
|
|
228
|
-
else if (n >= total)
|
|
229
|
-
n = total - 1;
|
|
230
|
-
e.preventDefault();
|
|
231
|
-
n = skip(n, n >= p ? 1 : -1, total);
|
|
232
|
-
if (n !== p)
|
|
233
|
-
move(n);
|
|
234
|
-
});
|
|
235
|
-
// ── Click handler ───────────────────────────────────────────
|
|
236
|
-
ctx.registerClickHandler((e) => {
|
|
237
|
-
if (engineState.destroyed)
|
|
238
|
-
return;
|
|
239
|
-
const el = e.target.closest("[data-index]");
|
|
240
|
-
if (!el)
|
|
241
|
-
return;
|
|
242
|
-
const idx = parseInt(el.dataset.index ?? "-1", 10);
|
|
243
|
-
if (idx < 0)
|
|
244
|
-
return;
|
|
245
|
-
const it = getItem(idx);
|
|
246
|
-
if (!it || it.__groupHeader)
|
|
247
|
-
return;
|
|
248
|
-
focusVis = false;
|
|
249
|
-
dom.content.focus({ preventScroll: true });
|
|
250
|
-
select(idx, false);
|
|
251
|
-
});
|
|
252
|
-
// ── Cleanup ─────────────────────────────────────────────────
|
|
253
|
-
ctx.registerDestroyHandler(() => {
|
|
254
|
-
dom.content.removeEventListener("focusin", onFocusIn);
|
|
255
|
-
dom.content.removeEventListener("focusout", onFocusOut);
|
|
256
|
-
});
|
|
257
|
-
},
|
|
258
|
-
};
|
|
259
|
-
}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* vlist - Data Domain
|
|
3
|
-
* Data management, sparse storage, and placeholder generation
|
|
4
|
-
*/
|
|
5
|
-
// v2 Plugin
|
|
6
|
-
export { data } from "./plugin";
|
|
7
|
-
// Data Manager
|
|
8
|
-
export { createDataManager, mergeRanges, calculateMissingRanges, isPlaceholderItem, filterPlaceholders, countRealItems, } from "./manager";
|
|
9
|
-
// Sparse Storage
|
|
10
|
-
export { createSparseStorage, } from "./sparse";
|
|
11
|
-
// Placeholder
|
|
12
|
-
export { createPlaceholderManager, } from "./placeholder";
|