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,309 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Virtual Scrolling Module - Core virtual scrolling calculations
|
|
3
|
-
* Handles visible range calculation and total virtual size management
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import type { ListManagerComponent, ItemRange } from "../../types";
|
|
7
|
-
import type { ItemSizeManager } from "./item-size";
|
|
8
|
-
// Removed calculateVisibleRangeUtil import - using unified index-based approach
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Configuration for virtual scrolling
|
|
12
|
-
*/
|
|
13
|
-
export interface VirtualConfig {
|
|
14
|
-
orientation: "vertical" | "horizontal";
|
|
15
|
-
overscan: number;
|
|
16
|
-
onDimensionsChanged?: (data: {
|
|
17
|
-
containerSize: number;
|
|
18
|
-
totalVirtualSize: number;
|
|
19
|
-
estimatedItemSize: number;
|
|
20
|
-
totalItems: number;
|
|
21
|
-
}) => void;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* Virtual scrolling state
|
|
26
|
-
*/
|
|
27
|
-
export interface VirtualState {
|
|
28
|
-
totalVirtualSize: number;
|
|
29
|
-
containerSize: number;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Virtual scrolling manager interface
|
|
34
|
-
*/
|
|
35
|
-
export interface VirtualManager {
|
|
36
|
-
// Range calculations
|
|
37
|
-
calculateVisibleRange(scrollPosition: number): ItemRange;
|
|
38
|
-
|
|
39
|
-
// Size management
|
|
40
|
-
updateTotalVirtualSize(totalItems: number): void;
|
|
41
|
-
getTotalVirtualSize(): number;
|
|
42
|
-
|
|
43
|
-
// Index-based scrolling utilities
|
|
44
|
-
calculateVirtualPositionForIndex(index: number): number;
|
|
45
|
-
calculateIndexFromVirtualPosition(position: number): number;
|
|
46
|
-
getMaxScrollPosition(): number;
|
|
47
|
-
|
|
48
|
-
// State management
|
|
49
|
-
updateState(updates: Partial<VirtualState>): void;
|
|
50
|
-
getState(): VirtualState;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* Creates a virtual scrolling manager using index-based approach
|
|
55
|
-
* This avoids browser height limitations by not creating massive DOM elements
|
|
56
|
-
*/
|
|
57
|
-
export const createVirtualManager = (
|
|
58
|
-
component: ListManagerComponent,
|
|
59
|
-
itemSizeManager: ItemSizeManager,
|
|
60
|
-
config: VirtualConfig,
|
|
61
|
-
getTotalItems?: () => number
|
|
62
|
-
): VirtualManager => {
|
|
63
|
-
const { orientation, overscan, onDimensionsChanged } = config;
|
|
64
|
-
|
|
65
|
-
// Virtual scrolling state
|
|
66
|
-
let totalVirtualSize = 0;
|
|
67
|
-
let containerSize = 0;
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
* Calculate visible range based on scroll position
|
|
71
|
-
* Uses unified index-based approach for all dataset sizes
|
|
72
|
-
*/
|
|
73
|
-
const calculateVisibleRange = (scrollPosition: number): ItemRange => {
|
|
74
|
-
const actualTotalItems = getTotalItems
|
|
75
|
-
? getTotalItems()
|
|
76
|
-
: component.totalItems;
|
|
77
|
-
|
|
78
|
-
if (actualTotalItems === 0) {
|
|
79
|
-
return { start: 0, end: 0 };
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
// Always use index-based calculation for consistency
|
|
83
|
-
if (totalVirtualSize > 0) {
|
|
84
|
-
// Map scroll position to item index using ratio
|
|
85
|
-
const scrollRatio = Math.min(1, scrollPosition / totalVirtualSize);
|
|
86
|
-
const exactScrollIndex = scrollRatio * actualTotalItems;
|
|
87
|
-
const startIndex = Math.floor(exactScrollIndex);
|
|
88
|
-
|
|
89
|
-
// Calculate viewport size in items
|
|
90
|
-
const viewportItemCount = Math.ceil(
|
|
91
|
-
containerSize / itemSizeManager.getEstimatedItemSize()
|
|
92
|
-
);
|
|
93
|
-
const itemsInViewport = Math.floor(
|
|
94
|
-
containerSize / itemSizeManager.getEstimatedItemSize()
|
|
95
|
-
);
|
|
96
|
-
|
|
97
|
-
// Special handling for when we're near the very end
|
|
98
|
-
const maxScrollPosition = totalVirtualSize - containerSize;
|
|
99
|
-
const distanceFromBottom = maxScrollPosition - scrollPosition;
|
|
100
|
-
|
|
101
|
-
// Calculate what the last possible start index should be
|
|
102
|
-
const maxStartIndex = Math.max(0, actualTotalItems - itemsInViewport);
|
|
103
|
-
|
|
104
|
-
// Use a larger threshold (500 pixels) to ensure smooth transitions
|
|
105
|
-
// This represents about 6 items worth of scrolling
|
|
106
|
-
const bottomThreshold = 500;
|
|
107
|
-
|
|
108
|
-
if (distanceFromBottom <= bottomThreshold && distanceFromBottom >= -1) {
|
|
109
|
-
// When near the bottom, interpolate between the calculated position and the last position
|
|
110
|
-
// This ensures smooth scrolling without jumps
|
|
111
|
-
|
|
112
|
-
if (distanceFromBottom <= 1 && distanceFromBottom >= -1) {
|
|
113
|
-
// At the very bottom, show exactly the last items
|
|
114
|
-
const lastStartIndex = maxStartIndex;
|
|
115
|
-
const start = Math.max(0, lastStartIndex - overscan);
|
|
116
|
-
const end = actualTotalItems - 1;
|
|
117
|
-
|
|
118
|
-
return { start, end };
|
|
119
|
-
} else {
|
|
120
|
-
// Near the bottom but not at the very end
|
|
121
|
-
// Smoothly interpolate between normal calculation and bottom position
|
|
122
|
-
const interpolationFactor =
|
|
123
|
-
(bottomThreshold - distanceFromBottom) / bottomThreshold;
|
|
124
|
-
|
|
125
|
-
// Calculate where we would be with normal scrolling
|
|
126
|
-
let normalStartIndex = startIndex;
|
|
127
|
-
if (normalStartIndex > maxStartIndex) {
|
|
128
|
-
normalStartIndex = maxStartIndex;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
// Interpolate between normal position and max position
|
|
132
|
-
const interpolatedStartIndex = Math.floor(
|
|
133
|
-
normalStartIndex +
|
|
134
|
-
(maxStartIndex - normalStartIndex) * interpolationFactor
|
|
135
|
-
);
|
|
136
|
-
|
|
137
|
-
const endIndex = Math.min(
|
|
138
|
-
interpolatedStartIndex + viewportItemCount - 1,
|
|
139
|
-
actualTotalItems - 1
|
|
140
|
-
);
|
|
141
|
-
|
|
142
|
-
// Apply overscan
|
|
143
|
-
const start = Math.max(0, interpolatedStartIndex - overscan);
|
|
144
|
-
const end = Math.min(actualTotalItems - 1, endIndex + overscan);
|
|
145
|
-
|
|
146
|
-
return { start, end };
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
// For positions not near the end, use normal index-based calculation
|
|
151
|
-
let adjustedStartIndex = startIndex;
|
|
152
|
-
if (startIndex > maxStartIndex) {
|
|
153
|
-
adjustedStartIndex = maxStartIndex;
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
const endIndex = Math.min(
|
|
157
|
-
adjustedStartIndex + viewportItemCount - 1,
|
|
158
|
-
actualTotalItems - 1
|
|
159
|
-
);
|
|
160
|
-
|
|
161
|
-
// Apply overscan
|
|
162
|
-
const start = Math.max(0, adjustedStartIndex - overscan);
|
|
163
|
-
const end = Math.min(actualTotalItems - 1, endIndex + overscan);
|
|
164
|
-
|
|
165
|
-
return { start, end };
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
// This should not happen as totalVirtualSize should always be > 0
|
|
169
|
-
console.warn(
|
|
170
|
-
`[VIRTUAL] Unexpected state: totalVirtualSize=${totalVirtualSize}`
|
|
171
|
-
);
|
|
172
|
-
return { start: 0, end: Math.min(10, actualTotalItems - 1) };
|
|
173
|
-
};
|
|
174
|
-
|
|
175
|
-
/**
|
|
176
|
-
* Update total virtual size based on total items
|
|
177
|
-
* Uses actual size when possible, caps at 10M pixels to prevent browser issues
|
|
178
|
-
*/
|
|
179
|
-
const updateTotalVirtualSize = (totalItems: number): void => {
|
|
180
|
-
const estimatedItemSize = itemSizeManager.getEstimatedItemSize();
|
|
181
|
-
|
|
182
|
-
// Cap the virtual size at a reasonable maximum to prevent browser issues
|
|
183
|
-
// This provides smooth scrolling for any dataset size
|
|
184
|
-
const MAX_VIRTUAL_SIZE = 10 * 1000 * 1000; // 10M pixels - well within browser limits
|
|
185
|
-
|
|
186
|
-
let newTotalVirtualSize: number;
|
|
187
|
-
|
|
188
|
-
if (totalItems * estimatedItemSize > MAX_VIRTUAL_SIZE) {
|
|
189
|
-
// Cap virtual size to prevent browser issues
|
|
190
|
-
newTotalVirtualSize = MAX_VIRTUAL_SIZE;
|
|
191
|
-
// console.log(
|
|
192
|
-
// `📐 [VIRTUAL] Capping virtual size at 10M pixels for ${totalItems.toLocaleString()} items (would be ${(
|
|
193
|
-
// (totalItems * estimatedItemSize) /
|
|
194
|
-
// 1_000_000
|
|
195
|
-
// ).toFixed(1)}M pixels)`
|
|
196
|
-
// );
|
|
197
|
-
} else {
|
|
198
|
-
// Use actual size when within limits
|
|
199
|
-
newTotalVirtualSize = totalItems * estimatedItemSize;
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
if (newTotalVirtualSize !== totalVirtualSize) {
|
|
203
|
-
totalVirtualSize = newTotalVirtualSize;
|
|
204
|
-
|
|
205
|
-
// Notify about dimensions change
|
|
206
|
-
onDimensionsChanged?.({
|
|
207
|
-
containerSize,
|
|
208
|
-
totalVirtualSize: newTotalVirtualSize,
|
|
209
|
-
estimatedItemSize,
|
|
210
|
-
totalItems,
|
|
211
|
-
});
|
|
212
|
-
}
|
|
213
|
-
};
|
|
214
|
-
|
|
215
|
-
/**
|
|
216
|
-
* Calculate virtual scroll position for a given item index
|
|
217
|
-
*/
|
|
218
|
-
const calculateVirtualPositionForIndex = (index: number): number => {
|
|
219
|
-
const actualTotalItems = getTotalItems
|
|
220
|
-
? getTotalItems()
|
|
221
|
-
: component.totalItems;
|
|
222
|
-
|
|
223
|
-
if (actualTotalItems === 0) return 0;
|
|
224
|
-
|
|
225
|
-
const itemSize = itemSizeManager.getEstimatedItemSize();
|
|
226
|
-
const actualPosition = index * itemSize;
|
|
227
|
-
|
|
228
|
-
// If using index-based scrolling, map to virtual space
|
|
229
|
-
const actualTotalSize = actualTotalItems * itemSize;
|
|
230
|
-
if (actualTotalSize > totalVirtualSize) {
|
|
231
|
-
const ratio = index / actualTotalItems;
|
|
232
|
-
return ratio * totalVirtualSize;
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
return actualPosition;
|
|
236
|
-
};
|
|
237
|
-
|
|
238
|
-
/**
|
|
239
|
-
* Calculate item index from virtual scroll position
|
|
240
|
-
*/
|
|
241
|
-
const calculateIndexFromVirtualPosition = (position: number): number => {
|
|
242
|
-
const actualTotalItems = getTotalItems
|
|
243
|
-
? getTotalItems()
|
|
244
|
-
: component.totalItems;
|
|
245
|
-
|
|
246
|
-
if (actualTotalItems === 0 || totalVirtualSize === 0) return 0;
|
|
247
|
-
|
|
248
|
-
const itemSize = itemSizeManager.getEstimatedItemSize();
|
|
249
|
-
const actualTotalSize = actualTotalItems * itemSize;
|
|
250
|
-
|
|
251
|
-
// If using index-based scrolling, map from virtual space
|
|
252
|
-
if (actualTotalSize > totalVirtualSize) {
|
|
253
|
-
const ratio = position / totalVirtualSize;
|
|
254
|
-
return Math.floor(ratio * actualTotalItems);
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
return Math.floor(position / itemSize);
|
|
258
|
-
};
|
|
259
|
-
|
|
260
|
-
/**
|
|
261
|
-
* Get maximum scroll position
|
|
262
|
-
*/
|
|
263
|
-
const getMaxScrollPosition = (): number => {
|
|
264
|
-
return Math.max(0, totalVirtualSize - containerSize);
|
|
265
|
-
};
|
|
266
|
-
|
|
267
|
-
/**
|
|
268
|
-
* Get current total virtual size
|
|
269
|
-
*/
|
|
270
|
-
const getTotalVirtualSize = (): number => totalVirtualSize;
|
|
271
|
-
|
|
272
|
-
/**
|
|
273
|
-
* Update virtual scrolling state
|
|
274
|
-
*/
|
|
275
|
-
const updateState = (updates: Partial<VirtualState>): void => {
|
|
276
|
-
if (updates.totalVirtualSize !== undefined) {
|
|
277
|
-
totalVirtualSize = updates.totalVirtualSize;
|
|
278
|
-
}
|
|
279
|
-
if (updates.containerSize !== undefined) {
|
|
280
|
-
containerSize = updates.containerSize;
|
|
281
|
-
}
|
|
282
|
-
};
|
|
283
|
-
|
|
284
|
-
/**
|
|
285
|
-
* Get current virtual scrolling state
|
|
286
|
-
*/
|
|
287
|
-
const getState = (): VirtualState => ({
|
|
288
|
-
totalVirtualSize,
|
|
289
|
-
containerSize,
|
|
290
|
-
});
|
|
291
|
-
|
|
292
|
-
return {
|
|
293
|
-
// Range calculations
|
|
294
|
-
calculateVisibleRange,
|
|
295
|
-
|
|
296
|
-
// Size management
|
|
297
|
-
updateTotalVirtualSize,
|
|
298
|
-
getTotalVirtualSize,
|
|
299
|
-
|
|
300
|
-
// Index-based scrolling utilities
|
|
301
|
-
calculateVirtualPositionForIndex,
|
|
302
|
-
calculateIndexFromVirtualPosition,
|
|
303
|
-
getMaxScrollPosition,
|
|
304
|
-
|
|
305
|
-
// State management
|
|
306
|
-
updateState,
|
|
307
|
-
getState,
|
|
308
|
-
};
|
|
309
|
-
};
|
|
@@ -1,279 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* List Manager Public API
|
|
3
|
-
* Main exports for the mtrl-addons List Manager system
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
// Import types first
|
|
7
|
-
import type {
|
|
8
|
-
ListManager,
|
|
9
|
-
ListManagerConfig,
|
|
10
|
-
CollectionConfig,
|
|
11
|
-
ItemRange,
|
|
12
|
-
ViewportInfo,
|
|
13
|
-
} from "./types";
|
|
14
|
-
import { createListManager } from "./list-manager";
|
|
15
|
-
import { createListManagerAPI, ListManagerAPI, ListManagerUtils } from "./api";
|
|
16
|
-
|
|
17
|
-
// Export all types
|
|
18
|
-
export type {
|
|
19
|
-
ListManager,
|
|
20
|
-
ListManagerConfig,
|
|
21
|
-
ListManagerConfigUpdate,
|
|
22
|
-
ListManagerObserver,
|
|
23
|
-
ListManagerUnsubscribe,
|
|
24
|
-
ItemRange,
|
|
25
|
-
ViewportInfo,
|
|
26
|
-
SpeedTracker,
|
|
27
|
-
ViewportFeature,
|
|
28
|
-
CollectionFeature,
|
|
29
|
-
FeatureContext,
|
|
30
|
-
RangeCalculationResult,
|
|
31
|
-
|
|
32
|
-
// Configuration types
|
|
33
|
-
CollectionConfig,
|
|
34
|
-
TemplateConfig,
|
|
35
|
-
VirtualConfig,
|
|
36
|
-
OrientationConfig,
|
|
37
|
-
InitialLoadConfig,
|
|
38
|
-
ErrorHandlingConfig,
|
|
39
|
-
PositioningConfig,
|
|
40
|
-
BoundariesConfig,
|
|
41
|
-
RecyclingConfig,
|
|
42
|
-
PerformanceConfig,
|
|
43
|
-
IntersectionConfig,
|
|
44
|
-
|
|
45
|
-
// Event system
|
|
46
|
-
ListManagerEventData,
|
|
47
|
-
} from "./types";
|
|
48
|
-
|
|
49
|
-
export { ListManagerEvents } from "./types";
|
|
50
|
-
|
|
51
|
-
// Export core functions
|
|
52
|
-
export { createListManager, ListManagerImpl } from "./list-manager";
|
|
53
|
-
export { createListManagerAPI, ListManagerAPI, ListManagerUtils } from "./api";
|
|
54
|
-
|
|
55
|
-
// Export constants
|
|
56
|
-
export { LIST_MANAGER_CONSTANTS, mergeConstants } from "./constants";
|
|
57
|
-
export type { ListManagerConstants } from "./constants";
|
|
58
|
-
|
|
59
|
-
// Export utility functions
|
|
60
|
-
export {
|
|
61
|
-
calculateTotalVirtualSize,
|
|
62
|
-
calculateContainerPosition,
|
|
63
|
-
calculateScrollPositionForIndex,
|
|
64
|
-
calculateScrollPositionForPage,
|
|
65
|
-
calculateScrollbarMetrics,
|
|
66
|
-
calculateInitialRangeSize,
|
|
67
|
-
calculateMissingRanges,
|
|
68
|
-
calculateBufferRanges,
|
|
69
|
-
clamp,
|
|
70
|
-
applyBoundaryResistance,
|
|
71
|
-
} from "./utils/calculations";
|
|
72
|
-
|
|
73
|
-
export {
|
|
74
|
-
createSpeedTracker,
|
|
75
|
-
updateSpeedTracker,
|
|
76
|
-
isFastScrolling,
|
|
77
|
-
isSlowScrolling,
|
|
78
|
-
getLoadingStrategy,
|
|
79
|
-
calculateScrollMomentum,
|
|
80
|
-
createSpeedBasedLoadingConfig,
|
|
81
|
-
resetSpeedTracker,
|
|
82
|
-
getScrollThrottleInterval,
|
|
83
|
-
hasSignificantDirectionChange,
|
|
84
|
-
calculateAdaptiveOverscan,
|
|
85
|
-
getSpeedTrackerDebugInfo,
|
|
86
|
-
} from "./utils/speed-tracker";
|
|
87
|
-
|
|
88
|
-
export {
|
|
89
|
-
calculateRangeIndex,
|
|
90
|
-
calculateRangeBounds,
|
|
91
|
-
calculateRequiredRanges,
|
|
92
|
-
calculatePrefetchRanges,
|
|
93
|
-
calculateRangeResult,
|
|
94
|
-
rangeToPaginationParams,
|
|
95
|
-
rangesToBatchParams,
|
|
96
|
-
calculateOptimalRangeSize,
|
|
97
|
-
isRangeInViewport,
|
|
98
|
-
calculateRangePriority,
|
|
99
|
-
sortRangesByPriority,
|
|
100
|
-
mergeAdjacentRanges,
|
|
101
|
-
calculateRangeCleanupCandidates,
|
|
102
|
-
calculateRangeLoadingOrder,
|
|
103
|
-
getRangeDebugInfo,
|
|
104
|
-
} from "./utils/range-calculator";
|
|
105
|
-
|
|
106
|
-
// Export feature factories
|
|
107
|
-
export { createViewportFeature } from "./features/viewport";
|
|
108
|
-
export { createCollectionFeature } from "./features/collection";
|
|
109
|
-
|
|
110
|
-
/**
|
|
111
|
-
* Default export - createListManager for convenience
|
|
112
|
-
*/
|
|
113
|
-
export { createListManager as default } from "./list-manager";
|
|
114
|
-
|
|
115
|
-
/**
|
|
116
|
-
* Version information
|
|
117
|
-
*/
|
|
118
|
-
export const LIST_MANAGER_VERSION = "1.0.0";
|
|
119
|
-
|
|
120
|
-
/**
|
|
121
|
-
* Feature compatibility flags
|
|
122
|
-
*/
|
|
123
|
-
export const FEATURES = {
|
|
124
|
-
VIRTUAL_SCROLLING: true,
|
|
125
|
-
CUSTOM_SCROLLBAR: true,
|
|
126
|
-
SPEED_BASED_LOADING: true,
|
|
127
|
-
PLACEHOLDER_SYSTEM: true,
|
|
128
|
-
ORIENTATION_SUPPORT: true,
|
|
129
|
-
RANGE_PAGINATION: true,
|
|
130
|
-
ELEMENT_RECYCLING: false, // Phase 2
|
|
131
|
-
SMOOTH_SCROLLING: false, // Phase 2
|
|
132
|
-
PERFORMANCE_MONITORING: false, // Phase 2
|
|
133
|
-
} as const;
|
|
134
|
-
|
|
135
|
-
/**
|
|
136
|
-
* Quick setup helpers for common use cases
|
|
137
|
-
*/
|
|
138
|
-
export const QuickSetup = {
|
|
139
|
-
/**
|
|
140
|
-
* Create a basic vertical list with static items
|
|
141
|
-
*/
|
|
142
|
-
verticalList: (
|
|
143
|
-
container: HTMLElement,
|
|
144
|
-
items: any[],
|
|
145
|
-
template: (item: any, index: number) => HTMLElement
|
|
146
|
-
): ListManager => {
|
|
147
|
-
return createListManager({
|
|
148
|
-
container,
|
|
149
|
-
items,
|
|
150
|
-
template: { template },
|
|
151
|
-
virtual: {
|
|
152
|
-
enabled: true,
|
|
153
|
-
itemSize: "auto",
|
|
154
|
-
estimatedItemSize: 84,
|
|
155
|
-
overscan: 5,
|
|
156
|
-
},
|
|
157
|
-
orientation: {
|
|
158
|
-
orientation: "vertical",
|
|
159
|
-
reverse: false,
|
|
160
|
-
crossAxisAlignment: "stretch",
|
|
161
|
-
},
|
|
162
|
-
debug: false,
|
|
163
|
-
prefix: "mtrl-list",
|
|
164
|
-
componentName: "List",
|
|
165
|
-
});
|
|
166
|
-
},
|
|
167
|
-
|
|
168
|
-
/**
|
|
169
|
-
* Create a horizontal list with static items
|
|
170
|
-
*/
|
|
171
|
-
horizontalList: (
|
|
172
|
-
container: HTMLElement,
|
|
173
|
-
items: any[],
|
|
174
|
-
template: (item: any, index: number) => HTMLElement
|
|
175
|
-
): ListManager => {
|
|
176
|
-
return createListManager({
|
|
177
|
-
container,
|
|
178
|
-
items,
|
|
179
|
-
template: { template },
|
|
180
|
-
virtual: {
|
|
181
|
-
enabled: true,
|
|
182
|
-
itemSize: "auto",
|
|
183
|
-
estimatedItemSize: 200,
|
|
184
|
-
overscan: 3,
|
|
185
|
-
},
|
|
186
|
-
orientation: {
|
|
187
|
-
orientation: "horizontal",
|
|
188
|
-
reverse: false,
|
|
189
|
-
crossAxisAlignment: "stretch",
|
|
190
|
-
},
|
|
191
|
-
debug: false,
|
|
192
|
-
prefix: "mtrl-list",
|
|
193
|
-
componentName: "HorizontalList",
|
|
194
|
-
});
|
|
195
|
-
},
|
|
196
|
-
|
|
197
|
-
/**
|
|
198
|
-
* Create an API-driven list with collection integration
|
|
199
|
-
*/
|
|
200
|
-
apiList: (
|
|
201
|
-
container: HTMLElement,
|
|
202
|
-
collection: CollectionConfig,
|
|
203
|
-
template: (item: any, index: number) => HTMLElement
|
|
204
|
-
): ListManager => {
|
|
205
|
-
return createListManager({
|
|
206
|
-
container,
|
|
207
|
-
collection,
|
|
208
|
-
template: { template },
|
|
209
|
-
virtual: {
|
|
210
|
-
enabled: true,
|
|
211
|
-
itemSize: "auto",
|
|
212
|
-
estimatedItemSize: 60,
|
|
213
|
-
overscan: 5,
|
|
214
|
-
},
|
|
215
|
-
orientation: {
|
|
216
|
-
orientation: "vertical",
|
|
217
|
-
reverse: false,
|
|
218
|
-
crossAxisAlignment: "stretch",
|
|
219
|
-
},
|
|
220
|
-
initialLoad: {
|
|
221
|
-
strategy: "placeholders",
|
|
222
|
-
viewportMultiplier: 1.5,
|
|
223
|
-
minItems: 10,
|
|
224
|
-
maxItems: 100,
|
|
225
|
-
},
|
|
226
|
-
debug: false,
|
|
227
|
-
prefix: "mtrl-list",
|
|
228
|
-
componentName: "ApiList",
|
|
229
|
-
});
|
|
230
|
-
},
|
|
231
|
-
|
|
232
|
-
/**
|
|
233
|
-
* Create a debug list for development
|
|
234
|
-
*/
|
|
235
|
-
debugList: (
|
|
236
|
-
container: HTMLElement,
|
|
237
|
-
itemCount: number = 1000
|
|
238
|
-
): ListManagerAPI => {
|
|
239
|
-
return createListManagerAPI(
|
|
240
|
-
ListManagerUtils.createTestConfig(container, itemCount)
|
|
241
|
-
);
|
|
242
|
-
},
|
|
243
|
-
};
|
|
244
|
-
|
|
245
|
-
/**
|
|
246
|
-
* Type guards for feature detection
|
|
247
|
-
*/
|
|
248
|
-
export const TypeGuards = {
|
|
249
|
-
isListManager: (obj: any): obj is ListManager => {
|
|
250
|
-
return (
|
|
251
|
-
obj &&
|
|
252
|
-
typeof obj.scrollToIndex === "function" &&
|
|
253
|
-
typeof obj.getVisibleRange === "function" &&
|
|
254
|
-
typeof obj.initialize === "function"
|
|
255
|
-
);
|
|
256
|
-
},
|
|
257
|
-
|
|
258
|
-
isListManagerAPI: (obj: any): obj is ListManagerAPI => {
|
|
259
|
-
return (
|
|
260
|
-
TypeGuards.isListManager(obj) &&
|
|
261
|
-
typeof obj.onScroll === "function" &&
|
|
262
|
-
typeof obj.getDebugInfo === "function"
|
|
263
|
-
);
|
|
264
|
-
},
|
|
265
|
-
|
|
266
|
-
isItemRange: (obj: any): obj is ItemRange => {
|
|
267
|
-
return obj && typeof obj.start === "number" && typeof obj.end === "number";
|
|
268
|
-
},
|
|
269
|
-
|
|
270
|
-
isViewportInfo: (obj: any): obj is ViewportInfo => {
|
|
271
|
-
return (
|
|
272
|
-
obj &&
|
|
273
|
-
typeof obj.containerSize === "number" &&
|
|
274
|
-
typeof obj.totalVirtualSize === "number" &&
|
|
275
|
-
TypeGuards.isItemRange(obj.visibleRange) &&
|
|
276
|
-
typeof obj.virtualScrollPosition === "number"
|
|
277
|
-
);
|
|
278
|
-
},
|
|
279
|
-
};
|