@shohojdhara/atomix 0.3.7 → 0.3.8

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 (53) hide show
  1. package/dist/atomix.css +77 -0
  2. package/dist/atomix.css.map +1 -1
  3. package/dist/atomix.min.css +77 -0
  4. package/dist/atomix.min.css.map +1 -1
  5. package/dist/charts.js.map +1 -1
  6. package/dist/core.d.ts +2 -2
  7. package/dist/core.js.map +1 -1
  8. package/dist/forms.js.map +1 -1
  9. package/dist/heavy.js.map +1 -1
  10. package/dist/index.d.ts +578 -515
  11. package/dist/index.esm.js +3157 -2626
  12. package/dist/index.esm.js.map +1 -1
  13. package/dist/index.js +10496 -9973
  14. package/dist/index.js.map +1 -1
  15. package/dist/index.min.js +1 -1
  16. package/dist/index.min.js.map +1 -1
  17. package/dist/theme.d.ts +237 -420
  18. package/dist/theme.js +1629 -1701
  19. package/dist/theme.js.map +1 -1
  20. package/package.json +1 -1
  21. package/src/components/DataTable/DataTable.stories.tsx +238 -0
  22. package/src/components/DataTable/DataTable.test.tsx +450 -0
  23. package/src/components/DataTable/DataTable.tsx +384 -61
  24. package/src/components/DatePicker/DatePicker.tsx +29 -38
  25. package/src/components/Upload/Upload.tsx +539 -40
  26. package/src/lib/composables/useDataTable.ts +355 -15
  27. package/src/lib/composables/useDatePicker.ts +19 -0
  28. package/src/lib/constants/components.ts +10 -0
  29. package/src/lib/theme/adapters/cssVariableMapper.ts +29 -14
  30. package/src/lib/theme/adapters/index.ts +1 -4
  31. package/src/lib/theme/config/configLoader.ts +53 -35
  32. package/src/lib/theme/core/composeTheme.ts +22 -30
  33. package/src/lib/theme/core/createTheme.ts +49 -26
  34. package/src/lib/theme/core/index.ts +0 -1
  35. package/src/lib/theme/generators/generateCSSNested.ts +4 -3
  36. package/src/lib/theme/generators/generateCSSVariables.ts +24 -16
  37. package/src/lib/theme/index.ts +10 -17
  38. package/src/lib/theme/runtime/ThemeApplicator.ts +6 -109
  39. package/src/lib/theme/runtime/ThemeErrorBoundary.tsx +3 -3
  40. package/src/lib/theme/runtime/ThemeProvider.tsx +186 -44
  41. package/src/lib/theme/runtime/useTheme.ts +1 -1
  42. package/src/lib/theme/runtime/useThemeTokens.ts +7 -16
  43. package/src/lib/theme/test/testTheme.ts +2 -1
  44. package/src/lib/theme/types.ts +14 -14
  45. package/src/lib/theme/utils/componentTheming.ts +35 -27
  46. package/src/lib/theme/utils/domUtils.ts +57 -15
  47. package/src/lib/theme/utils/injectCSS.ts +0 -1
  48. package/src/lib/theme/utils/themeHelpers.ts +1 -39
  49. package/src/lib/theme/utils/themeUtils.ts +1 -170
  50. package/src/lib/types/components.ts +145 -0
  51. package/src/lib/utils/dataTableExport.ts +143 -0
  52. package/src/styles/06-components/_components.data-table.scss +95 -0
  53. package/src/lib/hooks/useThemeTokens.ts +0 -105
@@ -148,7 +148,7 @@ export class ThemeErrorBoundary extends Component<
148
148
  };
149
149
  }
150
150
 
151
- componentDidCatch(error: Error, errorInfo: ErrorInfo): void {
151
+ override componentDidCatch(error: Error, errorInfo: ErrorInfo): void {
152
152
  // Log error
153
153
  const themeError = error instanceof ThemeError
154
154
  ? error
@@ -187,7 +187,7 @@ export class ThemeErrorBoundary extends Component<
187
187
  }
188
188
  }
189
189
 
190
- componentDidUpdate(prevProps: ThemeErrorBoundaryProps): void {
190
+ override componentDidUpdate(prevProps: ThemeErrorBoundaryProps): void {
191
191
  // Reset error if resetOnPropsChange is true and children changed
192
192
  if (
193
193
  this.props.resetOnPropsChange &&
@@ -202,7 +202,7 @@ export class ThemeErrorBoundary extends Component<
202
202
  }
203
203
  }
204
204
 
205
- render(): ReactNode {
205
+ override render(): ReactNode {
206
206
  if (this.state.hasError && this.state.error && this.state.errorInfo) {
207
207
  // Use custom fallback if provided
208
208
  if (this.props.fallback) {
@@ -7,8 +7,8 @@
7
7
 
8
8
  import React, { useState, useEffect, useCallback, useMemo, useRef } from 'react';
9
9
  import { ThemeContext } from './ThemeContext';
10
- import type { ThemeProviderProps, Theme, ThemeLoadOptions } from '../types';
11
- import { isJSTheme } from '../utils/themeUtils';
10
+ import type { ThemeProviderProps, ThemeLoadOptions } from '../types';
11
+ import type { DesignTokens } from '../tokens/tokens';
12
12
  import { getLogger } from '../errors';
13
13
  import { createTheme } from '../core';
14
14
  import { injectCSS, removeCSS } from '../utils/injectCSS';
@@ -30,7 +30,7 @@ import {
30
30
  * React context provider for theme management with separated concerns.
31
31
  * Simplified version focusing on core functionality:
32
32
  * - String-based themes (CSS files)
33
- * - JS Theme objects
33
+ * - DesignTokens (dynamic themes)
34
34
  * - Persistence via localStorage
35
35
  *
36
36
  * Falls back to 'default' theme if no configuration is found.
@@ -59,7 +59,7 @@ export const ThemeProvider: React.FC<ThemeProviderProps> = ({
59
59
  }, [onThemeChange, onError]);
60
60
 
61
61
  // Create stable wrapper functions that read from ref
62
- const handleThemeChange = useCallback((theme: string | Theme) => {
62
+ const handleThemeChange = useCallback((theme: string | DesignTokens) => {
63
63
  onThemeChangeRef.current?.(theme);
64
64
  }, []);
65
65
 
@@ -98,7 +98,7 @@ export const ThemeProvider: React.FC<ThemeProviderProps> = ({
98
98
  return 'config-theme';
99
99
  }
100
100
  } catch (error) {
101
- console.warn('Failed to load theme from config, using default');
101
+ // Failed to load theme from config, using default
102
102
  }
103
103
  }
104
104
 
@@ -106,15 +106,40 @@ export const ThemeProvider: React.FC<ThemeProviderProps> = ({
106
106
  return 'default';
107
107
  }, [defaultTheme, enablePersistence, storageKey]);
108
108
 
109
- // State for current theme
110
- const [currentTheme, setCurrentTheme] = useState<string | Theme>(() => initialDefaultTheme);
111
- const [activeTheme, setActiveTheme] = useState<Theme | null>(null);
109
+ // Initialize state - handle both string and DesignTokens for defaultTheme
110
+ const [currentTheme, setCurrentTheme] = useState<string>(() => {
111
+ if (typeof initialDefaultTheme === 'string') {
112
+ return initialDefaultTheme;
113
+ }
114
+ // If it's DesignTokens, we'll handle it in useEffect
115
+ return 'tokens-theme';
116
+ });
117
+
118
+ const [activeTokens, setActiveTokens] = useState<DesignTokens | null>(() => {
119
+ // If defaultTheme is DesignTokens, store them
120
+ if (defaultTheme && typeof defaultTheme !== 'string') {
121
+ const { createTokens } = require('../tokens/tokens');
122
+ return createTokens(defaultTheme);
123
+ }
124
+ return null;
125
+ });
112
126
  const [isLoading, setIsLoading] = useState(false);
113
127
  const [error, setError] = useState<Error | null>(null);
114
128
 
115
129
  // Track loaded themes
116
130
  const loadedThemesRef = useRef<Set<string>>(new Set());
117
131
  const themePromisesRef = useRef<Record<string, Promise<void>>>({});
132
+ // AbortController for cancelling in-flight theme loads
133
+ const abortControllerRef = useRef<AbortController | null>(null);
134
+
135
+ // Handle initial DesignTokens defaultTheme
136
+ useEffect(() => {
137
+ if (defaultTheme && typeof defaultTheme !== 'string' && activeTokens && !isServer()) {
138
+ // If defaultTheme is DesignTokens, inject CSS on mount
139
+ const css = createTheme(defaultTheme);
140
+ injectCSS(css, 'theme-tokens-theme');
141
+ }
142
+ }, [defaultTheme, activeTokens]); // Run when defaultTheme or activeTokens change
118
143
 
119
144
  // Apply initial theme attributes to document element
120
145
  useEffect(() => {
@@ -128,50 +153,120 @@ export const ThemeProvider: React.FC<ThemeProviderProps> = ({
128
153
  if (enablePersistence && storageAdapter.isAvailable()) {
129
154
  storageAdapter.setItem(storageKey, String(currentTheme));
130
155
  }
131
- }, [currentTheme, storageKey, enablePersistence]);
156
+ }, [currentTheme, storageKey, enablePersistence, storageAdapter]);
157
+
158
+ // Cleanup: Remove completed promises and abort controllers on unmount
159
+ useEffect(() => {
160
+ return () => {
161
+ // Cancel any in-flight theme loads
162
+ if (abortControllerRef.current) {
163
+ abortControllerRef.current.abort();
164
+ abortControllerRef.current = null;
165
+ }
166
+
167
+ // Clean up completed promises (keep only pending ones)
168
+ // In practice, completed promises are automatically garbage collected,
169
+ // but we can clear the ref to be explicit
170
+ const pendingPromises: Record<string, Promise<void>> = {};
171
+ Object.entries(themePromisesRef.current).forEach(([key, promise]) => {
172
+ // Check if promise is still pending (this is a best-effort cleanup)
173
+ // In practice, we rely on garbage collection for completed promises
174
+ pendingPromises[key] = promise;
175
+ });
176
+ // Clear all on unmount
177
+ themePromisesRef.current = {};
178
+ };
179
+ }, []);
132
180
 
133
181
  // Function to set theme with proper type handling
134
182
  const setTheme = useCallback(async (
135
- theme: string | Theme | import('../tokens').DesignTokens | Partial<import('../tokens').DesignTokens>,
183
+ theme: string | DesignTokens | Partial<DesignTokens>,
136
184
  options?: ThemeLoadOptions
137
185
  ) => {
186
+ // Cancel previous theme load if in progress
187
+ if (abortControllerRef.current) {
188
+ abortControllerRef.current.abort();
189
+ }
190
+
191
+ // Create new AbortController for this theme load
192
+ const abortController = new AbortController();
193
+ abortControllerRef.current = abortController;
194
+
138
195
  setIsLoading(true);
139
196
  setError(null);
140
197
 
141
198
  try {
142
199
  let themeName: string;
143
- let themeObj: Theme | null = null;
144
200
 
145
201
  if (typeof theme === 'string') {
146
202
  themeName = theme;
147
203
  } else {
148
- // If it's a Theme object or DesignTokens, we need to process it
149
- if (isJSTheme(theme)) {
150
- themeObj = theme as Theme;
151
- // For JS themes, we use a generic name
152
- themeName = 'js-theme';
153
- setActiveTheme(themeObj);
154
- } else {
155
- // For DesignTokens, we might create a theme from tokens
156
- themeName = 'tokens-theme';
157
- // Create theme from tokens if needed
204
+ // Check if aborted before processing
205
+ if (abortController.signal.aborted) {
206
+ return;
158
207
  }
208
+
209
+ // For DesignTokens, create CSS and inject it
210
+ const { createTheme } = await import('../core');
211
+ const css = createTheme(theme);
212
+ const themeId = 'tokens-theme';
213
+
214
+ // Check if aborted after async operation
215
+ if (abortController.signal.aborted) {
216
+ return;
217
+ }
218
+
219
+ // Remove any previously loaded theme CSS
220
+ removeCSS(`theme-${currentTheme}`);
221
+
222
+ // Inject new theme CSS
223
+ injectCSS(css, `theme-${themeId}`);
224
+
225
+ // Store tokens for reference
226
+ const { createTokens } = await import('../tokens/tokens');
227
+ const fullTokens = createTokens(theme);
228
+
229
+ // Check if aborted before state update
230
+ if (abortController.signal.aborted) {
231
+ return;
232
+ }
233
+
234
+ setActiveTokens(fullTokens);
235
+ setCurrentTheme(themeId);
236
+ handleThemeChange(fullTokens);
237
+ setIsLoading(false);
238
+ return;
159
239
  }
160
240
 
161
241
  // If it's a string theme name, load the associated CSS
162
242
  if (typeof theme === 'string' && themes[theme]) {
163
243
  // Check if theme is already loading
164
244
  if (themePromisesRef.current[theme]) {
165
- await themePromisesRef.current[theme];
166
- setCurrentTheme(theme);
167
- setActiveTheme(null);
168
- handleThemeChange(theme);
169
- return;
245
+ try {
246
+ await themePromisesRef.current[theme];
247
+ // Check if aborted
248
+ if (abortController.signal.aborted) {
249
+ return;
250
+ }
251
+ setCurrentTheme(theme);
252
+ setActiveTokens(null);
253
+ handleThemeChange(theme);
254
+ setIsLoading(false);
255
+ return;
256
+ } catch {
257
+ // If previous load failed, continue with new load
258
+ }
170
259
  }
171
260
 
172
261
  // Load CSS theme
173
262
  const themeLoadPromise = new Promise<void>(async (resolve, reject) => {
174
263
  try {
264
+ // Check if aborted
265
+ if (abortController.signal.aborted) {
266
+ resolve();
267
+ return;
268
+ }
269
+
175
270
  const themeMetadata = themes[theme];
176
271
 
177
272
  if (themeMetadata) {
@@ -183,21 +278,41 @@ export const ThemeProvider: React.FC<ThemeProviderProps> = ({
183
278
  cdnPath
184
279
  );
185
280
 
281
+ // Check if aborted
282
+ if (abortController.signal.aborted) {
283
+ resolve();
284
+ return;
285
+ }
286
+
287
+ // Load CSS file (using loadThemeCSS from domUtils)
288
+ const { loadThemeCSS } = await import('../utils/domUtils');
289
+ await loadThemeCSS(cssPath, `theme-${theme}`);
290
+
291
+ // Check if aborted after async operation
292
+ if (abortController.signal.aborted) {
293
+ resolve();
294
+ return;
295
+ }
296
+
186
297
  // Remove any previously loaded theme CSS
187
298
  removeCSS(`theme-${String(currentTheme)}`);
188
299
 
189
- // Inject new theme CSS
190
- await injectCSS(cssPath, `theme-${theme}`);
191
300
  loadedThemesRef.current.add(theme);
192
301
 
193
302
  setCurrentTheme(theme);
194
- setActiveTheme(null);
303
+ setActiveTokens(null);
195
304
  handleThemeChange(theme);
196
305
  resolve();
197
306
  } else {
198
307
  throw new Error(`Theme metadata not found for theme: ${theme}`);
199
308
  }
200
309
  } catch (err) {
310
+ // Don't reject if aborted
311
+ if (abortController.signal.aborted) {
312
+ resolve();
313
+ return;
314
+ }
315
+
201
316
  const error = err instanceof Error ? err : new Error(String(err));
202
317
  setError(error);
203
318
  handleError(error, String(theme));
@@ -206,24 +321,44 @@ export const ThemeProvider: React.FC<ThemeProviderProps> = ({
206
321
  });
207
322
 
208
323
  themePromisesRef.current[theme] = themeLoadPromise;
209
- await themeLoadPromise;
210
- } else if (themeObj) {
211
- // For JS themes, set them directly
212
- setCurrentTheme(themeName);
213
- setActiveTheme(themeObj);
214
- handleThemeChange(themeObj);
324
+
325
+ try {
326
+ await themeLoadPromise;
327
+ } catch {
328
+ // Error already handled in promise
329
+ }
330
+
331
+ // Clean up completed promise after a delay to prevent memory leak
332
+ setTimeout(() => {
333
+ if (themePromisesRef.current[theme] === themeLoadPromise) {
334
+ delete themePromisesRef.current[theme];
335
+ }
336
+ }, 1000);
215
337
  } else {
338
+ // Check if aborted
339
+ if (abortController.signal.aborted) {
340
+ return;
341
+ }
342
+
216
343
  // For string theme that isn't in our themes record, just set the name
217
344
  setCurrentTheme(themeName);
218
- setActiveTheme(null);
345
+ setActiveTokens(null);
219
346
  handleThemeChange(themeName);
220
347
  }
221
348
  } catch (err) {
349
+ // Don't set error if aborted
350
+ if (abortController.signal.aborted) {
351
+ return;
352
+ }
353
+
222
354
  const error = err instanceof Error ? err : new Error(String(err));
223
355
  setError(error);
224
356
  handleError(error, String(theme));
225
357
  } finally {
226
- setIsLoading(false);
358
+ // Only update loading state if not aborted
359
+ if (!abortController.signal.aborted) {
360
+ setIsLoading(false);
361
+ }
227
362
  }
228
363
  }, [themes, currentTheme, handleThemeChange, handleError, basePath, useMinified, cdnPath]);
229
364
 
@@ -269,14 +404,21 @@ export const ThemeProvider: React.FC<ThemeProviderProps> = ({
269
404
  } ;
270
405
  }, []);
271
406
 
407
+ // Memoize available themes to prevent unnecessary recalculations
408
+ const availableThemes = useMemo(() =>
409
+ Object.entries(themes).map(([name, metadata]) => ({
410
+ ...metadata,
411
+ name: name, // Ensure name is set from the key
412
+ })),
413
+ [themes]
414
+ );
415
+
272
416
  // Theme context value
273
417
  const contextValue = useMemo(() => ({
274
- theme: typeof currentTheme === 'string' ? currentTheme : 'js-theme',
275
- activeTheme,
418
+ theme: currentTheme,
419
+ activeTokens,
276
420
  setTheme,
277
- availableThemes: Object.entries(themes).map(([name, metadata]) => ({
278
- ...metadata
279
- })),
421
+ availableThemes,
280
422
  isLoading,
281
423
  error,
282
424
  isThemeLoaded,
@@ -284,9 +426,9 @@ export const ThemeProvider: React.FC<ThemeProviderProps> = ({
284
426
  themeManager,
285
427
  }), [
286
428
  currentTheme,
287
- activeTheme,
429
+ activeTokens,
288
430
  setTheme,
289
- themes,
431
+ availableThemes, // Use memoized value
290
432
  isLoading,
291
433
  error,
292
434
  isThemeLoaded,
@@ -38,7 +38,7 @@ export function useTheme(): UseThemeReturn {
38
38
 
39
39
  return {
40
40
  theme: context.theme,
41
- activeTheme: context.activeTheme,
41
+ activeTokens: context.activeTokens,
42
42
  setTheme: context.setTheme,
43
43
  availableThemes: context.availableThemes,
44
44
  isLoading: context.isLoading,
@@ -1,18 +1,17 @@
1
1
  import { useCallback } from 'react';
2
2
  import { useTheme } from './useTheme';
3
- import type { Theme } from '../types';
3
+ import type { DesignTokens } from '../tokens/tokens';
4
4
 
5
5
  /**
6
6
  * Standardized hook for accessing theme tokens in components
7
7
  *
8
- * Provides consistent access to theme values across all components
9
- * using either CSS custom properties or theme object values.
8
+ * Provides consistent access to theme values using CSS custom properties
9
+ * and DesignTokens.
10
10
  */
11
11
  type ThemeTokens = {
12
12
  theme: string;
13
- activeTheme: Theme | null;
13
+ activeTokens: DesignTokens | null;
14
14
  getToken: (tokenName: string, fallback?: string) => string;
15
- getThemeValue: (path: string, fallback?: any) => any;
16
15
  colors: {
17
16
  primary: string;
18
17
  secondary: string;
@@ -35,7 +34,7 @@ type ThemeTokens = {
35
34
  };
36
35
 
37
36
  export function useThemeTokens(): ThemeTokens {
38
- const { theme, activeTheme } = useTheme();
37
+ const { theme, activeTokens } = useTheme();
39
38
 
40
39
  // Helper function to get CSS variable value
41
40
  const getToken = useCallback((tokenName: string, fallback?: string) => {
@@ -46,20 +45,12 @@ export function useThemeTokens(): ThemeTokens {
46
45
  return computedStyle.getPropertyValue(cssVarName).trim() || fallback || '';
47
46
  }, []);
48
47
 
49
- // Helper function to get theme object value
50
- const getThemeValue = useCallback((path: string, fallback?: any) => {
51
- if (!activeTheme) return fallback;
52
-
53
- // Navigate through nested theme object using dot notation
54
- return path.split('.').reduce((obj, key) => obj?.[key], activeTheme) || fallback;
55
- }, [activeTheme]);
56
-
57
48
  // Return unified API for accessing theme values
49
+ // Note: For SSR or direct token access, use activeTokens directly
58
50
  return <ThemeTokens>{
59
51
  theme,
60
- activeTheme,
52
+ activeTokens,
61
53
  getToken,
62
- getThemeValue,
63
54
  // Commonly used tokens with fallbacks
64
55
  colors: {
65
56
  primary: getToken('primary', '#3b82f6'),
@@ -270,7 +270,8 @@ export function createTestThemeObject(): Theme {
270
270
  */
271
271
  export function generateTestThemeCSSFromObject(): string {
272
272
  const theme = createTestThemeObject();
273
- return createTheme(theme); // createTheme accepts both formats
273
+ const tokens = themeToDesignTokens(theme);
274
+ return createTheme(tokens);
274
275
  }
275
276
 
276
277
  // ============================================================================
@@ -50,8 +50,8 @@ export interface ThemeChangeEvent {
50
50
  previousTheme: string | null;
51
51
  /** New theme name */
52
52
  currentTheme: string;
53
- /** Theme object (for JS themes) */
54
- themeObject?: Theme | null;
53
+ /** DesignTokens if using tokens-based theme */
54
+ tokens?: import('./tokens').DesignTokens | null;
55
55
  /** Timestamp of the change */
56
56
  timestamp: number;
57
57
  /** Whether the change was from user action or system */
@@ -126,7 +126,7 @@ export interface UseThemeOptions {
126
126
  /** Custom storage key */
127
127
  storageKey?: string;
128
128
  /** Callback when theme changes */
129
- onChange?: (theme: string | Theme | import('./tokens').DesignTokens) => void;
129
+ onChange?: (theme: string | import('./tokens').DesignTokens) => void;
130
130
  }
131
131
 
132
132
  /**
@@ -135,10 +135,10 @@ export interface UseThemeOptions {
135
135
  export interface UseThemeReturn {
136
136
  /** Current theme name */
137
137
  theme: string;
138
- /** Current active theme object (for JS themes) */
139
- activeTheme: Theme | null;
140
- /** Function to change theme (supports string, Theme, or DesignTokens) */
141
- setTheme: (theme: string | Theme | import('./tokens').DesignTokens | Partial<import('./tokens').DesignTokens>, options?: ThemeLoadOptions) => Promise<void>;
138
+ /** Current active DesignTokens (if using tokens-based theme) */
139
+ activeTokens: import('./tokens').DesignTokens | null;
140
+ /** Function to change theme (supports string or DesignTokens) */
141
+ setTheme: (theme: string | import('./tokens').DesignTokens | Partial<import('./tokens').DesignTokens>, options?: ThemeLoadOptions) => Promise<void>;
142
142
  /** Available themes */
143
143
  availableThemes: ThemeMetadata[];
144
144
  /** Whether a theme is currently loading */
@@ -213,8 +213,8 @@ export interface ThemeComponentOverrides {
213
213
  export interface ThemeProviderProps {
214
214
  /** Child components */
215
215
  children: React.ReactNode;
216
- /** Default theme */
217
- defaultTheme?: string | Theme;
216
+ /** Default theme (string name or DesignTokens) */
217
+ defaultTheme?: string | import('./tokens').DesignTokens | Partial<import('./tokens').DesignTokens>;
218
218
  /** Available themes */
219
219
  themes?: Record<string, ThemeMetadata>;
220
220
  /** Base path for theme CSS */
@@ -234,7 +234,7 @@ export interface ThemeProviderProps {
234
234
  /** Use minified CSS */
235
235
  useMinified?: boolean;
236
236
  /** Callback when theme changes */
237
- onThemeChange?: (theme: string | Theme | import('./tokens').DesignTokens) => void;
237
+ onThemeChange?: (theme: string | import('./tokens').DesignTokens) => void;
238
238
  /** Callback on error */
239
239
  onError?: (error: Error, themeName: string) => void;
240
240
  }
@@ -245,10 +245,10 @@ export interface ThemeProviderProps {
245
245
  export interface ThemeContextValue {
246
246
  /** Current theme name */
247
247
  theme: string;
248
- /** Current active theme object (for JS themes) */
249
- activeTheme: Theme | null;
250
- /** Set theme function (supports string, Theme, or DesignTokens) */
251
- setTheme: (theme: string | Theme | import('./tokens').DesignTokens | Partial<import('./tokens').DesignTokens>, options?: ThemeLoadOptions) => Promise<void>;
248
+ /** Current active DesignTokens (if using tokens-based theme) */
249
+ activeTokens: import('./tokens').DesignTokens | null;
250
+ /** Set theme function (supports string or DesignTokens) */
251
+ setTheme: (theme: string | import('./tokens').DesignTokens | Partial<import('./tokens').DesignTokens>, options?: ThemeLoadOptions) => Promise<void>;
252
252
  /** Available themes */
253
253
  availableThemes: ThemeMetadata[];
254
254
  /** Loading state */
@@ -2,15 +2,16 @@
2
2
  * Component Theming Utilities
3
3
  *
4
4
  * Provides consistent patterns for applying theme values to components
5
+ * using DesignTokens and CSS variables
5
6
  */
6
7
 
7
- import type { Theme } from '../types';
8
+ import type { DesignTokens } from '../tokens/tokens';
8
9
 
9
10
  export interface ComponentThemeOptions {
10
11
  component: string;
11
12
  variant?: string;
12
13
  size?: string;
13
- theme: Theme;
14
+ tokens?: Partial<DesignTokens>;
14
15
  }
15
16
 
16
17
  /**
@@ -44,18 +45,18 @@ export function getComponentThemeValue(
44
45
  }
45
46
 
46
47
  /**
47
- * Generate component-specific CSS variables from theme
48
+ * Generate component-specific CSS variables from DesignTokens
48
49
  */
49
50
  export function generateComponentCSSVars(
50
51
  component: string,
51
- theme: Theme,
52
+ tokens?: Partial<DesignTokens>,
52
53
  variant?: string,
53
54
  size?: string
54
55
  ): Record<string, string> {
55
56
  const vars: Record<string, string> = {};
56
57
 
57
- // This is a simplified implementation - in a real system you'd have more
58
- // sophisticated logic to extract component-specific values from the theme
58
+ if (!tokens) return vars;
59
+
59
60
  const prefixParts = ['atomix', component];
60
61
 
61
62
  if (variant) {
@@ -68,47 +69,54 @@ export function generateComponentCSSVars(
68
69
 
69
70
  const prefix = prefixParts.join('-');
70
71
 
71
- // Add common component properties
72
- if (theme.palette) {
73
- vars[`--${prefix}-color`] = theme.palette.primary?.main || '#7c3aed';
74
- vars[`--${prefix}-color-hover`] = theme.palette.primary?.dark || '#5b21b6';
75
- vars[`--${prefix}-color-active`] = theme.palette.primary?.main || '#7c3aed';
76
- vars[`--${prefix}-color-disabled`] = theme.palette.text?.disabled || '#9ca3af';
72
+ // Map common DesignTokens to component-specific CSS variables
73
+ if (tokens.primary) {
74
+ vars[`--${prefix}-color`] = tokens.primary;
75
+ }
76
+ if (tokens['primary-9']) {
77
+ vars[`--${prefix}-color-hover`] = tokens['primary-9'];
78
+ }
79
+ if (tokens['body-color']) {
80
+ vars[`--${prefix}-color-disabled`] = tokens['body-color'];
77
81
  }
78
82
 
79
- if (theme.typography) {
80
- vars[`--${prefix}-font-family`] = theme.typography.fontFamily || 'Inter, sans-serif';
81
- vars[`--${prefix}-font-size`] = theme.typography.fontSize ? `${theme.typography.fontSize}px` : '16px';
83
+ if (tokens['body-font-family']) {
84
+ vars[`--${prefix}-font-family`] = tokens['body-font-family'];
85
+ }
86
+ if (tokens['body-font-size']) {
87
+ vars[`--${prefix}-font-size`] = tokens['body-font-size'];
82
88
  }
83
89
 
84
- if (theme.spacing) {
85
- const spacing = typeof theme.spacing === 'function' ? theme.spacing : (val: number) => val * 8;
86
- vars[`--${prefix}-spacing-unit`] = `${spacing(1)}px`;
87
- vars[`--${prefix}-spacing-sm`] = `${spacing(0.5)}px`;
88
- vars[`--${prefix}-spacing-md`] = `${spacing(1)}px`;
89
- vars[`--${prefix}-spacing-lg`] = `${spacing(2)}px`;
90
+ if (tokens['spacing-1']) {
91
+ vars[`--${prefix}-spacing-sm`] = tokens['spacing-1'];
92
+ }
93
+ if (tokens['spacing-2']) {
94
+ vars[`--${prefix}-spacing-md`] = tokens['spacing-2'];
95
+ }
96
+ if (tokens['spacing-4']) {
97
+ vars[`--${prefix}-spacing-lg`] = tokens['spacing-4'];
90
98
  }
91
99
 
92
100
  return vars;
93
101
  }
94
102
 
95
103
  /**
96
- * Apply consistent theme to component style object
104
+ * Apply consistent theme to component style object using DesignTokens
97
105
  */
98
106
  export function applyComponentTheme(
99
107
  component: string,
100
108
  style: React.CSSProperties = {},
101
109
  variant?: string,
102
110
  size?: string,
103
- theme?: Theme
111
+ tokens?: Partial<DesignTokens>
104
112
  ): React.CSSProperties {
105
- // If no theme provided, return original style
106
- if (!theme) {
113
+ // If no tokens provided, return original style
114
+ if (!tokens) {
107
115
  return style;
108
116
  }
109
117
 
110
118
  // Generate component-specific CSS variables
111
- const componentVars = generateComponentCSSVars(component, theme, variant, size);
119
+ const componentVars = generateComponentCSSVars(component, tokens, variant, size);
112
120
 
113
121
  // Merge with existing style
114
122
  return {
@@ -124,7 +132,7 @@ export function useComponentTheme(
124
132
  component: string,
125
133
  variant?: string,
126
134
  size?: string,
127
- theme?: Theme
135
+ tokens?: Partial<DesignTokens>
128
136
  ): (property: string) => string {
129
137
  return (property: string) => {
130
138
  return getComponentThemeValue(component, property, variant, size);