@rakeyshgidwani/roger-ui-bank-theme-stan-design 0.1.4 → 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,393 @@
|
|
|
1
|
+
import { useState, useCallback, useRef, useEffect } from 'react'
|
|
2
|
+
|
|
3
|
+
export interface TransitionConfig {
|
|
4
|
+
duration?: number
|
|
5
|
+
easing?: 'ease-out' | 'ease-in' | 'ease-in-out' | 'ease-out-quint' | 'ease-in-quint' | 'ease-in-out-quint' | 'ease-out-expo' | 'ease-in-expo' | 'ease-in-out-expo' | 'ease-out-circ' | 'ease-in-circ' | 'ease-in-out-circ'
|
|
6
|
+
delay?: number
|
|
7
|
+
performance?: boolean
|
|
8
|
+
deviceOptimization?: boolean
|
|
9
|
+
accessibility?: boolean
|
|
10
|
+
batteryAware?: boolean
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface TransitionState {
|
|
14
|
+
isTransitioning: boolean
|
|
15
|
+
currentEasing: string
|
|
16
|
+
currentDuration: number
|
|
17
|
+
currentDelay: number
|
|
18
|
+
performanceScore: number
|
|
19
|
+
deviceType: 'mobile' | 'tablet' | 'desktop'
|
|
20
|
+
batteryLevel: 'normal' | 'low' | 'critical'
|
|
21
|
+
reducedMotion: boolean
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface TransitionPerformanceMetrics {
|
|
25
|
+
frameRate: number
|
|
26
|
+
memoryUsage: number
|
|
27
|
+
transitionTime: number
|
|
28
|
+
smoothness: number
|
|
29
|
+
batteryImpact: number
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface AdvancedTransitionSystemCallbacks {
|
|
33
|
+
onTransitionStart?: (config: TransitionConfig) => void
|
|
34
|
+
onTransitionComplete?: (duration: number) => void
|
|
35
|
+
onPerformanceOptimized?: (metrics: TransitionPerformanceMetrics) => void
|
|
36
|
+
onDeviceOptimized?: (deviceType: string) => void
|
|
37
|
+
onAccessibilityEnhanced?: (feature: string) => void
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export const useAdvancedTransitionSystem = (
|
|
41
|
+
config: TransitionConfig = {},
|
|
42
|
+
callbacks: AdvancedTransitionSystemCallbacks = {}
|
|
43
|
+
) => {
|
|
44
|
+
const {
|
|
45
|
+
duration = 300,
|
|
46
|
+
easing = 'ease-out',
|
|
47
|
+
delay = 0,
|
|
48
|
+
performance: enablePerformance = true,
|
|
49
|
+
deviceOptimization = true,
|
|
50
|
+
accessibility = true,
|
|
51
|
+
batteryAware = true
|
|
52
|
+
} = config
|
|
53
|
+
|
|
54
|
+
const [transitionState, setTransitionState] = useState<TransitionState>({
|
|
55
|
+
isTransitioning: false,
|
|
56
|
+
currentEasing: easing,
|
|
57
|
+
currentDuration: duration,
|
|
58
|
+
currentDelay: delay,
|
|
59
|
+
performanceScore: 0,
|
|
60
|
+
deviceType: 'desktop',
|
|
61
|
+
batteryLevel: 'normal',
|
|
62
|
+
reducedMotion: false
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
const [performanceMetrics, setPerformanceMetrics] = useState<TransitionPerformanceMetrics>({
|
|
66
|
+
frameRate: 60,
|
|
67
|
+
memoryUsage: 0,
|
|
68
|
+
transitionTime: 0,
|
|
69
|
+
smoothness: 0,
|
|
70
|
+
batteryImpact: 0
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
const [isOptimizing, setIsOptimizing] = useState(false)
|
|
74
|
+
const [optimizations, setOptimizations] = useState<string[]>([])
|
|
75
|
+
|
|
76
|
+
const transitionStartTimeRef = useRef(0)
|
|
77
|
+
const frameCountRef = useRef(0)
|
|
78
|
+
const lastFrameTimeRef = useRef(0)
|
|
79
|
+
const performanceTimerRef = useRef<number | null>(null)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
// Detect device type and optimize transitions accordingly
|
|
83
|
+
const detectDeviceType = useCallback(() => {
|
|
84
|
+
const width = window.innerWidth
|
|
85
|
+
|
|
86
|
+
let deviceType: TransitionState['deviceType'] = 'desktop'
|
|
87
|
+
|
|
88
|
+
if (width <= 480) {
|
|
89
|
+
deviceType = 'mobile'
|
|
90
|
+
} else if (width <= 768) {
|
|
91
|
+
deviceType = 'tablet'
|
|
92
|
+
} else {
|
|
93
|
+
deviceType = 'desktop'
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
setTransitionState(prev => ({
|
|
97
|
+
...prev,
|
|
98
|
+
deviceType
|
|
99
|
+
}))
|
|
100
|
+
|
|
101
|
+
return deviceType
|
|
102
|
+
}, [])
|
|
103
|
+
|
|
104
|
+
// Detect reduced motion preference
|
|
105
|
+
const detectReducedMotion = useCallback(() => {
|
|
106
|
+
const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches
|
|
107
|
+
|
|
108
|
+
setTransitionState(prev => ({
|
|
109
|
+
...prev,
|
|
110
|
+
reducedMotion: prefersReducedMotion
|
|
111
|
+
}))
|
|
112
|
+
|
|
113
|
+
return prefersReducedMotion
|
|
114
|
+
}, [])
|
|
115
|
+
|
|
116
|
+
// Simulate battery level detection (in real app, use Battery API)
|
|
117
|
+
const detectBatteryLevel = useCallback(() => {
|
|
118
|
+
// Simulate battery levels for demo purposes
|
|
119
|
+
const batteryLevels = ['normal', 'low', 'critical'] as const
|
|
120
|
+
const randomLevel = batteryLevels[Math.floor(Math.random() * batteryLevels.length)]
|
|
121
|
+
|
|
122
|
+
setTransitionState(prev => ({
|
|
123
|
+
...prev,
|
|
124
|
+
batteryLevel: randomLevel
|
|
125
|
+
}))
|
|
126
|
+
|
|
127
|
+
return randomLevel
|
|
128
|
+
}, [])
|
|
129
|
+
|
|
130
|
+
// Optimize transition duration based on device and battery
|
|
131
|
+
const optimizeTransitionDuration = useCallback((baseDuration: number) => {
|
|
132
|
+
let optimizedDuration = baseDuration
|
|
133
|
+
|
|
134
|
+
// Device-specific optimization
|
|
135
|
+
if (deviceOptimization) {
|
|
136
|
+
switch (transitionState.deviceType) {
|
|
137
|
+
case 'mobile':
|
|
138
|
+
optimizedDuration = Math.min(baseDuration, 200)
|
|
139
|
+
break
|
|
140
|
+
case 'tablet':
|
|
141
|
+
optimizedDuration = Math.min(baseDuration, 300)
|
|
142
|
+
break
|
|
143
|
+
case 'desktop':
|
|
144
|
+
optimizedDuration = baseDuration
|
|
145
|
+
break
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Battery-aware optimization
|
|
150
|
+
if (batteryAware) {
|
|
151
|
+
switch (transitionState.batteryLevel) {
|
|
152
|
+
case 'low':
|
|
153
|
+
optimizedDuration = Math.min(optimizedDuration, 150)
|
|
154
|
+
break
|
|
155
|
+
case 'critical':
|
|
156
|
+
optimizedDuration = Math.min(optimizedDuration, 100)
|
|
157
|
+
break
|
|
158
|
+
case 'normal':
|
|
159
|
+
default:
|
|
160
|
+
break
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// Reduced motion optimization
|
|
165
|
+
if (transitionState.reducedMotion) {
|
|
166
|
+
optimizedDuration = 0
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
return optimizedDuration
|
|
170
|
+
}, [deviceOptimization, batteryAware, transitionState.deviceType, transitionState.batteryLevel, transitionState.reducedMotion])
|
|
171
|
+
|
|
172
|
+
// Start a transition with optimization
|
|
173
|
+
const startTransition = useCallback((customConfig?: Partial<TransitionConfig>) => {
|
|
174
|
+
const finalConfig = { ...config, ...customConfig }
|
|
175
|
+
const optimizedDuration = optimizeTransitionDuration(finalConfig.duration || duration)
|
|
176
|
+
|
|
177
|
+
setTransitionState(prev => ({
|
|
178
|
+
...prev,
|
|
179
|
+
isTransitioning: true,
|
|
180
|
+
currentDuration: optimizedDuration,
|
|
181
|
+
currentDelay: finalConfig.delay || delay,
|
|
182
|
+
currentEasing: finalConfig.easing || easing
|
|
183
|
+
}))
|
|
184
|
+
|
|
185
|
+
transitionStartTimeRef.current = performance.now()
|
|
186
|
+
frameCountRef.current = 0
|
|
187
|
+
lastFrameTimeRef.current = performance.now()
|
|
188
|
+
|
|
189
|
+
callbacks.onTransitionStart?.(finalConfig)
|
|
190
|
+
|
|
191
|
+
// Complete transition after duration
|
|
192
|
+
setTimeout(() => {
|
|
193
|
+
setTransitionState(prev => ({
|
|
194
|
+
...prev,
|
|
195
|
+
isTransitioning: false
|
|
196
|
+
}))
|
|
197
|
+
|
|
198
|
+
const actualDuration = performance.now() - transitionStartTimeRef.current
|
|
199
|
+
callbacks.onTransitionComplete?.(actualDuration)
|
|
200
|
+
}, optimizedDuration + (finalConfig.delay || delay))
|
|
201
|
+
}, [config, duration, delay, easing, optimizeTransitionDuration, callbacks])
|
|
202
|
+
|
|
203
|
+
// Performance monitoring
|
|
204
|
+
const startPerformanceMonitoring = useCallback(() => {
|
|
205
|
+
if (!enablePerformance) return () => {}
|
|
206
|
+
|
|
207
|
+
const measurePerformance = () => {
|
|
208
|
+
const currentTime = performance.now()
|
|
209
|
+
const deltaTime = currentTime - lastFrameTimeRef.current
|
|
210
|
+
|
|
211
|
+
if (deltaTime > 0) {
|
|
212
|
+
frameCountRef.current++
|
|
213
|
+
const currentFrameRate = 1000 / deltaTime
|
|
214
|
+
|
|
215
|
+
// Calculate smoothness based on frame rate consistency
|
|
216
|
+
const smoothness = Math.max(0, 100 - Math.abs(currentFrameRate - 60))
|
|
217
|
+
|
|
218
|
+
// Simulate memory usage (in real app, use Performance API)
|
|
219
|
+
const memoryUsage = Math.random() * 100
|
|
220
|
+
|
|
221
|
+
// Calculate transition time if transitioning
|
|
222
|
+
const transitionTime = transitionState.isTransitioning
|
|
223
|
+
? currentTime - transitionStartTimeRef.current
|
|
224
|
+
: 0
|
|
225
|
+
|
|
226
|
+
// Calculate battery impact based on performance
|
|
227
|
+
const batteryImpact = Math.max(0, 100 - (currentFrameRate * 0.5) - memoryUsage * 0.3)
|
|
228
|
+
|
|
229
|
+
setPerformanceMetrics({
|
|
230
|
+
frameRate: Math.round(currentFrameRate),
|
|
231
|
+
memoryUsage: Math.round(memoryUsage),
|
|
232
|
+
transitionTime: Math.round(transitionTime),
|
|
233
|
+
smoothness: Math.round(smoothness),
|
|
234
|
+
batteryImpact: Math.round(batteryImpact)
|
|
235
|
+
})
|
|
236
|
+
|
|
237
|
+
// Update performance score
|
|
238
|
+
const overallScore = Math.round((smoothness + batteryImpact) / 2)
|
|
239
|
+
setTransitionState(prev => ({
|
|
240
|
+
...prev,
|
|
241
|
+
performanceScore: overallScore
|
|
242
|
+
}))
|
|
243
|
+
|
|
244
|
+
lastFrameTimeRef.current = currentTime
|
|
245
|
+
|
|
246
|
+
callbacks.onPerformanceOptimized?.({
|
|
247
|
+
frameRate: Math.round(currentFrameRate),
|
|
248
|
+
memoryUsage: Math.round(memoryUsage),
|
|
249
|
+
transitionTime: Math.round(transitionTime),
|
|
250
|
+
smoothness: Math.round(smoothness),
|
|
251
|
+
batteryImpact: Math.round(batteryImpact)
|
|
252
|
+
})
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
performanceTimerRef.current = requestAnimationFrame(measurePerformance)
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
performanceTimerRef.current = requestAnimationFrame(measurePerformance)
|
|
259
|
+
|
|
260
|
+
return () => {
|
|
261
|
+
if (performanceTimerRef.current) {
|
|
262
|
+
cancelAnimationFrame(performanceTimerRef.current)
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
}, [performance, transitionState.isTransitioning, callbacks])
|
|
266
|
+
|
|
267
|
+
// Device optimization
|
|
268
|
+
const optimizeForDevice = useCallback(() => {
|
|
269
|
+
if (!deviceOptimization) return
|
|
270
|
+
|
|
271
|
+
const deviceType = detectDeviceType()
|
|
272
|
+
const optimizations: string[] = []
|
|
273
|
+
|
|
274
|
+
switch (deviceType) {
|
|
275
|
+
case 'mobile':
|
|
276
|
+
optimizations.push('Mobile-optimized transitions (200ms max)')
|
|
277
|
+
optimizations.push('Reduced animation complexity')
|
|
278
|
+
optimizations.push('Touch-friendly timing')
|
|
279
|
+
break
|
|
280
|
+
case 'tablet':
|
|
281
|
+
optimizations.push('Tablet-optimized transitions (300ms max)')
|
|
282
|
+
optimizations.push('Balanced performance and smoothness')
|
|
283
|
+
break
|
|
284
|
+
case 'desktop':
|
|
285
|
+
optimizations.push('Desktop-optimized transitions (full duration)')
|
|
286
|
+
optimizations.push('Maximum visual quality')
|
|
287
|
+
break
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
setOptimizations(prev => [...prev, ...optimizations])
|
|
291
|
+
callbacks.onDeviceOptimized?.(deviceType)
|
|
292
|
+
}, [deviceOptimization, detectDeviceType, callbacks])
|
|
293
|
+
|
|
294
|
+
// Accessibility enhancement
|
|
295
|
+
const enhanceAccessibility = useCallback(() => {
|
|
296
|
+
if (!accessibility) return
|
|
297
|
+
|
|
298
|
+
const enhancements = [
|
|
299
|
+
'Reduced motion support',
|
|
300
|
+
'Screen reader compatibility',
|
|
301
|
+
'Focus management during transitions',
|
|
302
|
+
'ARIA transition states',
|
|
303
|
+
'Keyboard navigation support'
|
|
304
|
+
]
|
|
305
|
+
|
|
306
|
+
enhancements.forEach(enhancement => {
|
|
307
|
+
callbacks.onAccessibilityEnhanced?.(enhancement)
|
|
308
|
+
})
|
|
309
|
+
}, [accessibility, callbacks])
|
|
310
|
+
|
|
311
|
+
// Auto-optimize on mount
|
|
312
|
+
const autoOptimize = useCallback(() => {
|
|
313
|
+
setIsOptimizing(true)
|
|
314
|
+
|
|
315
|
+
setTimeout(() => {
|
|
316
|
+
detectDeviceType()
|
|
317
|
+
detectReducedMotion()
|
|
318
|
+
detectBatteryLevel()
|
|
319
|
+
optimizeForDevice()
|
|
320
|
+
enhanceAccessibility()
|
|
321
|
+
|
|
322
|
+
setIsOptimizing(false)
|
|
323
|
+
}, 200)
|
|
324
|
+
}, [detectDeviceType, detectReducedMotion, detectBatteryLevel, optimizeForDevice, enhanceAccessibility])
|
|
325
|
+
|
|
326
|
+
// Initialize on mount
|
|
327
|
+
useEffect(() => {
|
|
328
|
+
autoOptimize()
|
|
329
|
+
|
|
330
|
+
const stopPerformanceMonitoring = startPerformanceMonitoring()
|
|
331
|
+
|
|
332
|
+
// Listen for device changes
|
|
333
|
+
const handleResize = () => {
|
|
334
|
+
detectDeviceType()
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
// Listen for reduced motion changes
|
|
338
|
+
const mediaQuery = window.matchMedia('(prefers-reduced-motion: reduce)')
|
|
339
|
+
const handleMotionChange = () => {
|
|
340
|
+
detectReducedMotion()
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
window.addEventListener('resize', handleResize)
|
|
344
|
+
mediaQuery.addEventListener('change', handleMotionChange)
|
|
345
|
+
|
|
346
|
+
return () => {
|
|
347
|
+
stopPerformanceMonitoring()
|
|
348
|
+
window.removeEventListener('resize', handleResize)
|
|
349
|
+
mediaQuery.removeEventListener('change', handleMotionChange)
|
|
350
|
+
}
|
|
351
|
+
}, [autoOptimize, startPerformanceMonitoring, detectDeviceType, detectReducedMotion])
|
|
352
|
+
|
|
353
|
+
// Cleanup on unmount
|
|
354
|
+
useEffect(() => {
|
|
355
|
+
return () => {
|
|
356
|
+
if (performanceTimerRef.current) {
|
|
357
|
+
cancelAnimationFrame(performanceTimerRef.current)
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
}, [])
|
|
361
|
+
|
|
362
|
+
return {
|
|
363
|
+
// State
|
|
364
|
+
transitionState,
|
|
365
|
+
performanceMetrics,
|
|
366
|
+
isOptimizing,
|
|
367
|
+
optimizations,
|
|
368
|
+
|
|
369
|
+
// Functions
|
|
370
|
+
startTransition,
|
|
371
|
+
optimizeForDevice,
|
|
372
|
+
enhanceAccessibility,
|
|
373
|
+
startPerformanceMonitoring,
|
|
374
|
+
autoOptimize,
|
|
375
|
+
|
|
376
|
+
// Utility functions
|
|
377
|
+
getTransitionDuration: () => transitionState.currentDuration,
|
|
378
|
+
getTransitionEasing: () => transitionState.currentEasing,
|
|
379
|
+
getTransitionDelay: () => transitionState.currentDelay,
|
|
380
|
+
isTransitionActive: () => transitionState.isTransitioning,
|
|
381
|
+
getDeviceType: () => transitionState.deviceType,
|
|
382
|
+
getBatteryLevel: () => transitionState.batteryLevel,
|
|
383
|
+
getReducedMotion: () => transitionState.reducedMotion,
|
|
384
|
+
getPerformanceScore: () => transitionState.performanceScore,
|
|
385
|
+
isPerformanceOptimal: () => transitionState.performanceScore >= 80,
|
|
386
|
+
getFrameRate: () => performanceMetrics.frameRate,
|
|
387
|
+
getSmoothness: () => performanceMetrics.smoothness,
|
|
388
|
+
getBatteryImpact: () => performanceMetrics.batteryImpact,
|
|
389
|
+
clearOptimizations: () => setOptimizations([])
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
export default useAdvancedTransitionSystem
|
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
import { useState, useEffect, useCallback, useMemo } from 'react'
|
|
2
|
+
import { useDevice } from './use-device'
|
|
3
|
+
|
|
4
|
+
export interface AnimationProfile {
|
|
5
|
+
duration: {
|
|
6
|
+
fast: string
|
|
7
|
+
normal: string
|
|
8
|
+
slow: string
|
|
9
|
+
}
|
|
10
|
+
easing: {
|
|
11
|
+
ease: string
|
|
12
|
+
easeIn: string
|
|
13
|
+
easeOut: string
|
|
14
|
+
easeInOut: string
|
|
15
|
+
bounce: string
|
|
16
|
+
}
|
|
17
|
+
performance: {
|
|
18
|
+
mode: 'high' | 'medium' | 'low'
|
|
19
|
+
batteryOptimized: boolean
|
|
20
|
+
reducedMotion: boolean
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface PerformanceMetrics {
|
|
25
|
+
fps: number
|
|
26
|
+
memoryUsage?: number
|
|
27
|
+
batteryLevel?: number
|
|
28
|
+
isLowPowerMode?: boolean
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export const useAnimationProfile = () => {
|
|
32
|
+
const deviceInfo = useDevice()
|
|
33
|
+
const [performanceMetrics, setPerformanceMetrics] = useState<PerformanceMetrics>({
|
|
34
|
+
fps: 60,
|
|
35
|
+
memoryUsage: undefined,
|
|
36
|
+
batteryLevel: undefined,
|
|
37
|
+
isLowPowerMode: false
|
|
38
|
+
})
|
|
39
|
+
const [isReducedMotion, setIsReducedMotion] = useState(false)
|
|
40
|
+
|
|
41
|
+
// Check for reduced motion preference
|
|
42
|
+
useEffect(() => {
|
|
43
|
+
const checkReducedMotion = () => {
|
|
44
|
+
if (typeof window !== 'undefined' && window.matchMedia) {
|
|
45
|
+
const reducedMotionQuery = window.matchMedia('(prefers-reduced-motion: reduce)')
|
|
46
|
+
setIsReducedMotion(reducedMotionQuery.matches)
|
|
47
|
+
|
|
48
|
+
reducedMotionQuery.addEventListener('change', (e) => {
|
|
49
|
+
setIsReducedMotion(e.matches)
|
|
50
|
+
})
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
checkReducedMotion()
|
|
55
|
+
}, [])
|
|
56
|
+
|
|
57
|
+
// Monitor frame rate
|
|
58
|
+
useEffect(() => {
|
|
59
|
+
let frameCount = 0
|
|
60
|
+
let lastTime = performance.now()
|
|
61
|
+
let animationId: number
|
|
62
|
+
|
|
63
|
+
const measureFPS = () => {
|
|
64
|
+
frameCount++
|
|
65
|
+
const currentTime = performance.now()
|
|
66
|
+
|
|
67
|
+
if (currentTime - lastTime >= 1000) {
|
|
68
|
+
const fps = Math.round((frameCount * 1000) / (currentTime - lastTime))
|
|
69
|
+
setPerformanceMetrics(prev => ({ ...prev, fps }))
|
|
70
|
+
frameCount = 0
|
|
71
|
+
lastTime = currentTime
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
animationId = requestAnimationFrame(measureFPS)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
animationId = requestAnimationFrame(measureFPS)
|
|
78
|
+
|
|
79
|
+
return () => {
|
|
80
|
+
if (animationId) {
|
|
81
|
+
cancelAnimationFrame(animationId)
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}, [])
|
|
85
|
+
|
|
86
|
+
// Monitor memory usage (if available)
|
|
87
|
+
useEffect(() => {
|
|
88
|
+
const updateMemoryInfo = () => {
|
|
89
|
+
if ('memory' in performance) {
|
|
90
|
+
const memory = (performance as any).memory
|
|
91
|
+
setPerformanceMetrics(prev => ({
|
|
92
|
+
...prev,
|
|
93
|
+
memoryUsage: memory.usedJSHeapSize / memory.jsHeapSizeLimit
|
|
94
|
+
}))
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const interval = setInterval(updateMemoryInfo, 5000)
|
|
99
|
+
updateMemoryInfo()
|
|
100
|
+
|
|
101
|
+
return () => clearInterval(interval)
|
|
102
|
+
}, [])
|
|
103
|
+
|
|
104
|
+
// Monitor battery status (if available)
|
|
105
|
+
useEffect(() => {
|
|
106
|
+
const updateBatteryInfo = async () => {
|
|
107
|
+
if ('getBattery' in navigator) {
|
|
108
|
+
try {
|
|
109
|
+
const battery = await (navigator as any).getBattery()
|
|
110
|
+
setPerformanceMetrics(prev => ({
|
|
111
|
+
...prev,
|
|
112
|
+
batteryLevel: battery.level,
|
|
113
|
+
isLowPowerMode: battery.level < 0.2
|
|
114
|
+
}))
|
|
115
|
+
|
|
116
|
+
battery.addEventListener('levelchange', () => {
|
|
117
|
+
setPerformanceMetrics(prev => ({
|
|
118
|
+
...prev,
|
|
119
|
+
batteryLevel: battery.level,
|
|
120
|
+
isLowPowerMode: battery.level < 0.2
|
|
121
|
+
}))
|
|
122
|
+
})
|
|
123
|
+
} catch (error) {
|
|
124
|
+
console.warn('Battery API not available:', error)
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
updateBatteryInfo()
|
|
130
|
+
}, [])
|
|
131
|
+
|
|
132
|
+
// Determine performance mode based on metrics
|
|
133
|
+
const performanceMode = useMemo(() => {
|
|
134
|
+
if (performanceMetrics.fps < 30) return 'low'
|
|
135
|
+
if (performanceMetrics.fps < 50) return 'medium'
|
|
136
|
+
return 'high'
|
|
137
|
+
}, [performanceMetrics.fps])
|
|
138
|
+
|
|
139
|
+
// Determine if battery optimization should be enabled
|
|
140
|
+
const shouldOptimizeForBattery = useMemo(() => {
|
|
141
|
+
return (
|
|
142
|
+
performanceMetrics.isLowPowerMode ||
|
|
143
|
+
(performanceMetrics.batteryLevel !== undefined && performanceMetrics.batteryLevel < 0.3) ||
|
|
144
|
+
performanceMode === 'low'
|
|
145
|
+
)
|
|
146
|
+
}, [performanceMetrics.isLowPowerMode, performanceMetrics.batteryLevel, performanceMode])
|
|
147
|
+
|
|
148
|
+
// Get device-specific animation profile
|
|
149
|
+
const getAnimationProfile = useCallback((): AnimationProfile => {
|
|
150
|
+
const baseProfile: AnimationProfile = {
|
|
151
|
+
duration: {
|
|
152
|
+
fast: '0.15s',
|
|
153
|
+
normal: '0.3s',
|
|
154
|
+
slow: '0.5s'
|
|
155
|
+
},
|
|
156
|
+
easing: {
|
|
157
|
+
ease: 'ease',
|
|
158
|
+
easeIn: 'ease-in',
|
|
159
|
+
easeOut: 'ease-out',
|
|
160
|
+
easeInOut: 'ease-in-out',
|
|
161
|
+
bounce: 'cubic-bezier(0.68, -0.55, 0.265, 1.55)'
|
|
162
|
+
},
|
|
163
|
+
performance: {
|
|
164
|
+
mode: performanceMode,
|
|
165
|
+
batteryOptimized: shouldOptimizeForBattery,
|
|
166
|
+
reducedMotion: isReducedMotion
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Apply device-specific optimizations
|
|
171
|
+
if (deviceInfo.isMobile) {
|
|
172
|
+
baseProfile.duration.fast = '0.1s'
|
|
173
|
+
baseProfile.duration.normal = '0.2s'
|
|
174
|
+
baseProfile.duration.slow = '0.3s'
|
|
175
|
+
} else if (deviceInfo.isTablet) {
|
|
176
|
+
baseProfile.duration.fast = '0.15s'
|
|
177
|
+
baseProfile.duration.normal = '0.25s'
|
|
178
|
+
baseProfile.duration.slow = '0.4s'
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// Apply performance-based optimizations
|
|
182
|
+
if (performanceMode === 'low' || shouldOptimizeForBattery) {
|
|
183
|
+
baseProfile.duration.fast = '0.05s'
|
|
184
|
+
baseProfile.duration.normal = '0.1s'
|
|
185
|
+
baseProfile.duration.slow = '0.15s'
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// Apply reduced motion preferences
|
|
189
|
+
if (isReducedMotion) {
|
|
190
|
+
baseProfile.duration.fast = '0.01s'
|
|
191
|
+
baseProfile.duration.normal = '0.01s'
|
|
192
|
+
baseProfile.duration.slow = '0.01s'
|
|
193
|
+
baseProfile.easing.ease = 'linear'
|
|
194
|
+
baseProfile.easing.easeIn = 'linear'
|
|
195
|
+
baseProfile.easing.easeOut = 'linear'
|
|
196
|
+
baseProfile.easing.easeInOut = 'linear'
|
|
197
|
+
baseProfile.easing.bounce = 'linear'
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
return baseProfile
|
|
201
|
+
}, [deviceInfo.isMobile, deviceInfo.isTablet, performanceMode, shouldOptimizeForBattery, isReducedMotion])
|
|
202
|
+
|
|
203
|
+
// Get CSS classes for the current animation profile
|
|
204
|
+
const getAnimationClasses = useCallback(() => {
|
|
205
|
+
const profile = getAnimationProfile()
|
|
206
|
+
const classes = []
|
|
207
|
+
|
|
208
|
+
// Device-specific classes
|
|
209
|
+
if (deviceInfo.isMobile) {
|
|
210
|
+
classes.push('coach-stan-mobile-animation')
|
|
211
|
+
} else if (deviceInfo.isTablet) {
|
|
212
|
+
classes.push('coach-stan-tablet-animation')
|
|
213
|
+
} else {
|
|
214
|
+
classes.push('coach-stan-desktop-animation')
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// Performance-based classes
|
|
218
|
+
if (profile.performance.mode === 'low' || profile.performance.batteryOptimized) {
|
|
219
|
+
classes.push('coach-stan-performance-mode')
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
if (profile.performance.batteryOptimized) {
|
|
223
|
+
classes.push('coach-stan-battery-saver')
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// Reduced motion classes
|
|
227
|
+
if (profile.performance.reducedMotion) {
|
|
228
|
+
classes.push('reduced-motion')
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
return classes.join(' ')
|
|
232
|
+
}, [deviceInfo.isMobile, deviceInfo.isTablet, getAnimationProfile])
|
|
233
|
+
|
|
234
|
+
// Get optimized duration for specific use case
|
|
235
|
+
const getOptimizedDuration = useCallback((type: 'fast' | 'normal' | 'slow' = 'normal') => {
|
|
236
|
+
const profile = getAnimationProfile()
|
|
237
|
+
return profile.duration[type]
|
|
238
|
+
}, [getAnimationProfile])
|
|
239
|
+
|
|
240
|
+
// Get optimized easing for specific use case
|
|
241
|
+
const getOptimizedEasing = useCallback((type: keyof AnimationProfile['easing'] = 'ease') => {
|
|
242
|
+
const profile = getAnimationProfile()
|
|
243
|
+
return profile.easing[type]
|
|
244
|
+
}, [getAnimationProfile])
|
|
245
|
+
|
|
246
|
+
// Check if animations should be disabled
|
|
247
|
+
const shouldDisableAnimations = useCallback(() => {
|
|
248
|
+
return (
|
|
249
|
+
isReducedMotion ||
|
|
250
|
+
performanceMode === 'low' ||
|
|
251
|
+
shouldOptimizeForBattery
|
|
252
|
+
)
|
|
253
|
+
}, [isReducedMotion, performanceMode, shouldOptimizeForBattery])
|
|
254
|
+
|
|
255
|
+
return {
|
|
256
|
+
profile: getAnimationProfile(),
|
|
257
|
+
performanceMetrics,
|
|
258
|
+
deviceInfo,
|
|
259
|
+
getAnimationClasses,
|
|
260
|
+
getOptimizedDuration,
|
|
261
|
+
getOptimizedEasing,
|
|
262
|
+
shouldDisableAnimations,
|
|
263
|
+
isReducedMotion,
|
|
264
|
+
performanceMode,
|
|
265
|
+
shouldOptimizeForBattery
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// Convenience hooks for specific use cases
|
|
270
|
+
export const useAnimationDuration = (type: 'fast' | 'normal' | 'slow' = 'normal') => {
|
|
271
|
+
const { getOptimizedDuration } = useAnimationProfile()
|
|
272
|
+
return getOptimizedDuration(type)
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
export const useAnimationEasing = (type: keyof AnimationProfile['easing'] = 'ease') => {
|
|
276
|
+
const { getOptimizedEasing } = useAnimationProfile()
|
|
277
|
+
return getOptimizedEasing(type)
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
export const useAnimationClasses = () => {
|
|
281
|
+
const { getAnimationClasses } = useAnimationProfile()
|
|
282
|
+
return getAnimationClasses()
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
export const usePerformanceMode = () => {
|
|
286
|
+
const { performanceMode, shouldOptimizeForBattery } = useAnimationProfile()
|
|
287
|
+
return { performanceMode, shouldOptimizeForBattery }
|
|
288
|
+
}
|