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.
Files changed (91) hide show
  1. package/README.github.md +2 -2
  2. package/README.md +2 -2
  3. package/dist/core/dom.d.ts +1 -1
  4. package/dist/core/index.d.ts +1 -1
  5. package/dist/core/pipeline.d.ts +2 -2
  6. package/dist/core/scroll.d.ts +1 -1
  7. package/dist/core/types.d.ts +7 -1
  8. package/dist/index.d.ts +1 -1
  9. package/dist/index.js +1 -28
  10. package/dist/internals.js +1 -60
  11. package/dist/plugins/scrollbar/controller.d.ts +3 -3
  12. package/dist/plugins/scrollbar/scrollbar.d.ts +2 -2
  13. package/dist/rendering/renderer.d.ts +2 -2
  14. package/dist/rendering/viewport.d.ts +1 -1
  15. package/dist/size.json +1 -1
  16. package/dist/types.d.ts +1 -1
  17. package/package.json +1 -1
  18. package/dist/constants.js +0 -83
  19. package/dist/core/create.js +0 -740
  20. package/dist/core/dom.js +0 -47
  21. package/dist/core/hooks.js +0 -67
  22. package/dist/core/index.js +0 -13
  23. package/dist/core/pipeline.js +0 -307
  24. package/dist/core/pool.js +0 -42
  25. package/dist/core/scroll.js +0 -137
  26. package/dist/core/sizes.js +0 -6
  27. package/dist/core/state.js +0 -56
  28. package/dist/core/types.js +0 -7
  29. package/dist/core/velocity.js +0 -33
  30. package/dist/events/emitter.js +0 -60
  31. package/dist/events/index.js +0 -6
  32. package/dist/plugins/a11y/index.js +0 -1
  33. package/dist/plugins/a11y/plugin.js +0 -259
  34. package/dist/plugins/async/index.js +0 -12
  35. package/dist/plugins/async/manager.js +0 -568
  36. package/dist/plugins/async/placeholder.js +0 -154
  37. package/dist/plugins/async/plugin.js +0 -311
  38. package/dist/plugins/async/sparse.js +0 -540
  39. package/dist/plugins/autosize/index.js +0 -4
  40. package/dist/plugins/autosize/plugin.js +0 -185
  41. package/dist/plugins/grid/index.js +0 -5
  42. package/dist/plugins/grid/layout.js +0 -275
  43. package/dist/plugins/grid/plugin.js +0 -347
  44. package/dist/plugins/grid/renderer.js +0 -525
  45. package/dist/plugins/grid/types.js +0 -11
  46. package/dist/plugins/groups/async-bridge.js +0 -246
  47. package/dist/plugins/groups/index.js +0 -13
  48. package/dist/plugins/groups/layout.js +0 -294
  49. package/dist/plugins/groups/plugin.js +0 -571
  50. package/dist/plugins/groups/sticky.js +0 -255
  51. package/dist/plugins/groups/types.js +0 -12
  52. package/dist/plugins/masonry/index.js +0 -6
  53. package/dist/plugins/masonry/layout.js +0 -261
  54. package/dist/plugins/masonry/plugin.js +0 -381
  55. package/dist/plugins/masonry/renderer.js +0 -354
  56. package/dist/plugins/masonry/types.js +0 -9
  57. package/dist/plugins/page/index.js +0 -5
  58. package/dist/plugins/page/plugin.js +0 -166
  59. package/dist/plugins/scale/index.js +0 -4
  60. package/dist/plugins/scale/plugin.js +0 -507
  61. package/dist/plugins/scrollbar/controller.js +0 -574
  62. package/dist/plugins/scrollbar/index.js +0 -6
  63. package/dist/plugins/scrollbar/plugin.js +0 -93
  64. package/dist/plugins/scrollbar/scrollbar.js +0 -556
  65. package/dist/plugins/selection/index.js +0 -7
  66. package/dist/plugins/selection/plugin.js +0 -601
  67. package/dist/plugins/selection/state.js +0 -332
  68. package/dist/plugins/snapshots/index.js +0 -5
  69. package/dist/plugins/snapshots/plugin.js +0 -301
  70. package/dist/plugins/sortable/index.js +0 -6
  71. package/dist/plugins/sortable/plugin.js +0 -753
  72. package/dist/plugins/table/header.js +0 -501
  73. package/dist/plugins/table/index.js +0 -12
  74. package/dist/plugins/table/layout.js +0 -211
  75. package/dist/plugins/table/plugin.js +0 -391
  76. package/dist/plugins/table/renderer.js +0 -625
  77. package/dist/plugins/table/types.js +0 -12
  78. package/dist/plugins/transition/index.js +0 -5
  79. package/dist/plugins/transition/plugin.js +0 -405
  80. package/dist/rendering/aria.js +0 -23
  81. package/dist/rendering/index.js +0 -18
  82. package/dist/rendering/measured.js +0 -98
  83. package/dist/rendering/renderer.js +0 -586
  84. package/dist/rendering/scale.js +0 -267
  85. package/dist/rendering/scroll.js +0 -71
  86. package/dist/rendering/sizes.js +0 -193
  87. package/dist/rendering/sort.js +0 -65
  88. package/dist/rendering/viewport.js +0 -268
  89. package/dist/types.js +0 -5
  90. package/dist/utils/padding.js +0 -49
  91. package/dist/utils/stats.js +0 -124
@@ -1,7 +0,0 @@
1
- /**
2
- * vlist v2 — Core Type Definitions
3
- *
4
- * Zero-allocation pipeline types. All hot-path state lives in TypedArrays
5
- * on the EngineState singleton — no intermediate object allocation.
6
- */
7
- export {};
@@ -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
- };
@@ -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
- };
@@ -1,6 +0,0 @@
1
- /**
2
- * vlist - Events Domain
3
- * Event emitter system
4
- */
5
- // Event Emitter
6
- export { createEmitter } from "./emitter";
@@ -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";