@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,348 @@
|
|
|
1
|
+
import { useState, useEffect, useCallback, useRef } from 'react'
|
|
2
|
+
|
|
3
|
+
export interface PerformanceThrottlingConfig {
|
|
4
|
+
enablePerformanceMonitoring?: boolean
|
|
5
|
+
enableAutomaticThrottling?: boolean
|
|
6
|
+
enableUserExperienceOptimization?: boolean
|
|
7
|
+
enableBatteryPreservation?: boolean
|
|
8
|
+
performanceThreshold?: number
|
|
9
|
+
frameRateTarget?: number
|
|
10
|
+
memoryThreshold?: number
|
|
11
|
+
cpuThreshold?: number
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface PerformanceMetrics {
|
|
15
|
+
fps: number
|
|
16
|
+
frameTime: number
|
|
17
|
+
memoryUsage: number
|
|
18
|
+
cpuUsage: number
|
|
19
|
+
performanceScore: number
|
|
20
|
+
isThrottling: boolean
|
|
21
|
+
throttleReason: string
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface PerformanceThrottlingCallbacks {
|
|
25
|
+
onPerformanceWarning?: (metrics: PerformanceMetrics) => void
|
|
26
|
+
onThrottlingApplied?: (level: string, reason: string) => void
|
|
27
|
+
onPerformanceRecovery?: (metrics: PerformanceMetrics) => void
|
|
28
|
+
onUserExperienceOptimized?: (optimization: string) => void
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export const usePerformanceThrottling = (
|
|
32
|
+
config: PerformanceThrottlingConfig = {},
|
|
33
|
+
callbacks: PerformanceThrottlingCallbacks = {}
|
|
34
|
+
) => {
|
|
35
|
+
const {
|
|
36
|
+
enablePerformanceMonitoring = true,
|
|
37
|
+
enableAutomaticThrottling = true,
|
|
38
|
+
enableUserExperienceOptimization = true,
|
|
39
|
+
enableBatteryPreservation = true,
|
|
40
|
+
performanceThreshold = 70,
|
|
41
|
+
frameRateTarget = 60,
|
|
42
|
+
memoryThreshold = 80,
|
|
43
|
+
cpuThreshold = 80
|
|
44
|
+
} = config
|
|
45
|
+
|
|
46
|
+
const [metrics, setMetrics] = useState<PerformanceMetrics>({
|
|
47
|
+
fps: 60,
|
|
48
|
+
frameTime: 16.67,
|
|
49
|
+
memoryUsage: 0,
|
|
50
|
+
cpuUsage: 0,
|
|
51
|
+
performanceScore: 100,
|
|
52
|
+
isThrottling: false,
|
|
53
|
+
throttleReason: 'none'
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
const [isOptimizing, setIsOptimizing] = useState(false)
|
|
57
|
+
const [optimizations, setOptimizations] = useState<string[]>([])
|
|
58
|
+
const [throttleLevel, setThrottleLevel] = useState<'none' | 'light' | 'moderate' | 'aggressive'>('none')
|
|
59
|
+
|
|
60
|
+
const frameCountRef = useRef(0)
|
|
61
|
+
const lastFrameTimeRef = useRef(performance.now())
|
|
62
|
+
const performanceTimerRef = useRef<number | null>(null)
|
|
63
|
+
const throttlingTimerRef = useRef<number | null>(null)
|
|
64
|
+
|
|
65
|
+
// Performance monitoring
|
|
66
|
+
const measurePerformance = useCallback(() => {
|
|
67
|
+
if (!enablePerformanceMonitoring) return
|
|
68
|
+
|
|
69
|
+
try {
|
|
70
|
+
const now = performance.now()
|
|
71
|
+
frameCountRef.current++
|
|
72
|
+
|
|
73
|
+
if (now - lastFrameTimeRef.current >= 1000) {
|
|
74
|
+
const fps = Math.round((frameCountRef.current * 1000) / (now - lastFrameTimeRef.current))
|
|
75
|
+
const frameTime = 1000 / fps
|
|
76
|
+
|
|
77
|
+
// Simulate memory and CPU usage
|
|
78
|
+
const memoryUsage = Math.random() * 100
|
|
79
|
+
const cpuUsage = Math.random() * 100
|
|
80
|
+
|
|
81
|
+
// Calculate performance score
|
|
82
|
+
const fpsScore = Math.min((fps / frameRateTarget) * 100, 100)
|
|
83
|
+
const timeScore = Math.max(100 - (frameTime - 16.67) * 10, 0)
|
|
84
|
+
const memoryScore = Math.max(100 - memoryUsage, 0)
|
|
85
|
+
const cpuScore = Math.max(100 - cpuUsage, 0)
|
|
86
|
+
|
|
87
|
+
const performanceScore = Math.round((fpsScore + timeScore + memoryScore + cpuScore) / 4)
|
|
88
|
+
|
|
89
|
+
// Determine if throttling is needed
|
|
90
|
+
const isThrottling = performanceScore < performanceThreshold ||
|
|
91
|
+
fps < frameRateTarget * 0.8 ||
|
|
92
|
+
memoryUsage > memoryThreshold ||
|
|
93
|
+
cpuUsage > cpuThreshold
|
|
94
|
+
|
|
95
|
+
let throttleReason = 'none'
|
|
96
|
+
if (performanceScore < performanceThreshold) throttleReason = 'low_performance'
|
|
97
|
+
else if (fps < frameRateTarget * 0.8) throttleReason = 'low_fps'
|
|
98
|
+
else if (memoryUsage > memoryThreshold) throttleReason = 'high_memory'
|
|
99
|
+
else if (cpuUsage > cpuThreshold) throttleReason = 'high_cpu'
|
|
100
|
+
|
|
101
|
+
const newMetrics: PerformanceMetrics = {
|
|
102
|
+
fps,
|
|
103
|
+
frameTime,
|
|
104
|
+
memoryUsage,
|
|
105
|
+
cpuUsage,
|
|
106
|
+
performanceScore,
|
|
107
|
+
isThrottling,
|
|
108
|
+
throttleReason
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
setMetrics(newMetrics)
|
|
112
|
+
|
|
113
|
+
// Trigger callbacks
|
|
114
|
+
if (isThrottling) {
|
|
115
|
+
callbacks.onPerformanceWarning?.(newMetrics)
|
|
116
|
+
} else if (metrics.isThrottling) {
|
|
117
|
+
callbacks.onPerformanceRecovery?.(newMetrics)
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
frameCountRef.current = 0
|
|
121
|
+
lastFrameTimeRef.current = now
|
|
122
|
+
}
|
|
123
|
+
} catch (error) {
|
|
124
|
+
console.warn('Performance measurement failed:', error)
|
|
125
|
+
}
|
|
126
|
+
}, [enablePerformanceMonitoring, performanceThreshold, frameRateTarget, memoryThreshold, cpuThreshold, callbacks, metrics.isThrottling])
|
|
127
|
+
|
|
128
|
+
// Automatic throttling
|
|
129
|
+
const applyPerformanceThrottling = useCallback(() => {
|
|
130
|
+
if (!enableAutomaticThrottling) return
|
|
131
|
+
|
|
132
|
+
setIsOptimizing(true)
|
|
133
|
+
|
|
134
|
+
setTimeout(() => {
|
|
135
|
+
let newThrottleLevel: 'none' | 'light' | 'moderate' | 'aggressive' = 'none'
|
|
136
|
+
let optimizations: string[] = []
|
|
137
|
+
|
|
138
|
+
// Determine throttle level based on performance metrics
|
|
139
|
+
if (metrics.performanceScore < 50 || metrics.fps < 30) {
|
|
140
|
+
newThrottleLevel = 'aggressive'
|
|
141
|
+
optimizations.push('Critical performance: Maximum throttling applied')
|
|
142
|
+
optimizations.push('All non-essential animations disabled')
|
|
143
|
+
optimizations.push('Frame rate limited to 30fps')
|
|
144
|
+
optimizations.push('Memory usage optimized')
|
|
145
|
+
} else if (metrics.performanceScore < 70 || metrics.fps < 45) {
|
|
146
|
+
newThrottleLevel = 'moderate'
|
|
147
|
+
optimizations.push('Performance issue: Moderate throttling applied')
|
|
148
|
+
optimizations.push('Animation complexity reduced by 50%')
|
|
149
|
+
optimizations.push('Frame rate limited to 45fps')
|
|
150
|
+
optimizations.push('Memory optimization enabled')
|
|
151
|
+
} else if (metrics.performanceScore < 85 || metrics.fps < 55) {
|
|
152
|
+
newThrottleLevel = 'light'
|
|
153
|
+
optimizations.push('Performance warning: Light throttling applied')
|
|
154
|
+
optimizations.push('Animation complexity reduced by 25%')
|
|
155
|
+
optimizations.push('Frame rate limited to 55fps')
|
|
156
|
+
optimizations.push('Performance monitoring enhanced')
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Battery preservation considerations
|
|
160
|
+
if (enableBatteryPreservation && newThrottleLevel !== 'none') {
|
|
161
|
+
optimizations.push('Battery preservation: Animation efficiency optimized')
|
|
162
|
+
optimizations.push('GPU usage minimized for power efficiency')
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// User experience optimization
|
|
166
|
+
if (enableUserExperienceOptimization && newThrottleLevel !== 'none') {
|
|
167
|
+
optimizations.push('User experience: Smooth performance prioritized')
|
|
168
|
+
optimizations.push('Animation quality balanced with performance')
|
|
169
|
+
optimizations.push('Responsive interactions maintained')
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
setThrottleLevel(newThrottleLevel)
|
|
173
|
+
setOptimizations(prev => [...prev, ...optimizations])
|
|
174
|
+
setIsOptimizing(false)
|
|
175
|
+
|
|
176
|
+
callbacks.onThrottlingApplied?.(newThrottleLevel, metrics.throttleReason)
|
|
177
|
+
|
|
178
|
+
optimizations.forEach(optimization => {
|
|
179
|
+
callbacks.onUserExperienceOptimized?.(optimization)
|
|
180
|
+
})
|
|
181
|
+
}, 200)
|
|
182
|
+
}, [enableAutomaticThrottling, enableBatteryPreservation, enableUserExperienceOptimization, metrics, callbacks])
|
|
183
|
+
|
|
184
|
+
// Get throttling recommendations
|
|
185
|
+
const getThrottlingRecommendations = useCallback(() => {
|
|
186
|
+
const recommendations = []
|
|
187
|
+
|
|
188
|
+
if (metrics.performanceScore < 50) {
|
|
189
|
+
recommendations.push('Critical: Disable all animations and complex UI operations')
|
|
190
|
+
recommendations.push('Use static UI elements and minimal interactions')
|
|
191
|
+
recommendations.push('Implement aggressive memory cleanup')
|
|
192
|
+
} else if (metrics.performanceScore < 70) {
|
|
193
|
+
recommendations.push('High: Significantly reduce animation complexity')
|
|
194
|
+
recommendations.push('Limit concurrent animations to 2-3 maximum')
|
|
195
|
+
recommendations.push('Use CSS transforms instead of JavaScript animations')
|
|
196
|
+
} else if (metrics.performanceScore < 85) {
|
|
197
|
+
recommendations.push('Medium: Consider light performance optimization')
|
|
198
|
+
recommendations.push('Monitor animation frame rates closely')
|
|
199
|
+
recommendations.push('Implement animation debouncing')
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
if (metrics.fps < frameRateTarget * 0.8) {
|
|
203
|
+
recommendations.push('Low FPS: Reduce animation frame rate')
|
|
204
|
+
recommendations.push('Use requestAnimationFrame for smooth animations')
|
|
205
|
+
recommendations.push('Implement frame skipping for complex animations')
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
if (metrics.memoryUsage > memoryThreshold) {
|
|
209
|
+
recommendations.push('High Memory: Optimize memory usage')
|
|
210
|
+
recommendations.push('Clean up animation references')
|
|
211
|
+
recommendations.push('Use object pooling for repeated animations')
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
if (metrics.cpuUsage > cpuThreshold) {
|
|
215
|
+
recommendations.push('High CPU: Reduce computational complexity')
|
|
216
|
+
recommendations.push('Use CSS animations instead of JavaScript')
|
|
217
|
+
recommendations.push('Implement animation pausing when not visible')
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
return recommendations
|
|
221
|
+
}, [metrics, frameRateTarget, memoryThreshold, cpuThreshold])
|
|
222
|
+
|
|
223
|
+
// Get optimal performance settings
|
|
224
|
+
const getOptimalPerformanceSettings = useCallback(() => {
|
|
225
|
+
const settings = {
|
|
226
|
+
maxConcurrentAnimations: 5,
|
|
227
|
+
frameRateLimit: 60,
|
|
228
|
+
animationQuality: 'high',
|
|
229
|
+
memoryOptimization: false,
|
|
230
|
+
cpuOptimization: false
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
switch (throttleLevel) {
|
|
234
|
+
case 'aggressive':
|
|
235
|
+
settings.maxConcurrentAnimations = 1
|
|
236
|
+
settings.frameRateLimit = 30
|
|
237
|
+
settings.animationQuality = 'minimal'
|
|
238
|
+
settings.memoryOptimization = true
|
|
239
|
+
settings.cpuOptimization = true
|
|
240
|
+
break
|
|
241
|
+
case 'moderate':
|
|
242
|
+
settings.maxConcurrentAnimations = 2
|
|
243
|
+
settings.frameRateLimit = 45
|
|
244
|
+
settings.animationQuality = 'medium'
|
|
245
|
+
settings.memoryOptimization = true
|
|
246
|
+
settings.cpuOptimization = true
|
|
247
|
+
break
|
|
248
|
+
case 'light':
|
|
249
|
+
settings.maxConcurrentAnimations = 3
|
|
250
|
+
settings.frameRateLimit = 55
|
|
251
|
+
settings.animationQuality = 'high'
|
|
252
|
+
settings.memoryOptimization = true
|
|
253
|
+
settings.cpuOptimization = false
|
|
254
|
+
break
|
|
255
|
+
default:
|
|
256
|
+
settings.maxConcurrentAnimations = 5
|
|
257
|
+
settings.frameRateLimit = 60
|
|
258
|
+
settings.animationQuality = 'high'
|
|
259
|
+
settings.memoryOptimization = false
|
|
260
|
+
settings.cpuOptimization = false
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
return settings
|
|
264
|
+
}, [throttleLevel])
|
|
265
|
+
|
|
266
|
+
// Reset throttling
|
|
267
|
+
const resetThrottling = useCallback(() => {
|
|
268
|
+
setThrottleLevel('none')
|
|
269
|
+
setOptimizations([])
|
|
270
|
+
setMetrics(prev => ({
|
|
271
|
+
...prev,
|
|
272
|
+
isThrottling: false,
|
|
273
|
+
throttleReason: 'none'
|
|
274
|
+
}))
|
|
275
|
+
}, [])
|
|
276
|
+
|
|
277
|
+
// Initialize performance monitoring
|
|
278
|
+
useEffect(() => {
|
|
279
|
+
if (!enablePerformanceMonitoring) return
|
|
280
|
+
|
|
281
|
+
try {
|
|
282
|
+
performanceTimerRef.current = window.setInterval(measurePerformance, 1000)
|
|
283
|
+
|
|
284
|
+
return () => {
|
|
285
|
+
if (performanceTimerRef.current) {
|
|
286
|
+
clearInterval(performanceTimerRef.current)
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
} catch (error) {
|
|
290
|
+
console.warn('Performance monitoring initialization failed:', error)
|
|
291
|
+
}
|
|
292
|
+
}, [enablePerformanceMonitoring, measurePerformance])
|
|
293
|
+
|
|
294
|
+
// Apply throttling when performance degrades
|
|
295
|
+
useEffect(() => {
|
|
296
|
+
if (enableAutomaticThrottling && metrics.isThrottling) {
|
|
297
|
+
throttlingTimerRef.current = window.setTimeout(applyPerformanceThrottling, 1000)
|
|
298
|
+
|
|
299
|
+
return () => {
|
|
300
|
+
if (throttlingTimerRef.current) {
|
|
301
|
+
clearTimeout(throttlingTimerRef.current)
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
}, [enableAutomaticThrottling, metrics.isThrottling, applyPerformanceThrottling])
|
|
306
|
+
|
|
307
|
+
// Cleanup on unmount
|
|
308
|
+
useEffect(() => {
|
|
309
|
+
return () => {
|
|
310
|
+
if (throttlingTimerRef.current) {
|
|
311
|
+
clearTimeout(throttlingTimerRef.current)
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
}, [])
|
|
315
|
+
|
|
316
|
+
return {
|
|
317
|
+
// State
|
|
318
|
+
metrics,
|
|
319
|
+
isOptimizing,
|
|
320
|
+
optimizations,
|
|
321
|
+
throttleLevel,
|
|
322
|
+
|
|
323
|
+
// Actions
|
|
324
|
+
measurePerformance,
|
|
325
|
+
applyPerformanceThrottling,
|
|
326
|
+
resetThrottling,
|
|
327
|
+
|
|
328
|
+
// Computed values
|
|
329
|
+
isThrottling: throttleLevel !== 'none',
|
|
330
|
+
performanceLevel: metrics.performanceScore >= 90 ? 'excellent' :
|
|
331
|
+
metrics.performanceScore >= 80 ? 'good' :
|
|
332
|
+
metrics.performanceScore >= 70 ? 'fair' : 'poor',
|
|
333
|
+
needsOptimization: metrics.performanceScore < 70,
|
|
334
|
+
recommendations: getThrottlingRecommendations(),
|
|
335
|
+
performanceSettings: getOptimalPerformanceSettings(),
|
|
336
|
+
|
|
337
|
+
// Utility functions
|
|
338
|
+
getPerformanceHealth: () => {
|
|
339
|
+
if (metrics.performanceScore >= 90) return 'excellent'
|
|
340
|
+
if (metrics.performanceScore >= 80) return 'good'
|
|
341
|
+
if (metrics.performanceScore >= 70) return 'fair'
|
|
342
|
+
if (metrics.performanceScore >= 50) return 'poor'
|
|
343
|
+
return 'critical'
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
export default usePerformanceThrottling
|
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
import { useState, useEffect, useCallback, useMemo, useRef } from 'react'
|
|
2
|
+
|
|
3
|
+
export interface PerformanceMetrics {
|
|
4
|
+
fps: number
|
|
5
|
+
frameTime: number
|
|
6
|
+
memoryUsage?: number
|
|
7
|
+
memoryLimit?: number
|
|
8
|
+
memoryPercentage?: number
|
|
9
|
+
batteryLevel?: number
|
|
10
|
+
isLowPowerMode?: boolean
|
|
11
|
+
isCharging?: boolean
|
|
12
|
+
performanceMode: 'high' | 'medium' | 'low'
|
|
13
|
+
throttlingEnabled: boolean
|
|
14
|
+
throttlingReason?: string
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface PerformanceThresholds {
|
|
18
|
+
fps: {
|
|
19
|
+
warning: number
|
|
20
|
+
critical: number
|
|
21
|
+
}
|
|
22
|
+
memory: {
|
|
23
|
+
warning: number
|
|
24
|
+
critical: number
|
|
25
|
+
}
|
|
26
|
+
battery: {
|
|
27
|
+
low: number
|
|
28
|
+
critical: number
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface PerformanceCallbacks {
|
|
33
|
+
onFPSWarning?: (fps: number) => void
|
|
34
|
+
onMemoryWarning?: (usage: number) => void
|
|
35
|
+
onBatteryLow?: (level: number) => void
|
|
36
|
+
onPerformanceModeChange?: (mode: PerformanceMetrics['performanceMode']) => void
|
|
37
|
+
onThrottlingChange?: (enabled: boolean, reason?: string) => void
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface PerformanceOptions {
|
|
41
|
+
updateInterval?: number
|
|
42
|
+
thresholds?: Partial<PerformanceThresholds>
|
|
43
|
+
enableThrottling?: boolean
|
|
44
|
+
enableBatteryOptimization?: boolean
|
|
45
|
+
callbacks?: PerformanceCallbacks
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const DEFAULT_THRESHOLDS: PerformanceThresholds = {
|
|
49
|
+
fps: {
|
|
50
|
+
warning: 45,
|
|
51
|
+
critical: 30
|
|
52
|
+
},
|
|
53
|
+
memory: {
|
|
54
|
+
warning: 0.7,
|
|
55
|
+
critical: 0.85
|
|
56
|
+
},
|
|
57
|
+
battery: {
|
|
58
|
+
low: 0.3,
|
|
59
|
+
critical: 0.15
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export const usePerformance = (options: PerformanceOptions = {}) => {
|
|
64
|
+
const {
|
|
65
|
+
updateInterval = 1000,
|
|
66
|
+
thresholds = {},
|
|
67
|
+
enableThrottling = true,
|
|
68
|
+
enableBatteryOptimization = true,
|
|
69
|
+
callbacks = {}
|
|
70
|
+
} = options
|
|
71
|
+
|
|
72
|
+
const [metrics, setMetrics] = useState<PerformanceMetrics>({
|
|
73
|
+
fps: 60,
|
|
74
|
+
frameTime: 16.67,
|
|
75
|
+
performanceMode: 'high',
|
|
76
|
+
throttlingEnabled: false
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
const [isMonitoring, setIsMonitoring] = useState(false)
|
|
80
|
+
const frameCountRef = useRef(0)
|
|
81
|
+
const lastTimeRef = useRef(performance.now())
|
|
82
|
+
const animationIdRef = useRef<number>()
|
|
83
|
+
const intervalIdRef = useRef<NodeJS.Timeout>()
|
|
84
|
+
|
|
85
|
+
// Merge default thresholds with custom ones
|
|
86
|
+
const finalThresholds = useMemo(() => ({
|
|
87
|
+
...DEFAULT_THRESHOLDS,
|
|
88
|
+
...thresholds
|
|
89
|
+
}), [thresholds])
|
|
90
|
+
|
|
91
|
+
// Frame rate monitoring
|
|
92
|
+
const measureFrameRate = useCallback(() => {
|
|
93
|
+
frameCountRef.current++
|
|
94
|
+
const currentTime = performance.now()
|
|
95
|
+
|
|
96
|
+
if (currentTime - lastTimeRef.current >= updateInterval) {
|
|
97
|
+
const fps = Math.round((frameCountRef.current * 1000) / (currentTime - lastTimeRef.current))
|
|
98
|
+
const frameTime = 1000 / fps
|
|
99
|
+
|
|
100
|
+
setMetrics(prev => ({
|
|
101
|
+
...prev,
|
|
102
|
+
fps,
|
|
103
|
+
frameTime
|
|
104
|
+
}))
|
|
105
|
+
|
|
106
|
+
// Check FPS thresholds
|
|
107
|
+
if (fps <= finalThresholds.fps.critical && callbacks.onFPSWarning) {
|
|
108
|
+
callbacks.onFPSWarning(fps)
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
frameCountRef.current = 0
|
|
112
|
+
lastTimeRef.current = currentTime
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
animationIdRef.current = requestAnimationFrame(measureFrameRate)
|
|
116
|
+
}, [updateInterval, finalThresholds.fps.critical, callbacks.onFPSWarning])
|
|
117
|
+
|
|
118
|
+
// Memory usage monitoring
|
|
119
|
+
const updateMemoryInfo = useCallback(() => {
|
|
120
|
+
if ('memory' in performance) {
|
|
121
|
+
const memory = (performance as any).memory
|
|
122
|
+
const memoryUsage = memory.usedJSHeapSize / memory.jsHeapSizeLimit
|
|
123
|
+
|
|
124
|
+
setMetrics(prev => ({
|
|
125
|
+
...prev,
|
|
126
|
+
memoryUsage,
|
|
127
|
+
memoryLimit: memory.jsHeapSizeLimit,
|
|
128
|
+
memoryPercentage: memoryUsage * 100
|
|
129
|
+
}))
|
|
130
|
+
|
|
131
|
+
// Check memory thresholds
|
|
132
|
+
if (memoryUsage >= finalThresholds.memory.critical && callbacks.onMemoryWarning) {
|
|
133
|
+
callbacks.onMemoryWarning(memoryUsage)
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}, [finalThresholds.memory.critical, callbacks.onMemoryWarning])
|
|
137
|
+
|
|
138
|
+
// Battery status monitoring
|
|
139
|
+
const updateBatteryInfo = useCallback(async () => {
|
|
140
|
+
if ('getBattery' in navigator) {
|
|
141
|
+
try {
|
|
142
|
+
const battery = await (navigator as any).getBattery()
|
|
143
|
+
|
|
144
|
+
setMetrics(prev => ({
|
|
145
|
+
...prev,
|
|
146
|
+
batteryLevel: battery.level,
|
|
147
|
+
isLowPowerMode: battery.level < finalThresholds.battery.low,
|
|
148
|
+
isCharging: battery.charging
|
|
149
|
+
}))
|
|
150
|
+
|
|
151
|
+
// Check battery thresholds
|
|
152
|
+
if (battery.level <= finalThresholds.battery.critical && callbacks.onBatteryLow) {
|
|
153
|
+
callbacks.onBatteryLow(battery.level)
|
|
154
|
+
}
|
|
155
|
+
} catch (error) {
|
|
156
|
+
console.warn('Battery API not available:', error)
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}, [finalThresholds.battery.low, finalThresholds.battery.critical, callbacks.onBatteryLow])
|
|
160
|
+
|
|
161
|
+
// Performance mode determination
|
|
162
|
+
const determinePerformanceMode = useCallback((fps: number, memoryUsage?: number): PerformanceMetrics['performanceMode'] => {
|
|
163
|
+
if (fps < finalThresholds.fps.critical || (memoryUsage && memoryUsage > finalThresholds.memory.critical)) {
|
|
164
|
+
return 'low'
|
|
165
|
+
}
|
|
166
|
+
if (fps < finalThresholds.fps.warning || (memoryUsage && memoryUsage > finalThresholds.memory.warning)) {
|
|
167
|
+
return 'medium'
|
|
168
|
+
}
|
|
169
|
+
return 'high'
|
|
170
|
+
}, [finalThresholds])
|
|
171
|
+
|
|
172
|
+
// Performance throttling logic
|
|
173
|
+
const shouldThrottle = useCallback((): { should: boolean; reason?: string } => {
|
|
174
|
+
const { fps, memoryPercentage, batteryLevel, isLowPowerMode } = metrics
|
|
175
|
+
|
|
176
|
+
// FPS-based throttling
|
|
177
|
+
if (fps < finalThresholds.fps.critical) {
|
|
178
|
+
return { should: true, reason: 'Low FPS' }
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// Memory-based throttling
|
|
182
|
+
if (memoryPercentage && memoryPercentage > finalThresholds.memory.critical * 100) {
|
|
183
|
+
return { should: true, reason: 'High memory usage' }
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// Battery-based throttling
|
|
187
|
+
if (enableBatteryOptimization && (isLowPowerMode || (batteryLevel && batteryLevel < finalThresholds.battery.low))) {
|
|
188
|
+
return { should: true, reason: 'Low battery' }
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
return { should: false }
|
|
192
|
+
}, [metrics, finalThresholds, enableBatteryOptimization])
|
|
193
|
+
|
|
194
|
+
// Update performance mode and throttling
|
|
195
|
+
useEffect(() => {
|
|
196
|
+
const newMode = determinePerformanceMode(metrics.fps, metrics.memoryUsage)
|
|
197
|
+
const { should: shouldThrottleNow, reason } = shouldThrottle()
|
|
198
|
+
|
|
199
|
+
setMetrics(prev => ({
|
|
200
|
+
...prev,
|
|
201
|
+
performanceMode: newMode,
|
|
202
|
+
throttlingEnabled: enableThrottling && shouldThrottleNow,
|
|
203
|
+
throttlingReason: reason
|
|
204
|
+
}))
|
|
205
|
+
|
|
206
|
+
// Notify callbacks
|
|
207
|
+
if (newMode !== metrics.performanceMode && callbacks.onPerformanceModeChange) {
|
|
208
|
+
callbacks.onPerformanceModeChange(newMode)
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
if (enableThrottling && shouldThrottleNow !== metrics.throttlingEnabled && callbacks.onThrottlingChange) {
|
|
212
|
+
callbacks.onThrottlingChange(shouldThrottleNow, reason)
|
|
213
|
+
}
|
|
214
|
+
}, [metrics.fps, metrics.memoryUsage, metrics.batteryLevel, metrics.isLowPowerMode, enableThrottling, determinePerformanceMode, shouldThrottle, callbacks, metrics.performanceMode, metrics.throttlingEnabled])
|
|
215
|
+
|
|
216
|
+
// Start monitoring
|
|
217
|
+
const startMonitoring = useCallback(() => {
|
|
218
|
+
if (isMonitoring) return
|
|
219
|
+
|
|
220
|
+
setIsMonitoring(true)
|
|
221
|
+
measureFrameRate()
|
|
222
|
+
|
|
223
|
+
// Set up interval for memory and battery updates
|
|
224
|
+
intervalIdRef.current = setInterval(() => {
|
|
225
|
+
updateMemoryInfo()
|
|
226
|
+
updateBatteryInfo()
|
|
227
|
+
}, updateInterval)
|
|
228
|
+
}, [isMonitoring, measureFrameRate, updateMemoryInfo, updateBatteryInfo, updateInterval])
|
|
229
|
+
|
|
230
|
+
// Stop monitoring
|
|
231
|
+
const stopMonitoring = useCallback(() => {
|
|
232
|
+
setIsMonitoring(false)
|
|
233
|
+
|
|
234
|
+
if (animationIdRef.current) {
|
|
235
|
+
cancelAnimationFrame(animationIdRef.current)
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
if (intervalIdRef.current) {
|
|
239
|
+
clearInterval(intervalIdRef.current)
|
|
240
|
+
}
|
|
241
|
+
}, [])
|
|
242
|
+
|
|
243
|
+
// Auto-start monitoring on mount
|
|
244
|
+
useEffect(() => {
|
|
245
|
+
startMonitoring()
|
|
246
|
+
return () => stopMonitoring()
|
|
247
|
+
}, [startMonitoring, stopMonitoring])
|
|
248
|
+
|
|
249
|
+
// Performance optimization recommendations
|
|
250
|
+
const getOptimizationRecommendations = useCallback(() => {
|
|
251
|
+
const recommendations: string[] = []
|
|
252
|
+
|
|
253
|
+
if (metrics.fps < finalThresholds.fps.warning) {
|
|
254
|
+
recommendations.push('Consider reducing animation complexity or enabling performance mode')
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
if (metrics.memoryPercentage && metrics.memoryPercentage > finalThresholds.memory.warning * 100) {
|
|
258
|
+
recommendations.push('Memory usage is high - consider implementing lazy loading or cleanup')
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
if (metrics.isLowPowerMode) {
|
|
262
|
+
recommendations.push('Low battery detected - performance optimizations are active')
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
return recommendations
|
|
266
|
+
}, [metrics, finalThresholds])
|
|
267
|
+
|
|
268
|
+
// Throttling controls
|
|
269
|
+
const enableThrottlingMode = useCallback(() => {
|
|
270
|
+
setMetrics(prev => ({
|
|
271
|
+
...prev,
|
|
272
|
+
throttlingEnabled: true,
|
|
273
|
+
throttlingReason: 'Manual override'
|
|
274
|
+
}))
|
|
275
|
+
}, [])
|
|
276
|
+
|
|
277
|
+
const disableThrottlingMode = useCallback(() => {
|
|
278
|
+
setMetrics(prev => ({
|
|
279
|
+
...prev,
|
|
280
|
+
throttlingEnabled: false,
|
|
281
|
+
throttlingReason: undefined
|
|
282
|
+
}))
|
|
283
|
+
}, [])
|
|
284
|
+
|
|
285
|
+
return {
|
|
286
|
+
// Metrics
|
|
287
|
+
metrics,
|
|
288
|
+
|
|
289
|
+
// Controls
|
|
290
|
+
startMonitoring,
|
|
291
|
+
stopMonitoring,
|
|
292
|
+
isMonitoring,
|
|
293
|
+
|
|
294
|
+
// Throttling
|
|
295
|
+
throttlingEnabled: metrics.throttlingEnabled,
|
|
296
|
+
throttlingReason: metrics.throttlingReason,
|
|
297
|
+
enableThrottlingMode,
|
|
298
|
+
disableThrottlingMode,
|
|
299
|
+
|
|
300
|
+
// Performance mode
|
|
301
|
+
performanceMode: metrics.performanceMode,
|
|
302
|
+
|
|
303
|
+
// Recommendations
|
|
304
|
+
getOptimizationRecommendations,
|
|
305
|
+
|
|
306
|
+
// Thresholds
|
|
307
|
+
thresholds: finalThresholds,
|
|
308
|
+
|
|
309
|
+
// Raw values for advanced usage
|
|
310
|
+
fps: metrics.fps,
|
|
311
|
+
frameTime: metrics.frameTime,
|
|
312
|
+
memoryUsage: metrics.memoryUsage,
|
|
313
|
+
batteryLevel: metrics.batteryLevel,
|
|
314
|
+
isLowPowerMode: metrics.isLowPowerMode
|
|
315
|
+
}
|
|
316
|
+
}
|