@rakeyshgidwani/roger-ui-bank-theme-stan-design 0.1.3 → 0.1.5
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/CHANGELOG.md +1 -1
- package/dist/index.d.ts +131 -131
- package/dist/index.esm.js +148 -148
- package/dist/index.js +148 -148
- package/dist/styles.css +1 -1
- package/package.json +1 -1
- package/src/components/ui/accessibility-demo.tsx +271 -0
- package/src/components/ui/advanced-component-architecture-demo.tsx +916 -0
- package/src/components/ui/advanced-transition-system-demo.tsx +670 -0
- package/src/components/ui/advanced-transition-system.tsx +395 -0
- package/src/components/ui/animation/animated-container.tsx +166 -0
- package/src/components/ui/animation/index.ts +19 -0
- package/src/components/ui/animation/staggered-container.tsx +68 -0
- package/src/components/ui/animation-demo.tsx +250 -0
- package/src/components/ui/badge.tsx +33 -0
- package/src/components/ui/battery-conscious-animation-demo.tsx +568 -0
- package/src/components/ui/border-radius-shadow-demo.tsx +187 -0
- package/src/components/ui/button.tsx +36 -0
- package/src/components/ui/card.tsx +207 -0
- package/src/components/ui/checkbox.tsx +30 -0
- package/src/components/ui/color-preview.tsx +411 -0
- package/src/components/ui/data-display/chart.tsx +653 -0
- package/src/components/ui/data-display/data-grid-simple.tsx +76 -0
- package/src/components/ui/data-display/data-grid.tsx +680 -0
- package/src/components/ui/data-display/list.tsx +456 -0
- package/src/components/ui/data-display/table.tsx +482 -0
- package/src/components/ui/data-display/timeline.tsx +441 -0
- package/src/components/ui/data-display/tree.tsx +602 -0
- package/src/components/ui/data-display/types.ts +536 -0
- package/src/components/ui/enterprise-mobile-experience-demo.tsx +749 -0
- package/src/components/ui/enterprise-mobile-experience.tsx +464 -0
- package/src/components/ui/feedback/alert.tsx +157 -0
- package/src/components/ui/feedback/progress.tsx +292 -0
- package/src/components/ui/feedback/skeleton.tsx +185 -0
- package/src/components/ui/feedback/toast.tsx +280 -0
- package/src/components/ui/feedback/types.ts +125 -0
- package/src/components/ui/font-preview.tsx +288 -0
- package/src/components/ui/form-demo.tsx +553 -0
- package/src/components/ui/hardware-acceleration-demo.tsx +547 -0
- package/src/components/ui/input.tsx +35 -0
- package/src/components/ui/label.tsx +16 -0
- package/src/components/ui/layout-demo.tsx +367 -0
- package/src/components/ui/layouts/adaptive-layout.tsx +139 -0
- package/src/components/ui/layouts/desktop-layout.tsx +224 -0
- package/src/components/ui/layouts/index.ts +10 -0
- package/src/components/ui/layouts/mobile-layout.tsx +162 -0
- package/src/components/ui/layouts/tablet-layout.tsx +197 -0
- package/src/components/ui/mobile-form-validation.tsx +451 -0
- package/src/components/ui/mobile-input-demo.tsx +201 -0
- package/src/components/ui/mobile-input.tsx +281 -0
- package/src/components/ui/mobile-skeleton-loading-demo.tsx +638 -0
- package/src/components/ui/navigation/breadcrumb.tsx +158 -0
- package/src/components/ui/navigation/index.ts +36 -0
- package/src/components/ui/navigation/menu.tsx +374 -0
- package/src/components/ui/navigation/navigation-demo.tsx +324 -0
- package/src/components/ui/navigation/pagination.tsx +272 -0
- package/src/components/ui/navigation/sidebar.tsx +383 -0
- package/src/components/ui/navigation/stepper.tsx +303 -0
- package/src/components/ui/navigation/tabs.tsx +205 -0
- package/src/components/ui/navigation/types.ts +299 -0
- package/src/components/ui/overlay/backdrop.tsx +81 -0
- package/src/components/ui/overlay/focus-manager.tsx +143 -0
- package/src/components/ui/overlay/index.ts +36 -0
- package/src/components/ui/overlay/modal.tsx +270 -0
- package/src/components/ui/overlay/overlay-manager.tsx +110 -0
- package/src/components/ui/overlay/popover.tsx +462 -0
- package/src/components/ui/overlay/portal.tsx +79 -0
- package/src/components/ui/overlay/tooltip.tsx +303 -0
- package/src/components/ui/overlay/types.ts +196 -0
- package/src/components/ui/performance-demo.tsx +596 -0
- package/src/components/ui/semantic-input-system-demo.tsx +502 -0
- package/src/components/ui/semantic-input-system-demo.tsx.disabled +873 -0
- package/src/components/ui/tablet-layout.tsx +192 -0
- package/src/components/ui/theme-customizer.tsx +386 -0
- package/src/components/ui/theme-preview.tsx +310 -0
- package/src/components/ui/theme-switcher.tsx +264 -0
- package/src/components/ui/theme-toggle.tsx +38 -0
- package/src/components/ui/token-demo.tsx +195 -0
- package/src/components/ui/touch-demo.tsx +462 -0
- package/src/components/ui/touch-friendly-interface-demo.tsx +519 -0
- package/src/components/ui/touch-friendly-interface.tsx +296 -0
- package/src/hooks/index.ts +190 -0
- package/src/hooks/use-accessibility-support.ts +518 -0
- package/src/hooks/use-adaptive-layout.ts +289 -0
- package/src/hooks/use-advanced-patterns.ts +294 -0
- package/src/hooks/use-advanced-transition-system.ts +393 -0
- package/src/hooks/use-animation-profile.ts +288 -0
- package/src/hooks/use-battery-animations.ts +384 -0
- package/src/hooks/use-battery-conscious-loading.ts +475 -0
- package/src/hooks/use-battery-optimization.ts +330 -0
- package/src/hooks/use-battery-status.ts +299 -0
- package/src/hooks/use-component-performance.ts +344 -0
- package/src/hooks/use-device-loading-states.ts +459 -0
- package/src/hooks/use-device.tsx +110 -0
- package/src/hooks/use-enterprise-mobile-experience.ts +488 -0
- package/src/hooks/use-form-feedback.ts +403 -0
- package/src/hooks/use-form-performance.ts +513 -0
- package/src/hooks/use-frame-rate.ts +251 -0
- package/src/hooks/use-gestures.ts +338 -0
- package/src/hooks/use-hardware-acceleration.ts +341 -0
- package/src/hooks/use-input-accessibility.ts +455 -0
- package/src/hooks/use-input-performance.ts +506 -0
- package/src/hooks/use-layout-performance.ts +319 -0
- package/src/hooks/use-loading-accessibility.ts +535 -0
- package/src/hooks/use-loading-performance.ts +473 -0
- package/src/hooks/use-memory-usage.ts +287 -0
- package/src/hooks/use-mobile-form-layout.ts +464 -0
- package/src/hooks/use-mobile-form-validation.ts +518 -0
- package/src/hooks/use-mobile-keyboard-optimization.ts +472 -0
- package/src/hooks/use-mobile-layout.ts +302 -0
- package/src/hooks/use-mobile-optimization.ts +406 -0
- package/src/hooks/use-mobile-skeleton.ts +402 -0
- package/src/hooks/use-mobile-touch.ts +414 -0
- package/src/hooks/use-performance-throttling.ts +348 -0
- package/src/hooks/use-performance.ts +316 -0
- package/src/hooks/use-reusable-architecture.ts +414 -0
- package/src/hooks/use-semantic-input-types.ts +357 -0
- package/src/hooks/use-semantic-input.ts +565 -0
- package/src/hooks/use-tablet-layout.ts +384 -0
- package/src/hooks/use-touch-friendly-input.ts +524 -0
- package/src/hooks/use-touch-friendly-interface.ts +331 -0
- package/src/hooks/use-touch-optimization.ts +375 -0
- package/src/index.ts +279 -279
- package/src/lib/utils.ts +6 -0
- package/src/themes/README.md +272 -0
- package/src/themes/ThemeContext.tsx +31 -0
- package/src/themes/ThemeProvider.tsx +232 -0
- package/src/themes/accessibility/index.ts +27 -0
- package/src/themes/accessibility.ts +259 -0
- package/src/themes/aria-patterns.ts +420 -0
- package/src/themes/base-themes.ts +55 -0
- package/src/themes/colorManager.ts +380 -0
- package/src/themes/examples/dark-theme.ts +154 -0
- package/src/themes/examples/minimal-theme.ts +108 -0
- package/src/themes/focus-management.ts +701 -0
- package/src/themes/fontLoader.ts +201 -0
- package/src/themes/high-contrast.ts +621 -0
- package/src/themes/index.ts +19 -0
- package/src/themes/inheritance.ts +227 -0
- package/src/themes/keyboard-navigation.ts +550 -0
- package/src/themes/motion-reduction.ts +662 -0
- package/src/themes/navigation.ts +238 -0
- package/src/themes/screen-reader.ts +645 -0
- package/src/themes/systemThemeDetector.ts +182 -0
- package/src/themes/themeCSSUpdater.ts +262 -0
- package/src/themes/themePersistence.ts +238 -0
- package/src/themes/themes/default.ts +586 -0
- package/src/themes/themes/harvey.ts +554 -0
- package/src/themes/themes/stan-design.ts +683 -0
- package/src/themes/types.ts +460 -0
- package/src/themes/useSystemTheme.ts +48 -0
- package/src/themes/useTheme.ts +87 -0
- package/src/themes/validation.ts +462 -0
- package/src/tokens/index.ts +34 -0
- package/src/tokens/tokenExporter.ts +397 -0
- package/src/tokens/tokenGenerator.ts +276 -0
- package/src/tokens/tokenManager.ts +248 -0
- package/src/tokens/tokenValidator.ts +543 -0
- package/src/tokens/types.ts +78 -0
- package/src/utils/bundle-analyzer.ts +260 -0
- package/src/utils/bundle-splitting.ts +483 -0
- package/src/utils/lazy-loading.ts +441 -0
- package/src/utils/performance-monitor.ts +513 -0
- package/src/utils/tree-shaking.ts +274 -0
|
@@ -0,0 +1,441 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
// Lazy loading utilities for code splitting and dynamic imports
|
|
4
|
+
export interface LazyLoadConfig {
|
|
5
|
+
enabled: boolean;
|
|
6
|
+
preloadThreshold: number;
|
|
7
|
+
cacheSize: number;
|
|
8
|
+
retryAttempts: number;
|
|
9
|
+
retryDelay: number;
|
|
10
|
+
loadingTimeout: number;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface LazyLoadResult<T> {
|
|
14
|
+
data: T | null;
|
|
15
|
+
loading: boolean;
|
|
16
|
+
error: Error | null;
|
|
17
|
+
retry: () => Promise<LazyLoadResult<T>>;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface LazyLoadStats {
|
|
21
|
+
totalRequests: number;
|
|
22
|
+
successfulLoads: number;
|
|
23
|
+
failedLoads: number;
|
|
24
|
+
cacheHits: number;
|
|
25
|
+
averageLoadTime: number;
|
|
26
|
+
totalLoadTime: number;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export class LazyLoader {
|
|
30
|
+
private config: LazyLoadConfig;
|
|
31
|
+
private cache: Map<string, { data: any; timestamp: number; ttl: number }>;
|
|
32
|
+
private loadingStates: Map<string, boolean>;
|
|
33
|
+
private errorStates: Map<string, Error>;
|
|
34
|
+
private stats: LazyLoadStats;
|
|
35
|
+
private preloadQueue: Set<string>;
|
|
36
|
+
private retryCounts: Map<string, number>;
|
|
37
|
+
|
|
38
|
+
constructor(config: LazyLoadConfig = {
|
|
39
|
+
enabled: true,
|
|
40
|
+
preloadThreshold: 0.8,
|
|
41
|
+
cacheSize: 100,
|
|
42
|
+
retryAttempts: 3,
|
|
43
|
+
retryDelay: 1000,
|
|
44
|
+
loadingTimeout: 10000
|
|
45
|
+
}) {
|
|
46
|
+
this.config = config;
|
|
47
|
+
this.cache = new Map();
|
|
48
|
+
this.loadingStates = new Map();
|
|
49
|
+
this.errorStates = new Map();
|
|
50
|
+
this.stats = {
|
|
51
|
+
totalRequests: 0,
|
|
52
|
+
successfulLoads: 0,
|
|
53
|
+
failedLoads: 0,
|
|
54
|
+
cacheHits: 0,
|
|
55
|
+
averageLoadTime: 0,
|
|
56
|
+
totalLoadTime: 0
|
|
57
|
+
};
|
|
58
|
+
this.preloadQueue = new Set();
|
|
59
|
+
this.retryCounts = new Map();
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Lazy load a module with dynamic import
|
|
63
|
+
async lazyLoad<T>(
|
|
64
|
+
modulePath: string,
|
|
65
|
+
importFn: () => Promise<T>,
|
|
66
|
+
options: {
|
|
67
|
+
cacheKey?: string;
|
|
68
|
+
ttl?: number;
|
|
69
|
+
preload?: boolean;
|
|
70
|
+
} = {}
|
|
71
|
+
): Promise<LazyLoadResult<T>> {
|
|
72
|
+
const cacheKey = options.cacheKey || modulePath;
|
|
73
|
+
const ttl = options.ttl || 300000; // 5 minutes default
|
|
74
|
+
|
|
75
|
+
// Check cache first
|
|
76
|
+
if (this.config.enabled && this.cache.has(cacheKey)) {
|
|
77
|
+
const cached = this.cache.get(cacheKey)!;
|
|
78
|
+
if (Date.now() - cached.timestamp < cached.ttl) {
|
|
79
|
+
this.stats.cacheHits++;
|
|
80
|
+
this.stats.totalRequests++; // Count cache hits as requests too
|
|
81
|
+
return {
|
|
82
|
+
data: cached.data,
|
|
83
|
+
loading: false,
|
|
84
|
+
error: null,
|
|
85
|
+
retry: () => {
|
|
86
|
+
// Clear error state before retrying
|
|
87
|
+
this.errorStates.delete(cacheKey);
|
|
88
|
+
this.retryCounts.delete(cacheKey);
|
|
89
|
+
return this.lazyLoad(modulePath, importFn, options);
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
} else {
|
|
93
|
+
// Remove expired cache entry
|
|
94
|
+
this.cache.delete(cacheKey);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Check if already loading
|
|
99
|
+
if (this.loadingStates.get(cacheKey)) {
|
|
100
|
+
return {
|
|
101
|
+
data: null,
|
|
102
|
+
loading: true,
|
|
103
|
+
error: null,
|
|
104
|
+
retry: () => this.lazyLoad(modulePath, importFn, options)
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Check for previous errors
|
|
109
|
+
const previousError = this.errorStates.get(cacheKey);
|
|
110
|
+
if (previousError) {
|
|
111
|
+
return {
|
|
112
|
+
data: null,
|
|
113
|
+
loading: false,
|
|
114
|
+
error: previousError,
|
|
115
|
+
retry: () => this.lazyLoad(modulePath, importFn, options)
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Start loading
|
|
120
|
+
this.loadingStates.set(cacheKey, true);
|
|
121
|
+
this.stats.totalRequests++;
|
|
122
|
+
|
|
123
|
+
const startTime = Date.now();
|
|
124
|
+
|
|
125
|
+
try {
|
|
126
|
+
const data = await Promise.race([
|
|
127
|
+
importFn(),
|
|
128
|
+
this.createTimeout(this.config.loadingTimeout)
|
|
129
|
+
]);
|
|
130
|
+
|
|
131
|
+
// Success
|
|
132
|
+
this.loadingStates.delete(cacheKey);
|
|
133
|
+
this.errorStates.delete(cacheKey);
|
|
134
|
+
this.stats.successfulLoads++;
|
|
135
|
+
|
|
136
|
+
// Cache the result
|
|
137
|
+
if (this.config.enabled) {
|
|
138
|
+
this.cacheResult(cacheKey, data, ttl);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Update stats
|
|
142
|
+
const loadTime = Date.now() - startTime;
|
|
143
|
+
this.updateLoadTimeStats(loadTime);
|
|
144
|
+
|
|
145
|
+
// Preload related modules if enabled
|
|
146
|
+
if (options.preload && this.config.enabled) {
|
|
147
|
+
this.queuePreload(modulePath);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
return {
|
|
151
|
+
data,
|
|
152
|
+
loading: false,
|
|
153
|
+
error: null,
|
|
154
|
+
retry: () => this.lazyLoad(modulePath, importFn, options)
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
} catch (error) {
|
|
158
|
+
// Handle error
|
|
159
|
+
this.loadingStates.delete(cacheKey);
|
|
160
|
+
this.stats.failedLoads++;
|
|
161
|
+
|
|
162
|
+
const loadTime = Date.now() - startTime;
|
|
163
|
+
this.updateLoadTimeStats(loadTime);
|
|
164
|
+
|
|
165
|
+
const retryCount = this.retryCounts.get(cacheKey) || 0;
|
|
166
|
+
if (retryCount < this.config.retryAttempts) {
|
|
167
|
+
this.retryCounts.set(cacheKey, retryCount + 1);
|
|
168
|
+
|
|
169
|
+
// Auto-retry after delay
|
|
170
|
+
setTimeout(() => {
|
|
171
|
+
this.retryCounts.delete(cacheKey);
|
|
172
|
+
}, this.config.retryDelay);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
const errorObj = error instanceof Error ? error : new Error(String(error));
|
|
176
|
+
this.errorStates.set(cacheKey, errorObj);
|
|
177
|
+
|
|
178
|
+
return {
|
|
179
|
+
data: null,
|
|
180
|
+
loading: false,
|
|
181
|
+
error: errorObj,
|
|
182
|
+
retry: () => {
|
|
183
|
+
// Clear error state before retrying
|
|
184
|
+
this.errorStates.delete(cacheKey);
|
|
185
|
+
this.retryCounts.delete(cacheKey);
|
|
186
|
+
return this.lazyLoad(modulePath, importFn, options);
|
|
187
|
+
}
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// Preload a module without waiting for the result
|
|
193
|
+
preload<T>(modulePath: string, importFn: () => Promise<T>): void {
|
|
194
|
+
if (!this.config.enabled) return;
|
|
195
|
+
|
|
196
|
+
// Limit preload queue size
|
|
197
|
+
if (this.preloadQueue.size >= 10) {
|
|
198
|
+
const oldestKey = this.preloadQueue.values().next().value;
|
|
199
|
+
if (oldestKey) {
|
|
200
|
+
this.preloadQueue.delete(oldestKey);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
this.preloadQueue.add(modulePath);
|
|
205
|
+
|
|
206
|
+
// Use requestIdleCallback if available, otherwise setTimeout
|
|
207
|
+
if ('requestIdleCallback' in window) {
|
|
208
|
+
(window as any).requestIdleCallback(() => {
|
|
209
|
+
this.executePreload(modulePath, importFn);
|
|
210
|
+
});
|
|
211
|
+
} else {
|
|
212
|
+
setTimeout(() => {
|
|
213
|
+
this.executePreload(modulePath, importFn);
|
|
214
|
+
}, 100);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// Execute preload
|
|
219
|
+
private async executePreload<T>(modulePath: string, importFn: () => Promise<T>): Promise<void> {
|
|
220
|
+
try {
|
|
221
|
+
await this.lazyLoad(modulePath, importFn, { cacheKey: modulePath, ttl: 600000 }); // 10 minutes for preloaded modules
|
|
222
|
+
} catch (error) {
|
|
223
|
+
// Silently fail preloads
|
|
224
|
+
console.debug(`Preload failed for ${modulePath}:`, error);
|
|
225
|
+
} finally {
|
|
226
|
+
this.preloadQueue.delete(modulePath);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// Queue preload for later execution
|
|
231
|
+
private queuePreload(modulePath: string): void {
|
|
232
|
+
if (this.preloadQueue.size < 10) { // Limit preload queue
|
|
233
|
+
this.preloadQueue.add(modulePath);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
// Cache a result
|
|
240
|
+
private cacheResult(key: string, data: any, ttl: number): void {
|
|
241
|
+
// Implement LRU cache eviction
|
|
242
|
+
if (this.cache.size >= this.config.cacheSize) {
|
|
243
|
+
const oldestKey = this.cache.keys().next().value;
|
|
244
|
+
if (oldestKey) {
|
|
245
|
+
this.cache.delete(oldestKey);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
this.cache.set(key, {
|
|
250
|
+
data,
|
|
251
|
+
timestamp: Date.now(),
|
|
252
|
+
ttl
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// Create a timeout promise
|
|
257
|
+
private createTimeout(ms: number): Promise<never> {
|
|
258
|
+
return new Promise((_, reject) => {
|
|
259
|
+
setTimeout(() => reject(new Error(`Loading timeout after ${ms}ms`)), ms);
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// Update load time statistics
|
|
264
|
+
private updateLoadTimeStats(loadTime: number): void {
|
|
265
|
+
this.stats.totalLoadTime += loadTime;
|
|
266
|
+
this.stats.averageLoadTime = this.stats.totalLoadTime / this.stats.totalRequests;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// Get loading state for a module
|
|
270
|
+
isLoading(modulePath: string): boolean {
|
|
271
|
+
return this.loadingStates.has(modulePath);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// Get error state for a module
|
|
275
|
+
getError(modulePath: string): Error | null {
|
|
276
|
+
return this.errorStates.get(modulePath) || null;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// Clear cache for a specific module
|
|
280
|
+
clearCache(modulePath: string): void {
|
|
281
|
+
this.cache.delete(modulePath);
|
|
282
|
+
this.errorStates.delete(modulePath);
|
|
283
|
+
this.retryCounts.delete(modulePath);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
// Clear all cache
|
|
287
|
+
clearAllCache(): void {
|
|
288
|
+
this.cache.clear();
|
|
289
|
+
this.errorStates.clear();
|
|
290
|
+
this.retryCounts.clear();
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
// Get cache statistics
|
|
294
|
+
getCacheStats(): {
|
|
295
|
+
size: number;
|
|
296
|
+
maxSize: number;
|
|
297
|
+
hitRate: number;
|
|
298
|
+
} {
|
|
299
|
+
const hitRate = this.stats.totalRequests > 0
|
|
300
|
+
? (this.stats.cacheHits / this.stats.totalRequests) * 100
|
|
301
|
+
: 0;
|
|
302
|
+
|
|
303
|
+
return {
|
|
304
|
+
size: this.cache.size,
|
|
305
|
+
maxSize: this.config.cacheSize,
|
|
306
|
+
hitRate
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
// Get performance statistics
|
|
311
|
+
getStats(): LazyLoadStats {
|
|
312
|
+
return { ...this.stats };
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
// Reset all statistics
|
|
316
|
+
resetStats(): void {
|
|
317
|
+
this.stats = {
|
|
318
|
+
totalRequests: 0,
|
|
319
|
+
successfulLoads: 0,
|
|
320
|
+
failedLoads: 0,
|
|
321
|
+
cacheHits: 0,
|
|
322
|
+
averageLoadTime: 0,
|
|
323
|
+
totalLoadTime: 0
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
// Check if preload is in progress
|
|
328
|
+
isPreloading(modulePath: string): boolean {
|
|
329
|
+
return this.preloadQueue.has(modulePath);
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
// Get preload queue status
|
|
333
|
+
getPreloadQueue(): string[] {
|
|
334
|
+
return Array.from(this.preloadQueue);
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
// Update configuration
|
|
338
|
+
updateConfig(newConfig: Partial<LazyLoadConfig>): void {
|
|
339
|
+
this.config = { ...this.config, ...newConfig };
|
|
340
|
+
|
|
341
|
+
// Adjust cache size if needed
|
|
342
|
+
if (newConfig.cacheSize && newConfig.cacheSize < this.cache.size) {
|
|
343
|
+
const entries = Array.from(this.cache.entries());
|
|
344
|
+
entries.sort((a, b) => a[1].timestamp - b[1].timestamp);
|
|
345
|
+
|
|
346
|
+
// Remove oldest entries
|
|
347
|
+
const toRemove = entries.slice(0, this.cache.size - newConfig.cacheSize);
|
|
348
|
+
toRemove.forEach(([key]) => this.cache.delete(key));
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
// Export lazy loading analysis
|
|
353
|
+
exportAnalysis(): string {
|
|
354
|
+
const cacheStats = this.getCacheStats();
|
|
355
|
+
const stats = this.getStats();
|
|
356
|
+
const preloadQueue = this.getPreloadQueue();
|
|
357
|
+
|
|
358
|
+
return JSON.stringify({
|
|
359
|
+
config: this.config,
|
|
360
|
+
cacheStats,
|
|
361
|
+
performanceStats: stats,
|
|
362
|
+
preloadQueue,
|
|
363
|
+
timestamp: new Date().toISOString()
|
|
364
|
+
}, null, 2);
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
// Create and export default instance
|
|
369
|
+
export const lazyLoader = new LazyLoader();
|
|
370
|
+
|
|
371
|
+
// Utility function for React lazy loading
|
|
372
|
+
export function createLazyComponent<T>(
|
|
373
|
+
importFn: () => Promise<{ default: React.ComponentType<T> }>
|
|
374
|
+
): React.LazyExoticComponent<React.ComponentType<T>> {
|
|
375
|
+
return React.lazy(importFn);
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
// Utility function for conditional lazy loading
|
|
379
|
+
export function conditionalLazyLoad<T>(
|
|
380
|
+
condition: boolean,
|
|
381
|
+
importFn: () => Promise<T>,
|
|
382
|
+
fallback: T
|
|
383
|
+
): Promise<T> {
|
|
384
|
+
if (condition) {
|
|
385
|
+
return importFn();
|
|
386
|
+
}
|
|
387
|
+
return Promise.resolve(fallback);
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
// Utility function for batch lazy loading
|
|
391
|
+
export function batchLazyLoad<T>(
|
|
392
|
+
modules: Array<{ path: string; importFn: () => Promise<T> }>,
|
|
393
|
+
options: { parallel?: boolean; maxConcurrent?: number } = {}
|
|
394
|
+
): Promise<T[]> {
|
|
395
|
+
const { parallel = true, maxConcurrent = 3 } = options;
|
|
396
|
+
|
|
397
|
+
if (!parallel) {
|
|
398
|
+
// Sequential loading
|
|
399
|
+
return modules.reduce(async (promise, module) => {
|
|
400
|
+
const results = await promise;
|
|
401
|
+
const result = await module.importFn();
|
|
402
|
+
return [...results, result];
|
|
403
|
+
}, Promise.resolve([] as T[]));
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
// Parallel loading with concurrency limit
|
|
407
|
+
const results: T[] = [];
|
|
408
|
+
const queue = [...modules];
|
|
409
|
+
const active: Promise<void>[] = [];
|
|
410
|
+
|
|
411
|
+
return new Promise((resolve, reject) => {
|
|
412
|
+
function processQueue() {
|
|
413
|
+
if (queue.length === 0 && active.length === 0) {
|
|
414
|
+
resolve(results);
|
|
415
|
+
return;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
while (active.length < maxConcurrent && queue.length > 0) {
|
|
419
|
+
const module = queue.shift()!;
|
|
420
|
+
const index = modules.indexOf(module);
|
|
421
|
+
|
|
422
|
+
const promise = module.importFn()
|
|
423
|
+
.then(result => {
|
|
424
|
+
results[index] = result;
|
|
425
|
+
})
|
|
426
|
+
.catch(reject)
|
|
427
|
+
.finally(() => {
|
|
428
|
+
const activeIndex = active.indexOf(promise);
|
|
429
|
+
if (activeIndex > -1) {
|
|
430
|
+
active.splice(activeIndex, 1);
|
|
431
|
+
}
|
|
432
|
+
processQueue();
|
|
433
|
+
});
|
|
434
|
+
|
|
435
|
+
active.push(promise);
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
processQueue();
|
|
440
|
+
});
|
|
441
|
+
}
|