@shohojdhara/atomix 0.3.2 → 0.3.4

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 (84) hide show
  1. package/README.md +58 -21
  2. package/dist/atomix.css +96 -121
  3. package/dist/atomix.min.css +3 -3
  4. package/dist/index.d.ts +7937 -7765
  5. package/dist/index.esm.js +3677 -4031
  6. package/dist/index.esm.js.map +1 -1
  7. package/dist/index.js +3648 -3952
  8. package/dist/index.js.map +1 -1
  9. package/dist/index.min.js +1 -1
  10. package/dist/index.min.js.map +1 -1
  11. package/package.json +44 -16
  12. package/scripts/atomix-cli.js +1764 -0
  13. package/scripts/build-themes.js +208 -0
  14. package/scripts/cli/interactive-init.js +520 -0
  15. package/scripts/cli/migration-tools.js +603 -0
  16. package/scripts/cli/theme-bridge.js +129 -0
  17. package/scripts/cli/token-manager.js +519 -0
  18. package/scripts/sync-theme-config.js +309 -0
  19. package/src/components/Button/Button.tsx +36 -1
  20. package/src/components/List/ListGroup.tsx +1 -2
  21. package/src/components/Popover/Popover.tsx +2 -2
  22. package/src/components/Tooltip/Tooltip.stories.tsx +49 -12
  23. package/src/components/Tooltip/Tooltip.tsx +32 -58
  24. package/src/lib/composables/useTooltip.ts +285 -0
  25. package/src/lib/config/index.ts +275 -0
  26. package/src/lib/config/loader.ts +105 -0
  27. package/src/lib/constants/cssVariables.ts +390 -0
  28. package/src/lib/hooks/__tests__/useComponentCustomization.test.ts +151 -0
  29. package/src/lib/hooks/index.ts +19 -0
  30. package/src/lib/hooks/useComponentCustomization.ts +175 -0
  31. package/src/lib/index.ts +14 -1
  32. package/src/lib/patterns/__tests__/slots.test.ts +108 -0
  33. package/src/lib/patterns/index.ts +35 -0
  34. package/src/lib/patterns/slots.tsx +421 -0
  35. package/src/lib/theme/composeTheme.ts +0 -5
  36. package/src/lib/theme/config/index.ts +1 -1
  37. package/src/lib/theme/config/loader.ts +75 -41
  38. package/src/lib/theme/config/types.ts +21 -7
  39. package/src/lib/theme/config/validator.ts +1 -1
  40. package/src/lib/theme/constants.ts +12 -2
  41. package/src/lib/theme/createTheme.ts +2 -135
  42. package/src/lib/theme/createThemeFromConfig.ts +132 -0
  43. package/src/lib/theme/cssVariableMapper.ts +261 -0
  44. package/src/lib/theme/devtools/CLI.ts +161 -76
  45. package/src/lib/theme/devtools/Comparator.tsx +343 -0
  46. package/src/lib/theme/devtools/IMPROVEMENTS.md +429 -0
  47. package/src/lib/theme/devtools/Inspector.tsx +21 -6
  48. package/src/lib/theme/devtools/LiveEditor.tsx +393 -0
  49. package/src/lib/theme/devtools/README.md +433 -0
  50. package/src/lib/theme/devtools/index.ts +12 -11
  51. package/src/lib/theme/generateCSSVariables.ts +79 -38
  52. package/src/lib/theme/index.ts +45 -246
  53. package/src/lib/theme/runtime/ThemeApplicator.ts +252 -0
  54. package/src/lib/theme/runtime/ThemeManager.test.ts +17 -1
  55. package/src/lib/theme/runtime/ThemeManager.ts +7 -7
  56. package/src/lib/theme/themeUtils.ts +27 -5
  57. package/src/lib/theme/types.ts +59 -1
  58. package/src/lib/theme-tools.ts +125 -0
  59. package/src/lib/types/components.ts +260 -72
  60. package/src/lib/types/partProps.ts +426 -0
  61. package/src/lib/utils/__tests__/componentUtils.test.ts +144 -0
  62. package/src/lib/utils/componentUtils.ts +163 -0
  63. package/src/lib/utils/index.ts +17 -57
  64. package/src/styles/01-settings/_settings.colors.scss +10 -10
  65. package/src/styles/01-settings/_settings.navbar.scss +1 -1
  66. package/src/styles/01-settings/_settings.tooltip.scss +1 -1
  67. package/src/styles/03-generic/_generated-root.css +5 -0
  68. package/src/styles/06-components/_components.navbar.scss +12 -5
  69. package/src/styles/06-components/_components.tooltip.scss +31 -81
  70. package/src/themes/README.md +442 -0
  71. package/src/themes/themes.config.js +35 -0
  72. package/src/lib/theme/errors.test.ts +0 -207
  73. package/src/lib/theme/generators/CSSGenerator.ts +0 -311
  74. package/src/lib/theme/generators/ConfigGenerator.ts +0 -287
  75. package/src/lib/theme/generators/TypeGenerator.ts +0 -228
  76. package/src/lib/theme/generators/index.ts +0 -21
  77. package/src/lib/theme/monitoring/ThemeAnalytics.ts +0 -409
  78. package/src/lib/theme/monitoring/index.ts +0 -17
  79. package/src/lib/theme/overrides/ComponentOverrides.ts +0 -243
  80. package/src/lib/theme/overrides/index.ts +0 -15
  81. package/src/lib/theme/studio/ThemeStudio.tsx +0 -312
  82. package/src/lib/theme/studio/index.ts +0 -8
  83. package/src/lib/theme/whitelabel/WhiteLabelManager.ts +0 -364
  84. package/src/lib/theme/whitelabel/index.ts +0 -13
@@ -0,0 +1,252 @@
1
+ /**
2
+ * Theme Applicator
3
+ *
4
+ * Applies theme configurations to the DOM, including CSS variables,
5
+ * component overrides, typography, spacing, and color palettes.
6
+ */
7
+
8
+ import { applyCSSVariables, removeCSSVariables } from '../cssVariableMapper';
9
+ import type { Theme, ThemeComponentOverrides, ComponentThemeOverride } from '../types';
10
+
11
+ /**
12
+ * Theme applicator class for runtime theme application
13
+ */
14
+ export class ThemeApplicator {
15
+ private appliedVars: Set<string> = new Set();
16
+ private root: HTMLElement;
17
+
18
+ constructor(root: HTMLElement = document.documentElement) {
19
+ this.root = root;
20
+ }
21
+
22
+ /**
23
+ * Apply a complete theme configuration
24
+ */
25
+ applyTheme(theme: Theme): void {
26
+ // Clear previously applied variables
27
+ this.clearAppliedVars();
28
+
29
+ // Apply global CSS variables
30
+ if (theme.cssVars) {
31
+ this.applyGlobalCSSVars(theme.cssVars);
32
+ }
33
+
34
+ // Apply typography system
35
+ if (theme.typography) {
36
+ this.applyTypography(theme.typography);
37
+ }
38
+
39
+ // Apply spacing system
40
+ if (theme.spacing) {
41
+ this.applySpacing(theme.spacing);
42
+ }
43
+
44
+ // Apply color palette
45
+ if (theme.palette) {
46
+ this.applyPalette(theme.palette);
47
+ }
48
+
49
+ // Apply component overrides
50
+ if (theme.components) {
51
+ this.applyComponentOverrides(theme.components);
52
+ }
53
+ }
54
+
55
+ /**
56
+ * Apply global CSS variables
57
+ */
58
+ private applyGlobalCSSVars(vars: Record<string, string | number>): void {
59
+ Object.entries(vars).forEach(([key, value]) => {
60
+ this.root.style.setProperty(key, String(value));
61
+ this.appliedVars.add(key);
62
+ });
63
+ }
64
+
65
+ /**
66
+ * Apply typography system
67
+ */
68
+ private applyTypography(typography: Theme['typography']): void {
69
+ if (!typography) return;
70
+
71
+ const vars: Record<string, string | number> = {};
72
+
73
+ if (typography.fontFamily) {
74
+ vars['--atomix-font-family'] = typography.fontFamily;
75
+ }
76
+
77
+ if (typography.fontSize) {
78
+ Object.entries(typography.fontSize).forEach(([key, value]) => {
79
+ vars[`--atomix-font-size-${key}`] = value;
80
+ });
81
+ }
82
+
83
+ if (typography.fontWeight) {
84
+ Object.entries(typography.fontWeight).forEach(([key, value]) => {
85
+ vars[`--atomix-font-weight-${key}`] = value;
86
+ });
87
+ }
88
+
89
+ if (typography.lineHeight) {
90
+ Object.entries(typography.lineHeight).forEach(([key, value]) => {
91
+ vars[`--atomix-line-height-${key}`] = value;
92
+ });
93
+ }
94
+
95
+ this.applyGlobalCSSVars(vars);
96
+ }
97
+
98
+ /**
99
+ * Apply spacing system
100
+ */
101
+ private applySpacing(spacing: Record<string, string | number>): void {
102
+ const vars: Record<string, string | number> = {};
103
+
104
+ Object.entries(spacing).forEach(([key, value]) => {
105
+ vars[`--atomix-space-${key}`] = value;
106
+ });
107
+
108
+ this.applyGlobalCSSVars(vars);
109
+ }
110
+
111
+ /**
112
+ * Apply color palette
113
+ */
114
+ private applyPalette(palette: Theme['palette']): void {
115
+ if (!palette) return;
116
+
117
+ const vars: Record<string, string | number> = {};
118
+
119
+ Object.entries(palette).forEach(([colorName, colorScale]) => {
120
+ if (colorScale) {
121
+ Object.entries(colorScale).forEach(([shade, value]) => {
122
+ if (value) {
123
+ vars[`--atomix-color-${colorName}-${shade}`] = value;
124
+ }
125
+ });
126
+ }
127
+ });
128
+
129
+ this.applyGlobalCSSVars(vars);
130
+ }
131
+
132
+ /**
133
+ * Apply component-level overrides
134
+ */
135
+ private applyComponentOverrides(overrides: ThemeComponentOverrides): void {
136
+ Object.entries(overrides).forEach(([componentName, override]) => {
137
+ if (override) {
138
+ this.applyComponentOverride(componentName, override);
139
+ }
140
+ });
141
+ }
142
+
143
+ /**
144
+ * Apply override for a specific component
145
+ */
146
+ private applyComponentOverride(
147
+ componentName: string,
148
+ override: ComponentThemeOverride
149
+ ): void {
150
+ const vars: Record<string, string | number> = {};
151
+ const componentKey = componentName.toLowerCase();
152
+
153
+ // Apply component-level CSS variables
154
+ if (override.cssVars) {
155
+ Object.entries(override.cssVars).forEach(([key, value]) => {
156
+ // If key doesn't start with --, add component prefix
157
+ const varKey = key.startsWith('--')
158
+ ? key
159
+ : `--atomix-${componentKey}-${key}`;
160
+ vars[varKey] = value;
161
+ });
162
+ }
163
+
164
+ // Apply part-specific CSS variables
165
+ if (override.parts) {
166
+ Object.entries(override.parts).forEach(([partName, partOverride]) => {
167
+ if (partOverride.cssVars) {
168
+ Object.entries(partOverride.cssVars).forEach(([key, value]) => {
169
+ const varKey = key.startsWith('--')
170
+ ? key
171
+ : `--atomix-${componentKey}-${partName}-${key}`;
172
+ vars[varKey] = value;
173
+ });
174
+ }
175
+ });
176
+ }
177
+
178
+ // Apply variant-specific CSS variables
179
+ if (override.variants) {
180
+ Object.entries(override.variants).forEach(([variantName, variantOverride]) => {
181
+ if (variantOverride.cssVars) {
182
+ Object.entries(variantOverride.cssVars).forEach(([key, value]) => {
183
+ const varKey = key.startsWith('--')
184
+ ? key
185
+ : `--atomix-${componentKey}-${variantName}-${key}`;
186
+ vars[varKey] = value;
187
+ });
188
+ }
189
+ });
190
+ }
191
+
192
+ this.applyGlobalCSSVars(vars);
193
+ }
194
+
195
+ /**
196
+ * Clear all applied CSS variables
197
+ */
198
+ private clearAppliedVars(): void {
199
+ removeCSSVariables(Array.from(this.appliedVars), this.root);
200
+ this.appliedVars.clear();
201
+ }
202
+
203
+ /**
204
+ * Get all currently applied variables
205
+ */
206
+ getAppliedVars(): string[] {
207
+ return Array.from(this.appliedVars);
208
+ }
209
+
210
+ /**
211
+ * Remove theme application
212
+ */
213
+ removeTheme(): void {
214
+ this.clearAppliedVars();
215
+ }
216
+
217
+ /**
218
+ * Update specific CSS variables without clearing all
219
+ */
220
+ updateCSSVars(vars: Record<string, string | number>): void {
221
+ this.applyGlobalCSSVars(vars);
222
+ }
223
+ }
224
+
225
+ /**
226
+ * Global theme applicator instance
227
+ */
228
+ let globalApplicator: ThemeApplicator | null = null;
229
+
230
+ /**
231
+ * Get or create global theme applicator
232
+ */
233
+ export function getThemeApplicator(): ThemeApplicator {
234
+ if (!globalApplicator) {
235
+ globalApplicator = new ThemeApplicator();
236
+ }
237
+ return globalApplicator;
238
+ }
239
+
240
+ /**
241
+ * Apply theme using global applicator
242
+ */
243
+ export function applyTheme(theme: Theme): void {
244
+ getThemeApplicator().applyTheme(theme);
245
+ }
246
+
247
+ /**
248
+ * Remove theme using global applicator
249
+ */
250
+ export function removeTheme(): void {
251
+ getThemeApplicator().removeTheme();
252
+ }
@@ -10,7 +10,23 @@ import { ThemeError, ThemeErrorCode } from '../errors';
10
10
  import type { ThemeMetadata } from '../types';
11
11
 
12
12
  // Mock dependencies
13
- vi.mock('../core/ThemeEngine');
13
+ vi.mock('../core/ThemeEngine', () => {
14
+ return {
15
+ ThemeEngine: class {
16
+ initialize = vi.fn().mockResolvedValue(undefined);
17
+ on = vi.fn();
18
+ getRegistry = vi.fn().mockReturnValue({
19
+ has: vi.fn().mockReturnValue(false),
20
+ register: vi.fn(),
21
+ getAllMetadata: vi.fn().mockReturnValue([]),
22
+ });
23
+ setTheme = vi.fn().mockResolvedValue(undefined);
24
+ getActiveTheme = vi.fn().mockReturnValue(null);
25
+ isThemeLoaded = vi.fn().mockReturnValue(false);
26
+ preloadTheme = vi.fn().mockResolvedValue(undefined);
27
+ },
28
+ };
29
+ });
14
30
  vi.mock('../config/loader');
15
31
  vi.mock('../utils', () => ({
16
32
  isBrowser: () => true,
@@ -63,7 +63,7 @@ const DEFAULT_CONFIG: Partial<ThemeManagerConfig> = {
63
63
  * // No defaultTheme - uses built-in styles
64
64
  * });
65
65
  *
66
- * await themeManager.setTheme('flashtrade');
66
+ * await themeManager.setTheme('my-custom-theme');
67
67
  * ```
68
68
  */
69
69
  export class ThemeManager {
@@ -356,13 +356,13 @@ export class ThemeManager {
356
356
  * Emit theme error event
357
357
  */
358
358
  private emitThemeError(error: Error, themeName: string): void {
359
- const themeError = error instanceof ThemeError
360
- ? error
359
+ const themeError = error instanceof ThemeError
360
+ ? error
361
361
  : new ThemeError(
362
- error.message,
363
- ThemeErrorCode.THEME_LOAD_FAILED,
364
- { themeName, originalError: error.message }
365
- );
362
+ error.message,
363
+ ThemeErrorCode.THEME_LOAD_FAILED,
364
+ { themeName, originalError: error.message }
365
+ );
366
366
 
367
367
  if (this.config.onError) {
368
368
  try {
@@ -5,7 +5,7 @@
5
5
  * spacing helpers, and theme value accessors.
6
6
  */
7
7
 
8
- import type { Theme, SpacingFunction } from './types';
8
+ import type { Theme, SpacingFunction, SpacingOptions } from './types';
9
9
 
10
10
  // ============================================================================
11
11
  // Color Manipulation Utilities
@@ -150,15 +150,37 @@ export function emphasize(color: string, coefficient: number = 0.15): string {
150
150
  // ============================================================================
151
151
 
152
152
  /**
153
- * Create a spacing function with a given base unit
153
+ * Create a spacing function from various input types
154
154
  *
155
- * @param base - Base spacing unit in pixels, default 4
155
+ * @param spacingInput - Spacing configuration (number, array, or function), default 4
156
156
  * @returns Spacing function
157
157
  */
158
- export function createSpacing(base: number = 4): SpacingFunction {
158
+ export function createSpacing(spacingInput: SpacingOptions = 4): SpacingFunction {
159
+ // If it's already a function, return it
160
+ if (typeof spacingInput === 'function') {
161
+ return spacingInput;
162
+ }
163
+
164
+ // If it's a number, create a function that multiplies by that number
165
+ if (typeof spacingInput === 'number') {
166
+ return (...values: number[]) => {
167
+ if (values.length === 0) return '0px';
168
+ return values.map((value) => `${value * spacingInput}px`).join(' ');
169
+ };
170
+ }
171
+
172
+ // If it's an array, use it as a scale
173
+ if (Array.isArray(spacingInput)) {
174
+ return (...values: number[]) => {
175
+ if (values.length === 0) return '0px';
176
+ return values.map((value) => `${spacingInput[value] || value}px`).join(' ');
177
+ };
178
+ }
179
+
180
+ // Default to 4px base
159
181
  return (...values: number[]) => {
160
182
  if (values.length === 0) return '0px';
161
- return values.map((value) => `${value * base}px`).join(' ');
183
+ return values.map((value) => `${value * 4}px`).join(' ');
162
184
  };
163
185
  }
164
186
 
@@ -5,6 +5,7 @@
5
5
  */
6
6
 
7
7
  import type { ThemeManager as ThemeManagerType } from './runtime/ThemeManager';
8
+ import type { PartStyleProps } from '../types/partProps';
8
9
 
9
10
  /**
10
11
  * Theme metadata interface matching themes.config.js structure
@@ -184,6 +185,62 @@ export interface UseThemeReturn {
184
185
  preloadTheme: (themeName: string) => Promise<void>;
185
186
  }
186
187
 
188
+ /**
189
+ * Component-level theme override configuration
190
+ */
191
+ export interface ComponentThemeOverride {
192
+ /** CSS variable overrides for the component */
193
+ cssVars?: Record<string, string | number>;
194
+
195
+ /** Default prop overrides */
196
+ defaultProps?: Record<string, any>;
197
+
198
+ /** Part-specific overrides */
199
+ parts?: Record<string, {
200
+ cssVars?: Record<string, string | number>;
201
+ className?: string;
202
+ }>;
203
+
204
+ /** Variant overrides */
205
+ variants?: Record<string, {
206
+ cssVars?: Record<string, string | number>;
207
+ className?: string;
208
+ }>;
209
+
210
+ /** Additional className for the component */
211
+ className?: string;
212
+ }
213
+
214
+ /**
215
+ * Theme component overrides for all components
216
+ */
217
+ export interface ThemeComponentOverrides {
218
+ Button?: ComponentThemeOverride;
219
+ Card?: ComponentThemeOverride;
220
+ Input?: ComponentThemeOverride;
221
+ Modal?: ComponentThemeOverride;
222
+ Dropdown?: ComponentThemeOverride;
223
+ Badge?: ComponentThemeOverride;
224
+ Tabs?: ComponentThemeOverride;
225
+ Progress?: ComponentThemeOverride;
226
+ Tooltip?: ComponentThemeOverride;
227
+ Select?: ComponentThemeOverride;
228
+ Checkbox?: ComponentThemeOverride;
229
+ Radio?: ComponentThemeOverride;
230
+ Textarea?: ComponentThemeOverride;
231
+ FormGroup?: ComponentThemeOverride;
232
+ Navbar?: ComponentThemeOverride;
233
+ Accordion?: ComponentThemeOverride;
234
+ DataTable?: ComponentThemeOverride;
235
+ Avatar?: ComponentThemeOverride;
236
+ List?: ComponentThemeOverride;
237
+ Popover?: ComponentThemeOverride;
238
+ Messages?: ComponentThemeOverride;
239
+ Callout?: ComponentThemeOverride;
240
+ Spinner?: ComponentThemeOverride;
241
+ [key: string]: ComponentThemeOverride | undefined;
242
+ }
243
+
187
244
  /**
188
245
  * Theme provider props
189
246
  */
@@ -277,7 +334,6 @@ export interface PaletteOptions {
277
334
  /** Background colors */
278
335
  background?: {
279
336
  default?: string;
280
- paper?: string;
281
337
  subtle?: string;
282
338
  };
283
339
  /** Text colors */
@@ -559,6 +615,8 @@ export interface Theme extends ThemeMetadata {
559
615
  borderRadius: Required<BorderRadiusOptions>;
560
616
  /** Custom properties */
561
617
  custom: ThemeCustomProperties;
618
+ /** Global CSS variables to apply */
619
+ cssVars?: Record<string, string | number>;
562
620
  /** Indicates this is a JS theme (not CSS-only) */
563
621
  __isJSTheme: true;
564
622
  }
@@ -0,0 +1,125 @@
1
+ /**
2
+ * Theme Tools for Library Users
3
+ *
4
+ * Developer-friendly utilities for working with Atomix themes
5
+ */
6
+
7
+ import { Theme, ThemeMetadata } from './theme/types';
8
+ import { createTheme } from './theme/createTheme';
9
+ import { extendTheme, mergeTheme } from './theme/composeTheme';
10
+ import { generateCSSVariables } from './theme/generateCSSVariables';
11
+
12
+ /**
13
+ * Quick theme creator with sensible defaults
14
+ */
15
+ export function quickTheme(name: string, primaryColor: string, secondaryColor?: string): Theme {
16
+ return createTheme({
17
+ name,
18
+ palette: {
19
+ primary: { main: primaryColor },
20
+ secondary: secondaryColor ? { main: secondaryColor } : undefined,
21
+ },
22
+ });
23
+ }
24
+
25
+ /**
26
+ * Create a dark theme variant from a light theme
27
+ */
28
+ export function createDarkVariant(lightTheme: Theme): Theme {
29
+ return extendTheme(lightTheme, {
30
+ name: `${lightTheme.name} Dark`,
31
+ palette: {
32
+ mode: 'dark',
33
+ background: {
34
+ default: '#121212',
35
+ paper: '#1e1e1e',
36
+ },
37
+ text: {
38
+ primary: '#ffffff',
39
+ secondary: 'rgba(255, 255, 255, 0.7)',
40
+ },
41
+ },
42
+ });
43
+ }
44
+
45
+ /**
46
+ * Validate theme structure
47
+ */
48
+ export function validateTheme(theme: Theme): { valid: boolean; errors: string[] } {
49
+ const errors: string[] = [];
50
+
51
+ if (!theme.name) {
52
+ errors.push('Theme must have a name');
53
+ }
54
+
55
+ if (!theme.palette) {
56
+ errors.push('Theme must have a palette');
57
+ }
58
+
59
+ if (theme.palette && !theme.palette.primary) {
60
+ errors.push('Theme palette must have a primary color');
61
+ }
62
+
63
+ return {
64
+ valid: errors.length === 0,
65
+ errors,
66
+ };
67
+ }
68
+
69
+ /**
70
+ * Generate CSS string from theme
71
+ */
72
+ export function themeToCSS(theme: Theme, selector = ':root'): string {
73
+ return generateCSSVariables(theme, {
74
+ selector,
75
+ prefix: 'atomix',
76
+ });
77
+ }
78
+
79
+ /**
80
+ * Get theme metadata
81
+ */
82
+ export function getThemeMetadata(theme: Theme): ThemeMetadata {
83
+ return {
84
+ name: theme.name || 'Custom Theme',
85
+ description: theme.description,
86
+ author: theme.author,
87
+ version: theme.version || '1.0.0',
88
+ tags: theme.tags || [],
89
+ supportsDarkMode: theme.palette?.mode === 'dark',
90
+ status: 'stable',
91
+ color: theme.palette?.primary?.main || '#7AFFD7',
92
+ };
93
+ }
94
+
95
+ /**
96
+ * Check if theme supports dark mode
97
+ */
98
+ export function supportsDarkMode(theme: Theme): boolean {
99
+ return theme.palette?.mode === 'dark' ||
100
+ theme.supportsDarkMode === true ||
101
+ Boolean(theme.a11y?.modes?.includes('dark'));
102
+ }
103
+
104
+ /**
105
+ * Export theme as JSON
106
+ */
107
+ export function exportTheme(theme: Theme): string {
108
+ return JSON.stringify(theme, null, 2);
109
+ }
110
+
111
+ /**
112
+ * Import theme from JSON
113
+ */
114
+ export function importTheme(json: string): Theme {
115
+ try {
116
+ return JSON.parse(json) as Theme;
117
+ } catch (error) {
118
+ throw new Error('Invalid theme JSON');
119
+ }
120
+ }
121
+
122
+ // Re-export commonly used functions
123
+ export { createTheme, extendTheme, mergeTheme };
124
+ export { generateCSSVariables };
125
+ export { RTLManager } from './theme/i18n/rtl';