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,593 +0,0 @@
1
- import {
2
- describe,
3
- it,
4
- expect,
5
- beforeEach,
6
- afterEach,
7
- mock,
8
- spyOn,
9
- } from "bun:test";
10
- import {
11
- createListManager,
12
- ListManagerImpl,
13
- } from "../../../src/core/list-manager/list-manager";
14
- import { ListManagerEvents } from "../../../src/core/list-manager/types";
15
- import type {
16
- ListManagerConfig,
17
- ListManagerConfigUpdate,
18
- } from "../../../src/core/list-manager/types";
19
-
20
- // Mock DOM environment
21
- const mockContainer = {
22
- getBoundingClientRect: () => ({ width: 400, height: 600, top: 0, left: 0 }),
23
- scrollTop: 0,
24
- scrollLeft: 0,
25
- clientWidth: 400,
26
- clientHeight: 600,
27
- addEventListener: mock(),
28
- removeEventListener: mock(),
29
- appendChild: mock(),
30
- removeChild: mock(),
31
- style: {},
32
- } as unknown as HTMLElement;
33
-
34
- // Mock features
35
- const mockViewportFeature = {
36
- initialize: mock(),
37
- destroy: mock(),
38
- scrollToIndex: mock(),
39
- calculateVisibleRange: mock(() => ({ start: 0, end: 10 })),
40
- getViewportInfo: mock(() => ({
41
- containerSize: 600,
42
- totalVirtualSize: 50000,
43
- visibleRange: { start: 0, end: 10 },
44
- virtualScrollPosition: 0,
45
- })),
46
- updateContainerPosition: mock(),
47
- updateScrollbar: mock(),
48
- setTotalItems: mock(),
49
- virtualScrollPosition: 0,
50
- orientation: "vertical",
51
- estimatedItemSize: 50,
52
- };
53
-
54
- const mockCollectionFeature = {
55
- initialize: mock(),
56
- destroy: mock(),
57
- setTemplate: mock(),
58
- setItems: mock(),
59
- getItemsInRange: mock(() => [] as any[]),
60
- handleVisibleRangeChange: mock(),
61
- handleScrollPositionChange: mock(),
62
- adaptPaginationStrategy: mock(),
63
- paginationStrategy: "page",
64
- };
65
-
66
- // Mock feature factories
67
- mock.module("../../../src/core/list-manager/features/viewport", () => ({
68
- createViewportFeature: mock(() => mockViewportFeature),
69
- }));
70
-
71
- mock.module("../../../src/core/list-manager/features/collection", () => ({
72
- createCollectionFeature: mock(() => mockCollectionFeature),
73
- }));
74
-
75
- describe("ListManager", () => {
76
- let config: ListManagerConfig;
77
- let listManager: ListManagerImpl;
78
-
79
- beforeEach(() => {
80
- // Reset all mocks
81
- mock.restore();
82
-
83
- // Create test configuration with all required properties
84
- config = {
85
- container: mockContainer,
86
- items: Array.from({ length: 100 }, (_, i) => ({
87
- id: i,
88
- name: `Item ${i}`,
89
- })),
90
- template: {
91
- template: (item: any, index: number) => {
92
- const div = document.createElement("div");
93
- div.textContent = `${index}: ${item.name}`;
94
- return div;
95
- },
96
- },
97
- virtual: {
98
- enabled: true,
99
- itemSize: "auto",
100
- estimatedItemSize: 50,
101
- overscan: 5,
102
- },
103
- orientation: {
104
- orientation: "vertical",
105
- reverse: false,
106
- crossAxisAlignment: "stretch",
107
- },
108
- initialLoad: {
109
- strategy: "placeholders",
110
- viewportMultiplier: 1.5,
111
- minItems: 10,
112
- maxItems: 100,
113
- },
114
- errorHandling: {
115
- timeout: 5000,
116
- showErrorItems: true,
117
- retryAttempts: 3,
118
- preserveScrollOnError: true,
119
- },
120
- positioning: {
121
- precisePositioning: true,
122
- allowPartialItems: true,
123
- snapToItems: false,
124
- },
125
- boundaries: {
126
- preventOverscroll: true,
127
- maintainEdgeRanges: true,
128
- boundaryResistance: 0.15,
129
- },
130
- recycling: {
131
- enabled: false,
132
- maxPoolSize: 50,
133
- minPoolSize: 10,
134
- },
135
- performance: {
136
- frameScheduling: true,
137
- memoryCleanup: true,
138
- },
139
- intersection: {
140
- pagination: {
141
- enabled: false,
142
- rootMargin: "100px",
143
- threshold: 0.1,
144
- },
145
- loading: {
146
- enabled: false,
147
- },
148
- },
149
- debug: true,
150
- prefix: "test-list",
151
- componentName: "TestList",
152
- };
153
- });
154
-
155
- afterEach(() => {
156
- if (listManager) {
157
- listManager.destroy();
158
- }
159
- });
160
-
161
- describe("Initialization", () => {
162
- it("should create a ListManager with valid config", () => {
163
- listManager = new ListManagerImpl(config);
164
- expect(listManager).toBeDefined();
165
- expect(listManager.getTotalItems()).toBe(100);
166
- });
167
-
168
- it("should throw error with invalid container", () => {
169
- const invalidConfig = { ...config, container: null as any };
170
- expect(() => new ListManagerImpl(invalidConfig)).toThrow();
171
- });
172
-
173
- it("should initialize features when initialize() is called", () => {
174
- listManager = new ListManagerImpl(config);
175
- listManager.initialize();
176
-
177
- expect(mockViewportFeature.initialize).toHaveBeenCalled();
178
- expect(mockCollectionFeature.initialize).toHaveBeenCalled();
179
- });
180
-
181
- it("should not initialize twice", () => {
182
- listManager = new ListManagerImpl(config);
183
- listManager.initialize();
184
- listManager.initialize();
185
-
186
- expect(mockViewportFeature.initialize).toHaveBeenCalledTimes(1);
187
- });
188
-
189
- it("should set template if provided", () => {
190
- listManager = new ListManagerImpl(config);
191
- listManager.initialize();
192
-
193
- expect(mockCollectionFeature.setTemplate).toHaveBeenCalledWith(
194
- config.template!.template
195
- );
196
- });
197
-
198
- it("should set items if provided", () => {
199
- listManager = new ListManagerImpl(config);
200
- listManager.initialize();
201
-
202
- expect(mockCollectionFeature.setItems).toHaveBeenCalledWith(config.items);
203
- });
204
- });
205
-
206
- describe("Virtual Scrolling API", () => {
207
- beforeEach(() => {
208
- listManager = new ListManagerImpl(config);
209
- listManager.initialize();
210
- });
211
-
212
- it("should scroll to index", () => {
213
- listManager.scrollToIndex(50, "center");
214
- expect(mockViewportFeature.scrollToIndex).toHaveBeenCalledWith(
215
- 50,
216
- "center"
217
- );
218
- });
219
-
220
- it("should not scroll to invalid index", () => {
221
- const consoleSpy = spyOn(console, "warn").mockImplementation(() => {});
222
-
223
- listManager.scrollToIndex(-1);
224
- listManager.scrollToIndex(1000);
225
-
226
- expect(mockViewportFeature.scrollToIndex).not.toHaveBeenCalled();
227
- expect(consoleSpy).toHaveBeenCalledTimes(2);
228
-
229
- consoleSpy.mockRestore();
230
- });
231
-
232
- it("should scroll to page", () => {
233
- listManager.scrollToPage(5, "start");
234
-
235
- // Page 5 should target index 80 (assuming default page size of 20)
236
- expect(mockViewportFeature.scrollToIndex).toHaveBeenCalledWith(
237
- 80,
238
- "start"
239
- );
240
- });
241
-
242
- it("should not scroll to page out of range", () => {
243
- const consoleSpy = spyOn(console, "warn").mockImplementation(() => {});
244
-
245
- listManager.scrollToPage(100); // Way beyond item count
246
-
247
- expect(mockViewportFeature.scrollToIndex).not.toHaveBeenCalled();
248
- expect(consoleSpy).toHaveBeenCalled();
249
-
250
- consoleSpy.mockRestore();
251
- });
252
-
253
- it("should get scroll position", () => {
254
- mockViewportFeature.virtualScrollPosition = 1000;
255
- expect(listManager.getScrollPosition()).toBe(1000);
256
- });
257
- });
258
-
259
- describe("Viewport Management", () => {
260
- beforeEach(() => {
261
- listManager = new ListManagerImpl(config);
262
- listManager.initialize();
263
- });
264
-
265
- it("should get visible range", () => {
266
- const range = listManager.getVisibleRange();
267
- expect(range).toEqual({ start: 0, end: 10 });
268
- expect(mockViewportFeature.calculateVisibleRange).toHaveBeenCalled();
269
- });
270
-
271
- it("should get viewport info", () => {
272
- const info = listManager.getViewportInfo();
273
- expect(info).toEqual({
274
- containerSize: 600,
275
- totalVirtualSize: 50000,
276
- visibleRange: { start: 0, end: 10 },
277
- virtualScrollPosition: 0,
278
- });
279
- });
280
-
281
- it("should update viewport", () => {
282
- listManager.updateViewport();
283
-
284
- expect(mockViewportFeature.updateContainerPosition).toHaveBeenCalled();
285
- expect(mockViewportFeature.updateScrollbar).toHaveBeenCalled();
286
- expect(mockCollectionFeature.handleVisibleRangeChange).toHaveBeenCalled();
287
- });
288
-
289
- it("should return default values when not initialized", () => {
290
- const uninitializedManager = new ListManagerImpl(config);
291
-
292
- expect(uninitializedManager.getVisibleRange()).toEqual({
293
- start: 0,
294
- end: 0,
295
- });
296
- expect(uninitializedManager.getScrollPosition()).toBe(0);
297
- });
298
- });
299
-
300
- describe("Collection Integration", () => {
301
- beforeEach(() => {
302
- listManager = new ListManagerImpl(config);
303
- listManager.initialize();
304
- });
305
-
306
- it("should set items", () => {
307
- const newItems = [{ id: 1, name: "New Item" }];
308
- listManager.setItems(newItems);
309
-
310
- expect(mockViewportFeature.setTotalItems).toHaveBeenCalledWith(1);
311
- expect(mockCollectionFeature.setItems).toHaveBeenCalledWith(newItems);
312
- expect(listManager.getTotalItems()).toBe(1);
313
- });
314
-
315
- it("should set total items", () => {
316
- listManager.setTotalItems(500);
317
-
318
- expect(mockViewportFeature.setTotalItems).toHaveBeenCalledWith(500);
319
- expect(listManager.getTotalItems()).toBe(500);
320
- });
321
-
322
- it("should get items in visible range", () => {
323
- const mockItems: any[] = [
324
- { item: { id: 1, name: "Item 1" }, index: 0 },
325
- { item: { id: 2, name: "Item 2" }, index: 1 },
326
- ];
327
- mockCollectionFeature.getItemsInRange.mockReturnValue(mockItems);
328
-
329
- const items = listManager.getItems();
330
- expect(items).toEqual([
331
- { id: 1, name: "Item 1" },
332
- { id: 2, name: "Item 2" },
333
- ]);
334
- });
335
-
336
- it("should set pagination strategy", () => {
337
- listManager.setPaginationStrategy("cursor");
338
-
339
- expect(
340
- mockCollectionFeature.adaptPaginationStrategy
341
- ).toHaveBeenCalledWith("cursor");
342
- });
343
-
344
- it("should get pagination strategy", () => {
345
- mockCollectionFeature.paginationStrategy = "offset";
346
- expect(listManager.getPaginationStrategy()).toBe("offset");
347
- });
348
- });
349
-
350
- describe("Configuration Management", () => {
351
- beforeEach(() => {
352
- listManager = new ListManagerImpl(config);
353
- listManager.initialize();
354
- });
355
-
356
- it("should update configuration", () => {
357
- const configUpdate: ListManagerConfigUpdate = {
358
- virtual: {
359
- enabled: true,
360
- itemSize: "auto",
361
- estimatedItemSize: 100,
362
- overscan: 5,
363
- },
364
- debug: false,
365
- };
366
-
367
- listManager.updateConfig(configUpdate);
368
-
369
- const updatedConfig = listManager.getConfig();
370
- expect(updatedConfig.virtual.estimatedItemSize).toBe(100);
371
- expect(updatedConfig.debug).toBe(false);
372
- });
373
-
374
- it("should return copy of config", () => {
375
- const returnedConfig = listManager.getConfig();
376
- returnedConfig.debug = false;
377
-
378
- expect(listManager.getConfig().debug).toBe(true); // Original should be unchanged
379
- });
380
- });
381
-
382
- describe("Event System", () => {
383
- beforeEach(() => {
384
- listManager = new ListManagerImpl(config);
385
- listManager.initialize();
386
- });
387
-
388
- it("should subscribe to events", () => {
389
- const observer = mock();
390
- const unsubscribe = listManager.subscribe(observer);
391
-
392
- listManager.emit(ListManagerEvents.INITIALIZED, { config });
393
-
394
- expect(observer).toHaveBeenCalledWith(ListManagerEvents.INITIALIZED, {
395
- config,
396
- });
397
-
398
- unsubscribe();
399
- });
400
-
401
- it("should unsubscribe from events", () => {
402
- const observer = mock();
403
- const unsubscribe = listManager.subscribe(observer);
404
-
405
- unsubscribe();
406
- listManager.emit(ListManagerEvents.INITIALIZED, { config });
407
-
408
- expect(observer).not.toHaveBeenCalled();
409
- });
410
-
411
- it("should handle observer errors gracefully", () => {
412
- const badObserver = mock(() => {
413
- throw new Error("Observer error");
414
- });
415
- const consoleSpy = spyOn(console, "error").mockImplementation(() => {});
416
-
417
- listManager.subscribe(badObserver);
418
- listManager.emit(ListManagerEvents.INITIALIZED, { config });
419
-
420
- expect(consoleSpy).toHaveBeenCalledWith(
421
- "[List Manager] Observer error:",
422
- expect.any(Error)
423
- );
424
- consoleSpy.mockRestore();
425
- });
426
-
427
- it("should emit events to multiple observers", () => {
428
- const observer1 = mock();
429
- const observer2 = mock();
430
-
431
- listManager.subscribe(observer1);
432
- listManager.subscribe(observer2);
433
-
434
- listManager.emit(ListManagerEvents.INITIALIZED, { config });
435
-
436
- expect(observer1).toHaveBeenCalled();
437
- expect(observer2).toHaveBeenCalled();
438
- });
439
- });
440
-
441
- describe("Feature Coordination", () => {
442
- beforeEach(() => {
443
- listManager = new ListManagerImpl(config);
444
- listManager.initialize();
445
- });
446
-
447
- it("should coordinate scroll events between features", () => {
448
- // Simulate scroll position change
449
- listManager.emit(ListManagerEvents.SCROLL_POSITION_CHANGED, {
450
- position: 1000,
451
- direction: "forward",
452
- });
453
-
454
- expect(
455
- mockCollectionFeature.handleScrollPositionChange
456
- ).toHaveBeenCalledWith(1000, "forward");
457
- });
458
-
459
- it("should coordinate range change events", () => {
460
- const newRange = { start: 10, end: 20 };
461
-
462
- listManager.emit(ListManagerEvents.VIRTUAL_RANGE_CHANGED, newRange);
463
-
464
- expect(
465
- mockCollectionFeature.handleVisibleRangeChange
466
- ).toHaveBeenCalledWith(newRange);
467
- });
468
-
469
- it("should coordinate viewport change events", () => {
470
- const viewportData = {
471
- containerSize: 600,
472
- totalVirtualSize: 50000,
473
- visibleRange: { start: 5, end: 15 },
474
- virtualScrollPosition: 500,
475
- };
476
-
477
- listManager.emit(ListManagerEvents.VIEWPORT_CHANGED, viewportData);
478
-
479
- expect(
480
- mockCollectionFeature.handleVisibleRangeChange
481
- ).toHaveBeenCalledWith(viewportData.visibleRange);
482
- });
483
- });
484
-
485
- describe("Lifecycle Management", () => {
486
- beforeEach(() => {
487
- listManager = new ListManagerImpl(config);
488
- listManager.initialize();
489
- });
490
-
491
- it("should destroy properly", () => {
492
- listManager.destroy();
493
-
494
- expect(mockViewportFeature.destroy).toHaveBeenCalled();
495
- expect(mockCollectionFeature.destroy).toHaveBeenCalled();
496
- });
497
-
498
- it("should not destroy twice", () => {
499
- listManager.destroy();
500
- listManager.destroy();
501
-
502
- expect(mockViewportFeature.destroy).toHaveBeenCalledTimes(1);
503
- });
504
-
505
- it("should emit destroy event", () => {
506
- const observer = mock();
507
- listManager.subscribe(observer);
508
-
509
- listManager.destroy();
510
-
511
- expect(observer).toHaveBeenCalledWith(ListManagerEvents.DESTROYED, {
512
- reason: "manual-destroy",
513
- });
514
- });
515
- });
516
- });
517
-
518
- describe("createListManager factory", () => {
519
- it("should create and auto-initialize ListManager", () => {
520
- const consoleSpy = spyOn(console, "log").mockImplementation(() => {});
521
-
522
- const factoryConfig: ListManagerConfig = {
523
- container: mockContainer,
524
- virtual: {
525
- enabled: true,
526
- itemSize: "auto",
527
- estimatedItemSize: 50,
528
- overscan: 5,
529
- },
530
- orientation: {
531
- orientation: "vertical",
532
- reverse: false,
533
- crossAxisAlignment: "stretch",
534
- },
535
- initialLoad: {
536
- strategy: "placeholders",
537
- viewportMultiplier: 1.5,
538
- minItems: 10,
539
- maxItems: 100,
540
- },
541
- errorHandling: {
542
- timeout: 5000,
543
- showErrorItems: true,
544
- retryAttempts: 3,
545
- preserveScrollOnError: true,
546
- },
547
- positioning: {
548
- precisePositioning: true,
549
- allowPartialItems: true,
550
- snapToItems: false,
551
- },
552
- boundaries: {
553
- preventOverscroll: true,
554
- maintainEdgeRanges: true,
555
- boundaryResistance: 0.15,
556
- },
557
- recycling: {
558
- enabled: false,
559
- maxPoolSize: 50,
560
- minPoolSize: 10,
561
- },
562
- performance: {
563
- frameScheduling: true,
564
- memoryCleanup: true,
565
- },
566
- intersection: {
567
- pagination: {
568
- enabled: false,
569
- rootMargin: "100px",
570
- threshold: 0.1,
571
- },
572
- loading: {
573
- enabled: false,
574
- },
575
- },
576
- debug: true,
577
- prefix: "test-list",
578
- componentName: "TestList",
579
- };
580
-
581
- const listManager = createListManager(factoryConfig);
582
-
583
- expect(listManager).toBeDefined();
584
- expect(listManager.getTotalItems()).toBe(0);
585
- expect(consoleSpy).toHaveBeenCalledWith(
586
- "[List Manager] Created with config:",
587
- expect.any(Object)
588
- );
589
-
590
- consoleSpy.mockRestore();
591
- listManager.destroy();
592
- });
593
- });