mtrl-addons 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.cursorrules +117 -0
- package/AI.md +241 -0
- package/build.js +170 -0
- package/bun.lock +792 -0
- package/index.ts +7 -0
- package/package.json +10 -17
- package/scripts/analyze-orphaned-functions.ts +387 -0
- package/src/components/index.ts +45 -0
- package/src/components/list/api.ts +314 -0
- package/src/components/list/config.ts +352 -0
- package/src/components/list/constants.ts +56 -0
- package/src/components/list/features/api.ts +428 -0
- package/src/components/list/features/index.ts +31 -0
- package/src/components/list/features/list-manager.ts +502 -0
- package/src/components/list/features.ts +112 -0
- package/src/components/list/index.ts +39 -0
- package/src/components/list/list.ts +234 -0
- package/src/components/list/types.ts +513 -0
- package/src/core/collection/base-collection.ts +100 -0
- package/src/core/collection/collection-composer.ts +178 -0
- package/src/core/collection/collection.ts +745 -0
- package/src/core/collection/constants.ts +172 -0
- package/src/core/collection/events.ts +428 -0
- package/src/core/collection/features/api/loading.ts +279 -0
- package/src/core/collection/features/operations/data-operations.ts +147 -0
- package/src/core/collection/index.ts +104 -0
- package/src/core/collection/state.ts +497 -0
- package/src/core/collection/types.ts +404 -0
- package/src/core/compose/features/collection.ts +119 -0
- package/src/core/compose/features/index.ts +39 -0
- package/src/core/compose/features/performance.ts +161 -0
- package/src/core/compose/features/selection.ts +213 -0
- package/src/core/compose/features/styling.ts +108 -0
- package/src/core/compose/index.ts +31 -0
- package/src/core/index.ts +167 -0
- package/src/core/layout/config.ts +102 -0
- package/src/core/layout/index.ts +168 -0
- package/src/core/layout/jsx.ts +174 -0
- package/src/core/layout/schema.ts +963 -0
- package/src/core/layout/types.ts +92 -0
- package/src/core/list-manager/api.ts +599 -0
- package/src/core/list-manager/config.ts +593 -0
- package/src/core/list-manager/constants.ts +268 -0
- package/src/core/list-manager/features/api.ts +58 -0
- package/src/core/list-manager/features/collection/collection.ts +705 -0
- package/src/core/list-manager/features/collection/index.ts +17 -0
- package/src/core/list-manager/features/viewport/constants.ts +42 -0
- package/src/core/list-manager/features/viewport/index.ts +16 -0
- package/src/core/list-manager/features/viewport/item-size.ts +274 -0
- package/src/core/list-manager/features/viewport/loading.ts +263 -0
- package/src/core/list-manager/features/viewport/placeholders.ts +281 -0
- package/src/core/list-manager/features/viewport/rendering.ts +575 -0
- package/src/core/list-manager/features/viewport/scrollbar.ts +495 -0
- package/src/core/list-manager/features/viewport/scrolling.ts +795 -0
- package/src/core/list-manager/features/viewport/template.ts +220 -0
- package/src/core/list-manager/features/viewport/viewport.ts +654 -0
- package/src/core/list-manager/features/viewport/virtual.ts +309 -0
- package/src/core/list-manager/index.ts +279 -0
- package/src/core/list-manager/list-manager.ts +206 -0
- package/src/core/list-manager/types.ts +439 -0
- package/src/core/list-manager/utils/calculations.ts +290 -0
- package/src/core/list-manager/utils/range-calculator.ts +349 -0
- package/src/core/list-manager/utils/speed-tracker.ts +273 -0
- package/src/index.ts +17 -0
- package/src/styles/components/_list.scss +244 -0
- package/src/styles/index.scss +12 -0
- package/src/types/mtrl.d.ts +6 -0
- package/test/benchmarks/layout/advanced.test.ts +656 -0
- package/test/benchmarks/layout/comparison.test.ts +519 -0
- package/test/benchmarks/layout/performance-comparison.test.ts +274 -0
- package/test/benchmarks/layout/real-components.test.ts +733 -0
- package/test/benchmarks/layout/simple.test.ts +321 -0
- package/test/benchmarks/layout/stress.test.ts +990 -0
- package/test/collection/basic.test.ts +304 -0
- package/test/components/list.test.ts +256 -0
- package/test/core/collection/collection.test.ts +394 -0
- package/test/core/collection/failed-ranges.test.ts +270 -0
- package/test/core/compose/features.test.ts +183 -0
- package/test/core/layout/layout.test.ts +201 -0
- package/test/core/list-manager/features/collection.test.ts +704 -0
- package/test/core/list-manager/features/viewport.test.ts +698 -0
- package/test/core/list-manager/list-manager.test.ts +593 -0
- package/test/core/list-manager/utils/calculations.test.ts +433 -0
- package/test/core/list-manager/utils/range-calculator.test.ts +569 -0
- package/test/core/list-manager/utils/speed-tracker.test.ts +530 -0
- package/test/utils/dom-helpers.ts +275 -0
- package/test/utils/performance-helpers.ts +392 -0
- package/tsconfig.build.json +14 -0
- package/tsconfig.json +20 -0
- package/dist/index.d.ts +0 -5
- package/dist/index.js +0 -38
- package/dist/index.mjs +0 -8
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* mtrl-addons List Component
|
|
3
|
+
*
|
|
4
|
+
* Next-generation list component built on the collection system.
|
|
5
|
+
* Uses mtrl's compose system with addons-specific features.
|
|
6
|
+
* Follows mtrl patterns for component architecture.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type {
|
|
10
|
+
ListConfig,
|
|
11
|
+
ListComponent,
|
|
12
|
+
ListItem,
|
|
13
|
+
ListPerformanceMetrics,
|
|
14
|
+
} from "./types";
|
|
15
|
+
|
|
16
|
+
// Import mtrl compose system
|
|
17
|
+
import { pipe } from "mtrl/src/core/compose/pipe";
|
|
18
|
+
import { createBase, withElement } from "mtrl/src/core/compose/component";
|
|
19
|
+
import { withEvents, withLifecycle } from "mtrl/src/core/compose/features";
|
|
20
|
+
|
|
21
|
+
// Import list-specific utilities
|
|
22
|
+
import { createBaseConfig, getElementConfig, getApiConfig } from "./config";
|
|
23
|
+
import { LIST_CLASSES } from "./constants";
|
|
24
|
+
import { withListManager } from "./features/list-manager";
|
|
25
|
+
import { withAPI } from "./api";
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Creates list-specific configuration from user config
|
|
29
|
+
*/
|
|
30
|
+
function createListConfig<T extends ListItem = ListItem>(
|
|
31
|
+
config: ListConfig<T>
|
|
32
|
+
) {
|
|
33
|
+
return {
|
|
34
|
+
...config,
|
|
35
|
+
componentName: "list",
|
|
36
|
+
prefix: "mtrl",
|
|
37
|
+
className: config.className || "addons-list",
|
|
38
|
+
ariaLabel: config.ariaLabel || "List",
|
|
39
|
+
interactive: true, // Enable touch support
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Default list item template
|
|
45
|
+
*/
|
|
46
|
+
function getDefaultListTemplate() {
|
|
47
|
+
return {
|
|
48
|
+
tag: "div",
|
|
49
|
+
className: "mtrl-list-item",
|
|
50
|
+
attributes: { "data-id": "{{id}}", role: "listitem" },
|
|
51
|
+
children: [
|
|
52
|
+
{
|
|
53
|
+
tag: "div",
|
|
54
|
+
className: "mtrl-list-item__content",
|
|
55
|
+
textContent: "{{name || id}}",
|
|
56
|
+
},
|
|
57
|
+
],
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Creates a new List component using the 3-layer architecture
|
|
63
|
+
*
|
|
64
|
+
* The List component provides high-performance virtual scrolling with:
|
|
65
|
+
* - Collection (Data Layer): Pure data management with API integration
|
|
66
|
+
* - List Manager (Performance Layer): Virtual scrolling, element recycling
|
|
67
|
+
* - List Component (Presentation Layer): mtrl integration and user interface
|
|
68
|
+
*
|
|
69
|
+
* This component supports both static data and API-driven dynamic data with
|
|
70
|
+
* infinite scrolling, intelligent caching, and optimal DOM performance.
|
|
71
|
+
*
|
|
72
|
+
* @param {ListConfig<T>} config - List configuration options
|
|
73
|
+
* @returns {ListComponent<T>} A fully configured list component instance
|
|
74
|
+
*
|
|
75
|
+
* @throws {Error} If list creation fails due to invalid configuration
|
|
76
|
+
*
|
|
77
|
+
* @example
|
|
78
|
+
* ```typescript
|
|
79
|
+
* // Create a simple static list
|
|
80
|
+
* const simpleList = createList({
|
|
81
|
+
* items: ['Apple', 'Banana', 'Cherry'],
|
|
82
|
+
* container: '#my-list'
|
|
83
|
+
* });
|
|
84
|
+
*
|
|
85
|
+
* // Create an API-driven list with virtual scrolling
|
|
86
|
+
* const apiList = createList({
|
|
87
|
+
* collection: {
|
|
88
|
+
* baseUrl: 'https://api.example.com',
|
|
89
|
+
* endpoint: '/items',
|
|
90
|
+
* pageSize: 50
|
|
91
|
+
* },
|
|
92
|
+
* scroll: {
|
|
93
|
+
* virtual: true,
|
|
94
|
+
* itemSize: 60,
|
|
95
|
+
* overscan: 5
|
|
96
|
+
* },
|
|
97
|
+
* selection: {
|
|
98
|
+
* enabled: true,
|
|
99
|
+
* mode: 'multiple'
|
|
100
|
+
* },
|
|
101
|
+
* template: (item, index) => `
|
|
102
|
+
* <div class="item">
|
|
103
|
+
* <h3>${item.title}</h3>
|
|
104
|
+
* <p>${item.description}</p>
|
|
105
|
+
* </div>
|
|
106
|
+
* `,
|
|
107
|
+
* on: {
|
|
108
|
+
* onItemClick: (item, index) => {
|
|
109
|
+
* console.log('Clicked:', item);
|
|
110
|
+
* },
|
|
111
|
+
* onLoadMore: async (direction) => {
|
|
112
|
+
* console.log('Load more:', direction);
|
|
113
|
+
* }
|
|
114
|
+
* }
|
|
115
|
+
* });
|
|
116
|
+
*
|
|
117
|
+
* // Add to DOM
|
|
118
|
+
* document.querySelector('#app').appendChild(apiList.element);
|
|
119
|
+
*
|
|
120
|
+
* // Use API methods
|
|
121
|
+
* await apiList.loadData();
|
|
122
|
+
* apiList.selectItems([0, 1, 2]);
|
|
123
|
+
* await apiList.scrollToIndex(100);
|
|
124
|
+
* ```
|
|
125
|
+
*
|
|
126
|
+
* @category Components
|
|
127
|
+
* @module components/list
|
|
128
|
+
*/
|
|
129
|
+
export const createList = <T = any>(
|
|
130
|
+
config: ListConfig<T> = {}
|
|
131
|
+
): ListComponent<T> => {
|
|
132
|
+
try {
|
|
133
|
+
// Validate and create base configuration
|
|
134
|
+
const baseConfig = createBaseConfig(config as any);
|
|
135
|
+
|
|
136
|
+
console.log(`📋 Creating List component with simplified architecture:
|
|
137
|
+
- List Manager (with built-in Collection): ${
|
|
138
|
+
baseConfig.items && baseConfig.items.length > 0 ? "Static" : "API"
|
|
139
|
+
} data source
|
|
140
|
+
- Virtual scrolling: true, Element recycling: true
|
|
141
|
+
- Template: ${!!baseConfig.template}, Selection: ${!!baseConfig.selection
|
|
142
|
+
?.enabled}`);
|
|
143
|
+
|
|
144
|
+
// Create the List component through functional composition
|
|
145
|
+
const component = pipe(
|
|
146
|
+
// 1. Foundation layer
|
|
147
|
+
createBase, // Base component with event system
|
|
148
|
+
withEvents(), // Event handling capabilities
|
|
149
|
+
withElement(getElementConfig(baseConfig)), // DOM element creation
|
|
150
|
+
|
|
151
|
+
// 2. Core integration layer
|
|
152
|
+
withListManager<T>(baseConfig as any), // Simplified List Manager with built-in Collection
|
|
153
|
+
|
|
154
|
+
// 3. Component lifecycle
|
|
155
|
+
withLifecycle(), // Lifecycle management
|
|
156
|
+
|
|
157
|
+
// 4. Public API layer
|
|
158
|
+
(comp) => withAPI({ component: comp as any, config: baseConfig })(comp) // Clean public API
|
|
159
|
+
)(baseConfig);
|
|
160
|
+
|
|
161
|
+
// Set up initial event handlers from config
|
|
162
|
+
if (baseConfig.on && typeof component.on === "function") {
|
|
163
|
+
// Data events
|
|
164
|
+
if (baseConfig.on.onLoadMore) {
|
|
165
|
+
component.on("load:more", ({ direction }: { direction: string }) => {
|
|
166
|
+
baseConfig.on!.onLoadMore!(direction as any);
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Scroll events
|
|
171
|
+
if (baseConfig.on.onScroll) {
|
|
172
|
+
component.on(
|
|
173
|
+
"scroll:change",
|
|
174
|
+
({
|
|
175
|
+
scrollTop,
|
|
176
|
+
direction,
|
|
177
|
+
}: {
|
|
178
|
+
scrollTop: number;
|
|
179
|
+
direction: string;
|
|
180
|
+
}) => {
|
|
181
|
+
baseConfig.on!.onScroll!(scrollTop, direction as any);
|
|
182
|
+
}
|
|
183
|
+
);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// Viewport events
|
|
187
|
+
if (baseConfig.on.onViewportChange) {
|
|
188
|
+
component.on(
|
|
189
|
+
"viewport:change",
|
|
190
|
+
({ visibleRange }: { visibleRange: any }) => {
|
|
191
|
+
baseConfig.on!.onViewportChange!(visibleRange);
|
|
192
|
+
}
|
|
193
|
+
);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// Selection events
|
|
197
|
+
if (baseConfig.on.onSelectionChange) {
|
|
198
|
+
component.on(
|
|
199
|
+
"selection:change",
|
|
200
|
+
({
|
|
201
|
+
selectedItems,
|
|
202
|
+
selectedIndices,
|
|
203
|
+
}: {
|
|
204
|
+
selectedItems: T[];
|
|
205
|
+
selectedIndices: number[];
|
|
206
|
+
}) => {
|
|
207
|
+
baseConfig.on!.onSelectionChange!(
|
|
208
|
+
selectedItems as any,
|
|
209
|
+
selectedIndices
|
|
210
|
+
);
|
|
211
|
+
}
|
|
212
|
+
);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// Item events are handled in orchestration layer
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// Initialize component
|
|
219
|
+
if (component.lifecycle?.init) {
|
|
220
|
+
component.lifecycle.init();
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
console.log("✅ List component created successfully");
|
|
224
|
+
return component as ListComponent<T>;
|
|
225
|
+
} catch (error) {
|
|
226
|
+
console.error("❌ List creation error:", error);
|
|
227
|
+
throw new Error(`Failed to create list: ${(error as Error).message}`);
|
|
228
|
+
}
|
|
229
|
+
};
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Export the main component creation function
|
|
233
|
+
*/
|
|
234
|
+
export default createList;
|