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,17 +0,0 @@
|
|
|
1
|
-
// src/core/list-manager/features/collection/index.ts
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Main collection feature - Data management & API integration
|
|
5
|
-
*
|
|
6
|
-
* This is the core collection management system that handles:
|
|
7
|
-
* - Data loading and caching
|
|
8
|
-
* - Range-based loading strategies
|
|
9
|
-
* - Pagination triggers
|
|
10
|
-
* - API adapter integration
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
|
-
export { withCollection } from "./collection";
|
|
14
|
-
|
|
15
|
-
// TODO: Create these core collection utilities
|
|
16
|
-
// export { rangeLoading } from "./range-loading";
|
|
17
|
-
// export { paginationTrigger } from "./pagination-trigger";
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Viewport Constants
|
|
3
|
-
* Centralized constants for viewport features
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
export const VIEWPORT_CONSTANTS = {
|
|
7
|
-
/**
|
|
8
|
-
* Request queue configuration
|
|
9
|
-
*/
|
|
10
|
-
REQUEST_QUEUE: {
|
|
11
|
-
ENABLED: true, // Enable/disable request queue system
|
|
12
|
-
MAX_QUEUE_SIZE: 50, // Maximum number of queued requests
|
|
13
|
-
MAX_ACTIVE_REQUESTS: 1, // Maximum concurrent active requests (1 = sequential)
|
|
14
|
-
},
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Loading configuration
|
|
18
|
-
*/
|
|
19
|
-
LOADING: {
|
|
20
|
-
CANCEL_THRESHOLD: 1, // px/ms - velocity above which loads are cancelled (lowered for better scrollbar response)
|
|
21
|
-
},
|
|
22
|
-
|
|
23
|
-
// Placeholder settings
|
|
24
|
-
PLACEHOLDER: {
|
|
25
|
-
MASK_CHARACTER: "x",
|
|
26
|
-
CSS_CLASS: "list-item__placeholder",
|
|
27
|
-
MIN_SAMPLE_SIZE: 5, // Minimum items needed for reliable analysis
|
|
28
|
-
MAX_SAMPLE_SIZE: 20, // Maximum items to analyze for performance
|
|
29
|
-
},
|
|
30
|
-
|
|
31
|
-
// Scrolling settings
|
|
32
|
-
SCROLLING: {
|
|
33
|
-
OVERSCAN: 2,
|
|
34
|
-
DEBOUNCE_MS: 50,
|
|
35
|
-
},
|
|
36
|
-
|
|
37
|
-
// Rendering settings
|
|
38
|
-
RENDERING: {
|
|
39
|
-
BATCH_SIZE: 100,
|
|
40
|
-
MIN_ITEM_HEIGHT: 20,
|
|
41
|
-
},
|
|
42
|
-
};
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
// src/core/list-manager/features/viewport/index.ts
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Viewport features export
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
export { withViewport } from "./viewport";
|
|
8
|
-
export { withPlaceholders } from "./placeholders";
|
|
9
|
-
|
|
10
|
-
// Types
|
|
11
|
-
export type { ViewportComponent } from "./viewport";
|
|
12
|
-
export type { PlaceholdersComponent } from "./placeholders";
|
|
13
|
-
|
|
14
|
-
// Configs
|
|
15
|
-
export type { ViewportConfig } from "./viewport";
|
|
16
|
-
export type { PlaceholdersConfig } from "./placeholders";
|
|
@@ -1,281 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Placeholders Feature - Smart Structure Analysis
|
|
3
|
-
* Analyzes first loaded data to generate realistic masked placeholders
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import type { ListManagerComponent, ItemRange } from "../../types";
|
|
7
|
-
import { PLACEHOLDER } from "../../constants";
|
|
8
|
-
import { VIEWPORT_CONSTANTS } from "./constants";
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Configuration for placeholders enhancer
|
|
12
|
-
*/
|
|
13
|
-
export interface PlaceholdersConfig {
|
|
14
|
-
enabled?: boolean;
|
|
15
|
-
analyzeFirstLoad?: boolean;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Field structure analysis result
|
|
20
|
-
*/
|
|
21
|
-
export interface FieldStructure {
|
|
22
|
-
minLength: number;
|
|
23
|
-
maxLength: number;
|
|
24
|
-
avgLength: number;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* Component interface after placeholders enhancement
|
|
29
|
-
*/
|
|
30
|
-
export interface PlaceholdersComponent {
|
|
31
|
-
placeholders: {
|
|
32
|
-
// Structure analysis
|
|
33
|
-
analyzeDataStructure(items: any[]): void;
|
|
34
|
-
hasAnalyzedStructure(): boolean;
|
|
35
|
-
|
|
36
|
-
// Placeholder generation
|
|
37
|
-
generatePlaceholderItem(index: number): any;
|
|
38
|
-
generatePlaceholderItems(range: ItemRange): any[];
|
|
39
|
-
|
|
40
|
-
// Placeholder management
|
|
41
|
-
showPlaceholders(range: ItemRange): void;
|
|
42
|
-
isPlaceholder(item: any): boolean;
|
|
43
|
-
|
|
44
|
-
// State
|
|
45
|
-
isEnabled(): boolean;
|
|
46
|
-
clear(): void;
|
|
47
|
-
};
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* Adds placeholders functionality to a List Manager component
|
|
52
|
-
*/
|
|
53
|
-
export const withPlaceholders =
|
|
54
|
-
(config: PlaceholdersConfig = {}) =>
|
|
55
|
-
<T extends ListManagerComponent>(component: T): T & PlaceholdersComponent => {
|
|
56
|
-
// Configuration with defaults
|
|
57
|
-
const placeholdersConfig: PlaceholdersConfig = {
|
|
58
|
-
enabled: config.enabled !== false,
|
|
59
|
-
analyzeFirstLoad: config.analyzeFirstLoad !== false,
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
// Placeholder state
|
|
63
|
-
let fieldStructures: Map<string, FieldStructure> | null = null;
|
|
64
|
-
let hasAnalyzed = false;
|
|
65
|
-
let placeholderIdCounter = 0;
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* Analyze data structure from first loaded items
|
|
69
|
-
*/
|
|
70
|
-
const analyzeDataStructure = (items: any[]): void => {
|
|
71
|
-
if (!placeholdersConfig.enabled || hasAnalyzed || !items.length) {
|
|
72
|
-
return;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
console.log(
|
|
76
|
-
`🔍 [PLACEHOLDERS] Analyzing data structure from ${items.length} items`
|
|
77
|
-
);
|
|
78
|
-
|
|
79
|
-
const structures = new Map<string, FieldStructure>();
|
|
80
|
-
const sampleSize = Math.min(
|
|
81
|
-
items.length,
|
|
82
|
-
VIEWPORT_CONSTANTS.PLACEHOLDER.MAX_SAMPLE_SIZE
|
|
83
|
-
);
|
|
84
|
-
|
|
85
|
-
// Analyze each field across all sample items
|
|
86
|
-
const fieldStats = new Map<string, number[]>();
|
|
87
|
-
|
|
88
|
-
for (let i = 0; i < sampleSize; i++) {
|
|
89
|
-
const item = items[i];
|
|
90
|
-
if (!item || typeof item !== "object") continue;
|
|
91
|
-
|
|
92
|
-
Object.keys(item).forEach((field) => {
|
|
93
|
-
// Skip internal fields
|
|
94
|
-
if (field.startsWith("_") || field === PLACEHOLDER.PLACEHOLDER_FLAG) {
|
|
95
|
-
return;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
const value = item[field];
|
|
99
|
-
if (value === null || value === undefined) return;
|
|
100
|
-
|
|
101
|
-
const length = String(value).length;
|
|
102
|
-
|
|
103
|
-
if (!fieldStats.has(field)) {
|
|
104
|
-
fieldStats.set(field, []);
|
|
105
|
-
}
|
|
106
|
-
fieldStats.get(field)!.push(length);
|
|
107
|
-
});
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
// Calculate min/max/avg for each field
|
|
111
|
-
fieldStats.forEach((lengths, field) => {
|
|
112
|
-
if (lengths.length === 0) return;
|
|
113
|
-
|
|
114
|
-
const minLength = Math.min(...lengths);
|
|
115
|
-
const maxLength = Math.max(...lengths);
|
|
116
|
-
const avgLength = Math.round(
|
|
117
|
-
lengths.reduce((sum, len) => sum + len, 0) / lengths.length
|
|
118
|
-
);
|
|
119
|
-
|
|
120
|
-
structures.set(field, {
|
|
121
|
-
minLength,
|
|
122
|
-
maxLength,
|
|
123
|
-
avgLength,
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
console.log(
|
|
127
|
-
`📊 [PLACEHOLDERS] Field "${field}": min=${minLength}, max=${maxLength}, avg=${avgLength}`
|
|
128
|
-
);
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
fieldStructures = structures;
|
|
132
|
-
hasAnalyzed = true;
|
|
133
|
-
|
|
134
|
-
component.emit?.("placeholders:analyzed", {
|
|
135
|
-
fieldCount: structures.size,
|
|
136
|
-
sampleSize,
|
|
137
|
-
});
|
|
138
|
-
};
|
|
139
|
-
|
|
140
|
-
/**
|
|
141
|
-
* Generate a single placeholder item based on analyzed structure
|
|
142
|
-
*/
|
|
143
|
-
const generatePlaceholderItem = (index: number): any => {
|
|
144
|
-
if (!placeholdersConfig.enabled || !fieldStructures) {
|
|
145
|
-
return null;
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
const placeholder: Record<string, any> = {
|
|
149
|
-
id: `placeholder-${++placeholderIdCounter}`,
|
|
150
|
-
[PLACEHOLDER.PLACEHOLDER_FLAG]: true,
|
|
151
|
-
};
|
|
152
|
-
|
|
153
|
-
// Generate masked values for each analyzed field
|
|
154
|
-
fieldStructures.forEach((structure, field) => {
|
|
155
|
-
const { minLength, maxLength } = structure;
|
|
156
|
-
|
|
157
|
-
// Random length within the range
|
|
158
|
-
const length =
|
|
159
|
-
minLength === maxLength
|
|
160
|
-
? minLength
|
|
161
|
-
: Math.floor(Math.random() * (maxLength - minLength + 1)) +
|
|
162
|
-
minLength;
|
|
163
|
-
|
|
164
|
-
// Generate masked string
|
|
165
|
-
placeholder[field] =
|
|
166
|
-
VIEWPORT_CONSTANTS.PLACEHOLDER.MASK_CHARACTER.repeat(length);
|
|
167
|
-
});
|
|
168
|
-
|
|
169
|
-
return placeholder;
|
|
170
|
-
};
|
|
171
|
-
|
|
172
|
-
/**
|
|
173
|
-
* Generate multiple placeholder items for a range
|
|
174
|
-
*/
|
|
175
|
-
const generatePlaceholderItems = (range: ItemRange): any[] => {
|
|
176
|
-
const items: any[] = [];
|
|
177
|
-
|
|
178
|
-
for (let i = range.start; i <= range.end; i++) {
|
|
179
|
-
items.push(generatePlaceholderItem(i));
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
return items;
|
|
183
|
-
};
|
|
184
|
-
|
|
185
|
-
/**
|
|
186
|
-
* Show placeholders for a range
|
|
187
|
-
*/
|
|
188
|
-
const showPlaceholders = (range: ItemRange): void => {
|
|
189
|
-
if (!placeholdersConfig.enabled || !hasAnalyzed) {
|
|
190
|
-
return;
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
const placeholderItems = generatePlaceholderItems(range);
|
|
194
|
-
|
|
195
|
-
// Add placeholders to component items
|
|
196
|
-
placeholderItems.forEach((item, index) => {
|
|
197
|
-
const targetIndex = range.start + index;
|
|
198
|
-
const existingItem = component.items[targetIndex];
|
|
199
|
-
const shouldReplace = !existingItem || isPlaceholder(existingItem);
|
|
200
|
-
|
|
201
|
-
if (shouldReplace) {
|
|
202
|
-
component.items[targetIndex] = item;
|
|
203
|
-
}
|
|
204
|
-
});
|
|
205
|
-
|
|
206
|
-
component.emit?.("placeholders:shown", {
|
|
207
|
-
range,
|
|
208
|
-
count: placeholderItems.length,
|
|
209
|
-
});
|
|
210
|
-
};
|
|
211
|
-
|
|
212
|
-
/**
|
|
213
|
-
* Check if an item is a placeholder
|
|
214
|
-
*/
|
|
215
|
-
const isPlaceholder = (item: any): boolean => {
|
|
216
|
-
return (
|
|
217
|
-
item &&
|
|
218
|
-
typeof item === "object" &&
|
|
219
|
-
item[PLACEHOLDER.PLACEHOLDER_FLAG] === true
|
|
220
|
-
);
|
|
221
|
-
};
|
|
222
|
-
|
|
223
|
-
/**
|
|
224
|
-
* Check if placeholders are enabled
|
|
225
|
-
*/
|
|
226
|
-
const isEnabled = (): boolean => {
|
|
227
|
-
return placeholdersConfig.enabled || false;
|
|
228
|
-
};
|
|
229
|
-
|
|
230
|
-
/**
|
|
231
|
-
* Clear placeholder state
|
|
232
|
-
*/
|
|
233
|
-
const clear = (): void => {
|
|
234
|
-
fieldStructures = null;
|
|
235
|
-
hasAnalyzed = false;
|
|
236
|
-
placeholderIdCounter = 0;
|
|
237
|
-
};
|
|
238
|
-
|
|
239
|
-
/**
|
|
240
|
-
* Check if structure has been analyzed
|
|
241
|
-
*/
|
|
242
|
-
const hasAnalyzedStructure = (): boolean => {
|
|
243
|
-
return hasAnalyzed;
|
|
244
|
-
};
|
|
245
|
-
|
|
246
|
-
// Listen for first data load to analyze structure
|
|
247
|
-
if (placeholdersConfig.analyzeFirstLoad && component.on) {
|
|
248
|
-
component.on("range:loaded", (data: any) => {
|
|
249
|
-
if (
|
|
250
|
-
!hasAnalyzed &&
|
|
251
|
-
data?.items?.length >= VIEWPORT_CONSTANTS.PLACEHOLDER.MIN_SAMPLE_SIZE
|
|
252
|
-
) {
|
|
253
|
-
analyzeDataStructure(data.items);
|
|
254
|
-
}
|
|
255
|
-
});
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
// Placeholders API
|
|
259
|
-
const placeholdersAPI = {
|
|
260
|
-
// Structure analysis
|
|
261
|
-
analyzeDataStructure,
|
|
262
|
-
hasAnalyzedStructure,
|
|
263
|
-
|
|
264
|
-
// Placeholder generation
|
|
265
|
-
generatePlaceholderItem,
|
|
266
|
-
generatePlaceholderItems,
|
|
267
|
-
|
|
268
|
-
// Placeholder management
|
|
269
|
-
showPlaceholders,
|
|
270
|
-
isPlaceholder,
|
|
271
|
-
|
|
272
|
-
// State
|
|
273
|
-
isEnabled,
|
|
274
|
-
clear,
|
|
275
|
-
};
|
|
276
|
-
|
|
277
|
-
return {
|
|
278
|
-
...component,
|
|
279
|
-
placeholders: placeholdersAPI,
|
|
280
|
-
};
|
|
281
|
-
};
|