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,206 @@
1
+ /**
2
+ * List Manager - High-Performance Virtual List Management
3
+ * A clean, composable factory for creating optimized virtual lists
4
+ */
5
+
6
+ import { pipe } from "../compose";
7
+ import { withCollection } from "./features/collection/collection";
8
+ import { withViewport } from "./features/viewport/viewport";
9
+ import { withPlaceholders } from "./features/viewport/placeholders";
10
+ import { createLoadingManager } from "./features/viewport/loading";
11
+ import { LIST_MANAGER_CONSTANTS } from "./constants";
12
+ import type { ListManagerConfig, ListManagerComponent } from "./types";
13
+
14
+ /**
15
+ * Default configuration for List Manager
16
+ */
17
+ const DEFAULT_CONFIG: Partial<ListManagerConfig> = {
18
+ orientation: {
19
+ orientation: "vertical",
20
+ reverse: false,
21
+ crossAxisAlignment: "stretch",
22
+ },
23
+ virtual: {
24
+ estimatedItemSize: LIST_MANAGER_CONSTANTS.VIRTUAL_SCROLL.DEFAULT_ITEM_SIZE,
25
+ itemSize: LIST_MANAGER_CONSTANTS.VIRTUAL_SCROLL.DEFAULT_ITEM_SIZE,
26
+ overscan: LIST_MANAGER_CONSTANTS.VIRTUAL_SCROLL.OVERSCAN_BUFFER,
27
+ enabled: true,
28
+ },
29
+ collection: {
30
+ pageSize: LIST_MANAGER_CONSTANTS.RANGE_LOADING.DEFAULT_RANGE_SIZE,
31
+ strategy: "page",
32
+ },
33
+ };
34
+
35
+ /**
36
+ * Creates a new List Manager component
37
+ */
38
+ export const createListManager = (
39
+ config: ListManagerConfig
40
+ ): ListManagerComponent => {
41
+ const container = config.container;
42
+
43
+ // Merge config with defaults - handle undefined properties
44
+ const mergedConfig: ListManagerConfig = {
45
+ ...DEFAULT_CONFIG,
46
+ ...config,
47
+ orientation: {
48
+ ...DEFAULT_CONFIG.orientation,
49
+ ...(config.orientation || {}),
50
+ },
51
+ virtual: {
52
+ ...DEFAULT_CONFIG.virtual,
53
+ ...(config.virtual || {}),
54
+ },
55
+ collection: {
56
+ ...DEFAULT_CONFIG.collection,
57
+ ...(config.collection || {}),
58
+ },
59
+ } as ListManagerConfig;
60
+
61
+ // Create base component
62
+ const createBaseComponent = (): ListManagerComponent => {
63
+ // Simple event system
64
+ const eventListeners = new Map<string, Function[]>();
65
+
66
+ const emit = (event: string, data?: any) => {
67
+ const listeners = eventListeners.get(event) || [];
68
+ listeners.forEach((listener) => {
69
+ try {
70
+ listener(data);
71
+ } catch (error) {
72
+ console.error(`Error in event listener for ${event}:`, error);
73
+ }
74
+ });
75
+ };
76
+
77
+ const on = (event: string, listener: Function) => {
78
+ if (!eventListeners.has(event)) {
79
+ eventListeners.set(event, []);
80
+ }
81
+ eventListeners.get(event)!.push(listener);
82
+
83
+ // Return unsubscribe function
84
+ return () => {
85
+ const listeners = eventListeners.get(event);
86
+ if (listeners) {
87
+ const index = listeners.indexOf(listener);
88
+ if (index > -1) {
89
+ listeners.splice(index, 1);
90
+ }
91
+ }
92
+ };
93
+ };
94
+
95
+ return {
96
+ element: container,
97
+ config: mergedConfig,
98
+ componentName: "list-manager",
99
+ getClass: (name: string) => `mtrl-list-manager__${name}`,
100
+ items: config.items || [],
101
+ totalItems: config.collection?.totalItems || config.items?.length || 0,
102
+ template: config.template?.template || null,
103
+ isInitialized: false,
104
+ isDestroyed: false,
105
+ emit,
106
+ on,
107
+ initialize: () => {
108
+ // console.log("🚀 [LIST-MANAGER] Initializing...");
109
+ },
110
+ destroy: () => {
111
+ // console.log("👋 [LIST-MANAGER] Destroying...");
112
+ },
113
+ updateConfig: (update: Partial<ListManagerConfig>) => {
114
+ Object.assign(mergedConfig, update);
115
+ },
116
+ getConfig: () => mergedConfig,
117
+ };
118
+ };
119
+
120
+ // Create loading manager
121
+ let loadingManager: ReturnType<typeof createLoadingManager> | null = null;
122
+
123
+ // Compose enhancers - CRITICAL: Collection must be applied before viewport
124
+ // so that viewport can access collection.loadMissingRanges
125
+ const enhance = pipe(
126
+ withCollection({
127
+ collection: config.collection?.adapter,
128
+ rangeSize: config.collection?.pageSize || 20,
129
+ strategy: config.collection?.strategy || "page",
130
+ enablePlaceholders: true,
131
+ }),
132
+ withPlaceholders({
133
+ enabled: true,
134
+ }),
135
+ withViewport({
136
+ orientation: mergedConfig.orientation?.orientation,
137
+ estimatedItemSize: mergedConfig.virtual?.estimatedItemSize,
138
+ overscan: mergedConfig.virtual?.overscan,
139
+ enableScrollbar: true,
140
+ measureItems: mergedConfig.virtual?.measureItems, // Pass measureItems flag
141
+ // Pass callback to load data for a specific range
142
+ loadDataForRange: (
143
+ range: { start: number; end: number },
144
+ priority?: "high" | "normal" | "low"
145
+ ) => {
146
+ // Use loading manager if available
147
+ if (loadingManager) {
148
+ // Check if this range is already being loaded
149
+ if (!loadingManager.isRangeLoading(range)) {
150
+ loadingManager.requestLoad(range, priority || "normal");
151
+ }
152
+ } else {
153
+ // Fallback to direct collection loading
154
+ setTimeout(() => {
155
+ const collectionComponent = component as any;
156
+ if (
157
+ collectionComponent.collection &&
158
+ typeof collectionComponent.collection.loadMissingRanges ===
159
+ "function"
160
+ ) {
161
+ collectionComponent.collection
162
+ .loadMissingRanges(range)
163
+ .catch((error: any) => {
164
+ console.error("Failed to load range:", error);
165
+ });
166
+ }
167
+ }, 0);
168
+ }
169
+ },
170
+ })
171
+ );
172
+
173
+ // Create and enhance component
174
+ const component = enhance(createBaseComponent());
175
+
176
+ // Create loading manager after component is enhanced
177
+ loadingManager = createLoadingManager(component, {
178
+ maxConcurrentRequests: config.collection?.maxConcurrentRequests,
179
+ });
180
+
181
+ // Wire up velocity updates from scrolling to loading manager
182
+ if (component.on) {
183
+ component.on("speed:changed", (data: any) => {
184
+ if (loadingManager) {
185
+ loadingManager.updateVelocity(data.speed, data.direction);
186
+ }
187
+ });
188
+ }
189
+
190
+ // Initialize component
191
+ if ((component as any).viewport?.initialize) {
192
+ (component as any).viewport.initialize();
193
+ }
194
+
195
+ // Return the enhanced component
196
+ return component;
197
+ };
198
+
199
+ /**
200
+ * Configuration for list manager enhancers
201
+ */
202
+ export interface ListManagerEnhancerConfig {
203
+ viewport?: Parameters<typeof withViewport>[0];
204
+ collection?: Parameters<typeof withCollection>[0];
205
+ placeholders?: Parameters<typeof withPlaceholders>[0];
206
+ }
@@ -0,0 +1,439 @@
1
+ /**
2
+ * Core type definitions for List Manager
3
+ * Performance and UI management layer types
4
+ */
5
+
6
+ import type { ListManagerConstants } from "./constants";
7
+
8
+ /**
9
+ * Core Range and Item Types
10
+ */
11
+ export interface ItemRange {
12
+ start: number;
13
+ end: number;
14
+ }
15
+
16
+ export interface ViewportInfo {
17
+ containerSize: number;
18
+ totalVirtualSize: number;
19
+ visibleRange: ItemRange;
20
+ virtualScrollPosition: number;
21
+ }
22
+
23
+ export interface SpeedTracker {
24
+ velocity: number; // px/ms
25
+ direction: "forward" | "backward"; // scroll direction (vertical: down/up, horizontal: right/left)
26
+ isAccelerating: boolean; // velocity increasing
27
+ lastMeasurement: number; // timestamp of last measurement
28
+ }
29
+
30
+ /**
31
+ * Feature Interfaces for Simplified Architecture
32
+ */
33
+
34
+ /**
35
+ * Viewport Feature - Complete Virtual Scrolling
36
+ */
37
+ export interface ViewportFeature {
38
+ // Orientation handling
39
+ orientation: "vertical" | "horizontal";
40
+
41
+ // Virtual scrolling (orientation-agnostic)
42
+ virtualScrollPosition: number;
43
+ totalVirtualSize: number;
44
+ containerSize: number;
45
+
46
+ // Item sizing (orientation-agnostic)
47
+ estimatedItemSize: number;
48
+ measuredSizes: Map<number, number>;
49
+
50
+ // Custom scrollbar
51
+ scrollbarThumb: HTMLElement | null;
52
+ scrollbarTrack: HTMLElement | null;
53
+ thumbPosition: number;
54
+
55
+ // Methods
56
+ handleWheel(event: WheelEvent): void;
57
+ updateContainerPosition(): void;
58
+ updateScrollbar(): void;
59
+ calculateVisibleRange(): ItemRange;
60
+ measureItemSize(element: HTMLElement, index: number): void;
61
+ initialize(): void;
62
+ destroy(): void;
63
+ }
64
+
65
+ /**
66
+ * Collection Feature - Data Management Integration
67
+ */
68
+ export interface CollectionFeature {
69
+ // Speed tracking
70
+ speedTracker: SpeedTracker;
71
+
72
+ // Range management
73
+ loadedRanges: Set<number>;
74
+ pendingRanges: Set<number>;
75
+
76
+ // Collection integration
77
+ collection: any;
78
+
79
+ // Pagination strategy
80
+ paginationStrategy: "page" | "offset" | "cursor";
81
+
82
+ // Placeholder system
83
+ placeholderStructure: Map<string, { min: number; max: number }> | null;
84
+ placeholderTemplate:
85
+ | ((item: any, index: number) => string | HTMLElement)
86
+ | null;
87
+
88
+ // Methods
89
+ loadMissingRanges(visibleRange: ItemRange): void;
90
+ showPlaceholders(range: ItemRange): void;
91
+ updateLoadedData(items: any[], offset: number): void;
92
+ adaptPaginationStrategy(strategy: "page" | "offset" | "cursor"): void;
93
+ analyzeDataStructure(items: any[]): void;
94
+ generatePlaceholderItem(index: number): any;
95
+ initialize(): void;
96
+ destroy(): void;
97
+ }
98
+
99
+ /**
100
+ * Configuration Types
101
+ */
102
+ export interface CollectionConfig {
103
+ adapter?: any;
104
+ pageSize?: number; // becomes rangeSize
105
+ strategy?: "page" | "offset" | "cursor";
106
+ [key: string]: any;
107
+ }
108
+
109
+ export interface TemplateConfig {
110
+ template: (item: any, index: number) => string | HTMLElement;
111
+ }
112
+
113
+ export interface VirtualConfig {
114
+ enabled: boolean;
115
+ itemSize: number | "auto";
116
+ estimatedItemSize: number;
117
+ overscan: number;
118
+ measureItems?: boolean; // Optional flag to enable/disable item measurement (default: false)
119
+ }
120
+
121
+ export interface OrientationConfig {
122
+ orientation: "vertical" | "horizontal";
123
+ reverse: boolean;
124
+ crossAxisAlignment: "start" | "center" | "end" | "stretch";
125
+ }
126
+
127
+ export interface InitialLoadConfig {
128
+ strategy: "placeholders" | "direct";
129
+ viewportMultiplier: number;
130
+ minItems: number;
131
+ maxItems: number;
132
+ }
133
+
134
+ export interface ErrorHandlingConfig {
135
+ timeout: number;
136
+ showErrorItems: boolean;
137
+ retryAttempts: number;
138
+ preserveScrollOnError: boolean;
139
+ }
140
+
141
+ export interface PositioningConfig {
142
+ precisePositioning: boolean;
143
+ allowPartialItems: boolean;
144
+ snapToItems: boolean;
145
+ }
146
+
147
+ export interface BoundariesConfig {
148
+ preventOverscroll: boolean;
149
+ maintainEdgeRanges: boolean;
150
+ boundaryResistance: number;
151
+ }
152
+
153
+ export interface RecyclingConfig {
154
+ enabled: boolean;
155
+ maxPoolSize: number;
156
+ minPoolSize: number;
157
+ }
158
+
159
+ export interface PerformanceConfig {
160
+ frameScheduling: boolean;
161
+ memoryCleanup: boolean;
162
+ }
163
+
164
+ export interface IntersectionConfig {
165
+ pagination: {
166
+ enabled: boolean;
167
+ rootMargin: string;
168
+ threshold: number;
169
+ };
170
+ loading: {
171
+ enabled: boolean;
172
+ };
173
+ }
174
+
175
+ /**
176
+ * Main List Manager Configuration
177
+ */
178
+ export interface ListManagerConfig {
179
+ // Container
180
+ container: HTMLElement;
181
+
182
+ // Collection integration
183
+ collection?: CollectionConfig;
184
+ items?: any[];
185
+
186
+ // Template
187
+ template?: TemplateConfig;
188
+
189
+ // Virtual scrolling
190
+ virtual: VirtualConfig;
191
+
192
+ // Orientation
193
+ orientation: OrientationConfig;
194
+
195
+ // Initial loading
196
+ initialLoad: InitialLoadConfig;
197
+
198
+ // Error handling
199
+ errorHandling: ErrorHandlingConfig;
200
+
201
+ // Positioning
202
+ positioning: PositioningConfig;
203
+
204
+ // Boundaries
205
+ boundaries: BoundariesConfig;
206
+
207
+ // Element recycling (Phase 2)
208
+ recycling: RecyclingConfig;
209
+
210
+ // Performance
211
+ performance: PerformanceConfig;
212
+
213
+ // Intersection observers
214
+ intersection: IntersectionConfig;
215
+
216
+ // Debug
217
+ debug: boolean;
218
+ prefix: string;
219
+ componentName: string;
220
+
221
+ // Constants override
222
+ constants?: Partial<ListManagerConstants>;
223
+ }
224
+
225
+ /**
226
+ * Event System
227
+ */
228
+ export enum ListManagerEvents {
229
+ // Virtual scrolling
230
+ VIEWPORT_CHANGED = "viewport:changed",
231
+ SCROLL_POSITION_CHANGED = "scroll:position:changed",
232
+ VIRTUAL_RANGE_CHANGED = "virtual:range:changed",
233
+ RANGE_RENDERED = "range:rendered",
234
+
235
+ // Collection coordination
236
+ LOADING_TRIGGERED = "loading:triggered",
237
+ SPEED_CHANGED = "speed:changed",
238
+ RANGE_LOADED = "range:loaded",
239
+
240
+ // Orientation
241
+ ORIENTATION_CHANGED = "orientation:changed",
242
+ DIMENSIONS_CHANGED = "orientation:dimensions:changed",
243
+
244
+ // Placeholder system
245
+ STRUCTURE_ANALYZED = "placeholder:structure:analyzed",
246
+ PLACEHOLDERS_SHOWN = "placeholder:shown",
247
+ PLACEHOLDERS_REPLACED = "placeholder:replaced",
248
+
249
+ // Element recycling events
250
+ ELEMENT_RENDERED = "element:rendered",
251
+ ELEMENT_UPDATED = "element:updated",
252
+ ELEMENT_RECYCLED = "element:recycled",
253
+ RECYCLING_INITIALIZED = "recycling:initialized",
254
+ RECYCLING_DESTROYED = "recycling:destroyed",
255
+
256
+ // Error handling
257
+ ERROR_OCCURRED = "error:occurred",
258
+ ERROR_RECOVERED = "error:recovered",
259
+
260
+ // Lifecycle
261
+ INITIALIZED = "lifecycle:initialized",
262
+ DESTROYED = "lifecycle:destroyed",
263
+ }
264
+
265
+ export interface ListManagerEventData {
266
+ [ListManagerEvents.VIEWPORT_CHANGED]: ViewportInfo;
267
+ [ListManagerEvents.SCROLL_POSITION_CHANGED]: {
268
+ position: number;
269
+ direction: "forward" | "backward";
270
+ };
271
+ [ListManagerEvents.VIRTUAL_RANGE_CHANGED]: ItemRange;
272
+ [ListManagerEvents.RANGE_RENDERED]: { range: ItemRange };
273
+ [ListManagerEvents.LOADING_TRIGGERED]: { range: ItemRange; strategy: string };
274
+ [ListManagerEvents.SPEED_CHANGED]: {
275
+ speed: number;
276
+ direction: "forward" | "backward";
277
+ };
278
+ [ListManagerEvents.RANGE_LOADED]: { range: ItemRange; items: any[] };
279
+ [ListManagerEvents.ORIENTATION_CHANGED]: {
280
+ orientation: "vertical" | "horizontal";
281
+ };
282
+ [ListManagerEvents.DIMENSIONS_CHANGED]: {
283
+ containerSize: number;
284
+ totalVirtualSize: number;
285
+ };
286
+ [ListManagerEvents.STRUCTURE_ANALYZED]: {
287
+ structure: Map<string, { min: number; max: number }>;
288
+ };
289
+ [ListManagerEvents.PLACEHOLDERS_SHOWN]: { range: ItemRange; count: number };
290
+ [ListManagerEvents.PLACEHOLDERS_REPLACED]: { range: ItemRange; items: any[] };
291
+ [ListManagerEvents.ELEMENT_RENDERED]: { element: HTMLElement };
292
+ [ListManagerEvents.ELEMENT_UPDATED]: { element: HTMLElement };
293
+ [ListManagerEvents.ELEMENT_RECYCLED]: { element: HTMLElement };
294
+ [ListManagerEvents.RECYCLING_INITIALIZED]: { config: ListManagerConfig };
295
+ [ListManagerEvents.RECYCLING_DESTROYED]: { reason?: string };
296
+ [ListManagerEvents.ERROR_OCCURRED]: { error: Error; context: string };
297
+ [ListManagerEvents.ERROR_RECOVERED]: {
298
+ previousError: Error;
299
+ context: string;
300
+ };
301
+ [ListManagerEvents.INITIALIZED]: { config: ListManagerConfig };
302
+ [ListManagerEvents.DESTROYED]: { reason?: string };
303
+ }
304
+
305
+ export interface ListManagerObserver {
306
+ <T extends ListManagerEvents>(event: T, data: ListManagerEventData[T]): void;
307
+ }
308
+
309
+ export type ListManagerUnsubscribe = () => void;
310
+
311
+ /**
312
+ * Main List Manager Interface
313
+ */
314
+ export interface ListManager {
315
+ // Virtual scrolling (orientation-agnostic)
316
+ scrollToIndex(index: number, alignment?: "start" | "center" | "end"): void;
317
+ scrollToPage(page: number, alignment?: "start" | "center" | "end"): void;
318
+ getScrollPosition(): number;
319
+
320
+ // Viewport management
321
+ getVisibleRange(): ItemRange;
322
+ getViewportInfo(): ViewportInfo;
323
+ updateViewport(): void;
324
+
325
+ // Collection integration
326
+ setItems(items: any[]): void;
327
+ setTotalItems(total: number): void;
328
+ getItems(): any[];
329
+ getTotalItems(): number;
330
+
331
+ // Pagination strategy
332
+ setPaginationStrategy(strategy: "page" | "offset" | "cursor"): void;
333
+ getPaginationStrategy(): "page" | "offset" | "cursor";
334
+
335
+ // Configuration
336
+ updateConfig(config: Partial<ListManagerConfig>): void;
337
+ getConfig(): ListManagerConfig;
338
+
339
+ // Events
340
+ subscribe(observer: ListManagerObserver): ListManagerUnsubscribe;
341
+ emit<T extends ListManagerEvents>(
342
+ event: T,
343
+ data: ListManagerEventData[T]
344
+ ): void;
345
+
346
+ // Lifecycle
347
+ initialize(): void;
348
+ destroy(): void;
349
+ }
350
+
351
+ /**
352
+ * Utility Types
353
+ */
354
+ export type ListManagerConfigUpdate = Partial<ListManagerConfig>;
355
+
356
+ export interface FeatureContext {
357
+ config: ListManagerConfig;
358
+ constants: ListManagerConstants;
359
+ emit: <T extends ListManagerEvents>(
360
+ event: T,
361
+ data: ListManagerEventData[T]
362
+ ) => void;
363
+ }
364
+
365
+ export interface RangeCalculationResult {
366
+ visibleRange: ItemRange;
367
+ loadedRanges: Set<number>;
368
+ missingRanges: ItemRange[];
369
+ bufferRanges: ItemRange[];
370
+ }
371
+
372
+ /**
373
+ * Type for the base List Manager component
374
+ */
375
+ export interface ListManagerComponent {
376
+ // mtrl base properties
377
+ element: HTMLElement;
378
+ config: ListManagerConfig;
379
+ componentName: string;
380
+ getClass: (name: string) => string;
381
+ emit?: (event: string, data?: any) => void;
382
+ on?: (event: string, handler: Function) => () => void;
383
+
384
+ // List Manager specific
385
+ items: any[];
386
+ totalItems: number;
387
+ template: ((item: any, index: number) => string | HTMLElement) | null;
388
+ isInitialized: boolean;
389
+ isDestroyed: boolean;
390
+
391
+ // Core methods
392
+ initialize(): void;
393
+ destroy(): void;
394
+ updateConfig(config: Partial<ListManagerConfig>): void;
395
+ getConfig(): ListManagerConfig;
396
+ }
397
+
398
+ export interface TemplateFunction {
399
+ (item: any, index: number): string | HTMLElement;
400
+ }
401
+
402
+ export interface CollectionComponent extends ListManagerComponent {
403
+ collection: {
404
+ // Data management
405
+ setItems: (items: any[]) => void;
406
+ getItems: () => any[];
407
+ setTotalItems: (total: number) => void;
408
+ getTotalItems: () => number;
409
+
410
+ // Range management
411
+ loadRange: (offset: number, limit: number) => Promise<any[]>;
412
+ loadMissingRanges: (visibleRange: ItemRange) => Promise<void>;
413
+ getLoadedRanges: () => Set<number>;
414
+ getPendingRanges: () => Set<number>;
415
+ getFailedRanges: () => Map<
416
+ number,
417
+ { attempts: number; lastError: Error; timestamp: number }
418
+ >;
419
+ clearFailedRanges: () => void;
420
+ retryFailedRange: (rangeId: number) => Promise<any[]>;
421
+
422
+ // Pagination strategy
423
+ setPaginationStrategy: (strategy: "page" | "offset" | "cursor") => void;
424
+ getPaginationStrategy: () => string;
425
+
426
+ // Placeholder system
427
+ analyzeDataStructure: (items: any[]) => void;
428
+ generatePlaceholderItem: (index: number) => any;
429
+ showPlaceholders: (count: number) => void;
430
+ getPlaceholderStructure: () => Map<
431
+ string,
432
+ { min: number; max: number }
433
+ > | null;
434
+
435
+ // State
436
+ isInitialized: () => boolean;
437
+ updateLoadedData: (items: any[], offset: number) => void;
438
+ };
439
+ }