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.
- package/AI.md +28 -230
- package/CLAUDE.md +882 -0
- package/build.js +253 -24
- package/package.json +14 -4
- package/scripts/debug/vlist-selection.ts +121 -0
- package/src/components/index.ts +5 -41
- package/src/components/{list → vlist}/config.ts +66 -95
- package/src/components/vlist/constants.ts +23 -0
- package/src/components/vlist/features/api.ts +626 -0
- package/src/components/vlist/features/index.ts +10 -0
- package/src/components/vlist/features/selection.ts +436 -0
- package/src/components/vlist/features/viewport.ts +59 -0
- package/src/components/vlist/index.ts +17 -0
- package/src/components/{list → vlist}/types.ts +242 -32
- package/src/components/vlist/vlist.ts +92 -0
- package/src/core/compose/features/gestures/index.ts +227 -0
- package/src/core/compose/features/gestures/longpress.ts +383 -0
- package/src/core/compose/features/gestures/pan.ts +424 -0
- package/src/core/compose/features/gestures/pinch.ts +475 -0
- package/src/core/compose/features/gestures/rotate.ts +485 -0
- package/src/core/compose/features/gestures/swipe.ts +492 -0
- package/src/core/compose/features/gestures/tap.ts +334 -0
- package/src/core/compose/features/index.ts +2 -38
- package/src/core/compose/index.ts +13 -29
- package/src/core/gestures/index.ts +31 -0
- package/src/core/gestures/longpress.ts +68 -0
- package/src/core/gestures/manager.ts +418 -0
- package/src/core/gestures/pan.ts +48 -0
- package/src/core/gestures/pinch.ts +58 -0
- package/src/core/gestures/rotate.ts +58 -0
- package/src/core/gestures/swipe.ts +66 -0
- package/src/core/gestures/tap.ts +45 -0
- package/src/core/gestures/types.ts +387 -0
- package/src/core/gestures/utils.ts +128 -0
- package/src/core/index.ts +27 -151
- package/src/core/layout/schema.ts +153 -72
- package/src/core/layout/types.ts +5 -2
- package/src/core/viewport/constants.ts +145 -0
- package/src/core/viewport/features/base.ts +73 -0
- package/src/core/viewport/features/collection.ts +1182 -0
- package/src/core/viewport/features/events.ts +130 -0
- package/src/core/viewport/features/index.ts +20 -0
- package/src/core/{list-manager/features/viewport → viewport/features}/item-size.ts +31 -34
- package/src/core/{list-manager/features/viewport → viewport/features}/loading.ts +4 -4
- package/src/core/viewport/features/momentum.ts +269 -0
- package/src/core/viewport/features/placeholders.ts +335 -0
- package/src/core/viewport/features/rendering.ts +962 -0
- package/src/core/viewport/features/scrollbar.ts +434 -0
- package/src/core/viewport/features/scrolling.ts +634 -0
- package/src/core/viewport/features/utils.ts +94 -0
- package/src/core/viewport/features/virtual.ts +525 -0
- package/src/core/viewport/index.ts +31 -0
- package/src/core/viewport/types.ts +133 -0
- package/src/core/viewport/utils/speed-tracker.ts +79 -0
- package/src/core/viewport/viewport.ts +265 -0
- package/src/index.ts +0 -7
- package/src/styles/components/_vlist.scss +352 -0
- package/src/styles/index.scss +1 -1
- package/test/components/vlist-selection.test.ts +240 -0
- package/test/components/vlist.test.ts +63 -0
- package/test/core/collection/adapter.test.ts +161 -0
- package/bun.lock +0 -792
- package/src/components/list/api.ts +0 -314
- package/src/components/list/constants.ts +0 -56
- package/src/components/list/features/api.ts +0 -428
- package/src/components/list/features/index.ts +0 -31
- package/src/components/list/features/list-manager.ts +0 -502
- package/src/components/list/index.ts +0 -39
- package/src/components/list/list.ts +0 -234
- package/src/core/collection/base-collection.ts +0 -100
- package/src/core/collection/collection-composer.ts +0 -178
- package/src/core/collection/collection.ts +0 -745
- package/src/core/collection/constants.ts +0 -172
- package/src/core/collection/events.ts +0 -428
- package/src/core/collection/features/api/loading.ts +0 -279
- package/src/core/collection/features/operations/data-operations.ts +0 -147
- package/src/core/collection/index.ts +0 -104
- package/src/core/collection/state.ts +0 -497
- package/src/core/collection/types.ts +0 -404
- package/src/core/compose/features/collection.ts +0 -119
- package/src/core/compose/features/selection.ts +0 -213
- package/src/core/compose/features/styling.ts +0 -108
- package/src/core/list-manager/api.ts +0 -599
- package/src/core/list-manager/config.ts +0 -593
- package/src/core/list-manager/constants.ts +0 -268
- package/src/core/list-manager/features/api.ts +0 -58
- package/src/core/list-manager/features/collection/collection.ts +0 -705
- package/src/core/list-manager/features/collection/index.ts +0 -17
- package/src/core/list-manager/features/viewport/constants.ts +0 -42
- package/src/core/list-manager/features/viewport/index.ts +0 -16
- package/src/core/list-manager/features/viewport/placeholders.ts +0 -281
- package/src/core/list-manager/features/viewport/rendering.ts +0 -575
- package/src/core/list-manager/features/viewport/scrollbar.ts +0 -495
- package/src/core/list-manager/features/viewport/scrolling.ts +0 -795
- package/src/core/list-manager/features/viewport/template.ts +0 -220
- package/src/core/list-manager/features/viewport/viewport.ts +0 -654
- package/src/core/list-manager/features/viewport/virtual.ts +0 -309
- package/src/core/list-manager/index.ts +0 -279
- package/src/core/list-manager/list-manager.ts +0 -206
- package/src/core/list-manager/types.ts +0 -439
- package/src/core/list-manager/utils/calculations.ts +0 -290
- package/src/core/list-manager/utils/range-calculator.ts +0 -349
- package/src/core/list-manager/utils/speed-tracker.ts +0 -273
- package/src/styles/components/_list.scss +0 -244
- package/src/types/mtrl.d.ts +0 -6
- package/test/components/list.test.ts +0 -256
- package/test/core/collection/failed-ranges.test.ts +0 -270
- package/test/core/compose/features.test.ts +0 -183
- package/test/core/list-manager/features/collection.test.ts +0 -704
- package/test/core/list-manager/features/viewport.test.ts +0 -698
- package/test/core/list-manager/list-manager.test.ts +0 -593
- package/test/core/list-manager/utils/calculations.test.ts +0 -433
- package/test/core/list-manager/utils/range-calculator.test.ts +0 -569
- package/test/core/list-manager/utils/speed-tracker.test.ts +0 -530
- package/tsconfig.build.json +0 -23
- /package/src/components/{list → vlist}/features.ts +0 -0
- /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;
|