mtrl-addons 0.1.2 → 0.2.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 (117) hide show
  1. package/AI.md +28 -230
  2. package/CLAUDE.md +882 -0
  3. package/build.js +253 -24
  4. package/package.json +14 -4
  5. package/scripts/debug/vlist-selection.ts +121 -0
  6. package/src/components/index.ts +5 -41
  7. package/src/components/{list → vlist}/config.ts +66 -95
  8. package/src/components/vlist/constants.ts +23 -0
  9. package/src/components/vlist/features/api.ts +626 -0
  10. package/src/components/vlist/features/index.ts +10 -0
  11. package/src/components/vlist/features/selection.ts +436 -0
  12. package/src/components/vlist/features/viewport.ts +59 -0
  13. package/src/components/vlist/index.ts +17 -0
  14. package/src/components/{list → vlist}/types.ts +242 -32
  15. package/src/components/vlist/vlist.ts +92 -0
  16. package/src/core/compose/features/gestures/index.ts +227 -0
  17. package/src/core/compose/features/gestures/longpress.ts +383 -0
  18. package/src/core/compose/features/gestures/pan.ts +424 -0
  19. package/src/core/compose/features/gestures/pinch.ts +475 -0
  20. package/src/core/compose/features/gestures/rotate.ts +485 -0
  21. package/src/core/compose/features/gestures/swipe.ts +492 -0
  22. package/src/core/compose/features/gestures/tap.ts +334 -0
  23. package/src/core/compose/features/index.ts +2 -38
  24. package/src/core/compose/index.ts +13 -29
  25. package/src/core/gestures/index.ts +31 -0
  26. package/src/core/gestures/longpress.ts +68 -0
  27. package/src/core/gestures/manager.ts +418 -0
  28. package/src/core/gestures/pan.ts +48 -0
  29. package/src/core/gestures/pinch.ts +58 -0
  30. package/src/core/gestures/rotate.ts +58 -0
  31. package/src/core/gestures/swipe.ts +66 -0
  32. package/src/core/gestures/tap.ts +45 -0
  33. package/src/core/gestures/types.ts +387 -0
  34. package/src/core/gestures/utils.ts +128 -0
  35. package/src/core/index.ts +27 -151
  36. package/src/core/layout/schema.ts +153 -72
  37. package/src/core/layout/types.ts +5 -2
  38. package/src/core/viewport/constants.ts +145 -0
  39. package/src/core/viewport/features/base.ts +73 -0
  40. package/src/core/viewport/features/collection.ts +1182 -0
  41. package/src/core/viewport/features/events.ts +130 -0
  42. package/src/core/viewport/features/index.ts +20 -0
  43. package/src/core/{list-manager/features/viewport → viewport/features}/item-size.ts +31 -34
  44. package/src/core/{list-manager/features/viewport → viewport/features}/loading.ts +4 -4
  45. package/src/core/viewport/features/momentum.ts +269 -0
  46. package/src/core/viewport/features/placeholders.ts +335 -0
  47. package/src/core/viewport/features/rendering.ts +962 -0
  48. package/src/core/viewport/features/scrollbar.ts +434 -0
  49. package/src/core/viewport/features/scrolling.ts +634 -0
  50. package/src/core/viewport/features/utils.ts +94 -0
  51. package/src/core/viewport/features/virtual.ts +525 -0
  52. package/src/core/viewport/index.ts +31 -0
  53. package/src/core/viewport/types.ts +133 -0
  54. package/src/core/viewport/utils/speed-tracker.ts +79 -0
  55. package/src/core/viewport/viewport.ts +265 -0
  56. package/src/index.ts +0 -7
  57. package/src/styles/components/_vlist.scss +352 -0
  58. package/src/styles/index.scss +1 -1
  59. package/test/components/vlist-selection.test.ts +240 -0
  60. package/test/components/vlist.test.ts +63 -0
  61. package/test/core/collection/adapter.test.ts +161 -0
  62. package/bun.lock +0 -792
  63. package/src/components/list/api.ts +0 -314
  64. package/src/components/list/constants.ts +0 -56
  65. package/src/components/list/features/api.ts +0 -428
  66. package/src/components/list/features/index.ts +0 -31
  67. package/src/components/list/features/list-manager.ts +0 -502
  68. package/src/components/list/index.ts +0 -39
  69. package/src/components/list/list.ts +0 -234
  70. package/src/core/collection/base-collection.ts +0 -100
  71. package/src/core/collection/collection-composer.ts +0 -178
  72. package/src/core/collection/collection.ts +0 -745
  73. package/src/core/collection/constants.ts +0 -172
  74. package/src/core/collection/events.ts +0 -428
  75. package/src/core/collection/features/api/loading.ts +0 -279
  76. package/src/core/collection/features/operations/data-operations.ts +0 -147
  77. package/src/core/collection/index.ts +0 -104
  78. package/src/core/collection/state.ts +0 -497
  79. package/src/core/collection/types.ts +0 -404
  80. package/src/core/compose/features/collection.ts +0 -119
  81. package/src/core/compose/features/selection.ts +0 -213
  82. package/src/core/compose/features/styling.ts +0 -108
  83. package/src/core/list-manager/api.ts +0 -599
  84. package/src/core/list-manager/config.ts +0 -593
  85. package/src/core/list-manager/constants.ts +0 -268
  86. package/src/core/list-manager/features/api.ts +0 -58
  87. package/src/core/list-manager/features/collection/collection.ts +0 -705
  88. package/src/core/list-manager/features/collection/index.ts +0 -17
  89. package/src/core/list-manager/features/viewport/constants.ts +0 -42
  90. package/src/core/list-manager/features/viewport/index.ts +0 -16
  91. package/src/core/list-manager/features/viewport/placeholders.ts +0 -281
  92. package/src/core/list-manager/features/viewport/rendering.ts +0 -575
  93. package/src/core/list-manager/features/viewport/scrollbar.ts +0 -495
  94. package/src/core/list-manager/features/viewport/scrolling.ts +0 -795
  95. package/src/core/list-manager/features/viewport/template.ts +0 -220
  96. package/src/core/list-manager/features/viewport/viewport.ts +0 -654
  97. package/src/core/list-manager/features/viewport/virtual.ts +0 -309
  98. package/src/core/list-manager/index.ts +0 -279
  99. package/src/core/list-manager/list-manager.ts +0 -206
  100. package/src/core/list-manager/types.ts +0 -439
  101. package/src/core/list-manager/utils/calculations.ts +0 -290
  102. package/src/core/list-manager/utils/range-calculator.ts +0 -349
  103. package/src/core/list-manager/utils/speed-tracker.ts +0 -273
  104. package/src/styles/components/_list.scss +0 -244
  105. package/src/types/mtrl.d.ts +0 -6
  106. package/test/components/list.test.ts +0 -256
  107. package/test/core/collection/failed-ranges.test.ts +0 -270
  108. package/test/core/compose/features.test.ts +0 -183
  109. package/test/core/list-manager/features/collection.test.ts +0 -704
  110. package/test/core/list-manager/features/viewport.test.ts +0 -698
  111. package/test/core/list-manager/list-manager.test.ts +0 -593
  112. package/test/core/list-manager/utils/calculations.test.ts +0 -433
  113. package/test/core/list-manager/utils/range-calculator.test.ts +0 -569
  114. package/test/core/list-manager/utils/speed-tracker.test.ts +0 -530
  115. package/tsconfig.build.json +0 -23
  116. /package/src/components/{list → vlist}/features.ts +0 -0
  117. /package/src/core/{compose → viewport}/features/performance.ts +0 -0
@@ -1,599 +0,0 @@
1
- /**
2
- * API Bridge for List Manager
3
- * Provides event helpers and component integration utilities
4
- */
5
-
6
- import type {
7
- ListManager,
8
- ListManagerConfig,
9
- ListManagerObserver,
10
- ListManagerEventData,
11
- ItemRange,
12
- ViewportInfo,
13
- } from "./types";
14
- import { ListManagerEvents } from "./types";
15
- import { createListManager } from "./list-manager";
16
-
17
- /**
18
- * Enhanced List Manager API with convenient methods
19
- */
20
- export interface ListManagerAPI {
21
- // Business logic API
22
- loadRange(
23
- pageOrOffset: number,
24
- size: number,
25
- strategy?: "page" | "offset",
26
- alignment?: "start" | "center" | "end"
27
- ): void;
28
-
29
- // Navigation API
30
- scrollToPosition(position: number): void;
31
- scrollToIndex(index: number, alignment?: "start" | "center" | "end"): void;
32
- scrollToPage(page: number, alignment?: "start" | "center" | "end"): void;
33
-
34
- // State API
35
- getScrollPosition(): number;
36
- getItems(): any[];
37
- getTotalItems(): number;
38
- getVisibleRange(): ItemRange;
39
-
40
- // Core lifecycle
41
- initialize(): void;
42
- destroy(): void;
43
- updateConfig(config: Partial<ListManagerConfig>): void;
44
-
45
- // Event system
46
- on(event: string, listener: Function): () => void;
47
-
48
- // Convenience methods
49
- onScroll(
50
- callback: (position: number, direction: "forward" | "backward") => void
51
- ): () => void;
52
- onRangeChange(callback: (range: ItemRange) => void): () => void;
53
- onViewportChange(callback: (viewport: ViewportInfo) => void): () => void;
54
- onLoading(callback: (range: ItemRange, strategy: string) => void): () => void;
55
- onPlaceholders(
56
- callback: (range: ItemRange, count: number) => void
57
- ): () => void;
58
-
59
- // State queries
60
- isLoading(): boolean;
61
- getLoadedRanges(): Set<number>;
62
- hasItem(index: number): boolean;
63
- getItem(index: number): any;
64
-
65
- // Debugging
66
- getDebugInfo(): ListManagerDebugInfo;
67
- enableDebug(): void;
68
- disableDebug(): void;
69
- }
70
-
71
- /**
72
- * Debug information interface
73
- */
74
- export interface ListManagerDebugInfo {
75
- config: ListManagerConfig;
76
- state: {
77
- isInitialized: boolean;
78
- totalItems: number;
79
- visibleRange: ItemRange;
80
- scrollPosition: number;
81
- paginationStrategy: string;
82
- };
83
- performance: {
84
- scrollVelocity: number;
85
- loadedRanges: number[];
86
- pendingRanges: number[];
87
- };
88
- features: {
89
- viewport: {
90
- orientation: string;
91
- containerSize: number;
92
- totalVirtualSize: number;
93
- estimatedItemSize: number;
94
- measuredItemsCount: number;
95
- };
96
- collection: {
97
- loadedItemsCount: number;
98
- hasPlaceholderStructure: boolean;
99
- placeholderFields: string[];
100
- };
101
- };
102
- }
103
-
104
- /**
105
- * Event helper functions
106
- */
107
- export class ListManagerEventHelpers {
108
- private listManager: any; // Enhanced component from createListManager
109
- private eventSubscriptions: Map<string, () => void> = new Map();
110
-
111
- constructor(listManager: any) {
112
- this.listManager = listManager;
113
- }
114
-
115
- /**
116
- * Subscribe to scroll position changes
117
- */
118
- onScroll(
119
- callback: (position: number, direction: "forward" | "backward") => void
120
- ): () => void {
121
- const unsubscribe = this.listManager.on(
122
- "scroll:position:changed",
123
- (data: any) => {
124
- callback(data.position, data.direction);
125
- }
126
- );
127
-
128
- const key = `scroll-${Date.now()}`;
129
- this.eventSubscriptions.set(key, unsubscribe);
130
-
131
- return () => {
132
- unsubscribe();
133
- this.eventSubscriptions.delete(key);
134
- };
135
- }
136
-
137
- /**
138
- * Subscribe to visible range changes
139
- */
140
- onRangeChange(callback: (range: ItemRange) => void): () => void {
141
- const unsubscribe = this.listManager.on(
142
- "virtual:range:changed",
143
- (data: any) => {
144
- callback(data);
145
- }
146
- );
147
-
148
- const key = `range-${Date.now()}`;
149
- this.eventSubscriptions.set(key, unsubscribe);
150
-
151
- return () => {
152
- unsubscribe();
153
- this.eventSubscriptions.delete(key);
154
- };
155
- }
156
-
157
- /**
158
- * Subscribe to viewport changes
159
- */
160
- onViewportChange(callback: (viewport: ViewportInfo) => void): () => void {
161
- const unsubscribe = this.listManager.on("viewport:changed", (data: any) => {
162
- callback(data);
163
- });
164
-
165
- const key = `viewport-${Date.now()}`;
166
- this.eventSubscriptions.set(key, unsubscribe);
167
-
168
- return () => {
169
- unsubscribe();
170
- this.eventSubscriptions.delete(key);
171
- };
172
- }
173
-
174
- /**
175
- * Subscribe to loading events
176
- */
177
- onLoading(
178
- callback: (range: ItemRange, strategy: string) => void
179
- ): () => void {
180
- const unsubscribe = this.listManager.on(
181
- "loading:triggered",
182
- (data: any) => {
183
- callback(data.range, data.strategy);
184
- }
185
- );
186
-
187
- const key = `loading-${Date.now()}`;
188
- this.eventSubscriptions.set(key, unsubscribe);
189
-
190
- return () => {
191
- unsubscribe();
192
- this.eventSubscriptions.delete(key);
193
- };
194
- }
195
-
196
- /**
197
- * Subscribe to placeholder events
198
- */
199
- onPlaceholders(
200
- callback: (range: ItemRange, count: number) => void
201
- ): () => void {
202
- const unsubscribe = this.listManager.on(
203
- "placeholders:shown",
204
- (data: any) => {
205
- callback(data.range, data.count);
206
- }
207
- );
208
-
209
- const key = `placeholders-${Date.now()}`;
210
- this.eventSubscriptions.set(key, unsubscribe);
211
-
212
- return () => {
213
- unsubscribe();
214
- this.eventSubscriptions.delete(key);
215
- };
216
- }
217
-
218
- /**
219
- * Clean up all event subscriptions
220
- */
221
- destroy(): void {
222
- this.eventSubscriptions.forEach((unsubscribe) => unsubscribe());
223
- this.eventSubscriptions.clear();
224
- }
225
- }
226
-
227
- /**
228
- * Enhanced List Manager implementation with API helpers
229
- */
230
- class ListManagerAPIImpl implements ListManagerAPI {
231
- private listManager: any; // Enhanced component from createListManager
232
- private eventHelpers: ListManagerEventHelpers;
233
-
234
- constructor(listManager: any) {
235
- this.listManager = listManager;
236
- this.eventHelpers = new ListManagerEventHelpers(listManager);
237
- }
238
-
239
- // Business logic API
240
- loadRange(
241
- pageOrOffset: number,
242
- size: number,
243
- strategy: "page" | "offset" = "page",
244
- alignment: "start" | "center" | "end" = "start"
245
- ): void {
246
- console.log(
247
- `🎯 [LIST-MANAGER-API] loadRange called: ${pageOrOffset}, size=${size}, strategy=${strategy}, alignment=${alignment}`
248
- );
249
-
250
- let targetIndex: number;
251
- let dataRange: { start: number; end: number };
252
-
253
- if (strategy === "page") {
254
- // Page-based loading: page 1 = items 0-19, page 2 = items 20-39
255
- const pageSize = size;
256
- targetIndex = (pageOrOffset - 1) * pageSize;
257
- dataRange = {
258
- start: targetIndex,
259
- end: targetIndex + pageSize - 1,
260
- };
261
- console.log(
262
- `📄 [LIST-MANAGER-API] Page ${pageOrOffset} → index ${targetIndex}, range ${dataRange.start}-${dataRange.end}`
263
- );
264
- } else {
265
- // Offset-based loading: offset 2 = start at item 2, load 'size' items
266
- targetIndex = pageOrOffset;
267
- dataRange = {
268
- start: targetIndex,
269
- end: targetIndex + size - 1,
270
- };
271
- console.log(
272
- `📍 [LIST-MANAGER-API] Offset ${pageOrOffset} → range ${dataRange.start}-${dataRange.end}`
273
- );
274
- }
275
-
276
- // 1. First, request data from collection (proactive)
277
- console.log(
278
- `📡 [LIST-MANAGER-API] Requesting data for range ${dataRange.start}-${dataRange.end}`
279
- );
280
- if (
281
- this.listManager.collection &&
282
- typeof this.listManager.collection.loadMissingRanges === "function"
283
- ) {
284
- this.listManager.collection
285
- .loadMissingRanges(dataRange)
286
- .catch((error: any) => {
287
- console.error("❌ [LIST-MANAGER-API] Failed to load range:", error);
288
- });
289
- }
290
-
291
- // 2. Then, tell viewport to scroll to visual position
292
- console.log(
293
- `🎯 [LIST-MANAGER-API] Instructing viewport to scroll to index ${targetIndex}`
294
- );
295
- if (this.listManager.viewport?.scrollToIndex) {
296
- this.listManager.viewport.scrollToIndex(targetIndex, alignment);
297
- } else {
298
- console.error(
299
- "❌ [LIST-MANAGER-API] Viewport or scrollToIndex method not available"
300
- );
301
- }
302
- }
303
-
304
- // Navigation API
305
- scrollToPosition(position: number): void {
306
- console.log(`🎯 [LIST-MANAGER-API] scrollToPosition called: ${position}px`);
307
- if (this.listManager.viewport?.scrollToPosition) {
308
- this.listManager.viewport.scrollToPosition(position);
309
- } else {
310
- console.error(
311
- "❌ [LIST-MANAGER-API] Viewport or scrollToPosition method not available"
312
- );
313
- }
314
- }
315
-
316
- // Delegate core methods to the enhanced component
317
- scrollToIndex(index: number, alignment?: "start" | "center" | "end"): void {
318
- console.log(
319
- `🎯 [LIST-MANAGER-API] scrollToIndex called: index=${index}, alignment=${alignment}`
320
- );
321
- if (this.listManager.viewport?.scrollToIndex) {
322
- this.listManager.viewport.scrollToIndex(index, alignment);
323
- } else {
324
- console.error(
325
- "❌ [LIST-MANAGER-API] Viewport or scrollToIndex method not available"
326
- );
327
- }
328
- }
329
-
330
- scrollToPage(page: number, alignment?: "start" | "center" | "end"): void {
331
- // Get the configured page size from collection or use default
332
- const collection = this.listManager.collection as any;
333
- let pageSize = 20; // Default
334
-
335
- if (collection) {
336
- // Try to get range size from collection
337
- if (collection.rangeSize) {
338
- pageSize = collection.rangeSize;
339
- } else if (collection.getLoadedRanges) {
340
- // Fallback to checking loaded ranges
341
- const loadedRanges = collection.getLoadedRanges();
342
- if (loadedRanges.size > 0) {
343
- // Infer from loaded ranges
344
- pageSize = this.listManager.config?.collection?.pageSize || 20;
345
- }
346
- }
347
- }
348
-
349
- // Also check config
350
- if (this.listManager.config?.collection?.pageSize) {
351
- pageSize = this.listManager.config.collection.pageSize;
352
- }
353
-
354
- console.log(
355
- `🎯 [LIST-MANAGER-API] scrollToPage called: page=${page}, pageSize=${pageSize}, alignment=${alignment}`
356
- );
357
- this.loadRange(page, pageSize, "page", alignment);
358
- }
359
-
360
- // State API
361
- getScrollPosition(): number {
362
- return this.listManager.viewport?.getScrollPosition() || 0;
363
- }
364
-
365
- getItems(): any[] {
366
- return this.listManager.items || [];
367
- }
368
-
369
- getTotalItems(): number {
370
- return this.listManager.totalItems || 0;
371
- }
372
-
373
- getVisibleRange(): ItemRange {
374
- return this.listManager.viewport?.getVisibleRange() || { start: 0, end: 0 };
375
- }
376
-
377
- // Core lifecycle
378
- initialize(): void {
379
- this.listManager.initialize();
380
- }
381
-
382
- destroy(): void {
383
- this.listManager.destroy();
384
- }
385
-
386
- updateConfig(config: Partial<ListManagerConfig>): void {
387
- this.listManager.updateConfig(config);
388
- }
389
-
390
- // Event system
391
- on(event: string, listener: Function): () => void {
392
- return this.listManager.on(event, listener);
393
- }
394
-
395
- // Convenience methods
396
- onScroll(
397
- callback: (position: number, direction: "forward" | "backward") => void
398
- ): () => void {
399
- return this.eventHelpers.onScroll(callback);
400
- }
401
-
402
- onRangeChange(callback: (range: ItemRange) => void): () => void {
403
- return this.eventHelpers.onRangeChange(callback);
404
- }
405
-
406
- onViewportChange(callback: (viewport: ViewportInfo) => void): () => void {
407
- return this.eventHelpers.onViewportChange(callback);
408
- }
409
-
410
- onLoading(
411
- callback: (range: ItemRange, strategy: string) => void
412
- ): () => void {
413
- return this.eventHelpers.onLoading(callback);
414
- }
415
-
416
- onPlaceholders(
417
- callback: (range: ItemRange, count: number) => void
418
- ): () => void {
419
- return this.eventHelpers.onPlaceholders(callback);
420
- }
421
-
422
- isLoading(): boolean {
423
- // TODO: Implement proper loading state check
424
- return false;
425
- }
426
-
427
- getLoadedRanges(): Set<number> {
428
- // TODO: Implement proper loaded ranges access
429
- return new Set();
430
- }
431
-
432
- hasItem(index: number): boolean {
433
- // TODO: Implement proper item check
434
- return false;
435
- }
436
-
437
- getItem(index: number): any {
438
- // TODO: Implement proper item access
439
- return null;
440
- }
441
-
442
- getDebugInfo(): ListManagerDebugInfo {
443
- const config = this.listManager.getConfig(); // Assuming getConfig is available on the enhanced component
444
- const viewport = this.listManager.getViewportInfo(); // Assuming getViewportInfo is available on the enhanced component
445
- const visibleRange = this.listManager.getVisibleRange(); // Assuming getVisibleRange is available on the enhanced component
446
-
447
- return {
448
- config,
449
- state: {
450
- isInitialized: true, // TODO: Access internal state
451
- totalItems: this.getTotalItems(),
452
- visibleRange,
453
- scrollPosition: this.getScrollPosition(),
454
- paginationStrategy: this.listManager.getPaginationStrategy(), // Assuming getPaginationStrategy is available on the enhanced component
455
- },
456
- performance: {
457
- scrollVelocity: 0, // TODO: Access speed tracker
458
- loadedRanges: [], // TODO: Access collection feature
459
- pendingRanges: [], // TODO: Access collection feature
460
- },
461
- features: {
462
- viewport: {
463
- orientation: config.orientation.orientation,
464
- containerSize: viewport.containerSize,
465
- totalVirtualSize: viewport.totalVirtualSize,
466
- estimatedItemSize: config.virtual.estimatedItemSize,
467
- measuredItemsCount: 0, // TODO: Access viewport feature
468
- },
469
- collection: {
470
- loadedItemsCount: 0, // TODO: Access collection feature
471
- hasPlaceholderStructure: false, // TODO: Access collection feature
472
- placeholderFields: [], // TODO: Access collection feature
473
- },
474
- },
475
- };
476
- }
477
-
478
- enableDebug(): void {
479
- this.listManager.updateConfig({ debug: true }); // Assuming updateConfig is available on the enhanced component
480
- }
481
-
482
- disableDebug(): void {
483
- this.listManager.updateConfig({ debug: false }); // Assuming updateConfig is available on the enhanced component
484
- }
485
- }
486
-
487
- /**
488
- * Create an enhanced List Manager with API helpers
489
- */
490
- export function createListManagerAPI(
491
- config: ListManagerConfig
492
- ): ListManagerAPI {
493
- const listManager = createListManager(config);
494
- return new ListManagerAPIImpl(listManager);
495
- }
496
-
497
- /**
498
- * Utility functions for common List Manager operations
499
- */
500
- export const ListManagerUtils = {
501
- /**
502
- * Create a simple template function for debugging
503
- */
504
- createDebugTemplate: (itemHeight: number = 50) => {
505
- return (item: any, index: number) => {
506
- const div = document.createElement("div");
507
- div.style.height = `${itemHeight}px`;
508
- div.style.padding = "8px";
509
- div.style.borderBottom = "1px solid #eee";
510
- div.style.display = "flex";
511
- div.style.alignItems = "center";
512
- div.innerHTML = `
513
- <span style="font-weight: bold; margin-right: 8px;">#${index}</span>
514
- <span>${JSON.stringify(item)}</span>
515
- `;
516
- return div;
517
- };
518
- },
519
-
520
- /**
521
- * Create a default configuration for testing
522
- */
523
- createTestConfig: (
524
- container: HTMLElement,
525
- itemCount: number = 1000
526
- ): Partial<ListManagerConfig> => {
527
- const items = Array.from({ length: itemCount }, (_, i) => ({
528
- id: i,
529
- name: `Item ${i}`,
530
- value: Math.random() * 100,
531
- }));
532
-
533
- return {
534
- container,
535
- items,
536
- virtual: {
537
- enabled: true,
538
- itemSize: "auto",
539
- estimatedItemSize: 50,
540
- overscan: 5,
541
- },
542
- orientation: {
543
- orientation: "vertical",
544
- reverse: false,
545
- crossAxisAlignment: "stretch",
546
- },
547
- template: {
548
- template: ListManagerUtils.createDebugTemplate(50),
549
- },
550
- debug: true,
551
- prefix: "test-list",
552
- componentName: "TestList",
553
- };
554
- },
555
-
556
- /**
557
- * Performance measurement helper
558
- */
559
- measurePerformance: (
560
- listManager: ListManagerAPI,
561
- duration: number = 5000
562
- ) => {
563
- const measurements = {
564
- scrollEvents: 0,
565
- rangeChanges: 0,
566
- loadingTriggers: 0,
567
- startTime: Date.now(),
568
- endTime: 0,
569
- };
570
-
571
- const unsubscribeScroll = listManager.onScroll(() => {
572
- measurements.scrollEvents++;
573
- });
574
-
575
- const unsubscribeRange = listManager.onRangeChange(() => {
576
- measurements.rangeChanges++;
577
- });
578
-
579
- const unsubscribeLoading = listManager.onLoading(() => {
580
- measurements.loadingTriggers++;
581
- });
582
-
583
- return new Promise<typeof measurements>((resolve) => {
584
- setTimeout(() => {
585
- measurements.endTime = Date.now();
586
- unsubscribeScroll();
587
- unsubscribeRange();
588
- unsubscribeLoading();
589
- resolve(measurements);
590
- }, duration);
591
- });
592
- },
593
- };
594
-
595
- /**
596
- * Default exports
597
- */
598
- export { createListManager };
599
- export default createListManagerAPI;