mtrl-addons 0.2.1 → 0.2.3

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 (128) hide show
  1. package/{src/components/index.ts → dist/components/index.d.ts} +0 -2
  2. package/dist/components/vlist/config.d.ts +86 -0
  3. package/{src/components/vlist/constants.ts → dist/components/vlist/constants.d.ts} +10 -11
  4. package/dist/components/vlist/features/api.d.ts +7 -0
  5. package/{src/components/vlist/features/index.ts → dist/components/vlist/features/index.d.ts} +0 -2
  6. package/dist/components/vlist/features/selection.d.ts +6 -0
  7. package/dist/components/vlist/features/viewport.d.ts +9 -0
  8. package/dist/components/vlist/features.d.ts +31 -0
  9. package/{src/components/vlist/index.ts → dist/components/vlist/index.d.ts} +1 -9
  10. package/dist/components/vlist/types.d.ts +596 -0
  11. package/dist/components/vlist/vlist.d.ts +29 -0
  12. package/dist/core/compose/features/gestures/index.d.ts +86 -0
  13. package/dist/core/compose/features/gestures/longpress.d.ts +85 -0
  14. package/dist/core/compose/features/gestures/pan.d.ts +108 -0
  15. package/dist/core/compose/features/gestures/pinch.d.ts +111 -0
  16. package/dist/core/compose/features/gestures/rotate.d.ts +111 -0
  17. package/dist/core/compose/features/gestures/swipe.d.ts +149 -0
  18. package/dist/core/compose/features/gestures/tap.d.ts +79 -0
  19. package/{src/core/compose/features/index.ts → dist/core/compose/features/index.d.ts} +1 -2
  20. package/{src/core/compose/index.ts → dist/core/compose/index.d.ts} +2 -11
  21. package/{src/core/gestures/index.ts → dist/core/gestures/index.d.ts} +1 -20
  22. package/dist/core/gestures/longpress.d.ts +23 -0
  23. package/dist/core/gestures/manager.d.ts +14 -0
  24. package/dist/core/gestures/pan.d.ts +12 -0
  25. package/dist/core/gestures/pinch.d.ts +14 -0
  26. package/dist/core/gestures/rotate.d.ts +14 -0
  27. package/dist/core/gestures/swipe.d.ts +20 -0
  28. package/dist/core/gestures/tap.d.ts +12 -0
  29. package/dist/core/gestures/types.d.ts +320 -0
  30. package/dist/core/gestures/utils.d.ts +57 -0
  31. package/dist/core/index.d.ts +13 -0
  32. package/dist/core/layout/config.d.ts +33 -0
  33. package/dist/core/layout/index.d.ts +51 -0
  34. package/dist/core/layout/jsx.d.ts +65 -0
  35. package/dist/core/layout/schema.d.ts +112 -0
  36. package/dist/core/layout/types.d.ts +69 -0
  37. package/dist/core/viewport/constants.d.ts +105 -0
  38. package/dist/core/viewport/features/base.d.ts +14 -0
  39. package/dist/core/viewport/features/collection.d.ts +41 -0
  40. package/dist/core/viewport/features/events.d.ts +13 -0
  41. package/{src/core/viewport/features/index.ts → dist/core/viewport/features/index.d.ts} +0 -7
  42. package/dist/core/viewport/features/item-size.d.ts +30 -0
  43. package/dist/core/viewport/features/loading.d.ts +34 -0
  44. package/dist/core/viewport/features/momentum.d.ts +17 -0
  45. package/dist/core/viewport/features/performance.d.ts +53 -0
  46. package/dist/core/viewport/features/placeholders.d.ts +38 -0
  47. package/dist/core/viewport/features/rendering.d.ts +16 -0
  48. package/dist/core/viewport/features/scrollbar.d.ts +26 -0
  49. package/dist/core/viewport/features/scrolling.d.ts +16 -0
  50. package/dist/core/viewport/features/utils.d.ts +43 -0
  51. package/dist/core/viewport/features/virtual.d.ts +18 -0
  52. package/{src/core/viewport/index.ts → dist/core/viewport/index.d.ts} +1 -17
  53. package/dist/core/viewport/types.d.ts +96 -0
  54. package/dist/core/viewport/utils/speed-tracker.d.ts +22 -0
  55. package/dist/core/viewport/viewport.d.ts +11 -0
  56. package/{src/index.ts → dist/index.d.ts} +0 -4
  57. package/dist/index.js +5143 -0
  58. package/dist/index.mjs +5111 -0
  59. package/dist/styles.css +254 -0
  60. package/dist/styles.css.map +1 -0
  61. package/package.json +6 -1
  62. package/src/styles/components/_vlist.scss +234 -213
  63. package/.cursorrules +0 -117
  64. package/AI.md +0 -241
  65. package/build.js +0 -201
  66. package/scripts/analyze-orphaned-functions.ts +0 -387
  67. package/scripts/debug/vlist-selection.ts +0 -121
  68. package/src/components/vlist/config.ts +0 -323
  69. package/src/components/vlist/features/api.ts +0 -322
  70. package/src/components/vlist/features/selection.ts +0 -444
  71. package/src/components/vlist/features/viewport.ts +0 -65
  72. package/src/components/vlist/features.ts +0 -112
  73. package/src/components/vlist/types.ts +0 -591
  74. package/src/components/vlist/vlist.ts +0 -92
  75. package/src/core/compose/features/gestures/index.ts +0 -227
  76. package/src/core/compose/features/gestures/longpress.ts +0 -383
  77. package/src/core/compose/features/gestures/pan.ts +0 -424
  78. package/src/core/compose/features/gestures/pinch.ts +0 -475
  79. package/src/core/compose/features/gestures/rotate.ts +0 -485
  80. package/src/core/compose/features/gestures/swipe.ts +0 -492
  81. package/src/core/compose/features/gestures/tap.ts +0 -334
  82. package/src/core/gestures/longpress.ts +0 -68
  83. package/src/core/gestures/manager.ts +0 -418
  84. package/src/core/gestures/pan.ts +0 -48
  85. package/src/core/gestures/pinch.ts +0 -58
  86. package/src/core/gestures/rotate.ts +0 -58
  87. package/src/core/gestures/swipe.ts +0 -66
  88. package/src/core/gestures/tap.ts +0 -45
  89. package/src/core/gestures/types.ts +0 -387
  90. package/src/core/gestures/utils.ts +0 -128
  91. package/src/core/index.ts +0 -43
  92. package/src/core/layout/config.ts +0 -102
  93. package/src/core/layout/index.ts +0 -168
  94. package/src/core/layout/jsx.ts +0 -174
  95. package/src/core/layout/schema.ts +0 -1001
  96. package/src/core/layout/types.ts +0 -95
  97. package/src/core/viewport/constants.ts +0 -140
  98. package/src/core/viewport/features/base.ts +0 -73
  99. package/src/core/viewport/features/collection.ts +0 -882
  100. package/src/core/viewport/features/events.ts +0 -130
  101. package/src/core/viewport/features/item-size.ts +0 -271
  102. package/src/core/viewport/features/loading.ts +0 -263
  103. package/src/core/viewport/features/momentum.ts +0 -260
  104. package/src/core/viewport/features/performance.ts +0 -161
  105. package/src/core/viewport/features/placeholders.ts +0 -335
  106. package/src/core/viewport/features/rendering.ts +0 -568
  107. package/src/core/viewport/features/scrollbar.ts +0 -434
  108. package/src/core/viewport/features/scrolling.ts +0 -618
  109. package/src/core/viewport/features/utils.ts +0 -88
  110. package/src/core/viewport/features/virtual.ts +0 -384
  111. package/src/core/viewport/types.ts +0 -133
  112. package/src/core/viewport/utils/speed-tracker.ts +0 -79
  113. package/src/core/viewport/viewport.ts +0 -246
  114. package/test/benchmarks/layout/advanced.test.ts +0 -656
  115. package/test/benchmarks/layout/comparison.test.ts +0 -519
  116. package/test/benchmarks/layout/performance-comparison.test.ts +0 -274
  117. package/test/benchmarks/layout/real-components.test.ts +0 -733
  118. package/test/benchmarks/layout/simple.test.ts +0 -321
  119. package/test/benchmarks/layout/stress.test.ts +0 -990
  120. package/test/collection/basic.test.ts +0 -304
  121. package/test/components/vlist-selection.test.ts +0 -240
  122. package/test/components/vlist.test.ts +0 -63
  123. package/test/core/collection/adapter.test.ts +0 -161
  124. package/test/core/collection/collection.test.ts +0 -394
  125. package/test/core/layout/layout.test.ts +0 -201
  126. package/test/utils/dom-helpers.ts +0 -275
  127. package/test/utils/performance-helpers.ts +0 -392
  128. package/tsconfig.json +0 -20
@@ -1,384 +0,0 @@
1
- /**
2
- * Virtual Feature - Core virtual scrolling calculations
3
- * Handles visible range calculation and total virtual size management
4
- */
5
-
6
- import type { ViewportContext, ViewportComponent } from "../types";
7
- import { VIEWPORT_CONSTANTS } from "../constants";
8
- import { wrapInitialize, getViewportState } from "./utils";
9
-
10
- export interface VirtualConfig {
11
- itemSize?: number;
12
- overscan?: number;
13
- orientation?: "vertical" | "horizontal";
14
- autoDetectItemSize?: boolean;
15
- debug?: boolean;
16
- }
17
-
18
- /**
19
- * Virtual scrolling feature for viewport
20
- * Handles visible range calculations with compression for large datasets
21
- */
22
- export const withVirtual = (config: VirtualConfig = {}) => {
23
- return <T extends ViewportContext & ViewportComponent>(component: T): T => {
24
- const {
25
- itemSize,
26
- overscan = VIEWPORT_CONSTANTS.VIRTUAL_SCROLL.OVERSCAN_BUFFER,
27
- orientation = "vertical",
28
- autoDetectItemSize = itemSize === undefined
29
- ? VIEWPORT_CONSTANTS.VIRTUAL_SCROLL.AUTO_DETECT_ITEM_SIZE
30
- : false,
31
- debug = false,
32
- } = config;
33
-
34
- // Use provided itemSize or default, but mark if we should auto-detect
35
- const initialItemSize =
36
- itemSize || VIEWPORT_CONSTANTS.VIRTUAL_SCROLL.DEFAULT_ITEM_SIZE;
37
-
38
- const MAX_VIRTUAL_SIZE = VIEWPORT_CONSTANTS.VIRTUAL_SCROLL.MAX_VIRTUAL_SIZE;
39
- let viewportState: any;
40
- let hasCalculatedItemSize = false;
41
-
42
- // Initialize using shared wrapper
43
- wrapInitialize(component, () => {
44
- viewportState = getViewportState(component);
45
- if (!viewportState) return;
46
-
47
- Object.assign(viewportState, {
48
- itemSize: initialItemSize,
49
- overscan,
50
- containerSize:
51
- viewportState.viewportElement?.[
52
- orientation === "horizontal" ? "offsetWidth" : "offsetHeight"
53
- ] || 600,
54
- });
55
-
56
- updateTotalVirtualSize(viewportState.totalItems);
57
- updateVisibleRange(viewportState.scrollPosition || 0);
58
-
59
- // Ensure container size is measured after DOM is ready
60
- requestAnimationFrame(() => {
61
- updateContainerSize();
62
- });
63
- });
64
-
65
- // Helper functions
66
- const getCompressionRatio = (): number => {
67
- if (!viewportState?.virtualTotalSize) return 1;
68
- const actualSize = viewportState.totalItems * viewportState.itemSize;
69
- return actualSize <= MAX_VIRTUAL_SIZE ? 1 : MAX_VIRTUAL_SIZE / actualSize;
70
- };
71
-
72
- const log = (message: string, data?: any) => {
73
- if (debug) console.log(`[Virtual] ${message}`, data);
74
- };
75
-
76
- // Calculate visible range
77
- const calculateVisibleRange = (
78
- scrollPosition: number
79
- ): { start: number; end: number } => {
80
- if (!viewportState) {
81
- console.warn("[Virtual] No viewport state, returning empty range");
82
- return { start: 0, end: 0 };
83
- }
84
-
85
- const { containerSize, totalItems } = viewportState;
86
-
87
- // Early returns for invalid states
88
- if (
89
- !containerSize ||
90
- containerSize <= 0 ||
91
- !totalItems ||
92
- totalItems <= 0
93
- ) {
94
- log(`Invalid state: container=${containerSize}, items=${totalItems}`);
95
- return { start: 0, end: 0 };
96
- }
97
-
98
- const virtualSize =
99
- viewportState.virtualTotalSize || totalItems * viewportState.itemSize;
100
- const visibleCount = Math.ceil(containerSize / viewportState.itemSize);
101
- const compressionRatio = getCompressionRatio();
102
-
103
- let start: number, end: number;
104
-
105
- if (compressionRatio < 1) {
106
- // Compressed space calculation
107
- const scrollRatio = scrollPosition / virtualSize;
108
- const exactIndex = scrollRatio * totalItems;
109
- start = Math.floor(exactIndex);
110
- end = Math.ceil(exactIndex) + visibleCount;
111
-
112
- // Near-bottom handling
113
- const maxScroll = virtualSize - containerSize;
114
- const distanceFromBottom = maxScroll - scrollPosition;
115
-
116
- if (distanceFromBottom <= containerSize && distanceFromBottom >= -1) {
117
- const itemsAtBottom = Math.floor(
118
- containerSize / viewportState.itemSize
119
- );
120
- const firstVisibleAtBottom = Math.max(0, totalItems - itemsAtBottom);
121
- const interpolation = Math.max(
122
- 0,
123
- Math.min(1, 1 - distanceFromBottom / containerSize)
124
- );
125
-
126
- start = Math.floor(
127
- start + (firstVisibleAtBottom - start) * interpolation
128
- );
129
- end =
130
- distanceFromBottom <= 1
131
- ? totalItems - 1
132
- : Math.min(totalItems - 1, start + visibleCount + overscan);
133
-
134
- log("Near bottom calculation:", {
135
- distanceFromBottom,
136
- interpolation,
137
- start,
138
- end,
139
- scrollPosition,
140
- totalItems,
141
- });
142
- }
143
-
144
- // Apply overscan
145
- start = Math.max(0, start - overscan);
146
- end = Math.min(totalItems - 1, end + overscan);
147
- } else {
148
- // Direct calculation
149
- start = Math.max(
150
- 0,
151
- Math.floor(scrollPosition / viewportState.itemSize) - overscan
152
- );
153
- end = Math.min(totalItems - 1, start + visibleCount + overscan * 2);
154
- }
155
-
156
- // Validate output
157
- if (isNaN(start) || isNaN(end)) {
158
- console.error("[Virtual] NaN in range calculation:", {
159
- scrollPosition,
160
- containerSize,
161
- totalItems,
162
- itemSize: viewportState.itemSize,
163
- compressionRatio,
164
- });
165
- return { start: 0, end: 0 };
166
- }
167
-
168
- // log(`Range: ${start}-${end} (scroll: ${scrollPosition})`);
169
-
170
- // Strategic log for last range
171
- // if (end >= totalItems - 10) {
172
- // console.log(
173
- // `[Virtual] Near end range: ${start}-${end}, totalItems=${totalItems}, lastItemPos=${
174
- // end * viewportState.itemSize
175
- // }px, virtualSize=${viewportState.virtualTotalSize}px`
176
- // );
177
- // }
178
-
179
- return { start, end };
180
- };
181
-
182
- // Update functions
183
- const updateVisibleRange = (scrollPosition: number) => {
184
- if (!viewportState) return;
185
- viewportState.visibleRange = calculateVisibleRange(scrollPosition);
186
- component.emit?.("viewport:range-changed", {
187
- range: viewportState.visibleRange,
188
- scrollPosition,
189
- });
190
- };
191
-
192
- // Update total virtual size
193
- const updateTotalVirtualSize = (totalItems: number) => {
194
- if (!viewportState) return;
195
-
196
- const oldSize = viewportState.virtualTotalSize;
197
- viewportState.totalItems = totalItems;
198
- const actualSize = totalItems * viewportState.itemSize;
199
-
200
- // Get padding from the items container if available
201
- let totalPadding = 0;
202
- if (viewportState.itemsContainer) {
203
- const computedStyle = window.getComputedStyle(
204
- viewportState.itemsContainer
205
- );
206
- const paddingTop = parseFloat(computedStyle.paddingTop) || 0;
207
- const paddingBottom = parseFloat(computedStyle.paddingBottom) || 0;
208
- totalPadding = paddingTop + paddingBottom;
209
- }
210
-
211
- // Include padding in the virtual size
212
- viewportState.virtualTotalSize = Math.min(
213
- actualSize + totalPadding,
214
- MAX_VIRTUAL_SIZE
215
- );
216
-
217
- // Strategic log for debugging gap issue
218
- // console.log(
219
- // `[Virtual] Total size update: items=${totalItems}, itemSize=${viewportState.itemSize}px, padding=${totalPadding}px, virtualSize=${viewportState.virtualTotalSize}px (was ${oldSize}px)`
220
- // );
221
-
222
- component.emit?.("viewport:virtual-size-changed", {
223
- totalVirtualSize: viewportState.virtualTotalSize,
224
- totalItems: totalItems,
225
- compressionRatio: getCompressionRatio(),
226
- });
227
- };
228
-
229
- // Update container size
230
- const updateContainerSize = () => {
231
- if (!viewportState || !viewportState.viewportElement) return;
232
-
233
- const size =
234
- viewportState.viewportElement[
235
- viewportState.orientation === "horizontal"
236
- ? "offsetWidth"
237
- : "offsetHeight"
238
- ];
239
-
240
- // Log the actual measurement
241
- // console.log(
242
- // `[Virtual] Container size measured: ${size}px from viewport element`
243
- // );
244
-
245
- if (size !== viewportState.containerSize) {
246
- viewportState.containerSize = size;
247
- updateVisibleRange(viewportState.scrollPosition || 0);
248
- updateTotalVirtualSize(viewportState.totalItems); // Also update virtual size
249
- component.emit?.("viewport:container-size-changed", {
250
- containerSize: size,
251
- });
252
- }
253
- };
254
-
255
- // Override viewport methods
256
- component.viewport.getVisibleRange = () =>
257
- viewportState?.visibleRange ||
258
- calculateVisibleRange(viewportState?.scrollPosition || 0);
259
-
260
- // Event listeners
261
- component.on?.("viewport:scroll", (data: any) =>
262
- updateVisibleRange(data.position)
263
- );
264
-
265
- component.on?.("viewport:items-changed", (data: any) => {
266
- if (data.totalItems !== undefined) {
267
- updateTotalVirtualSize(data.totalItems);
268
- updateVisibleRange(viewportState?.scrollPosition || 0);
269
- }
270
- });
271
-
272
- // Listen for total items changes (important for cursor pagination)
273
- component.on?.("viewport:total-items-changed", (data: any) => {
274
- if (
275
- data.total !== undefined &&
276
- data.total !== viewportState?.totalItems
277
- ) {
278
- log(
279
- `Total items changed from ${viewportState?.totalItems} to ${data.total}`
280
- );
281
- updateTotalVirtualSize(data.total);
282
- updateVisibleRange(viewportState?.scrollPosition || 0);
283
-
284
- // Trigger a render to update the view
285
- component.viewport?.renderItems?.();
286
- }
287
- });
288
-
289
- // Listen for container size changes to recalculate virtual size
290
- component.on?.("viewport:container-size-changed", (data: any) => {
291
- if (viewportState && data.containerSize !== viewportState.containerSize) {
292
- viewportState.containerSize = data.containerSize;
293
- // Recalculate virtual size with new container size
294
- updateTotalVirtualSize(viewportState.totalItems);
295
- updateVisibleRange(viewportState.scrollPosition || 0);
296
- }
297
- });
298
-
299
- component.on?.("collection:range-loaded", (data: any) => {
300
- if (
301
- data.total !== undefined &&
302
- data.total !== viewportState?.totalItems
303
- ) {
304
- updateTotalVirtualSize(data.total);
305
- }
306
- updateVisibleRange(viewportState?.scrollPosition || 0);
307
- component.viewport?.renderItems?.();
308
- });
309
-
310
- // Listen for first items rendered to calculate item size (if auto-detection is enabled)
311
- if (autoDetectItemSize) {
312
- component.on?.("viewport:items-rendered", (data: any) => {
313
- if (
314
- !hasCalculatedItemSize &&
315
- data.elements?.length > 0 &&
316
- viewportState
317
- ) {
318
- // Calculate average item size from first rendered batch
319
- const sizes: number[] = [];
320
- const sizeProperty =
321
- orientation === "horizontal" ? "offsetWidth" : "offsetHeight";
322
-
323
- data.elements.forEach((element: HTMLElement) => {
324
- const size = element[sizeProperty];
325
- if (size > 0) {
326
- sizes.push(size);
327
- }
328
- });
329
-
330
- if (sizes.length > 0) {
331
- const avgSize = Math.round(
332
- sizes.reduce((sum, size) => sum + size, 0) / sizes.length
333
- );
334
-
335
- // console.log(
336
- // `[Virtual] Auto-detected item size: ${avgSize}px (was ${viewportState.itemSize}px), based on ${sizes.length} items`
337
- // );
338
- viewportState.itemSize = avgSize;
339
-
340
- // Recalculate everything with new size
341
- updateTotalVirtualSize(viewportState.totalItems);
342
- updateVisibleRange(viewportState.scrollPosition || 0);
343
-
344
- // Re-render to adjust positions
345
- component.viewport?.renderItems?.();
346
-
347
- // Emit event for size change
348
- component.emit?.("viewport:item-size-detected", {
349
- previousSize: initialItemSize,
350
- detectedSize: avgSize,
351
- });
352
-
353
- hasCalculatedItemSize = true;
354
- }
355
- }
356
- });
357
- }
358
-
359
- // Expose virtual API
360
- const compressionRatio = getCompressionRatio();
361
- (component as any).virtual = {
362
- calculateVisibleRange,
363
- updateTotalVirtualSize,
364
- getTotalVirtualSize: () => viewportState?.virtualTotalSize || 0,
365
- getContainerSize: () => viewportState?.containerSize || 0,
366
- updateContainerSize: (size: number) => {
367
- if (viewportState) {
368
- viewportState.containerSize = size;
369
- updateVisibleRange(viewportState.scrollPosition || 0);
370
- }
371
- },
372
- getItemSize: () => viewportState?.itemSize || initialItemSize,
373
- calculateIndexFromPosition: (position: number) =>
374
- Math.floor(
375
- position /
376
- ((viewportState?.itemSize || initialItemSize) * compressionRatio)
377
- ),
378
- calculatePositionForIndex: (index: number) =>
379
- index * (viewportState?.itemSize || initialItemSize) * compressionRatio,
380
- };
381
-
382
- return component;
383
- };
384
- };
@@ -1,133 +0,0 @@
1
- // src/core/viewport/types.ts
2
-
3
- /**
4
- * Core type definitions for Viewport
5
- * Virtual scrolling and rendering types
6
- */
7
-
8
- import type { CollectionComponent } from "./features/collection";
9
-
10
- /**
11
- * Core Range and Item Types
12
- */
13
- export interface ItemRange {
14
- start: number;
15
- end: number;
16
- }
17
-
18
- export interface ViewportInfo {
19
- containerSize: number;
20
- totalVirtualSize: number;
21
- visibleRange: ItemRange;
22
- virtualScrollPosition: number;
23
- }
24
-
25
- /**
26
- * Viewport context interface - provides context for viewport features
27
- */
28
- export interface ViewportContext {
29
- element: HTMLElement;
30
- items: any[];
31
- totalItems: number;
32
- template?: (item: any, index: number) => string | HTMLElement;
33
- emit?: (event: string, data?: any) => void;
34
- on?: (event: string, handler: Function) => () => void;
35
- once?: (event: string, handler: Function) => () => void;
36
- off?: (event: string, handler: Function) => void;
37
- getClass?: (name: string) => string;
38
- }
39
-
40
- /**
41
- * Viewport configuration - Feature-oriented structure
42
- */
43
- export interface ViewportConfig {
44
- // Basic configuration
45
- element?: HTMLElement;
46
- className?: string;
47
- debug?: boolean;
48
-
49
- // Template for rendering items
50
- template?: (
51
- item: any,
52
- index: number
53
- ) => string | HTMLElement | any[] | Record<string, any>;
54
-
55
- // Collection/data source configuration
56
- collection?: {
57
- adapter?: any; // Data adapter
58
- transform?: (item: any) => any; // Transform items before rendering
59
- };
60
-
61
- // Pagination configuration
62
- pagination?: {
63
- strategy?: "page" | "offset" | "cursor";
64
- limit?: number; // Items per page/range
65
- };
66
-
67
- // Virtual scrolling configuration
68
- virtual?: {
69
- itemSize?: number;
70
- overscan?: number; // Extra items to render outside viewport
71
- autoDetectItemSize?: boolean; // Auto-detect item size from first render
72
- };
73
-
74
- // Scrolling configuration
75
- scrolling?: {
76
- orientation?: "vertical" | "horizontal";
77
- animation?: boolean; // Smooth scrolling
78
- sensitivity?: number; // Scroll sensitivity
79
- };
80
-
81
- // Scrollbar configuration
82
- scrollbar?: {
83
- enabled?: boolean;
84
- autoHide?: boolean;
85
- };
86
-
87
- // Performance configuration
88
- performance?: {
89
- maxConcurrentRequests?: number;
90
- cancelLoadThreshold?: number; // Velocity threshold for cancelling loads
91
- enableRequestQueue?: boolean;
92
- recycleElements?: boolean;
93
- bufferSize?: number;
94
- renderDebounce?: number;
95
- };
96
-
97
- // Placeholder configuration
98
- placeholders?: {
99
- enabled?: boolean;
100
- template?: (index: number) => string | HTMLElement;
101
- maskCharacter?: string;
102
- analyzeFirstLoad?: boolean;
103
- };
104
- }
105
-
106
- /**
107
- * Enhanced component after viewport is applied
108
- */
109
- export interface ViewportComponent extends ViewportContext {
110
- viewport: {
111
- // Core API
112
- initialize(): void;
113
- destroy(): void;
114
- updateViewport(): void;
115
-
116
- // Scrolling
117
- scrollToIndex(index: number, alignment?: "start" | "center" | "end"): void;
118
- scrollToPosition(position: number): void;
119
- getScrollPosition(): number;
120
- scrollBy(delta: number): void;
121
- getVelocity(): number;
122
-
123
- // Collection feature (optional)
124
- collection?: CollectionComponent["collection"];
125
-
126
- // Info
127
- getVisibleRange(): ItemRange;
128
- getViewportInfo(): ViewportInfo;
129
-
130
- // Rendering
131
- renderItems(): void;
132
- };
133
- }
@@ -1,79 +0,0 @@
1
- // src/core/viewport/utils/speed-tracker.ts
2
-
3
- /**
4
- * Speed tracking utility for viewport
5
- * Measures velocity and determines loading strategies
6
- */
7
-
8
- import { VIEWPORT_CONSTANTS } from "../constants";
9
-
10
- export interface SpeedTracker {
11
- velocity: number;
12
- direction: "forward" | "backward";
13
- isAccelerating: boolean;
14
- lastMeasurement: number;
15
- }
16
-
17
- /**
18
- * Create a new speed tracker instance
19
- */
20
- export function createSpeedTracker(): SpeedTracker {
21
- return {
22
- velocity: 0,
23
- direction: "forward",
24
- isAccelerating: false,
25
- lastMeasurement: Date.now(),
26
- };
27
- }
28
-
29
- /**
30
- * Update speed tracker with new scroll position
31
- */
32
- export function updateSpeedTracker(
33
- tracker: SpeedTracker,
34
- newPosition: number,
35
- previousPosition: number
36
- ): SpeedTracker {
37
- const now = Date.now();
38
- const deltaTime = now - tracker.lastMeasurement;
39
- const deltaPosition = newPosition - previousPosition;
40
-
41
- // Calculate velocity (px/ms)
42
- const currentVelocity =
43
- deltaTime > 0 ? Math.abs(deltaPosition) / deltaTime : 0;
44
-
45
- // Determine direction
46
- const direction = deltaPosition >= 0 ? "forward" : "backward";
47
-
48
- // Check if accelerating
49
- const isAccelerating = currentVelocity > tracker.velocity;
50
-
51
- // Apply smoothing for more stable velocity tracking
52
- const smoothingFactor = 0.85;
53
- const smoothedVelocity =
54
- tracker.velocity * smoothingFactor +
55
- currentVelocity * (1 - smoothingFactor);
56
-
57
- return {
58
- velocity: smoothedVelocity,
59
- direction,
60
- isAccelerating,
61
- lastMeasurement: now,
62
- };
63
- }
64
-
65
- /**
66
- * Determine if scroll speed is fast (should defer loading)
67
- */
68
- export function isFastScrolling(tracker: SpeedTracker): boolean {
69
- return tracker.velocity > VIEWPORT_CONSTANTS.LOADING.CANCEL_THRESHOLD;
70
- }
71
-
72
- /**
73
- * Get loading strategy based on current speed
74
- */
75
- export function getLoadingStrategy(
76
- tracker: SpeedTracker
77
- ): "defer" | "immediate" {
78
- return isFastScrolling(tracker) ? "defer" : "immediate";
79
- }