mtrl-addons 0.1.1 → 0.2.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.
- package/build.js +139 -108
- package/package.json +13 -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 +322 -0
- package/src/components/vlist/features/index.ts +10 -0
- package/src/components/vlist/features/selection.ts +444 -0
- package/src/components/vlist/features/viewport.ts +65 -0
- package/src/components/vlist/index.ts +16 -0
- package/src/components/{list → vlist}/types.ts +104 -26
- 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 +73 -35
- package/src/core/layout/types.ts +5 -2
- package/src/core/viewport/constants.ts +140 -0
- package/src/core/viewport/features/base.ts +73 -0
- package/src/core/viewport/features/collection.ts +882 -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 +27 -30
- package/src/core/{list-manager/features/viewport → viewport/features}/loading.ts +4 -4
- package/src/core/viewport/features/momentum.ts +260 -0
- package/src/core/viewport/features/placeholders.ts +335 -0
- package/src/core/viewport/features/rendering.ts +568 -0
- package/src/core/viewport/features/scrollbar.ts +434 -0
- package/src/core/viewport/features/scrolling.ts +618 -0
- package/src/core/viewport/features/utils.ts +88 -0
- package/src/core/viewport/features/virtual.ts +384 -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 +246 -0
- package/src/index.ts +0 -7
- package/src/styles/components/_vlist.scss +331 -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 -14
- /package/src/components/{list → vlist}/features.ts +0 -0
- /package/src/core/{compose → viewport}/features/performance.ts +0 -0
|
@@ -1,206 +0,0 @@
|
|
|
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
|
-
}
|
|
@@ -1,439 +0,0 @@
|
|
|
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
|
-
}
|