@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,182 @@
1
+ /**
2
+ * System Theme Detection Utility
3
+ * Detects and manages system theme preferences
4
+ */
5
+
6
+ export type SystemTheme = 'light' | 'dark';
7
+
8
+ export interface SystemThemeOptions {
9
+ defaultTheme?: SystemTheme;
10
+ storageKey?: string;
11
+ enablePersistence?: boolean;
12
+ }
13
+
14
+ export class SystemThemeDetector {
15
+ private mediaQuery: MediaQueryList | null = null;
16
+ private storageKey: string;
17
+ private enablePersistence: boolean;
18
+ private listeners: Set<(theme: SystemTheme) => void> = new Set();
19
+
20
+ constructor(options: SystemThemeOptions = {}) {
21
+ this.storageKey = options.storageKey || 'system-theme-preference';
22
+ this.enablePersistence = options.enablePersistence ?? true;
23
+
24
+ // Initialize media query if available
25
+ if (typeof window !== 'undefined' && window.matchMedia) {
26
+ this.mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
27
+ this.mediaQuery.addEventListener('change', this.handleMediaQueryChange);
28
+ }
29
+ }
30
+
31
+ /**
32
+ * Get the current system theme preference
33
+ */
34
+ getSystemTheme(): SystemTheme {
35
+ if (this.mediaQuery) {
36
+ return this.mediaQuery.matches ? 'dark' : 'light';
37
+ }
38
+
39
+ // Fallback to stored preference or default
40
+ if (this.enablePersistence) {
41
+ const stored = this.getStoredPreference();
42
+ if (stored) return stored;
43
+ }
44
+
45
+ return 'light';
46
+ }
47
+
48
+ /**
49
+ * Get stored theme preference
50
+ */
51
+ getStoredPreference(): SystemTheme | null {
52
+ if (!this.enablePersistence || typeof window === 'undefined') {
53
+ return null;
54
+ }
55
+
56
+ try {
57
+ const stored = localStorage.getItem(this.storageKey);
58
+ if (stored === 'light' || stored === 'dark') {
59
+ return stored;
60
+ }
61
+ } catch (error) {
62
+ console.warn('Failed to read system theme preference from storage:', error);
63
+ }
64
+
65
+ return null;
66
+ }
67
+
68
+ /**
69
+ * Store theme preference
70
+ */
71
+ setStoredPreference(theme: SystemTheme): void {
72
+ if (!this.enablePersistence || typeof window === 'undefined') {
73
+ return;
74
+ }
75
+
76
+ try {
77
+ localStorage.setItem(this.storageKey, theme);
78
+ } catch (error) {
79
+ console.warn('Failed to store system theme preference:', error);
80
+ }
81
+ }
82
+
83
+ /**
84
+ * Check if system theme detection is supported
85
+ */
86
+ isSupported(): boolean {
87
+ return typeof window !== 'undefined' &&
88
+ 'matchMedia' in window &&
89
+ 'addEventListener' in MediaQueryList.prototype;
90
+ }
91
+
92
+ /**
93
+ * Subscribe to system theme changes
94
+ */
95
+ subscribe(callback: (theme: SystemTheme) => void): () => void {
96
+ this.listeners.add(callback);
97
+
98
+ // Return unsubscribe function
99
+ return () => {
100
+ this.listeners.delete(callback);
101
+ };
102
+ }
103
+
104
+ /**
105
+ * Notify all listeners of theme change
106
+ */
107
+ private notifyListeners(theme: SystemTheme): void {
108
+ this.listeners.forEach(callback => {
109
+ try {
110
+ callback(theme);
111
+ } catch (error) {
112
+ console.error('Error in system theme change callback:', error);
113
+ }
114
+ });
115
+ }
116
+
117
+ /**
118
+ * Handle media query changes
119
+ */
120
+ private handleMediaQueryChange = (event: MediaQueryListEvent): void => {
121
+ const newTheme: SystemTheme = event.matches ? 'dark' : 'light';
122
+
123
+ if (this.enablePersistence) {
124
+ this.setStoredPreference(newTheme);
125
+ }
126
+
127
+ this.notifyListeners(newTheme);
128
+ };
129
+
130
+ /**
131
+ * Get theme-aware CSS variables
132
+ */
133
+ getThemeCSSVariables(theme: SystemTheme): Record<string, string> {
134
+ const baseVars = {
135
+ '--system-theme': theme,
136
+ '--system-theme-opposite': theme === 'light' ? 'dark' : 'light',
137
+ };
138
+
139
+ // Add system-specific color adjustments
140
+ if (theme === 'dark') {
141
+ return {
142
+ ...baseVars,
143
+ '--system-bg': '#000000',
144
+ '--system-text': '#ffffff',
145
+ '--system-border': '#333333',
146
+ };
147
+ } else {
148
+ return {
149
+ ...baseVars,
150
+ '--system-bg': '#ffffff',
151
+ '--system-text': '#000000',
152
+ '--system-border': '#e5e7eb',
153
+ };
154
+ }
155
+ }
156
+
157
+ /**
158
+ * Apply system theme CSS variables to document
159
+ */
160
+ applySystemThemeCSS(theme: SystemTheme): void {
161
+ if (typeof document === 'undefined') return;
162
+
163
+ const cssVars = this.getThemeCSSVariables(theme);
164
+
165
+ Object.entries(cssVars).forEach(([property, value]) => {
166
+ document.documentElement.style.setProperty(property, value);
167
+ });
168
+ }
169
+
170
+ /**
171
+ * Clean up event listeners
172
+ */
173
+ destroy(): void {
174
+ if (this.mediaQuery) {
175
+ this.mediaQuery.removeEventListener('change', this.handleMediaQueryChange);
176
+ }
177
+ this.listeners.clear();
178
+ }
179
+ }
180
+
181
+ // Note: React hook is exported separately in a React-specific file
182
+ // This file contains only the core SystemThemeDetector class
@@ -0,0 +1,262 @@
1
+ /**
2
+ * Theme CSS Variable Updater
3
+ * Applies theme configurations to CSS custom properties
4
+ */
5
+
6
+ import { CompleteThemeConfig } from './types';
7
+
8
+ export class ThemeCSSUpdater {
9
+ private root: HTMLElement;
10
+
11
+ constructor() {
12
+ this.root = document.documentElement;
13
+ }
14
+
15
+ /**
16
+ * Apply a complete theme configuration to CSS custom properties
17
+ */
18
+ applyTheme(theme: CompleteThemeConfig): void {
19
+ this.applyColors(theme.colors);
20
+ this.applyFonts(theme.fonts);
21
+ this.applySpacing(theme.spacing);
22
+ this.applyShadows(theme.shadows);
23
+ this.applyTransitions(theme.transitions);
24
+ this.applyBorderRadius(theme.borderRadius);
25
+ }
26
+
27
+ /**
28
+ * Apply color variables to CSS custom properties
29
+ */
30
+ private applyColors(colors: CompleteThemeConfig['colors']): void {
31
+ // Primary colors - set both flat and nested versions for compatibility
32
+ Object.entries(colors.primary).forEach(([shade, value]) => {
33
+ // Set flat version (for backward compatibility)
34
+ this.root.style.setProperty(`--cs-primary-${shade}`, value);
35
+ // Set nested version (for badge CSS and other components)
36
+ this.root.style.setProperty(`--cs-colors-primary-${shade}`, value);
37
+ });
38
+
39
+ // Secondary colors - set both flat and nested versions
40
+ Object.entries(colors.secondary).forEach(([shade, value]) => {
41
+ // Set flat version (for backward compatibility)
42
+ this.root.style.setProperty(`--cs-secondary-${shade}`, value);
43
+ // Set nested version (for badge CSS and other components)
44
+ this.root.style.setProperty(`--cs-colors-secondary-${shade}`, value);
45
+ });
46
+
47
+ // Semantic colors - set both flat and nested versions
48
+ this.root.style.setProperty('--cs-success', colors.semantic.success);
49
+ this.root.style.setProperty('--cs-colors-semantic-success', colors.semantic.success);
50
+ this.root.style.setProperty('--cs-warning', colors.semantic.warning);
51
+ this.root.style.setProperty('--cs-colors-semantic-warning', colors.semantic.warning);
52
+ this.root.style.setProperty('--cs-error', colors.semantic.error);
53
+ this.root.style.setProperty('--cs-colors-semantic-error', colors.semantic.error);
54
+ this.root.style.setProperty('--cs-info', colors.semantic.info);
55
+ this.root.style.setProperty('--cs-colors-semantic-info', colors.semantic.info);
56
+
57
+ // Neutral colors - set both flat and nested versions
58
+ Object.entries(colors.neutral).forEach(([shade, value]) => {
59
+ // Set flat version (for backward compatibility)
60
+ this.root.style.setProperty(`--cs-neutral-${shade}`, value);
61
+ // Set nested version (for components that expect it)
62
+ this.root.style.setProperty(`--cs-colors-neutral-${shade}`, value);
63
+ });
64
+
65
+ // Surface colors - set both flat and nested versions
66
+ this.root.style.setProperty('--cs-page-bg', colors.surface.background);
67
+ this.root.style.setProperty('--cs-colors-surface-background', colors.surface.background);
68
+ this.root.style.setProperty('--cs-surface-bg', colors.surface.surface);
69
+ this.root.style.setProperty('--cs-colors-surface-surface', colors.surface.surface);
70
+ this.root.style.setProperty('--cs-border', colors.surface.border);
71
+ this.root.style.setProperty('--cs-colors-border', colors.surface.border);
72
+ this.root.style.setProperty('--cs-divider', colors.surface.divider);
73
+ this.root.style.setProperty('--cs-colors-divider', colors.surface.divider);
74
+
75
+ // Text colors - set both flat and nested versions
76
+ this.root.style.setProperty('--cs-text-primary', colors.text.primary);
77
+ this.root.style.setProperty('--cs-colors-text-primary', colors.text.primary);
78
+ this.root.style.setProperty('--cs-text-secondary', colors.text.secondary);
79
+ this.root.style.setProperty('--cs-colors-text-secondary', colors.text.secondary);
80
+ this.root.style.setProperty('--cs-text-muted', colors.text.muted);
81
+ this.root.style.setProperty('--cs-colors-text-muted', colors.text.muted);
82
+ this.root.style.setProperty('--cs-text-inverse', colors.text.inverse);
83
+ this.root.style.setProperty('--cs-colors-text-inverse', colors.text.inverse);
84
+ this.root.style.setProperty('--cs-text-on-primary', colors.text.onPrimary);
85
+ this.root.style.setProperty('--cs-colors-text-on-primary', colors.text.onPrimary);
86
+ this.root.style.setProperty('--cs-text-on-secondary', colors.text.onSecondary);
87
+ this.root.style.setProperty('--cs-colors-text-on-secondary', colors.text.onSecondary);
88
+ this.root.style.setProperty('--cs-text-on-surface', colors.text.onSurface);
89
+ this.root.style.setProperty('--cs-colors-text-on-surface', colors.text.onSurface);
90
+
91
+ // Interactive colors - set both flat and nested versions
92
+ this.root.style.setProperty('--cs-hover-bg', colors.interactive.hover);
93
+ this.root.style.setProperty('--cs-colors-interactive-hover', colors.interactive.hover);
94
+ this.root.style.setProperty('--cs-active-bg', colors.interactive.active);
95
+ this.root.style.setProperty('--cs-colors-interactive-active', colors.interactive.active);
96
+ this.root.style.setProperty('--cs-focus', colors.interactive.focus);
97
+ this.root.style.setProperty('--cs-colors-interactive-focus', colors.interactive.focus);
98
+ this.root.style.setProperty('--cs-disabled', colors.interactive.disabled);
99
+ this.root.style.setProperty('--cs-colors-interactive-disabled', colors.interactive.disabled);
100
+ }
101
+
102
+ /**
103
+ * Apply font variables to CSS custom properties
104
+ */
105
+ private applyFonts(fonts: CompleteThemeConfig['fonts']): void {
106
+ // Helper function to build font family string with fallbacks
107
+ const buildFontFamily = (config: any) => {
108
+ if (config.fallbacks && config.fallbacks.length > 0) {
109
+ return `${config.family}, ${config.fallbacks.join(', ')}`;
110
+ }
111
+ return config.family;
112
+ };
113
+
114
+ // Primary font
115
+ this.root.style.setProperty('--cs-fonts-primary-family', buildFontFamily(fonts.primary));
116
+ this.root.style.setProperty('--cs-fonts-primary-weights', fonts.primary.weights.join(', '));
117
+
118
+ // Font sizes
119
+ Object.entries(fonts.primary.sizes).forEach(([size, value]) => {
120
+ this.root.style.setProperty(`--cs-fonts-primary-sizes-${size}`, value);
121
+ });
122
+
123
+ // Line heights
124
+ Object.entries(fonts.primary.lineHeights).forEach(([height, value]) => {
125
+ this.root.style.setProperty(`--cs-fonts-primary-line-heights-${height}`, value);
126
+ });
127
+
128
+ // Letter spacing
129
+ Object.entries(fonts.primary.letterSpacing).forEach(([spacing, value]) => {
130
+ this.root.style.setProperty(`--cs-fonts-primary-letter-spacing-${spacing}`, value);
131
+ });
132
+
133
+ // Secondary font
134
+ this.root.style.setProperty('--cs-fonts-secondary-family', buildFontFamily(fonts.secondary));
135
+
136
+ // Display font
137
+ this.root.style.setProperty('--cs-fonts-display-family', buildFontFamily(fonts.display));
138
+
139
+ // Body font
140
+ this.root.style.setProperty('--cs-fonts-body-family', buildFontFamily(fonts.body));
141
+
142
+ // Mono font
143
+ this.root.style.setProperty('--cs-fonts-mono-family', buildFontFamily(fonts.mono));
144
+ }
145
+
146
+ /**
147
+ * Apply spacing variables to CSS custom properties
148
+ */
149
+ private applySpacing(spacing: CompleteThemeConfig['spacing']): void {
150
+ // Scale spacing - set both flat and nested versions
151
+ Object.entries(spacing.scale).forEach(([size, value]) => {
152
+ // Set flat version (for backward compatibility)
153
+ this.root.style.setProperty(`--cs-spacing-${size}`, value);
154
+ // Set nested version (for badge CSS and other components)
155
+ this.root.style.setProperty(`--cs-spacing-scale-${size}`, value);
156
+ });
157
+
158
+ // Component spacing
159
+ this.root.style.setProperty('--cs-button-padding', spacing.component.button.padding);
160
+ this.root.style.setProperty('--cs-button-margin', spacing.component.button.margin);
161
+ this.root.style.setProperty('--cs-button-gap', spacing.component.button.gap);
162
+
163
+ this.root.style.setProperty('--cs-input-padding', spacing.component.input.padding);
164
+ this.root.style.setProperty('--cs-input-margin', spacing.component.input.margin);
165
+ this.root.style.setProperty('--cs-input-gap', spacing.component.input.gap);
166
+
167
+ this.root.style.setProperty('--cs-card-padding', spacing.component.card.padding);
168
+ this.root.style.setProperty('--cs-card-margin', spacing.component.card.margin);
169
+ this.root.style.setProperty('--cs-card-gap', spacing.component.card.gap);
170
+
171
+ // Layout spacing
172
+ this.root.style.setProperty('--cs-page-spacing', spacing.layout.page);
173
+ this.root.style.setProperty('--cs-section-spacing', spacing.layout.section);
174
+ this.root.style.setProperty('--cs-container-spacing', spacing.layout.container);
175
+ this.root.style.setProperty('--cs-grid-spacing', spacing.layout.grid);
176
+ }
177
+
178
+ /**
179
+ * Apply shadow variables to CSS custom properties
180
+ */
181
+ private applyShadows(shadows: CompleteThemeConfig['shadows']): void {
182
+ Object.entries(shadows).forEach(([shadow, value]) => {
183
+ // Set flat version (for backward compatibility)
184
+ this.root.style.setProperty(`--cs-shadow-${shadow}`, value);
185
+ // Set nested version (for badge CSS and other components)
186
+ this.root.style.setProperty(`--cs-shadows-${shadow}`, value);
187
+ });
188
+ }
189
+
190
+ /**
191
+ * Apply transition variables to CSS custom properties
192
+ */
193
+ private applyTransitions(transitions: CompleteThemeConfig['transitions']): void {
194
+ // Duration - set both flat and nested versions
195
+ Object.entries(transitions.duration).forEach(([duration, value]) => {
196
+ // Set flat version (for backward compatibility)
197
+ this.root.style.setProperty(`--cs-transition-duration-${duration}`, value);
198
+ // Set nested version (for badge CSS and other components)
199
+ this.root.style.setProperty(`--cs-transitions-duration-${duration}`, value);
200
+ });
201
+
202
+ // Easing - set both flat and nested versions
203
+ Object.entries(transitions.easing).forEach(([ease, value]) => {
204
+ // Set flat version (for backward compatibility)
205
+ this.root.style.setProperty(`--cs-transition-easing-${ease}`, value);
206
+ // Set nested version (for badge CSS and other components)
207
+ this.root.style.setProperty(`--cs-transitions-easing-${ease}`, value);
208
+ });
209
+
210
+ // Properties - set both flat and nested versions
211
+ Object.entries(transitions.properties).forEach(([property, value]) => {
212
+ // Set flat version (for backward compatibility)
213
+ this.root.style.setProperty(`--cs-transition-${property}`, value);
214
+ // Set nested version (for badge CSS and other components)
215
+ this.root.style.setProperty(`--cs-transitions-properties-${property}`, value);
216
+ });
217
+ }
218
+
219
+ /**
220
+ * Apply border radius variables to CSS custom properties
221
+ */
222
+ private applyBorderRadius(borderRadius: CompleteThemeConfig['borderRadius']): void {
223
+ Object.entries(borderRadius).forEach(([size, value]) => {
224
+ // Set flat version (for backward compatibility)
225
+ this.root.style.setProperty(`--cs-border-radius-${size}`, value);
226
+ // Set nested version (for badge CSS and other components)
227
+ this.root.style.setProperty(`--cs-border-radius-${size}`, value);
228
+ });
229
+ }
230
+
231
+ /**
232
+ * Clear all theme CSS variables
233
+ */
234
+ clearTheme(): void {
235
+ const cssVars = [
236
+ '--cs-primary-50', '--cs-primary-100', '--cs-primary-200', '--cs-primary-300',
237
+ '--cs-primary-400', '--cs-primary-500', '--cs-primary-600', '--cs-primary-700',
238
+ '--cs-primary-800', '--cs-primary-900',
239
+ '--cs-secondary-50', '--cs-secondary-100', '--cs-secondary-200', '--cs-secondary-300',
240
+ '--cs-secondary-400', '--cs-secondary-500', '--cs-secondary-600', '--cs-secondary-700',
241
+ '--cs-secondary-800', '--cs-secondary-900',
242
+ '--cs-success', '--cs-warning', '--cs-error', '--cs-info',
243
+ '--cs-neutral-50', '--cs-neutral-100', '--cs-neutral-200', '--cs-neutral-300',
244
+ '--cs-neutral-400', '--cs-neutral-500', '--cs-neutral-600', '--cs-neutral-700',
245
+ '--cs-neutral-800', '--cs-neutral-900',
246
+ '--cs-page-bg', '--cs-surface-bg', '--cs-border', '--cs-divider',
247
+ '--cs-text-primary', '--cs-text-secondary', '--cs-text-muted', '--cs-text-inverse',
248
+ '--cs-text-on-primary', '--cs-text-on-secondary', '--cs-text-on-surface',
249
+ '--cs-hover-bg', '--cs-active-bg', '--cs-focus', '--cs-disabled',
250
+ '--cs-font-primary', '--cs-font-secondary', '--cs-font-display', '--cs-font-body', '--cs-font-mono'
251
+ ];
252
+
253
+ cssVars.forEach(varName => {
254
+ this.root.style.removeProperty(varName);
255
+ });
256
+ }
257
+ }
258
+
259
+ /**
260
+ * Default theme CSS updater instance
261
+ */
262
+ export const themeCSSUpdater = new ThemeCSSUpdater();
@@ -0,0 +1,238 @@
1
+ /**
2
+ * Theme persistence utilities for managing theme preferences in localStorage
3
+ */
4
+
5
+ export interface ThemePersistenceOptions {
6
+ storageKey?: string;
7
+ defaultTheme?: string;
8
+ enableSystemPreference?: boolean;
9
+ enableSystemThemeDetection?: boolean;
10
+ systemThemeStorageKey?: string;
11
+ }
12
+
13
+ export class ThemePersistence {
14
+ private storageKey: string;
15
+ private defaultTheme: string;
16
+ private enableSystemPreference: boolean;
17
+ private enableSystemThemeDetection: boolean;
18
+ private systemThemeStorageKey: string;
19
+
20
+ constructor(options: ThemePersistenceOptions = {}) {
21
+ this.storageKey = options.storageKey || 'stan-design-theme';
22
+ this.defaultTheme = options.defaultTheme || 'stan-design';
23
+ this.enableSystemPreference = options.enableSystemPreference ?? true;
24
+ this.enableSystemThemeDetection = options.enableSystemThemeDetection ?? true;
25
+ this.systemThemeStorageKey = options.systemThemeStorageKey || 'stan-design-system-theme';
26
+ }
27
+
28
+ /**
29
+ * Get the stored theme preference
30
+ * Falls back to system preference if enabled, then default theme
31
+ */
32
+ getStoredTheme(): string {
33
+ try {
34
+ // Check localStorage first
35
+ const stored = localStorage.getItem(this.storageKey);
36
+ if (stored) {
37
+ return stored;
38
+ }
39
+
40
+ // Fall back to system preference if enabled
41
+ if (this.enableSystemPreference) {
42
+ const systemPreference = this.getSystemPreference();
43
+ if (systemPreference) {
44
+ return systemPreference;
45
+ }
46
+ }
47
+
48
+ // Finally fall back to default
49
+ return this.defaultTheme;
50
+ } catch (error) {
51
+ console.warn('Failed to read theme from storage:', error);
52
+ return this.defaultTheme;
53
+ }
54
+ }
55
+
56
+ /**
57
+ * Store the theme preference
58
+ */
59
+ setStoredTheme(themeName: string): void {
60
+ try {
61
+ localStorage.setItem(this.storageKey, themeName);
62
+ } catch (error) {
63
+ console.warn('Failed to store theme preference:', error);
64
+ }
65
+ }
66
+
67
+ /**
68
+ * Clear the stored theme preference
69
+ */
70
+ clearStoredTheme(): void {
71
+ try {
72
+ localStorage.removeItem(this.storageKey);
73
+ } catch (error) {
74
+ console.warn('Failed to clear theme preference:', error);
75
+ }
76
+ }
77
+
78
+ /**
79
+ * Get system color scheme preference
80
+ */
81
+ private getSystemPreference(): string | null {
82
+ try {
83
+ if (typeof window !== 'undefined' && window.matchMedia) {
84
+ const darkModeQuery = window.matchMedia('(prefers-color-scheme: dark)');
85
+ return darkModeQuery.matches ? 'dark' : 'light';
86
+ }
87
+ } catch (error) {
88
+ console.warn('Failed to detect system preference:', error);
89
+ }
90
+ return null;
91
+ }
92
+
93
+ /**
94
+ * Listen for system preference changes
95
+ */
96
+ onSystemPreferenceChange(callback: (preference: string) => void): (() => void) | null {
97
+ try {
98
+ if (typeof window !== 'undefined' && window.matchMedia) {
99
+ const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
100
+
101
+ const handleChange = (event: MediaQueryListEvent) => {
102
+ const preference = event.matches ? 'dark' : 'light';
103
+ callback(preference);
104
+ };
105
+
106
+ // Modern browsers
107
+ if (mediaQuery.addEventListener) {
108
+ mediaQuery.addEventListener('change', handleChange);
109
+ return () => mediaQuery.removeEventListener('change', handleChange);
110
+ }
111
+ // Legacy browsers
112
+ else if (mediaQuery.addListener) {
113
+ mediaQuery.addListener(handleChange);
114
+ return () => mediaQuery.removeListener(handleChange);
115
+ }
116
+ }
117
+ } catch (error) {
118
+ console.warn('Failed to set up system preference listener:', error);
119
+ }
120
+ return null;
121
+ }
122
+
123
+ /**
124
+ * Check if localStorage is available
125
+ */
126
+ isStorageAvailable(): boolean {
127
+ try {
128
+ const test = '__test__';
129
+ localStorage.setItem(test, test);
130
+ localStorage.removeItem(test);
131
+ return true;
132
+ } catch {
133
+ return false;
134
+ }
135
+ }
136
+
137
+ /**
138
+ * Get all available storage keys related to themes
139
+ */
140
+ getThemeKeys(): string[] {
141
+ try {
142
+ const keys: string[] = [];
143
+ for (let i = 0; i < localStorage.length; i++) {
144
+ const key = localStorage.key(i);
145
+ if (key && key.includes('theme')) {
146
+ keys.push(key);
147
+ }
148
+ }
149
+ return keys;
150
+ } catch (error) {
151
+ console.warn('Failed to get theme keys:', error);
152
+ return [];
153
+ }
154
+ }
155
+
156
+ /**
157
+ * Get stored system theme preference
158
+ */
159
+ getStoredSystemTheme(): 'light' | 'dark' | null {
160
+ try {
161
+ const stored = localStorage.getItem(this.systemThemeStorageKey);
162
+ if (stored === 'light' || stored === 'dark') {
163
+ return stored;
164
+ }
165
+ } catch (error) {
166
+ console.warn('Failed to read system theme from storage:', error);
167
+ }
168
+ return null;
169
+ }
170
+
171
+ /**
172
+ * Store system theme preference
173
+ */
174
+ setStoredSystemTheme(theme: 'light' | 'dark'): void {
175
+ try {
176
+ localStorage.setItem(this.systemThemeStorageKey, theme);
177
+ } catch (error) {
178
+ console.warn('Failed to store system theme preference:', error);
179
+ }
180
+ }
181
+
182
+ /**
183
+ * Clear stored system theme preference
184
+ */
185
+ clearStoredSystemTheme(): void {
186
+ try {
187
+ localStorage.removeItem(this.systemThemeStorageKey);
188
+ } catch (error) {
189
+ console.warn('Failed to clear system theme preference:', error);
190
+ }
191
+ }
192
+
193
+ /**
194
+ * Get comprehensive theme state including system theme
195
+ */
196
+ getThemeState(): {
197
+ theme: string;
198
+ systemTheme: 'light' | 'dark' | null;
199
+ isSystemThemeEnabled: boolean;
200
+ } {
201
+ return {
202
+ theme: this.getStoredTheme(),
203
+ systemTheme: this.getStoredSystemTheme(),
204
+ isSystemThemeEnabled: this.enableSystemThemeDetection
205
+ };
206
+ }
207
+
208
+ /**
209
+ * Set comprehensive theme state
210
+ */
211
+ setThemeState(state: {
212
+ theme?: string;
213
+ systemTheme?: 'light' | 'dark';
214
+ enableSystemTheme?: boolean;
215
+ }): void {
216
+ if (state.theme !== undefined) {
217
+ this.setStoredTheme(state.theme);
218
+ }
219
+ if (state.systemTheme !== undefined) {
220
+ this.setStoredSystemTheme(state.systemTheme);
221
+ }
222
+ if (state.enableSystemTheme !== undefined) {
223
+ this.enableSystemThemeDetection = state.enableSystemTheme;
224
+ }
225
+ }
226
+ }
227
+
228
+ /**
229
+ * Default theme persistence instance
230
+ */
231
+ export const defaultThemePersistence = new ThemePersistence();
232
+
233
+ /**
234
+ * Create a custom theme persistence instance
235
+ */
236
+ export const createThemePersistence = (options: ThemePersistenceOptions) => {
237
+ return new ThemePersistence(options);
238
+ };