@rakeyshgidwani/roger-ui-bank-theme-stan-design 0.1.4 → 0.1.6
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,259 @@
|
|
|
1
|
+
// Accessibility theme configuration interface
|
|
2
|
+
export interface AccessibilityThemeConfig {
|
|
3
|
+
highContrast: boolean;
|
|
4
|
+
reducedMotion: boolean;
|
|
5
|
+
focusVisible: boolean;
|
|
6
|
+
ariaLabels: Record<string, string>;
|
|
7
|
+
keyboardShortcuts: Record<string, string>;
|
|
8
|
+
focusRing: {
|
|
9
|
+
color: string;
|
|
10
|
+
width: string;
|
|
11
|
+
style: 'solid' | 'dashed' | 'dotted';
|
|
12
|
+
offset: string;
|
|
13
|
+
};
|
|
14
|
+
motion: {
|
|
15
|
+
duration: {
|
|
16
|
+
fast: string;
|
|
17
|
+
normal: string;
|
|
18
|
+
slow: string;
|
|
19
|
+
};
|
|
20
|
+
easing: {
|
|
21
|
+
ease: string;
|
|
22
|
+
easeIn: string;
|
|
23
|
+
easeOut: string;
|
|
24
|
+
easeInOut: string;
|
|
25
|
+
};
|
|
26
|
+
};
|
|
27
|
+
contrast: {
|
|
28
|
+
minimum: number; // WCAG AA minimum contrast ratio
|
|
29
|
+
enhanced: number; // WCAG AAA enhanced contrast ratio
|
|
30
|
+
target: number; // Target contrast ratio for the theme
|
|
31
|
+
};
|
|
32
|
+
spacing: {
|
|
33
|
+
focusRing: string;
|
|
34
|
+
touchTarget: string; // Minimum touch target size
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Default accessibility configuration
|
|
39
|
+
export const defaultAccessibilityConfig: AccessibilityThemeConfig = {
|
|
40
|
+
highContrast: false,
|
|
41
|
+
reducedMotion: false,
|
|
42
|
+
focusVisible: true,
|
|
43
|
+
ariaLabels: {
|
|
44
|
+
close: 'Close',
|
|
45
|
+
open: 'Open',
|
|
46
|
+
expand: 'Expand',
|
|
47
|
+
collapse: 'Collapse',
|
|
48
|
+
next: 'Next',
|
|
49
|
+
previous: 'Previous',
|
|
50
|
+
submit: 'Submit',
|
|
51
|
+
cancel: 'Cancel',
|
|
52
|
+
loading: 'Loading',
|
|
53
|
+
error: 'Error',
|
|
54
|
+
success: 'Success',
|
|
55
|
+
warning: 'Warning',
|
|
56
|
+
info: 'Information'
|
|
57
|
+
},
|
|
58
|
+
keyboardShortcuts: {
|
|
59
|
+
close: 'Escape',
|
|
60
|
+
submit: 'Enter',
|
|
61
|
+
cancel: 'Escape',
|
|
62
|
+
next: 'Tab',
|
|
63
|
+
previous: 'Shift+Tab',
|
|
64
|
+
expand: 'Space or Enter',
|
|
65
|
+
collapse: 'Space or Enter'
|
|
66
|
+
},
|
|
67
|
+
focusRing: {
|
|
68
|
+
color: '#3b82f6',
|
|
69
|
+
width: '2px',
|
|
70
|
+
style: 'solid',
|
|
71
|
+
offset: '2px'
|
|
72
|
+
},
|
|
73
|
+
motion: {
|
|
74
|
+
duration: {
|
|
75
|
+
fast: '150ms',
|
|
76
|
+
normal: '300ms',
|
|
77
|
+
slow: '500ms'
|
|
78
|
+
},
|
|
79
|
+
easing: {
|
|
80
|
+
ease: 'ease',
|
|
81
|
+
easeIn: 'ease-in',
|
|
82
|
+
easeOut: 'ease-out',
|
|
83
|
+
easeInOut: 'ease-in-out'
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
contrast: {
|
|
87
|
+
minimum: 4.5, // WCAG AA minimum
|
|
88
|
+
enhanced: 7.0, // WCAG AAA enhanced
|
|
89
|
+
target: 4.5
|
|
90
|
+
},
|
|
91
|
+
spacing: {
|
|
92
|
+
focusRing: '2px',
|
|
93
|
+
touchTarget: '44px'
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
// High contrast accessibility configuration
|
|
98
|
+
export const highContrastAccessibilityConfig: AccessibilityThemeConfig = {
|
|
99
|
+
...defaultAccessibilityConfig,
|
|
100
|
+
highContrast: true,
|
|
101
|
+
focusRing: {
|
|
102
|
+
color: '#ffffff',
|
|
103
|
+
width: '3px',
|
|
104
|
+
style: 'solid',
|
|
105
|
+
offset: '1px'
|
|
106
|
+
},
|
|
107
|
+
contrast: {
|
|
108
|
+
minimum: 7.0,
|
|
109
|
+
enhanced: 7.0,
|
|
110
|
+
target: 7.0
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
// Reduced motion accessibility configuration
|
|
115
|
+
export const reducedMotionAccessibilityConfig: AccessibilityThemeConfig = {
|
|
116
|
+
...defaultAccessibilityConfig,
|
|
117
|
+
reducedMotion: true,
|
|
118
|
+
motion: {
|
|
119
|
+
duration: {
|
|
120
|
+
fast: '0ms',
|
|
121
|
+
normal: '0ms',
|
|
122
|
+
slow: '0ms'
|
|
123
|
+
},
|
|
124
|
+
easing: {
|
|
125
|
+
ease: 'linear',
|
|
126
|
+
easeIn: 'linear',
|
|
127
|
+
easeOut: 'linear',
|
|
128
|
+
easeInOut: 'linear'
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
// Accessibility theme manager
|
|
134
|
+
export class AccessibilityThemeManager {
|
|
135
|
+
private config: AccessibilityThemeConfig;
|
|
136
|
+
private listeners: Set<(config: AccessibilityThemeConfig) => void>;
|
|
137
|
+
|
|
138
|
+
constructor(initialConfig: AccessibilityThemeConfig = defaultAccessibilityConfig) {
|
|
139
|
+
this.config = initialConfig;
|
|
140
|
+
this.listeners = new Set();
|
|
141
|
+
this.initializeSystemPreferences();
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Initialize system preferences
|
|
145
|
+
private initializeSystemPreferences() {
|
|
146
|
+
// Check for system high contrast preference
|
|
147
|
+
if (typeof window !== 'undefined' && window.matchMedia) {
|
|
148
|
+
const highContrastQuery = window.matchMedia('(prefers-contrast: high)');
|
|
149
|
+
const reducedMotionQuery = window.matchMedia('(prefers-reduced-motion: reduce)');
|
|
150
|
+
|
|
151
|
+
this.updateFromSystemPreferences(highContrastQuery.matches, reducedMotionQuery.matches);
|
|
152
|
+
|
|
153
|
+
// Listen for changes
|
|
154
|
+
highContrastQuery.addEventListener('change', (e) => {
|
|
155
|
+
this.updateFromSystemPreferences(e.matches, this.config.reducedMotion);
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
reducedMotionQuery.addEventListener('change', (e) => {
|
|
159
|
+
this.updateFromSystemPreferences(this.config.highContrast, e.matches);
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// Update configuration based on system preferences
|
|
165
|
+
private updateFromSystemPreferences(highContrast: boolean, reducedMotion: boolean) {
|
|
166
|
+
let newConfig = { ...this.config };
|
|
167
|
+
|
|
168
|
+
if (highContrast) {
|
|
169
|
+
newConfig = { ...newConfig, ...highContrastAccessibilityConfig };
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
if (reducedMotion) {
|
|
173
|
+
newConfig = { ...newConfig, ...reducedMotionAccessibilityConfig };
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
this.updateConfig(newConfig);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// Get current accessibility configuration
|
|
180
|
+
getConfig(): AccessibilityThemeConfig {
|
|
181
|
+
return { ...this.config };
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// Update accessibility configuration
|
|
185
|
+
updateConfig(newConfig: Partial<AccessibilityThemeConfig>) {
|
|
186
|
+
this.config = { ...this.config, ...newConfig };
|
|
187
|
+
this.notifyListeners();
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// Subscribe to accessibility configuration changes
|
|
191
|
+
subscribe(listener: (config: AccessibilityThemeConfig) => void): () => void {
|
|
192
|
+
this.listeners.add(listener);
|
|
193
|
+
return () => this.listeners.delete(listener);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// Notify all listeners of configuration changes
|
|
197
|
+
private notifyListeners() {
|
|
198
|
+
this.listeners.forEach(listener => listener(this.config));
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// Get CSS custom properties for accessibility
|
|
202
|
+
getCSSProperties(): Record<string, string> {
|
|
203
|
+
const { focusRing, motion, spacing } = this.config;
|
|
204
|
+
|
|
205
|
+
return {
|
|
206
|
+
'--focus-ring-color': focusRing.color,
|
|
207
|
+
'--focus-ring-width': focusRing.width,
|
|
208
|
+
'--focus-ring-style': focusRing.style,
|
|
209
|
+
'--focus-ring-offset': focusRing.offset,
|
|
210
|
+
'--motion-duration-fast': motion.duration.fast,
|
|
211
|
+
'--motion-duration-normal': motion.duration.normal,
|
|
212
|
+
'--motion-duration-slow': motion.duration.slow,
|
|
213
|
+
'--motion-easing-ease': motion.easing.ease,
|
|
214
|
+
'--motion-easing-ease-in': motion.easing.easeIn,
|
|
215
|
+
'--motion-easing-ease-out': motion.easing.easeOut,
|
|
216
|
+
'--motion-easing-ease-in-out': motion.easing.easeInOut,
|
|
217
|
+
'--spacing-focus-ring': spacing.focusRing,
|
|
218
|
+
'--spacing-touch-target': spacing.touchTarget
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// Check if high contrast mode is enabled
|
|
223
|
+
isHighContrast(): boolean {
|
|
224
|
+
return this.config.highContrast;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// Check if reduced motion is enabled
|
|
228
|
+
isReducedMotion(): boolean {
|
|
229
|
+
return this.config.reducedMotion;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// Check if focus visible is enabled
|
|
233
|
+
isFocusVisible(): boolean {
|
|
234
|
+
return this.config.focusVisible;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// Get ARIA label for a specific key
|
|
238
|
+
getAriaLabel(key: string): string {
|
|
239
|
+
return this.config.ariaLabels[key] || key;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// Get keyboard shortcut for a specific action
|
|
243
|
+
getKeyboardShortcut(action: string): string {
|
|
244
|
+
return this.config.keyboardShortcuts[action] || '';
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// Validate contrast ratio
|
|
248
|
+
validateContrastRatio(_foreground: string, _background: string): boolean {
|
|
249
|
+
// This would implement actual contrast ratio calculation
|
|
250
|
+
// For now, return true as placeholder
|
|
251
|
+
return true;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// Create and export default accessibility manager instance
|
|
256
|
+
export const accessibilityManager = new AccessibilityThemeManager();
|
|
257
|
+
|
|
258
|
+
// Export default configuration
|
|
259
|
+
export default defaultAccessibilityConfig;
|
|
@@ -0,0 +1,420 @@
|
|
|
1
|
+
import { accessibilityManager } from './accessibility';
|
|
2
|
+
|
|
3
|
+
// ARIA role definitions
|
|
4
|
+
export const ARIA_ROLES = {
|
|
5
|
+
// Landmark roles
|
|
6
|
+
banner: 'banner',
|
|
7
|
+
complementary: 'complementary',
|
|
8
|
+
contentinfo: 'contentinfo',
|
|
9
|
+
form: 'form',
|
|
10
|
+
main: 'main',
|
|
11
|
+
navigation: 'navigation',
|
|
12
|
+
region: 'region',
|
|
13
|
+
search: 'search',
|
|
14
|
+
|
|
15
|
+
// Widget roles
|
|
16
|
+
button: 'button',
|
|
17
|
+
checkbox: 'checkbox',
|
|
18
|
+
gridcell: 'gridcell',
|
|
19
|
+
link: 'link',
|
|
20
|
+
menuitem: 'menuitem',
|
|
21
|
+
menuitemcheckbox: 'menuitemcheckbox',
|
|
22
|
+
menuitemradio: 'menuitemradio',
|
|
23
|
+
option: 'option',
|
|
24
|
+
progressbar: 'progressbar',
|
|
25
|
+
radio: 'radio',
|
|
26
|
+
scrollbar: 'scrollbar',
|
|
27
|
+
searchbox: 'searchbox',
|
|
28
|
+
slider: 'slider',
|
|
29
|
+
spinbutton: 'spinbutton',
|
|
30
|
+
switch: 'switch',
|
|
31
|
+
tab: 'tab',
|
|
32
|
+
tabpanel: 'tabpanel',
|
|
33
|
+
textbox: 'textbox',
|
|
34
|
+
treeitem: 'treeitem',
|
|
35
|
+
|
|
36
|
+
// Document structure roles
|
|
37
|
+
article: 'article',
|
|
38
|
+
cell: 'cell',
|
|
39
|
+
columnheader: 'columnheader',
|
|
40
|
+
definition: 'definition',
|
|
41
|
+
directory: 'directory',
|
|
42
|
+
document: 'document',
|
|
43
|
+
group: 'group',
|
|
44
|
+
heading: 'heading',
|
|
45
|
+
img: 'img',
|
|
46
|
+
list: 'list',
|
|
47
|
+
listitem: 'listitem',
|
|
48
|
+
math: 'math',
|
|
49
|
+
note: 'note',
|
|
50
|
+
presentation: 'presentation',
|
|
51
|
+
row: 'row',
|
|
52
|
+
rowgroup: 'rowgroup',
|
|
53
|
+
rowheader: 'rowheader',
|
|
54
|
+
separator: 'separator',
|
|
55
|
+
table: 'table',
|
|
56
|
+
term: 'term',
|
|
57
|
+
toolbar: 'toolbar',
|
|
58
|
+
tooltip: 'tooltip',
|
|
59
|
+
tree: 'tree',
|
|
60
|
+
treegrid: 'treegrid'
|
|
61
|
+
} as const;
|
|
62
|
+
|
|
63
|
+
// ARIA state and property definitions
|
|
64
|
+
export const ARIA_STATES = {
|
|
65
|
+
// Boolean states
|
|
66
|
+
ariaExpanded: 'aria-expanded',
|
|
67
|
+
ariaHidden: 'aria-hidden',
|
|
68
|
+
ariaPressed: 'aria-pressed',
|
|
69
|
+
ariaSelected: 'aria-selected',
|
|
70
|
+
ariaChecked: 'aria-checked',
|
|
71
|
+
ariaDisabled: 'aria-disabled',
|
|
72
|
+
ariaReadonly: 'aria-readonly',
|
|
73
|
+
ariaRequired: 'aria-required',
|
|
74
|
+
ariaInvalid: 'aria-invalid',
|
|
75
|
+
ariaBusy: 'aria-busy',
|
|
76
|
+
ariaCurrent: 'aria-current',
|
|
77
|
+
ariaLive: 'aria-live',
|
|
78
|
+
ariaAtomic: 'aria-atomic',
|
|
79
|
+
ariaRelevant: 'aria-relevant',
|
|
80
|
+
ariaSort: 'aria-sort',
|
|
81
|
+
ariaGrabbed: 'aria-grabbed',
|
|
82
|
+
ariaDropeffect: 'aria-dropeffect',
|
|
83
|
+
ariaActivedescendant: 'aria-activedescendant',
|
|
84
|
+
ariaControls: 'aria-controls',
|
|
85
|
+
ariaDescribedby: 'aria-describedby',
|
|
86
|
+
ariaFlowto: 'aria-flowto',
|
|
87
|
+
ariaLabelledby: 'aria-labelledby',
|
|
88
|
+
ariaOwns: 'aria-owns',
|
|
89
|
+
ariaPosinset: 'aria-posinset',
|
|
90
|
+
ariaSetsize: 'aria-setsize',
|
|
91
|
+
ariaValuemin: 'aria-valuemin',
|
|
92
|
+
ariaValuemax: 'aria-valuemax',
|
|
93
|
+
ariaValuenow: 'aria-valuenow',
|
|
94
|
+
ariaValuetext: 'aria-valuetext',
|
|
95
|
+
ariaLevel: 'aria-level',
|
|
96
|
+
ariaMultiselectable: 'aria-multiselectable',
|
|
97
|
+
ariaOrientation: 'aria-orientation',
|
|
98
|
+
ariaColcount: 'aria-colcount',
|
|
99
|
+
ariaColindex: 'aria-colindex',
|
|
100
|
+
ariaRowcount: 'aria-rowcount',
|
|
101
|
+
ariaRowindex: 'aria-rowindex',
|
|
102
|
+
ariaColspan: 'aria-colspan',
|
|
103
|
+
ariaRowspan: 'aria-rowspan'
|
|
104
|
+
} as const;
|
|
105
|
+
|
|
106
|
+
// ARIA live region values
|
|
107
|
+
export const ARIA_LIVE_VALUES = {
|
|
108
|
+
off: 'off',
|
|
109
|
+
polite: 'polite',
|
|
110
|
+
assertive: 'assertive'
|
|
111
|
+
} as const;
|
|
112
|
+
|
|
113
|
+
// ARIA current values
|
|
114
|
+
export const ARIA_CURRENT_VALUES = {
|
|
115
|
+
page: 'page',
|
|
116
|
+
step: 'step',
|
|
117
|
+
location: 'location',
|
|
118
|
+
date: 'date',
|
|
119
|
+
time: 'time',
|
|
120
|
+
true: 'true',
|
|
121
|
+
false: 'false'
|
|
122
|
+
} as const;
|
|
123
|
+
|
|
124
|
+
// ARIA sort values
|
|
125
|
+
export const ARIA_SORT_VALUES = {
|
|
126
|
+
ascending: 'ascending',
|
|
127
|
+
descending: 'descending',
|
|
128
|
+
none: 'none',
|
|
129
|
+
other: 'other'
|
|
130
|
+
} as const;
|
|
131
|
+
|
|
132
|
+
// ARIA orientation values
|
|
133
|
+
export const ARIA_ORIENTATION_VALUES = {
|
|
134
|
+
horizontal: 'horizontal',
|
|
135
|
+
vertical: 'vertical'
|
|
136
|
+
} as const;
|
|
137
|
+
|
|
138
|
+
// ARIA pattern utilities
|
|
139
|
+
export class ARIAUtils {
|
|
140
|
+
// Generate ARIA attributes object
|
|
141
|
+
static generateAriaAttributes(attributes: Record<string, any>): Record<string, any> {
|
|
142
|
+
const ariaAttributes: Record<string, any> = {};
|
|
143
|
+
|
|
144
|
+
Object.entries(attributes).forEach(([key, value]) => {
|
|
145
|
+
if (key.startsWith('aria') && value !== undefined && value !== null) {
|
|
146
|
+
ariaAttributes[key] = value;
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
return ariaAttributes;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Generate proper ARIA label
|
|
154
|
+
static generateAriaLabel(label?: string, fallback?: string): string | undefined {
|
|
155
|
+
if (label) return label;
|
|
156
|
+
if (fallback) return accessibilityManager.getAriaLabel(fallback);
|
|
157
|
+
return undefined;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// Generate ARIA describedby
|
|
161
|
+
static generateAriaDescribedby(description?: string, id?: string): string | undefined {
|
|
162
|
+
if (description && id) return id;
|
|
163
|
+
return undefined;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Generate ARIA controls
|
|
167
|
+
static generateAriaControls(controlledId?: string): string | undefined {
|
|
168
|
+
return controlledId;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// Generate ARIA expanded state
|
|
172
|
+
static generateAriaExpanded(expanded?: boolean): boolean | undefined {
|
|
173
|
+
return expanded;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// Generate ARIA pressed state
|
|
177
|
+
static generateAriaPressed(pressed?: boolean): boolean | undefined {
|
|
178
|
+
return pressed;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// Generate ARIA selected state
|
|
182
|
+
static generateAriaSelected(selected?: boolean): boolean | undefined {
|
|
183
|
+
return selected;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// Generate ARIA checked state
|
|
187
|
+
static generateAriaChecked(checked?: boolean, indeterminate?: boolean): string | boolean | undefined {
|
|
188
|
+
if (indeterminate) return 'mixed';
|
|
189
|
+
return checked;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// Generate ARIA disabled state
|
|
193
|
+
static generateAriaDisabled(disabled?: boolean): boolean | undefined {
|
|
194
|
+
return disabled;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// Generate ARIA readonly state
|
|
198
|
+
static generateAriaReadonly(readonly?: boolean): boolean | undefined {
|
|
199
|
+
return readonly;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// Generate ARIA required state
|
|
203
|
+
static generateAriaRequired(required?: boolean): boolean | undefined {
|
|
204
|
+
return required;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// Generate ARIA invalid state
|
|
208
|
+
static generateAriaInvalid(invalid?: boolean, errorMessage?: string): boolean | 'grammar' | 'spelling' | undefined {
|
|
209
|
+
if (errorMessage) return true;
|
|
210
|
+
return invalid;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// Generate ARIA live region
|
|
214
|
+
static generateAriaLive(live?: keyof typeof ARIA_LIVE_VALUES, _atomic?: boolean): string | undefined {
|
|
215
|
+
return live;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// Generate ARIA current
|
|
219
|
+
static generateAriaCurrent(current?: keyof typeof ARIA_CURRENT_VALUES): string | undefined {
|
|
220
|
+
return current;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// Generate ARIA sort
|
|
224
|
+
static generateAriaSort(sort?: keyof typeof ARIA_SORT_VALUES): string | undefined {
|
|
225
|
+
return sort;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// Generate ARIA orientation
|
|
229
|
+
static generateAriaOrientation(orientation?: keyof typeof ARIA_ORIENTATION_VALUES): string | undefined {
|
|
230
|
+
return orientation;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
// Generate ARIA value attributes for range inputs
|
|
234
|
+
static generateAriaValueAttributes(
|
|
235
|
+
value?: number,
|
|
236
|
+
min?: number,
|
|
237
|
+
max?: number,
|
|
238
|
+
_step?: number
|
|
239
|
+
): Record<string, any> {
|
|
240
|
+
const ariaAttributes: Record<string, any> = {};
|
|
241
|
+
|
|
242
|
+
if (value !== undefined) ariaAttributes['aria-valuenow'] = value;
|
|
243
|
+
if (min !== undefined) ariaAttributes['aria-valuemin'] = min;
|
|
244
|
+
if (max !== undefined) ariaAttributes['aria-valuemax'] = max;
|
|
245
|
+
|
|
246
|
+
return ariaAttributes;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// Generate ARIA position and size attributes for list items
|
|
250
|
+
static generateAriaPositionAttributes(
|
|
251
|
+
position: number,
|
|
252
|
+
total: number
|
|
253
|
+
): Record<string, any> {
|
|
254
|
+
return {
|
|
255
|
+
'aria-posinset': position,
|
|
256
|
+
'aria-setsize': total
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// Generate ARIA level for headings and tree items
|
|
261
|
+
static generateAriaLevel(level: number): Record<string, any> {
|
|
262
|
+
return {
|
|
263
|
+
'aria-level': level
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// Generate ARIA multiselectable for selection components
|
|
268
|
+
static generateAriaMultiselectable(multiselectable: boolean): Record<string, any> {
|
|
269
|
+
return {
|
|
270
|
+
'aria-multiselectable': multiselectable
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// Generate ARIA col/row attributes for table cells
|
|
275
|
+
static generateAriaTableAttributes(
|
|
276
|
+
colIndex?: number,
|
|
277
|
+
rowIndex?: number,
|
|
278
|
+
colSpan?: number,
|
|
279
|
+
rowSpan?: number
|
|
280
|
+
): Record<string, any> {
|
|
281
|
+
const ariaAttributes: Record<string, any> = {};
|
|
282
|
+
|
|
283
|
+
if (colIndex !== undefined) ariaAttributes['aria-colindex'] = colIndex;
|
|
284
|
+
if (rowIndex !== undefined) ariaAttributes['aria-rowindex'] = rowIndex;
|
|
285
|
+
if (colSpan !== undefined) ariaAttributes['aria-colspan'] = colSpan;
|
|
286
|
+
if (rowSpan !== undefined) ariaAttributes['aria-rowspan'] = rowSpan;
|
|
287
|
+
|
|
288
|
+
return ariaAttributes;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
// Generate ARIA count attributes for tables
|
|
292
|
+
static generateAriaCountAttributes(
|
|
293
|
+
colCount?: number,
|
|
294
|
+
rowCount?: number
|
|
295
|
+
): Record<string, any> {
|
|
296
|
+
const ariaAttributes: Record<string, any> = {};
|
|
297
|
+
|
|
298
|
+
if (colCount !== undefined) ariaAttributes['aria-colcount'] = colCount;
|
|
299
|
+
if (rowCount !== undefined) ariaAttributes['aria-rowcount'] = rowCount;
|
|
300
|
+
|
|
301
|
+
return ariaAttributes;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
// Generate ARIA grabbed and dropeffect for drag and drop
|
|
305
|
+
static generateAriaDragDrop(
|
|
306
|
+
grabbed?: boolean,
|
|
307
|
+
dropEffect?: string
|
|
308
|
+
): Record<string, any> {
|
|
309
|
+
const ariaAttributes: Record<string, any> = {};
|
|
310
|
+
|
|
311
|
+
if (grabbed !== undefined) ariaAttributes['aria-grabbed'] = grabbed;
|
|
312
|
+
if (dropEffect) ariaAttributes['aria-dropeffect'] = dropEffect;
|
|
313
|
+
|
|
314
|
+
return ariaAttributes;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
// Generate ARIA active descendant for composite widgets
|
|
318
|
+
static generateAriaActiveDescendant(activeDescendantId?: string): Record<string, any> {
|
|
319
|
+
if (!activeDescendantId) return {};
|
|
320
|
+
|
|
321
|
+
return {
|
|
322
|
+
'aria-activedescendant': activeDescendantId
|
|
323
|
+
};
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
// Generate ARIA owns for composite widgets
|
|
327
|
+
static generateAriaOwns(ownedIds?: string[]): Record<string, any> {
|
|
328
|
+
if (!ownedIds || ownedIds.length === 0) return {};
|
|
329
|
+
|
|
330
|
+
return {
|
|
331
|
+
'aria-owns': ownedIds.join(' ')
|
|
332
|
+
};
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
// Generate ARIA flowto for composite widgets
|
|
336
|
+
static generateAriaFlowTo(flowToIds?: string[]): Record<string, any> {
|
|
337
|
+
if (!flowToIds || flowToIds.length === 0) return {};
|
|
338
|
+
|
|
339
|
+
return {
|
|
340
|
+
'aria-flowto': flowToIds.join(' ')
|
|
341
|
+
};
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
// Generate ARIA controls for composite widgets
|
|
345
|
+
static generateAriaControlsMultiple(controlIds?: string[]): Record<string, any> {
|
|
346
|
+
if (!controlIds || controlIds.length === 0) return {};
|
|
347
|
+
|
|
348
|
+
return {
|
|
349
|
+
'aria-controls': controlIds.join(' ')
|
|
350
|
+
};
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
// Generate ARIA describedby for multiple descriptions
|
|
354
|
+
static generateAriaDescribedbyMultiple(descriptionIds?: string[]): Record<string, any> {
|
|
355
|
+
if (!descriptionIds || descriptionIds.length === 0) return {};
|
|
356
|
+
|
|
357
|
+
return {
|
|
358
|
+
'aria-describedby': descriptionIds.join(' ')
|
|
359
|
+
};
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
// Generate ARIA labelledby for multiple labels
|
|
363
|
+
static generateAriaLabelledbyMultiple(labelIds?: string[]): Record<string, any> {
|
|
364
|
+
if (!labelIds || labelIds.length === 0) return {};
|
|
365
|
+
|
|
366
|
+
return {
|
|
367
|
+
'aria-labelledby': labelIds.join(' ')
|
|
368
|
+
};
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
// Validate ARIA attributes
|
|
372
|
+
static validateAriaAttributes(attributes: Record<string, any>): boolean {
|
|
373
|
+
// Basic validation - check if required attributes are present
|
|
374
|
+
// This is a simplified validation - in production you might want more comprehensive checks
|
|
375
|
+
|
|
376
|
+
for (const [key, value] of Object.entries(attributes)) {
|
|
377
|
+
if (key.startsWith('aria-')) {
|
|
378
|
+
// Check if value is not undefined or null
|
|
379
|
+
if (value === undefined || value === null) {
|
|
380
|
+
console.warn(`ARIA attribute ${key} has invalid value: ${value}`);
|
|
381
|
+
return false;
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
return true;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
// Get accessible name for an element
|
|
390
|
+
static getAccessibleName(element: HTMLElement): string {
|
|
391
|
+
// Priority order: aria-labelledby, aria-label, title, text content
|
|
392
|
+
const labelledby = element.getAttribute('aria-labelledby');
|
|
393
|
+
if (labelledby) {
|
|
394
|
+
const labelElement = document.getElementById(labelledby);
|
|
395
|
+
if (labelElement) return labelElement.textContent || '';
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
const label = element.getAttribute('aria-label');
|
|
399
|
+
if (label) return label;
|
|
400
|
+
|
|
401
|
+
const title = element.getAttribute('title');
|
|
402
|
+
if (title) return title;
|
|
403
|
+
|
|
404
|
+
return element.textContent || '';
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
// Get accessible description for an element
|
|
408
|
+
static getAccessibleDescription(element: HTMLElement): string {
|
|
409
|
+
const describedby = element.getAttribute('aria-describedby');
|
|
410
|
+
if (describedby) {
|
|
411
|
+
const descElement = document.getElementById(describedby);
|
|
412
|
+
if (descElement) return descElement.textContent || '';
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
return '';
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
// Export default ARIA utilities instance
|
|
420
|
+
export default ARIAUtils;
|