mtrl-addons 0.1.0 → 0.1.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.
Files changed (92) hide show
  1. package/.cursorrules +117 -0
  2. package/AI.md +241 -0
  3. package/build.js +170 -0
  4. package/bun.lock +792 -0
  5. package/index.ts +7 -0
  6. package/package.json +10 -17
  7. package/scripts/analyze-orphaned-functions.ts +387 -0
  8. package/src/components/index.ts +45 -0
  9. package/src/components/list/api.ts +314 -0
  10. package/src/components/list/config.ts +352 -0
  11. package/src/components/list/constants.ts +56 -0
  12. package/src/components/list/features/api.ts +428 -0
  13. package/src/components/list/features/index.ts +31 -0
  14. package/src/components/list/features/list-manager.ts +502 -0
  15. package/src/components/list/features.ts +112 -0
  16. package/src/components/list/index.ts +39 -0
  17. package/src/components/list/list.ts +234 -0
  18. package/src/components/list/types.ts +513 -0
  19. package/src/core/collection/base-collection.ts +100 -0
  20. package/src/core/collection/collection-composer.ts +178 -0
  21. package/src/core/collection/collection.ts +745 -0
  22. package/src/core/collection/constants.ts +172 -0
  23. package/src/core/collection/events.ts +428 -0
  24. package/src/core/collection/features/api/loading.ts +279 -0
  25. package/src/core/collection/features/operations/data-operations.ts +147 -0
  26. package/src/core/collection/index.ts +104 -0
  27. package/src/core/collection/state.ts +497 -0
  28. package/src/core/collection/types.ts +404 -0
  29. package/src/core/compose/features/collection.ts +119 -0
  30. package/src/core/compose/features/index.ts +39 -0
  31. package/src/core/compose/features/performance.ts +161 -0
  32. package/src/core/compose/features/selection.ts +213 -0
  33. package/src/core/compose/features/styling.ts +108 -0
  34. package/src/core/compose/index.ts +31 -0
  35. package/src/core/index.ts +167 -0
  36. package/src/core/layout/config.ts +102 -0
  37. package/src/core/layout/index.ts +168 -0
  38. package/src/core/layout/jsx.ts +174 -0
  39. package/src/core/layout/schema.ts +963 -0
  40. package/src/core/layout/types.ts +92 -0
  41. package/src/core/list-manager/api.ts +599 -0
  42. package/src/core/list-manager/config.ts +593 -0
  43. package/src/core/list-manager/constants.ts +268 -0
  44. package/src/core/list-manager/features/api.ts +58 -0
  45. package/src/core/list-manager/features/collection/collection.ts +705 -0
  46. package/src/core/list-manager/features/collection/index.ts +17 -0
  47. package/src/core/list-manager/features/viewport/constants.ts +42 -0
  48. package/src/core/list-manager/features/viewport/index.ts +16 -0
  49. package/src/core/list-manager/features/viewport/item-size.ts +274 -0
  50. package/src/core/list-manager/features/viewport/loading.ts +263 -0
  51. package/src/core/list-manager/features/viewport/placeholders.ts +281 -0
  52. package/src/core/list-manager/features/viewport/rendering.ts +575 -0
  53. package/src/core/list-manager/features/viewport/scrollbar.ts +495 -0
  54. package/src/core/list-manager/features/viewport/scrolling.ts +795 -0
  55. package/src/core/list-manager/features/viewport/template.ts +220 -0
  56. package/src/core/list-manager/features/viewport/viewport.ts +654 -0
  57. package/src/core/list-manager/features/viewport/virtual.ts +309 -0
  58. package/src/core/list-manager/index.ts +279 -0
  59. package/src/core/list-manager/list-manager.ts +206 -0
  60. package/src/core/list-manager/types.ts +439 -0
  61. package/src/core/list-manager/utils/calculations.ts +290 -0
  62. package/src/core/list-manager/utils/range-calculator.ts +349 -0
  63. package/src/core/list-manager/utils/speed-tracker.ts +273 -0
  64. package/src/index.ts +17 -0
  65. package/src/styles/components/_list.scss +244 -0
  66. package/src/styles/index.scss +12 -0
  67. package/src/types/mtrl.d.ts +6 -0
  68. package/test/benchmarks/layout/advanced.test.ts +656 -0
  69. package/test/benchmarks/layout/comparison.test.ts +519 -0
  70. package/test/benchmarks/layout/performance-comparison.test.ts +274 -0
  71. package/test/benchmarks/layout/real-components.test.ts +733 -0
  72. package/test/benchmarks/layout/simple.test.ts +321 -0
  73. package/test/benchmarks/layout/stress.test.ts +990 -0
  74. package/test/collection/basic.test.ts +304 -0
  75. package/test/components/list.test.ts +256 -0
  76. package/test/core/collection/collection.test.ts +394 -0
  77. package/test/core/collection/failed-ranges.test.ts +270 -0
  78. package/test/core/compose/features.test.ts +183 -0
  79. package/test/core/layout/layout.test.ts +201 -0
  80. package/test/core/list-manager/features/collection.test.ts +704 -0
  81. package/test/core/list-manager/features/viewport.test.ts +698 -0
  82. package/test/core/list-manager/list-manager.test.ts +593 -0
  83. package/test/core/list-manager/utils/calculations.test.ts +433 -0
  84. package/test/core/list-manager/utils/range-calculator.test.ts +569 -0
  85. package/test/core/list-manager/utils/speed-tracker.test.ts +530 -0
  86. package/test/utils/dom-helpers.ts +275 -0
  87. package/test/utils/performance-helpers.ts +392 -0
  88. package/tsconfig.build.json +14 -0
  89. package/tsconfig.json +20 -0
  90. package/dist/index.d.ts +0 -5
  91. package/dist/index.js +0 -38
  92. package/dist/index.mjs +0 -8
@@ -0,0 +1,92 @@
1
+ /**
2
+ * @module core/layout/types
3
+ * @description Essential type definitions for layout creation system
4
+ * Core types are defined in schema.ts for better tree-shaking
5
+ */
6
+
7
+ // Re-export core types from schema processor for backward compatibility
8
+ import type {
9
+ LayoutConfig,
10
+ LayoutItemConfig,
11
+ LayoutOptions,
12
+ LayoutResult,
13
+ } from "./schema";
14
+
15
+ export type { LayoutConfig, LayoutItemConfig, LayoutOptions, LayoutResult };
16
+
17
+ /**
18
+ * Interface for component-like objects
19
+ */
20
+ export interface ComponentLike {
21
+ /** DOM element reference */
22
+ element: any;
23
+ /** Optional method to clean up resources */
24
+ destroy?: () => void;
25
+ /** Allow additional properties */
26
+ [key: string]: any;
27
+ }
28
+
29
+ /**
30
+ * Extended options for element creation
31
+ * Used in object-based schemas
32
+ */
33
+ export interface ElementOptions extends Record<string, any> {
34
+ /** Layout configuration for the element */
35
+ layout?: LayoutConfig;
36
+
37
+ /** Layout item configuration */
38
+ layoutItem?: LayoutItemConfig;
39
+
40
+ /** CSS classes to apply */
41
+ class?: string;
42
+
43
+ /** Additional CSS classes (alias for class) */
44
+ className?: string;
45
+
46
+ /** HTML tag name for createElement */
47
+ tag?: string;
48
+
49
+ /** Text content for the element */
50
+ textContent?: string;
51
+
52
+ /** Inline styles */
53
+ style?: Record<string, string | number>;
54
+
55
+ /** HTML attributes */
56
+ attributes?: Record<string, string>;
57
+
58
+ /** Event handlers */
59
+ events?: Record<string, Function>;
60
+
61
+ /** Legacy event handler support */
62
+ event?: Record<string, Function>;
63
+ }
64
+
65
+ /**
66
+ * Definition for a single element in object-based layout schemas
67
+ */
68
+ export interface ElementDefinition {
69
+ /** Optional name to reference the element */
70
+ name?: string;
71
+
72
+ /** Creator function that produces a DOM element or ComponentLike */
73
+ creator?: (options?: Record<string, any>) => any;
74
+
75
+ /** Options to pass to the creator function */
76
+ options?: ElementOptions;
77
+
78
+ /** Child elements to create and attach */
79
+ children?: Record<string, ElementDefinition>;
80
+ }
81
+
82
+ /**
83
+ * Schema for object-based layout creation
84
+ * Array-based schemas are handled directly as arrays
85
+ */
86
+ export interface Schema {
87
+ /** Root element definition */
88
+ element?: ElementDefinition;
89
+
90
+ /** Additional elements */
91
+ [key: string]: ElementDefinition | undefined;
92
+ }
@@ -0,0 +1,599 @@
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;