@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.
Files changed (164) hide show
  1. package/CHANGELOG.md +1 -1
  2. package/dist/index.d.ts +131 -131
  3. package/dist/index.esm.js +148 -148
  4. package/dist/index.js +148 -148
  5. package/dist/styles.css +1 -1
  6. package/package.json +1 -1
  7. package/src/components/ui/accessibility-demo.tsx +271 -0
  8. package/src/components/ui/advanced-component-architecture-demo.tsx +916 -0
  9. package/src/components/ui/advanced-transition-system-demo.tsx +670 -0
  10. package/src/components/ui/advanced-transition-system.tsx +395 -0
  11. package/src/components/ui/animation/animated-container.tsx +166 -0
  12. package/src/components/ui/animation/index.ts +19 -0
  13. package/src/components/ui/animation/staggered-container.tsx +68 -0
  14. package/src/components/ui/animation-demo.tsx +250 -0
  15. package/src/components/ui/badge.tsx +33 -0
  16. package/src/components/ui/battery-conscious-animation-demo.tsx +568 -0
  17. package/src/components/ui/border-radius-shadow-demo.tsx +187 -0
  18. package/src/components/ui/button.tsx +36 -0
  19. package/src/components/ui/card.tsx +207 -0
  20. package/src/components/ui/checkbox.tsx +30 -0
  21. package/src/components/ui/color-preview.tsx +411 -0
  22. package/src/components/ui/data-display/chart.tsx +653 -0
  23. package/src/components/ui/data-display/data-grid-simple.tsx +76 -0
  24. package/src/components/ui/data-display/data-grid.tsx +680 -0
  25. package/src/components/ui/data-display/list.tsx +456 -0
  26. package/src/components/ui/data-display/table.tsx +482 -0
  27. package/src/components/ui/data-display/timeline.tsx +441 -0
  28. package/src/components/ui/data-display/tree.tsx +602 -0
  29. package/src/components/ui/data-display/types.ts +536 -0
  30. package/src/components/ui/enterprise-mobile-experience-demo.tsx +749 -0
  31. package/src/components/ui/enterprise-mobile-experience.tsx +464 -0
  32. package/src/components/ui/feedback/alert.tsx +157 -0
  33. package/src/components/ui/feedback/progress.tsx +292 -0
  34. package/src/components/ui/feedback/skeleton.tsx +185 -0
  35. package/src/components/ui/feedback/toast.tsx +280 -0
  36. package/src/components/ui/feedback/types.ts +125 -0
  37. package/src/components/ui/font-preview.tsx +288 -0
  38. package/src/components/ui/form-demo.tsx +553 -0
  39. package/src/components/ui/hardware-acceleration-demo.tsx +547 -0
  40. package/src/components/ui/input.tsx +35 -0
  41. package/src/components/ui/label.tsx +16 -0
  42. package/src/components/ui/layout-demo.tsx +367 -0
  43. package/src/components/ui/layouts/adaptive-layout.tsx +139 -0
  44. package/src/components/ui/layouts/desktop-layout.tsx +224 -0
  45. package/src/components/ui/layouts/index.ts +10 -0
  46. package/src/components/ui/layouts/mobile-layout.tsx +162 -0
  47. package/src/components/ui/layouts/tablet-layout.tsx +197 -0
  48. package/src/components/ui/mobile-form-validation.tsx +451 -0
  49. package/src/components/ui/mobile-input-demo.tsx +201 -0
  50. package/src/components/ui/mobile-input.tsx +281 -0
  51. package/src/components/ui/mobile-skeleton-loading-demo.tsx +638 -0
  52. package/src/components/ui/navigation/breadcrumb.tsx +158 -0
  53. package/src/components/ui/navigation/index.ts +36 -0
  54. package/src/components/ui/navigation/menu.tsx +374 -0
  55. package/src/components/ui/navigation/navigation-demo.tsx +324 -0
  56. package/src/components/ui/navigation/pagination.tsx +272 -0
  57. package/src/components/ui/navigation/sidebar.tsx +383 -0
  58. package/src/components/ui/navigation/stepper.tsx +303 -0
  59. package/src/components/ui/navigation/tabs.tsx +205 -0
  60. package/src/components/ui/navigation/types.ts +299 -0
  61. package/src/components/ui/overlay/backdrop.tsx +81 -0
  62. package/src/components/ui/overlay/focus-manager.tsx +143 -0
  63. package/src/components/ui/overlay/index.ts +36 -0
  64. package/src/components/ui/overlay/modal.tsx +270 -0
  65. package/src/components/ui/overlay/overlay-manager.tsx +110 -0
  66. package/src/components/ui/overlay/popover.tsx +462 -0
  67. package/src/components/ui/overlay/portal.tsx +79 -0
  68. package/src/components/ui/overlay/tooltip.tsx +303 -0
  69. package/src/components/ui/overlay/types.ts +196 -0
  70. package/src/components/ui/performance-demo.tsx +596 -0
  71. package/src/components/ui/semantic-input-system-demo.tsx +502 -0
  72. package/src/components/ui/semantic-input-system-demo.tsx.disabled +873 -0
  73. package/src/components/ui/tablet-layout.tsx +192 -0
  74. package/src/components/ui/theme-customizer.tsx +386 -0
  75. package/src/components/ui/theme-preview.tsx +310 -0
  76. package/src/components/ui/theme-switcher.tsx +264 -0
  77. package/src/components/ui/theme-toggle.tsx +38 -0
  78. package/src/components/ui/token-demo.tsx +195 -0
  79. package/src/components/ui/touch-demo.tsx +462 -0
  80. package/src/components/ui/touch-friendly-interface-demo.tsx +519 -0
  81. package/src/components/ui/touch-friendly-interface.tsx +296 -0
  82. package/src/hooks/index.ts +190 -0
  83. package/src/hooks/use-accessibility-support.ts +518 -0
  84. package/src/hooks/use-adaptive-layout.ts +289 -0
  85. package/src/hooks/use-advanced-patterns.ts +294 -0
  86. package/src/hooks/use-advanced-transition-system.ts +393 -0
  87. package/src/hooks/use-animation-profile.ts +288 -0
  88. package/src/hooks/use-battery-animations.ts +384 -0
  89. package/src/hooks/use-battery-conscious-loading.ts +475 -0
  90. package/src/hooks/use-battery-optimization.ts +330 -0
  91. package/src/hooks/use-battery-status.ts +299 -0
  92. package/src/hooks/use-component-performance.ts +344 -0
  93. package/src/hooks/use-device-loading-states.ts +459 -0
  94. package/src/hooks/use-device.tsx +110 -0
  95. package/src/hooks/use-enterprise-mobile-experience.ts +488 -0
  96. package/src/hooks/use-form-feedback.ts +403 -0
  97. package/src/hooks/use-form-performance.ts +513 -0
  98. package/src/hooks/use-frame-rate.ts +251 -0
  99. package/src/hooks/use-gestures.ts +338 -0
  100. package/src/hooks/use-hardware-acceleration.ts +341 -0
  101. package/src/hooks/use-input-accessibility.ts +455 -0
  102. package/src/hooks/use-input-performance.ts +506 -0
  103. package/src/hooks/use-layout-performance.ts +319 -0
  104. package/src/hooks/use-loading-accessibility.ts +535 -0
  105. package/src/hooks/use-loading-performance.ts +473 -0
  106. package/src/hooks/use-memory-usage.ts +287 -0
  107. package/src/hooks/use-mobile-form-layout.ts +464 -0
  108. package/src/hooks/use-mobile-form-validation.ts +518 -0
  109. package/src/hooks/use-mobile-keyboard-optimization.ts +472 -0
  110. package/src/hooks/use-mobile-layout.ts +302 -0
  111. package/src/hooks/use-mobile-optimization.ts +406 -0
  112. package/src/hooks/use-mobile-skeleton.ts +402 -0
  113. package/src/hooks/use-mobile-touch.ts +414 -0
  114. package/src/hooks/use-performance-throttling.ts +348 -0
  115. package/src/hooks/use-performance.ts +316 -0
  116. package/src/hooks/use-reusable-architecture.ts +414 -0
  117. package/src/hooks/use-semantic-input-types.ts +357 -0
  118. package/src/hooks/use-semantic-input.ts +565 -0
  119. package/src/hooks/use-tablet-layout.ts +384 -0
  120. package/src/hooks/use-touch-friendly-input.ts +524 -0
  121. package/src/hooks/use-touch-friendly-interface.ts +331 -0
  122. package/src/hooks/use-touch-optimization.ts +375 -0
  123. package/src/index.ts +279 -279
  124. package/src/lib/utils.ts +6 -0
  125. package/src/themes/README.md +272 -0
  126. package/src/themes/ThemeContext.tsx +31 -0
  127. package/src/themes/ThemeProvider.tsx +232 -0
  128. package/src/themes/accessibility/index.ts +27 -0
  129. package/src/themes/accessibility.ts +259 -0
  130. package/src/themes/aria-patterns.ts +420 -0
  131. package/src/themes/base-themes.ts +55 -0
  132. package/src/themes/colorManager.ts +380 -0
  133. package/src/themes/examples/dark-theme.ts +154 -0
  134. package/src/themes/examples/minimal-theme.ts +108 -0
  135. package/src/themes/focus-management.ts +701 -0
  136. package/src/themes/fontLoader.ts +201 -0
  137. package/src/themes/high-contrast.ts +621 -0
  138. package/src/themes/index.ts +19 -0
  139. package/src/themes/inheritance.ts +227 -0
  140. package/src/themes/keyboard-navigation.ts +550 -0
  141. package/src/themes/motion-reduction.ts +662 -0
  142. package/src/themes/navigation.ts +238 -0
  143. package/src/themes/screen-reader.ts +645 -0
  144. package/src/themes/systemThemeDetector.ts +182 -0
  145. package/src/themes/themeCSSUpdater.ts +262 -0
  146. package/src/themes/themePersistence.ts +238 -0
  147. package/src/themes/themes/default.ts +586 -0
  148. package/src/themes/themes/harvey.ts +554 -0
  149. package/src/themes/themes/stan-design.ts +683 -0
  150. package/src/themes/types.ts +460 -0
  151. package/src/themes/useSystemTheme.ts +48 -0
  152. package/src/themes/useTheme.ts +87 -0
  153. package/src/themes/validation.ts +462 -0
  154. package/src/tokens/index.ts +34 -0
  155. package/src/tokens/tokenExporter.ts +397 -0
  156. package/src/tokens/tokenGenerator.ts +276 -0
  157. package/src/tokens/tokenManager.ts +248 -0
  158. package/src/tokens/tokenValidator.ts +543 -0
  159. package/src/tokens/types.ts +78 -0
  160. package/src/utils/bundle-analyzer.ts +260 -0
  161. package/src/utils/bundle-splitting.ts +483 -0
  162. package/src/utils/lazy-loading.ts +441 -0
  163. package/src/utils/performance-monitor.ts +513 -0
  164. package/src/utils/tree-shaking.ts +274 -0
@@ -0,0 +1,662 @@
1
+ import { screenReaderOptimizer } from './screen-reader';
2
+
3
+ // Motion reduction theme configuration
4
+ export interface MotionReductionThemeConfig {
5
+ motion: {
6
+ reduced: boolean;
7
+ duration: {
8
+ fast: string;
9
+ normal: string;
10
+ slow: string;
11
+ };
12
+ easing: {
13
+ ease: string;
14
+ easeIn: string;
15
+ easeOut: string;
16
+ easeInOut: string;
17
+ };
18
+ animations: {
19
+ enabled: boolean;
20
+ type: 'none' | 'reduced' | 'full';
21
+ preferences: {
22
+ reduceMotion: boolean;
23
+ reduceAnimation: boolean;
24
+ reduceTransition: boolean;
25
+ reduceTransform: boolean;
26
+ };
27
+ };
28
+ };
29
+ }
30
+
31
+ // Motion reduction utilities
32
+ export class MotionReductionManager {
33
+ private isReducedMotion: boolean = false;
34
+ private isReducedAnimation: boolean = false;
35
+ private isReducedTransition: boolean = false;
36
+ private isReducedTransform: boolean = false;
37
+ // private motionPreferences: Set<string> = new Set(); // Unused for now
38
+ private originalStyles: Map<HTMLElement, string> = new Map();
39
+ private reducedMotionStyles: Map<HTMLElement, string> = new Map();
40
+
41
+ constructor() {
42
+ this.initializeSystemPreference();
43
+ this.setupEventListeners();
44
+ }
45
+
46
+ // Initialize system preference detection
47
+ private initializeSystemPreference(): void {
48
+ if (typeof window !== 'undefined' && window.matchMedia) {
49
+ const reducedMotionQuery = window.matchMedia('(prefers-reduced-motion: reduce)');
50
+ this.isReducedMotion = reducedMotionQuery.matches;
51
+
52
+ reducedMotionQuery.addEventListener('change', (e) => {
53
+ this.isReducedMotion = e.matches;
54
+ this.applyMotionReduction();
55
+ });
56
+ }
57
+ }
58
+
59
+ // Setup event listeners
60
+ private setupEventListeners(): void {
61
+ // Listen for preference changes
62
+ if (typeof window !== 'undefined') {
63
+ window.addEventListener('storage', (e) => {
64
+ if (e.key === 'motion-reduction-preferences') {
65
+ this.loadPreferences();
66
+ }
67
+ });
68
+ }
69
+ }
70
+
71
+ // Enable motion reduction
72
+ enable(): void {
73
+ this.isReducedMotion = true;
74
+ this.applyMotionReduction();
75
+ }
76
+
77
+ // Disable motion reduction
78
+ disable(): void {
79
+ this.isReducedMotion = false;
80
+ this.removeMotionReduction();
81
+ }
82
+
83
+ // Toggle motion reduction
84
+ toggle(): void {
85
+ if (this.isReducedMotion) {
86
+ this.disable();
87
+ } else {
88
+ this.enable();
89
+ }
90
+ }
91
+
92
+ // Check if motion reduction is enabled
93
+ isMotionReduced(): boolean {
94
+ return this.isReducedMotion;
95
+ }
96
+
97
+ // Set specific motion reduction preferences
98
+ setPreferences(preferences: {
99
+ reduceAnimation?: boolean;
100
+ reduceTransition?: boolean;
101
+ reduceTransform?: boolean;
102
+ }): void {
103
+ if (preferences.reduceAnimation !== undefined) {
104
+ this.isReducedAnimation = preferences.reduceAnimation;
105
+ }
106
+ if (preferences.reduceTransition !== undefined) {
107
+ this.isReducedTransition = preferences.reduceTransition;
108
+ }
109
+ if (preferences.reduceTransform !== undefined) {
110
+ this.isReducedTransform = preferences.reduceTransform;
111
+ }
112
+
113
+ this.savePreferences();
114
+ this.applyMotionReduction();
115
+ }
116
+
117
+ // Get current motion reduction preferences
118
+ getPreferences(): {
119
+ reduceMotion: boolean;
120
+ reduceAnimation: boolean;
121
+ reduceTransition: boolean;
122
+ reduceTransform: boolean;
123
+ } {
124
+ return {
125
+ reduceMotion: this.isReducedMotion,
126
+ reduceAnimation: this.isReducedAnimation,
127
+ reduceTransition: this.isReducedTransition,
128
+ reduceTransform: this.isReducedTransform
129
+ };
130
+ }
131
+
132
+ // Apply motion reduction to the document
133
+ applyMotionReduction(): void {
134
+ if (!this.isReducedMotion) return;
135
+
136
+ // Add reduced motion class to document
137
+ document.documentElement.classList.add('reduced-motion');
138
+
139
+ // Apply reduced motion styles
140
+ this.applyReducedMotionStyles();
141
+
142
+ // Process existing elements
143
+ this.processExistingElements();
144
+
145
+ // Announce motion reduction change
146
+ if (screenReaderOptimizer) {
147
+ screenReaderOptimizer.announceMotionChange(true);
148
+ }
149
+ }
150
+
151
+ // Remove motion reduction from the document
152
+ removeMotionReduction(): void {
153
+ // Remove reduced motion class
154
+ document.documentElement.classList.remove('reduced-motion');
155
+
156
+ // Remove reduced motion styles
157
+ this.removeReducedMotionStyles();
158
+
159
+ // Restore original styles
160
+ this.restoreOriginalStyles();
161
+
162
+ // Announce motion reduction change
163
+ if (screenReaderOptimizer) {
164
+ screenReaderOptimizer.announceMotionChange(false);
165
+ }
166
+ }
167
+
168
+ // Apply reduced motion styles
169
+ private applyReducedMotionStyles(): void {
170
+ const style = document.createElement('style');
171
+ style.id = 'reduced-motion-styles';
172
+
173
+ style.textContent = `
174
+ .reduced-motion,
175
+ .reduced-motion * {
176
+ /* Disable animations */
177
+ animation-duration: 0.01ms !important;
178
+ animation-iteration-count: 1 !important;
179
+ animation-delay: 0s !important;
180
+
181
+ /* Disable transitions */
182
+ transition-duration: 0.01ms !important;
183
+ transition-delay: 0s !important;
184
+
185
+ /* Disable transforms */
186
+ transform: none !important;
187
+
188
+ /* Disable scroll behavior */
189
+ scroll-behavior: auto !important;
190
+ }
191
+
192
+ .reduced-motion .motion-safe,
193
+ .reduced-motion *[data-motion-safe="true"] {
194
+ /* Allow safe motion for essential animations */
195
+ animation-duration: 150ms !important;
196
+ transition-duration: 150ms !important;
197
+ }
198
+
199
+ .reduced-motion .motion-reduce,
200
+ .reduced-motion *[data-motion-reduce="true"] {
201
+ /* Apply reduced motion for non-essential animations */
202
+ animation-duration: 50ms !important;
203
+ transition-duration: 50ms !important;
204
+ }
205
+
206
+ /* Specific component overrides */
207
+ .reduced-motion .modal,
208
+ .reduced-motion .tooltip,
209
+ .reduced-motion .popover {
210
+ animation: none !important;
211
+ transition: none !important;
212
+ }
213
+
214
+ .reduced-motion .skeleton {
215
+ animation: none !important;
216
+ }
217
+
218
+ .reduced-motion .progress-bar {
219
+ transition: none !important;
220
+ }
221
+
222
+ .reduced-motion .carousel,
223
+ .reduced-motion .slider {
224
+ scroll-behavior: auto !important;
225
+ }
226
+ `;
227
+
228
+ document.head.appendChild(style);
229
+ }
230
+
231
+ // Remove reduced motion styles
232
+ private removeReducedMotionStyles(): void {
233
+ const style = document.getElementById('reduced-motion-styles');
234
+ if (style) {
235
+ style.remove();
236
+ }
237
+ }
238
+
239
+ // Process existing elements
240
+ private processExistingElements(): void {
241
+ // Process elements with animations
242
+ const animatedElements = document.querySelectorAll('[class*="animate"], [class*="transition"], [class*="transform"]');
243
+ animatedElements.forEach(element => {
244
+ this.processElement(element as HTMLElement);
245
+ });
246
+
247
+ // Process elements with data attributes
248
+ const motionElements = document.querySelectorAll('[data-motion], [data-animation], [data-transition]');
249
+ motionElements.forEach(element => {
250
+ this.processElement(element as HTMLElement);
251
+ });
252
+ }
253
+
254
+ // Process individual element
255
+ private processElement(element: HTMLElement): void {
256
+ // Store original styles if not already stored
257
+ if (!this.originalStyles.has(element)) {
258
+ this.originalStyles.set(element, element.style.cssText);
259
+ }
260
+
261
+ // Apply reduced motion styles
262
+ const reducedStyles = this.getReducedMotionStyles(element);
263
+ element.style.cssText = reducedStyles;
264
+
265
+ // Store reduced styles
266
+ this.reducedMotionStyles.set(element, reducedStyles);
267
+ }
268
+
269
+ // Get reduced motion styles for element
270
+ private getReducedMotionStyles(element: HTMLElement): string {
271
+ const originalStyles = element.style.cssText;
272
+
273
+ let reducedStyles = originalStyles;
274
+
275
+ // Remove animation properties
276
+ if (this.isReducedAnimation) {
277
+ reducedStyles = reducedStyles.replace(/animation[^;]*;?/g, '');
278
+ reducedStyles += 'animation: none !important;';
279
+ }
280
+
281
+ // Remove transition properties
282
+ if (this.isReducedTransition) {
283
+ reducedStyles = reducedStyles.replace(/transition[^;]*;?/g, '');
284
+ reducedStyles += 'transition: none !important;';
285
+ }
286
+
287
+ // Remove transform properties
288
+ if (this.isReducedTransform) {
289
+ reducedStyles = reducedStyles.replace(/transform[^;]*;?/g, '');
290
+ reducedStyles += 'transform: none !important;';
291
+ }
292
+
293
+ return reducedStyles;
294
+ }
295
+
296
+ // Restore original styles
297
+ private restoreOriginalStyles(): void {
298
+ this.originalStyles.forEach((originalStyle, element) => {
299
+ if (element && element.offsetParent !== null) {
300
+ element.style.cssText = originalStyle;
301
+ }
302
+ });
303
+
304
+ this.originalStyles.clear();
305
+ this.reducedMotionStyles.clear();
306
+ }
307
+
308
+ // Save preferences to localStorage
309
+ private savePreferences(): void {
310
+ if (typeof window !== 'undefined' && window.localStorage) {
311
+ const preferences = {
312
+ reduceAnimation: this.isReducedAnimation,
313
+ reduceTransition: this.isReducedTransition,
314
+ reduceTransform: this.isReducedTransform,
315
+ timestamp: Date.now()
316
+ };
317
+
318
+ window.localStorage.setItem('motion-reduction-preferences', JSON.stringify(preferences));
319
+ }
320
+ }
321
+
322
+ // Load preferences from localStorage
323
+ private loadPreferences(): void {
324
+ if (typeof window !== 'undefined' && window.localStorage) {
325
+ try {
326
+ const stored = window.localStorage.getItem('motion-reduction-preferences');
327
+ if (stored) {
328
+ const preferences = JSON.parse(stored);
329
+
330
+ this.isReducedAnimation = preferences.reduceAnimation || false;
331
+ this.isReducedTransition = preferences.reduceTransition || false;
332
+ this.isReducedTransform = preferences.reduceTransform || false;
333
+ }
334
+ } catch (error) {
335
+ console.warn('Failed to load motion reduction preferences:', error);
336
+ }
337
+ }
338
+ }
339
+
340
+ // Check if element should have motion reduced
341
+ shouldReduceMotion(element: HTMLElement): boolean {
342
+ if (!this.isReducedMotion) return false;
343
+
344
+ // Check for motion-safe override
345
+ if (element.classList.contains('motion-safe') || element.getAttribute('data-motion-safe') === 'true') {
346
+ return false;
347
+ }
348
+
349
+ // Check for motion-reduce override
350
+ if (element.classList.contains('motion-reduce') || element.getAttribute('data-motion-reduce') === 'true') {
351
+ return true;
352
+ }
353
+
354
+ return true;
355
+ }
356
+
357
+ // Get appropriate duration for element
358
+ getDuration(element: HTMLElement, defaultDuration: string, type: 'animation' | 'transition'): string {
359
+ if (!this.shouldReduceMotion(element)) {
360
+ return defaultDuration;
361
+ }
362
+
363
+ // Parse duration
364
+ const duration = parseFloat(defaultDuration);
365
+ const unit = defaultDuration.replace(/[\d.]/g, '');
366
+
367
+ if (type === 'animation') {
368
+ return this.isReducedAnimation ? '0.01ms' : `${Math.min(duration * 0.1, 50)}${unit}`;
369
+ } else {
370
+ return this.isReducedTransition ? '0.01ms' : `${Math.min(duration * 0.1, 50)}${unit}`;
371
+ }
372
+ }
373
+
374
+ // Get appropriate easing for element
375
+ getEasing(element: HTMLElement, defaultEasing: string): string {
376
+ if (!this.shouldReduceMotion(element)) {
377
+ return defaultEasing;
378
+ }
379
+
380
+ // Use linear easing for reduced motion
381
+ return 'linear';
382
+ }
383
+
384
+ // Create motion-safe wrapper
385
+ createMotionSafeWrapper(element: HTMLElement, callback: () => void): void {
386
+ if (!this.shouldReduceMotion(element)) {
387
+ callback();
388
+ return;
389
+ }
390
+
391
+ // Execute callback without motion
392
+ const originalReducedMotion = this.isReducedMotion;
393
+ this.isReducedMotion = false;
394
+
395
+ try {
396
+ callback();
397
+ } finally {
398
+ this.isReducedMotion = originalReducedMotion;
399
+ }
400
+ }
401
+
402
+ // Animate element with motion reduction awareness
403
+ animateElement(
404
+ element: HTMLElement,
405
+ keyframes: Keyframe[],
406
+ options: KeyframeAnimationOptions
407
+ ): Animation {
408
+ if (this.shouldReduceMotion(element)) {
409
+ // Apply reduced motion options
410
+ const reducedOptions = {
411
+ ...options,
412
+ duration: Math.min(typeof options.duration === 'number' ? options.duration : 300, 50),
413
+ easing: 'linear'
414
+ };
415
+
416
+ return element.animate(keyframes, reducedOptions);
417
+ }
418
+
419
+ return element.animate(keyframes, options);
420
+ }
421
+
422
+ // Add motion reduction observer
423
+ addMotionReductionObserver(callback: (isReduced: boolean) => void): () => void {
424
+ const observer = new MutationObserver(() => {
425
+ callback(this.isReducedMotion);
426
+ });
427
+
428
+ observer.observe(document.documentElement, {
429
+ attributes: true,
430
+ attributeFilter: ['class']
431
+ });
432
+
433
+ // Return cleanup function
434
+ return () => observer.disconnect();
435
+ }
436
+
437
+ // Get motion reduction statistics
438
+ getStatistics(): {
439
+ totalElements: number;
440
+ reducedElements: number;
441
+ safeElements: number;
442
+ preferences: {
443
+ reduceMotion: boolean;
444
+ reduceAnimation: boolean;
445
+ reduceTransition: boolean;
446
+ reduceTransform: boolean;
447
+ };
448
+ } {
449
+ const totalElements = document.querySelectorAll('*').length;
450
+ const reducedElements = document.querySelectorAll('.reduced-motion *').length;
451
+ const safeElements = document.querySelectorAll('.motion-safe, [data-motion-safe="true"]').length;
452
+
453
+ return {
454
+ totalElements,
455
+ reducedElements,
456
+ safeElements,
457
+ preferences: this.getPreferences()
458
+ };
459
+ }
460
+
461
+ // Reset all motion reduction settings
462
+ reset(): void {
463
+ this.isReducedMotion = false;
464
+ this.isReducedAnimation = false;
465
+ this.isReducedTransition = false;
466
+ this.isReducedTransform = false;
467
+
468
+ this.removeMotionReduction();
469
+ this.clearPreferences();
470
+ }
471
+
472
+ // Clear stored preferences
473
+ private clearPreferences(): void {
474
+ if (typeof window !== 'undefined' && window.localStorage) {
475
+ window.localStorage.removeItem('motion-reduction-preferences');
476
+ }
477
+
478
+ this.originalStyles.clear();
479
+ this.reducedMotionStyles.clear();
480
+ }
481
+
482
+ // Destroy motion reduction manager
483
+ destroy(): void {
484
+ this.removeMotionReduction();
485
+ this.clearPreferences();
486
+
487
+ // Remove event listeners
488
+ if (typeof window !== 'undefined') {
489
+ window.removeEventListener('storage', this.loadPreferences.bind(this));
490
+ }
491
+ }
492
+ }
493
+
494
+ // Motion reduction utilities
495
+ export class MotionReductionUtils {
496
+ // Check if motion should be reduced for element
497
+ static shouldReduceMotion(element: HTMLElement): boolean {
498
+ // Check system preference
499
+ if (typeof window !== 'undefined' && window.matchMedia) {
500
+ const reducedMotionQuery = window.matchMedia('(prefers-reduced-motion: reduce)');
501
+ if (reducedMotionQuery.matches) return true;
502
+ }
503
+
504
+ // Check element attributes
505
+ if (element.classList.contains('motion-reduce') || element.getAttribute('data-motion-reduce') === 'true') {
506
+ return true;
507
+ }
508
+
509
+ // Check parent elements
510
+ const parent = element.closest('.motion-reduce, [data-motion-reduce="true"]');
511
+ if (parent) return true;
512
+
513
+ return false;
514
+ }
515
+
516
+ // Get reduced duration
517
+ static getReducedDuration(duration: string, reductionFactor: number = 0.1): string {
518
+ const parsed = parseFloat(duration);
519
+ const unit = duration.replace(/[\d.]/g, '');
520
+
521
+ return `${Math.max(parsed * reductionFactor, 1)}${unit}`;
522
+ }
523
+
524
+ // Get reduced easing
525
+ static getReducedEasing(_easing: string): string {
526
+ return 'linear';
527
+ }
528
+
529
+ // Create motion-safe animation
530
+ static createMotionSafeAnimation(
531
+ element: HTMLElement,
532
+ keyframes: Keyframe[],
533
+ options: KeyframeAnimationOptions
534
+ ): Animation | null {
535
+ if (this.shouldReduceMotion(element)) {
536
+ // Return null to indicate no animation should be performed
537
+ return null;
538
+ }
539
+
540
+ return element.animate(keyframes, options);
541
+ }
542
+
543
+ // Apply motion reduction to CSS custom properties
544
+ static applyMotionReductionToCSS(element: HTMLElement): void {
545
+ if (!this.shouldReduceMotion(element)) return;
546
+
547
+ const style = element.style;
548
+
549
+ // Reduce animation duration
550
+ if (style.getPropertyValue('--animation-duration')) {
551
+ const duration = style.getPropertyValue('--animation-duration');
552
+ style.setProperty('--animation-duration', this.getReducedDuration(duration));
553
+ }
554
+
555
+ // Reduce transition duration
556
+ if (style.getPropertyValue('--transition-duration')) {
557
+ const duration = style.getPropertyValue('--transition-duration');
558
+ style.setProperty('--transition-duration', this.getReducedDuration(duration));
559
+ }
560
+
561
+ // Set easing to linear
562
+ if (style.getPropertyValue('--animation-easing')) {
563
+ style.setProperty('--animation-easing', 'linear');
564
+ }
565
+
566
+ if (style.getPropertyValue('--transition-easing')) {
567
+ style.setProperty('--transition-easing', 'linear');
568
+ }
569
+ }
570
+
571
+ // Remove motion reduction from CSS custom properties
572
+ static removeMotionReductionFromCSS(element: HTMLElement): void {
573
+ const style = element.style;
574
+
575
+ // Remove custom properties
576
+ style.removeProperty('--animation-duration');
577
+ style.removeProperty('--transition-duration');
578
+ style.removeProperty('--animation-easing');
579
+ style.removeProperty('--transition-easing');
580
+ }
581
+
582
+ // Check if element has motion
583
+ static hasMotion(element: HTMLElement): boolean {
584
+ const computedStyle = window.getComputedStyle(element);
585
+
586
+ return (
587
+ computedStyle.animation !== 'none' ||
588
+ computedStyle.transition !== 'all 0s ease 0s' ||
589
+ computedStyle.transform !== 'none'
590
+ );
591
+ }
592
+
593
+ // Get motion information for element
594
+ static getMotionInfo(element: HTMLElement): {
595
+ hasAnimation: boolean;
596
+ hasTransition: boolean;
597
+ hasTransform: boolean;
598
+ animationDuration: string;
599
+ transitionDuration: string;
600
+ transform: string;
601
+ } {
602
+ const computedStyle = window.getComputedStyle(element);
603
+
604
+ return {
605
+ hasAnimation: computedStyle.animation !== 'none',
606
+ hasTransition: computedStyle.transition !== 'all 0s ease 0s',
607
+ hasTransform: computedStyle.transform !== 'none',
608
+ animationDuration: computedStyle.animationDuration,
609
+ transitionDuration: computedStyle.transitionDuration,
610
+ transform: computedStyle.transform
611
+ };
612
+ }
613
+ }
614
+
615
+ // Motion reduction hooks for React
616
+ export class MotionReductionHooks {
617
+ // Get motion reduction state
618
+ static useMotionReduction(): {
619
+ isReduced: boolean;
620
+ preferences: {
621
+ reduceAnimation: boolean;
622
+ reduceTransition: boolean;
623
+ reduceTransform: boolean;
624
+ };
625
+ shouldReduceMotion: (element: HTMLElement) => boolean;
626
+ } {
627
+ // This would be implemented in a React component
628
+ // For now, return a mock implementation
629
+ return {
630
+ isReduced: false,
631
+ preferences: {
632
+ reduceAnimation: false,
633
+ reduceTransition: false,
634
+ reduceTransform: false
635
+ },
636
+ shouldReduceMotion: () => false
637
+ };
638
+ }
639
+
640
+ // Get motion-safe duration
641
+ static useMotionSafeDuration(defaultDuration: string, _type: 'animation' | 'transition'): string {
642
+ // This would be implemented in a React component
643
+ return defaultDuration;
644
+ }
645
+
646
+ // Get motion-safe easing
647
+ static useMotionSafeEasing(defaultEasing: string): string {
648
+ // This would be implemented in a React component
649
+ return defaultEasing;
650
+ }
651
+ }
652
+
653
+ // Export default instances
654
+ export const motionReductionManager = new MotionReductionManager();
655
+
656
+ // Export default
657
+ export default {
658
+ MotionReductionManager,
659
+ MotionReductionUtils,
660
+ MotionReductionHooks,
661
+ motionReductionManager
662
+ };