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.
Files changed (117) hide show
  1. package/AI.md +28 -230
  2. package/CLAUDE.md +882 -0
  3. package/build.js +253 -24
  4. package/package.json +14 -4
  5. package/scripts/debug/vlist-selection.ts +121 -0
  6. package/src/components/index.ts +5 -41
  7. package/src/components/{list → vlist}/config.ts +66 -95
  8. package/src/components/vlist/constants.ts +23 -0
  9. package/src/components/vlist/features/api.ts +626 -0
  10. package/src/components/vlist/features/index.ts +10 -0
  11. package/src/components/vlist/features/selection.ts +436 -0
  12. package/src/components/vlist/features/viewport.ts +59 -0
  13. package/src/components/vlist/index.ts +17 -0
  14. package/src/components/{list → vlist}/types.ts +242 -32
  15. package/src/components/vlist/vlist.ts +92 -0
  16. package/src/core/compose/features/gestures/index.ts +227 -0
  17. package/src/core/compose/features/gestures/longpress.ts +383 -0
  18. package/src/core/compose/features/gestures/pan.ts +424 -0
  19. package/src/core/compose/features/gestures/pinch.ts +475 -0
  20. package/src/core/compose/features/gestures/rotate.ts +485 -0
  21. package/src/core/compose/features/gestures/swipe.ts +492 -0
  22. package/src/core/compose/features/gestures/tap.ts +334 -0
  23. package/src/core/compose/features/index.ts +2 -38
  24. package/src/core/compose/index.ts +13 -29
  25. package/src/core/gestures/index.ts +31 -0
  26. package/src/core/gestures/longpress.ts +68 -0
  27. package/src/core/gestures/manager.ts +418 -0
  28. package/src/core/gestures/pan.ts +48 -0
  29. package/src/core/gestures/pinch.ts +58 -0
  30. package/src/core/gestures/rotate.ts +58 -0
  31. package/src/core/gestures/swipe.ts +66 -0
  32. package/src/core/gestures/tap.ts +45 -0
  33. package/src/core/gestures/types.ts +387 -0
  34. package/src/core/gestures/utils.ts +128 -0
  35. package/src/core/index.ts +27 -151
  36. package/src/core/layout/schema.ts +153 -72
  37. package/src/core/layout/types.ts +5 -2
  38. package/src/core/viewport/constants.ts +145 -0
  39. package/src/core/viewport/features/base.ts +73 -0
  40. package/src/core/viewport/features/collection.ts +1182 -0
  41. package/src/core/viewport/features/events.ts +130 -0
  42. package/src/core/viewport/features/index.ts +20 -0
  43. package/src/core/{list-manager/features/viewport → viewport/features}/item-size.ts +31 -34
  44. package/src/core/{list-manager/features/viewport → viewport/features}/loading.ts +4 -4
  45. package/src/core/viewport/features/momentum.ts +269 -0
  46. package/src/core/viewport/features/placeholders.ts +335 -0
  47. package/src/core/viewport/features/rendering.ts +962 -0
  48. package/src/core/viewport/features/scrollbar.ts +434 -0
  49. package/src/core/viewport/features/scrolling.ts +634 -0
  50. package/src/core/viewport/features/utils.ts +94 -0
  51. package/src/core/viewport/features/virtual.ts +525 -0
  52. package/src/core/viewport/index.ts +31 -0
  53. package/src/core/viewport/types.ts +133 -0
  54. package/src/core/viewport/utils/speed-tracker.ts +79 -0
  55. package/src/core/viewport/viewport.ts +265 -0
  56. package/src/index.ts +0 -7
  57. package/src/styles/components/_vlist.scss +352 -0
  58. package/src/styles/index.scss +1 -1
  59. package/test/components/vlist-selection.test.ts +240 -0
  60. package/test/components/vlist.test.ts +63 -0
  61. package/test/core/collection/adapter.test.ts +161 -0
  62. package/bun.lock +0 -792
  63. package/src/components/list/api.ts +0 -314
  64. package/src/components/list/constants.ts +0 -56
  65. package/src/components/list/features/api.ts +0 -428
  66. package/src/components/list/features/index.ts +0 -31
  67. package/src/components/list/features/list-manager.ts +0 -502
  68. package/src/components/list/index.ts +0 -39
  69. package/src/components/list/list.ts +0 -234
  70. package/src/core/collection/base-collection.ts +0 -100
  71. package/src/core/collection/collection-composer.ts +0 -178
  72. package/src/core/collection/collection.ts +0 -745
  73. package/src/core/collection/constants.ts +0 -172
  74. package/src/core/collection/events.ts +0 -428
  75. package/src/core/collection/features/api/loading.ts +0 -279
  76. package/src/core/collection/features/operations/data-operations.ts +0 -147
  77. package/src/core/collection/index.ts +0 -104
  78. package/src/core/collection/state.ts +0 -497
  79. package/src/core/collection/types.ts +0 -404
  80. package/src/core/compose/features/collection.ts +0 -119
  81. package/src/core/compose/features/selection.ts +0 -213
  82. package/src/core/compose/features/styling.ts +0 -108
  83. package/src/core/list-manager/api.ts +0 -599
  84. package/src/core/list-manager/config.ts +0 -593
  85. package/src/core/list-manager/constants.ts +0 -268
  86. package/src/core/list-manager/features/api.ts +0 -58
  87. package/src/core/list-manager/features/collection/collection.ts +0 -705
  88. package/src/core/list-manager/features/collection/index.ts +0 -17
  89. package/src/core/list-manager/features/viewport/constants.ts +0 -42
  90. package/src/core/list-manager/features/viewport/index.ts +0 -16
  91. package/src/core/list-manager/features/viewport/placeholders.ts +0 -281
  92. package/src/core/list-manager/features/viewport/rendering.ts +0 -575
  93. package/src/core/list-manager/features/viewport/scrollbar.ts +0 -495
  94. package/src/core/list-manager/features/viewport/scrolling.ts +0 -795
  95. package/src/core/list-manager/features/viewport/template.ts +0 -220
  96. package/src/core/list-manager/features/viewport/viewport.ts +0 -654
  97. package/src/core/list-manager/features/viewport/virtual.ts +0 -309
  98. package/src/core/list-manager/index.ts +0 -279
  99. package/src/core/list-manager/list-manager.ts +0 -206
  100. package/src/core/list-manager/types.ts +0 -439
  101. package/src/core/list-manager/utils/calculations.ts +0 -290
  102. package/src/core/list-manager/utils/range-calculator.ts +0 -349
  103. package/src/core/list-manager/utils/speed-tracker.ts +0 -273
  104. package/src/styles/components/_list.scss +0 -244
  105. package/src/types/mtrl.d.ts +0 -6
  106. package/test/components/list.test.ts +0 -256
  107. package/test/core/collection/failed-ranges.test.ts +0 -270
  108. package/test/core/compose/features.test.ts +0 -183
  109. package/test/core/list-manager/features/collection.test.ts +0 -704
  110. package/test/core/list-manager/features/viewport.test.ts +0 -698
  111. package/test/core/list-manager/list-manager.test.ts +0 -593
  112. package/test/core/list-manager/utils/calculations.test.ts +0 -433
  113. package/test/core/list-manager/utils/range-calculator.test.ts +0 -569
  114. package/test/core/list-manager/utils/speed-tracker.test.ts +0 -530
  115. package/tsconfig.build.json +0 -23
  116. /package/src/components/{list → vlist}/features.ts +0 -0
  117. /package/src/core/{compose → viewport}/features/performance.ts +0 -0
@@ -1,172 +0,0 @@
1
- /**
2
- * Constants for the mtrl-addons collection system (Pure Data Layer)
3
- *
4
- * Data-related constants only - NO UI constants
5
- */
6
-
7
- /**
8
- * Data pagination constants
9
- */
10
- export const DATA_PAGINATION = {
11
- DEFAULT_PAGE_SIZE: 20,
12
- DEFAULT_CURRENT_PAGE: 1,
13
- MAX_PREFETCH_PAGES: 5,
14
- MIN_PAGE_SIZE: 1,
15
- MAX_PAGE_SIZE: 1000,
16
- } as const;
17
-
18
- /**
19
- * Data caching constants
20
- */
21
- export const DATA_CACHE = {
22
- DEFAULT_MAX_SIZE: 1000,
23
- DEFAULT_MAX_AGE: 60 * 60 * 1000, // 1 hour
24
- CLEANUP_INTERVAL: 5 * 60 * 1000, // 5 minutes
25
- DEFAULT_STRATEGY: "memory",
26
- LRU_DEFAULT_SIZE: 500,
27
- } as const;
28
-
29
- /**
30
- * Data persistence constants
31
- */
32
- export const DATA_PERSISTENCE = {
33
- DEFAULT_KEY_PREFIX: "mtrl-collection-",
34
- DEFAULT_VERSION: 1,
35
- SYNC_DEBOUNCE: 1000, // 1 second
36
- DEFAULT_STRATEGY: "localStorage",
37
- MAX_LOCALSTORAGE_SIZE: 5 * 1024 * 1024, // 5MB
38
- INDEXED_DB_VERSION: 1,
39
- } as const;
40
-
41
- /**
42
- * Web worker constants
43
- */
44
- export const WEB_WORKERS = {
45
- MAX_WORKERS:
46
- typeof navigator !== "undefined" ? navigator.hardwareConcurrency || 4 : 4,
47
- TASK_TIMEOUT: 30000, // 30 seconds
48
- CHUNK_SIZE: 1000, // Items per worker task
49
- DEFAULT_PRIORITY: "normal",
50
- RETRY_ATTEMPTS: 3,
51
- RETRY_DELAY: 1000, // 1 second
52
- } as const;
53
-
54
- /**
55
- * Data validation constants
56
- */
57
- export const DATA_VALIDATION = {
58
- DEFAULT_STRICT_MODE: false,
59
- MAX_VALIDATION_ERRORS: 100,
60
- VALIDATION_TIMEOUT: 5000, // 5 seconds
61
- DEFAULT_SANITIZE: true,
62
- } as const;
63
-
64
- /**
65
- * Data transformation constants
66
- */
67
- export const DATA_TRANSFORMATION = {
68
- MAX_TRANSFORM_TIME: 10000, // 10 seconds
69
- BATCH_SIZE: 500,
70
- DEFAULT_NORMALIZE: true,
71
- MAX_DEPTH: 10, // For nested object transformation
72
- } as const;
73
-
74
- /**
75
- * API adapter constants
76
- */
77
- export const API_ADAPTER = {
78
- DEFAULT_TIMEOUT: 30000, // 30 seconds
79
- RETRY_ATTEMPTS: 3,
80
- RETRY_DELAY: 1000, // 1 second
81
- MAX_CONCURRENT_REQUESTS: 5,
82
- DEFAULT_HEADERS: {
83
- "Content-Type": "application/json",
84
- },
85
- } as const;
86
-
87
- /**
88
- * Background processing constants
89
- */
90
- export const BACKGROUND_PROCESSING = {
91
- PREFETCH_THRESHOLD: 0.8, // Start prefetching when 80% through current data
92
- MAX_PREFETCH_QUEUE: 10,
93
- PREFETCH_DEBOUNCE: 500, // 500ms
94
- BACKGROUND_SYNC_INTERVAL: 30000, // 30 seconds
95
- } as const;
96
-
97
- /**
98
- * Data logging constants
99
- */
100
- export const DATA_LOGGING = {
101
- PREFIX: "[COLLECTION]",
102
- LEVELS: {
103
- ERROR: "ERROR",
104
- WARN: "WARN",
105
- INFO: "INFO",
106
- DEBUG: "DEBUG",
107
- },
108
- ENABLE_DEBUG: false, // Set to true for development
109
- } as const;
110
-
111
- /**
112
- * Collection state constants
113
- */
114
- export const COLLECTION_STATE = {
115
- INITIAL_SIZE: 0,
116
- INITIAL_PAGE: 1,
117
- INITIAL_LOADING: false,
118
- INITIAL_ERROR: null,
119
- INITIAL_HAS_MORE: true,
120
- } as const;
121
-
122
- /**
123
- * Data event timing constants
124
- */
125
- export const EVENT_TIMING = {
126
- DEBOUNCE_DELAY: 100, // 100ms
127
- THROTTLE_DELAY: 16, // ~60fps
128
- EMIT_TIMEOUT: 5000, // 5 seconds
129
- MAX_LISTENERS: 100,
130
- } as const;
131
-
132
- /**
133
- * Data aggregation constants
134
- */
135
- export const DATA_AGGREGATION = {
136
- SUPPORTED_OPERATIONS: [
137
- "sum",
138
- "count",
139
- "avg",
140
- "min",
141
- "max",
142
- "distinct",
143
- ] as const,
144
- MAX_FIELD_DEPTH: 5,
145
- AGGREGATION_TIMEOUT: 10000, // 10 seconds
146
- } as const;
147
-
148
- /**
149
- * Data search constants
150
- */
151
- export const DATA_SEARCH = {
152
- DEFAULT_FIELDS: ["id"],
153
- MAX_SEARCH_FIELDS: 20,
154
- SEARCH_DEBOUNCE: 300, // 300ms
155
- MIN_SEARCH_LENGTH: 1,
156
- MAX_SEARCH_LENGTH: 1000,
157
- } as const;
158
-
159
- /**
160
- * Collection defaults for initialization
161
- */
162
- export const COLLECTION_DEFAULTS = {
163
- PAGE_SIZE: DATA_PAGINATION.DEFAULT_PAGE_SIZE,
164
- CURRENT_PAGE: DATA_PAGINATION.DEFAULT_CURRENT_PAGE,
165
- CACHE_STRATEGY: DATA_CACHE.DEFAULT_STRATEGY,
166
- PERSISTENCE_STRATEGY: DATA_PERSISTENCE.DEFAULT_STRATEGY,
167
- WEB_WORKERS_ENABLED: false,
168
- VALIDATION_STRICT: DATA_VALIDATION.DEFAULT_STRICT_MODE,
169
- PREFETCH_ENABLED: false,
170
- } as const;
171
-
172
- // NO UI constants: STYLING, DOM, TEMPLATE, SCROLL, INTERSECTION - those belong to List Manager/Component
@@ -1,428 +0,0 @@
1
- /**
2
- * Event system for mtrl-addons collection (Pure Data Layer)
3
- *
4
- * Handles data-focused events with zero UI concerns
5
- */
6
-
7
- import type {
8
- CollectionItem,
9
- CollectionObserver,
10
- CollectionUnsubscribe,
11
- CollectionEventPayload,
12
- CollectionDataEvents,
13
- } from "./types";
14
- import { DATA_LOGGING, EVENT_TIMING } from "./constants";
15
-
16
- /**
17
- * Data-focused collection events (NO UI EVENTS)
18
- */
19
- export const CollectionEvents = {
20
- // Data lifecycle events
21
- ITEMS_LOADED: "items:loaded" as const,
22
- ITEMS_ADDED: "items:added" as const,
23
- ITEMS_UPDATED: "items:updated" as const,
24
- ITEMS_REMOVED: "items:removed" as const,
25
- ITEMS_CLEARED: "items:cleared" as const,
26
-
27
- // Data state events
28
- LOADING_START: "loading:start" as const,
29
- LOADING_END: "loading:end" as const,
30
- ERROR_OCCURRED: "error:occurred" as const,
31
-
32
- // Data operations events
33
- CACHE_HIT: "cache:hit" as const,
34
- CACHE_MISS: "cache:miss" as const,
35
- CACHE_CLEARED: "cache:cleared" as const,
36
- SYNC_START: "sync:start" as const,
37
- SYNC_COMPLETE: "sync:complete" as const,
38
-
39
- // Background operations events
40
- PREFETCH_START: "prefetch:start" as const,
41
- PREFETCH_COMPLETE: "prefetch:complete" as const,
42
- WORKER_TASK_START: "worker:task:start" as const,
43
- WORKER_TASK_COMPLETE: "worker:task:complete" as const,
44
-
45
- // Data validation events
46
- VALIDATION_START: "validation:start" as const,
47
- VALIDATION_COMPLETE: "validation:complete" as const,
48
- VALIDATION_ERROR: "validation:error" as const,
49
-
50
- // Data transformation events
51
- TRANSFORM_START: "transform:start" as const,
52
- TRANSFORM_COMPLETE: "transform:complete" as const,
53
- TRANSFORM_ERROR: "transform:error" as const,
54
-
55
- // Data persistence events
56
- SAVE_START: "save:start" as const,
57
- SAVE_COMPLETE: "save:complete" as const,
58
- SAVE_ERROR: "save:error" as const,
59
- LOAD_START: "load:start" as const,
60
- LOAD_COMPLETE: "load:complete" as const,
61
- LOAD_ERROR: "load:error" as const,
62
-
63
- // NO UI events: render:start, scroll:changed, viewport:changed, etc.
64
- } as const;
65
-
66
- /**
67
- * Collection event emitter interface
68
- */
69
- export interface CollectionEventEmitter<
70
- T extends CollectionItem = CollectionItem
71
- > {
72
- subscribe(observer: CollectionObserver<T>): CollectionUnsubscribe;
73
- emit(event: CollectionDataEvents, data?: any): void;
74
- removeAllListeners(): void;
75
- getListenerCount(): number;
76
- destroy(): void;
77
- }
78
-
79
- /**
80
- * Creates a data-focused event emitter for collection
81
- */
82
- export function createCollectionEventEmitter<
83
- T extends CollectionItem = CollectionItem
84
- >(): CollectionEventEmitter<T> {
85
- const listeners = new Map<string, Set<CollectionObserver<T>>>();
86
- let isDestroyed = false;
87
-
88
- /**
89
- * Subscribe to data events
90
- */
91
- const subscribe = (
92
- observer: CollectionObserver<T>
93
- ): CollectionUnsubscribe => {
94
- if (isDestroyed) {
95
- console.warn(
96
- `${DATA_LOGGING.PREFIX} Cannot subscribe to destroyed event emitter`
97
- );
98
- return () => {};
99
- }
100
-
101
- // Validate observer
102
- if (typeof observer !== "function") {
103
- throw new Error("Observer must be a function");
104
- }
105
-
106
- // Check listener limit
107
- const totalListeners = Array.from(listeners.values()).reduce(
108
- (sum, set) => sum + set.size,
109
- 0
110
- );
111
-
112
- if (totalListeners >= EVENT_TIMING.MAX_LISTENERS) {
113
- console.warn(
114
- `${DATA_LOGGING.PREFIX} Maximum listeners (${EVENT_TIMING.MAX_LISTENERS}) reached`
115
- );
116
- }
117
-
118
- // Add observer to all data events
119
- Object.values(CollectionEvents).forEach((event) => {
120
- if (!listeners.has(event)) {
121
- listeners.set(event, new Set());
122
- }
123
- listeners.get(event)!.add(observer);
124
- });
125
-
126
- // Return unsubscribe function
127
- return () => {
128
- Object.values(CollectionEvents).forEach((event) => {
129
- const eventListeners = listeners.get(event);
130
- if (eventListeners) {
131
- eventListeners.delete(observer);
132
- if (eventListeners.size === 0) {
133
- listeners.delete(event);
134
- }
135
- }
136
- });
137
- };
138
- };
139
-
140
- /**
141
- * Emit data events to subscribers
142
- */
143
- const emit = (event: CollectionDataEvents, data?: any): void => {
144
- if (isDestroyed) {
145
- console.warn(
146
- `${DATA_LOGGING.PREFIX} Cannot emit on destroyed event emitter`
147
- );
148
- return;
149
- }
150
-
151
- const eventListeners = listeners.get(event);
152
- if (!eventListeners || eventListeners.size === 0) {
153
- return; // No listeners for this event
154
- }
155
-
156
- const payload: CollectionEventPayload<T> = {
157
- event,
158
- data,
159
- timestamp: Date.now(),
160
- source: "collection",
161
- };
162
-
163
- // Emit to all listeners with error handling
164
- eventListeners.forEach((observer) => {
165
- try {
166
- // Use timeout to prevent blocking
167
- const timeoutId = setTimeout(() => {
168
- observer(payload);
169
- }, 0);
170
-
171
- // Clear timeout after emit timeout
172
- setTimeout(() => {
173
- clearTimeout(timeoutId);
174
- }, EVENT_TIMING.EMIT_TIMEOUT);
175
- } catch (error) {
176
- console.error(`${DATA_LOGGING.PREFIX} Error in event observer:`, error);
177
-
178
- // Remove problematic observer
179
- eventListeners.delete(observer);
180
-
181
- // Emit error event
182
- if (event !== CollectionEvents.ERROR_OCCURRED) {
183
- emit(CollectionEvents.ERROR_OCCURRED, {
184
- error,
185
- originalEvent: event,
186
- observer: observer.name || "anonymous",
187
- });
188
- }
189
- }
190
- });
191
-
192
- // Debug logging
193
- if (DATA_LOGGING.ENABLE_DEBUG) {
194
- console.log(`${DATA_LOGGING.PREFIX} Event emitted:`, {
195
- event,
196
- data,
197
- listenerCount: eventListeners.size,
198
- });
199
- }
200
- };
201
-
202
- /**
203
- * Remove all listeners
204
- */
205
- const removeAllListeners = (): void => {
206
- listeners.clear();
207
- };
208
-
209
- /**
210
- * Get total listener count
211
- */
212
- const getListenerCount = (): number => {
213
- return Array.from(listeners.values()).reduce(
214
- (sum, set) => sum + set.size,
215
- 0
216
- );
217
- };
218
-
219
- /**
220
- * Destroy the event emitter
221
- */
222
- const destroy = (): void => {
223
- removeAllListeners();
224
- isDestroyed = true;
225
- };
226
-
227
- return {
228
- subscribe,
229
- emit,
230
- removeAllListeners,
231
- getListenerCount,
232
- destroy,
233
- };
234
- }
235
-
236
- /**
237
- * Event payload factory functions for type safety
238
- */
239
- export const createEventPayload = {
240
- itemsLoaded: <T extends CollectionItem>(
241
- items: T[],
242
- meta?: any
243
- ): CollectionEventPayload<T> => ({
244
- event: CollectionEvents.ITEMS_LOADED,
245
- data: { items, meta },
246
- items,
247
- timestamp: Date.now(),
248
- source: "collection",
249
- }),
250
-
251
- itemsAdded: <T extends CollectionItem>(
252
- items: T[],
253
- indices: number[]
254
- ): CollectionEventPayload<T> => ({
255
- event: CollectionEvents.ITEMS_ADDED,
256
- data: { items, indices },
257
- items,
258
- timestamp: Date.now(),
259
- source: "collection",
260
- }),
261
-
262
- itemsUpdated: <T extends CollectionItem>(
263
- items: T[],
264
- indices: number[]
265
- ): CollectionEventPayload<T> => ({
266
- event: CollectionEvents.ITEMS_UPDATED,
267
- data: { items, indices },
268
- items,
269
- timestamp: Date.now(),
270
- source: "collection",
271
- }),
272
-
273
- itemsRemoved: <T extends CollectionItem>(
274
- ids: string[]
275
- ): CollectionEventPayload<T> => ({
276
- event: CollectionEvents.ITEMS_REMOVED,
277
- data: { ids },
278
- timestamp: Date.now(),
279
- source: "collection",
280
- }),
281
-
282
- loadingStart: <T extends CollectionItem>(
283
- reason: string
284
- ): CollectionEventPayload<T> => ({
285
- event: CollectionEvents.LOADING_START,
286
- data: { reason },
287
- timestamp: Date.now(),
288
- source: "collection",
289
- }),
290
-
291
- loadingEnd: <T extends CollectionItem>(
292
- reason: string
293
- ): CollectionEventPayload<T> => ({
294
- event: CollectionEvents.LOADING_END,
295
- data: { reason },
296
- timestamp: Date.now(),
297
- source: "collection",
298
- }),
299
-
300
- errorOccurred: <T extends CollectionItem>(
301
- error: Error,
302
- context?: any
303
- ): CollectionEventPayload<T> => ({
304
- event: CollectionEvents.ERROR_OCCURRED,
305
- data: { error, context },
306
- error,
307
- timestamp: Date.now(),
308
- source: "collection",
309
- }),
310
-
311
- cacheHit: <T extends CollectionItem>(
312
- key: string,
313
- size: number
314
- ): CollectionEventPayload<T> => ({
315
- event: CollectionEvents.CACHE_HIT,
316
- data: { key, size },
317
- timestamp: Date.now(),
318
- source: "collection",
319
- }),
320
-
321
- cacheMiss: <T extends CollectionItem>(
322
- key: string
323
- ): CollectionEventPayload<T> => ({
324
- event: CollectionEvents.CACHE_MISS,
325
- data: { key },
326
- timestamp: Date.now(),
327
- source: "collection",
328
- }),
329
-
330
- workerTaskStart: <T extends CollectionItem>(
331
- operation: string,
332
- itemCount: number
333
- ): CollectionEventPayload<T> => ({
334
- event: CollectionEvents.WORKER_TASK_START,
335
- data: { operation, itemCount },
336
- timestamp: Date.now(),
337
- source: "collection",
338
- }),
339
-
340
- workerTaskComplete: <T extends CollectionItem>(
341
- operation: string,
342
- duration: number,
343
- result?: any
344
- ): CollectionEventPayload<T> => ({
345
- event: CollectionEvents.WORKER_TASK_COMPLETE,
346
- data: { operation, duration, result },
347
- timestamp: Date.now(),
348
- source: "collection",
349
- }),
350
-
351
- prefetchStart: <T extends CollectionItem>(
352
- pages: number[]
353
- ): CollectionEventPayload<T> => ({
354
- event: CollectionEvents.PREFETCH_START,
355
- data: { pages },
356
- timestamp: Date.now(),
357
- source: "collection",
358
- }),
359
-
360
- prefetchComplete: <T extends CollectionItem>(
361
- items: T[],
362
- pages: number[]
363
- ): CollectionEventPayload<T> => ({
364
- event: CollectionEvents.PREFETCH_COMPLETE,
365
- data: { items, pages },
366
- items,
367
- timestamp: Date.now(),
368
- source: "collection",
369
- }),
370
- };
371
-
372
- /**
373
- * Event utilities for debugging and monitoring
374
- */
375
- export const eventUtils = {
376
- /**
377
- * Log event for debugging
378
- */
379
- logEvent: <T extends CollectionItem>(
380
- payload: CollectionEventPayload<T>
381
- ): void => {
382
- if (DATA_LOGGING.ENABLE_DEBUG) {
383
- console.log(`${DATA_LOGGING.PREFIX} ${payload.event}:`, {
384
- data: payload.data,
385
- timestamp: new Date(payload.timestamp).toISOString(),
386
- source: payload.source,
387
- });
388
- }
389
- },
390
-
391
- /**
392
- * Check if event is a data lifecycle event
393
- */
394
- isDataLifecycleEvent: (event: string): boolean => {
395
- return [
396
- CollectionEvents.ITEMS_LOADED,
397
- CollectionEvents.ITEMS_ADDED,
398
- CollectionEvents.ITEMS_UPDATED,
399
- CollectionEvents.ITEMS_REMOVED,
400
- CollectionEvents.ITEMS_CLEARED,
401
- ].includes(event as any);
402
- },
403
-
404
- /**
405
- * Check if event is a background operation event
406
- */
407
- isBackgroundEvent: (event: string): boolean => {
408
- return [
409
- CollectionEvents.PREFETCH_START,
410
- CollectionEvents.PREFETCH_COMPLETE,
411
- CollectionEvents.WORKER_TASK_START,
412
- CollectionEvents.WORKER_TASK_COMPLETE,
413
- ].includes(event as any);
414
- },
415
-
416
- /**
417
- * Check if event is an error event
418
- */
419
- isErrorEvent: (event: string): boolean => {
420
- return [
421
- CollectionEvents.ERROR_OCCURRED,
422
- CollectionEvents.VALIDATION_ERROR,
423
- CollectionEvents.TRANSFORM_ERROR,
424
- CollectionEvents.SAVE_ERROR,
425
- CollectionEvents.LOAD_ERROR,
426
- ].includes(event as any);
427
- },
428
- };