@shohojdhara/atomix 0.3.6 → 0.3.7

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 (51) hide show
  1. package/README.md +3 -3
  2. package/dist/charts.js +50 -142
  3. package/dist/charts.js.map +1 -1
  4. package/dist/core.js +179 -274
  5. package/dist/core.js.map +1 -1
  6. package/dist/forms.js +50 -142
  7. package/dist/forms.js.map +1 -1
  8. package/dist/heavy.js +179 -274
  9. package/dist/heavy.js.map +1 -1
  10. package/dist/index.d.ts +669 -703
  11. package/dist/index.esm.js +966 -1649
  12. package/dist/index.esm.js.map +1 -1
  13. package/dist/index.js +1211 -1890
  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 +163 -334
  18. package/dist/theme.js +774 -1473
  19. package/dist/theme.js.map +1 -1
  20. package/package.json +1 -1
  21. package/src/components/AtomixGlass/AtomixGlass.tsx +128 -356
  22. package/src/components/AtomixGlass/AtomixGlassContainer.tsx +1 -1
  23. package/src/components/Button/Button.tsx +85 -167
  24. package/src/lib/composables/useAtomixGlass.ts +7 -7
  25. package/src/lib/config/loader.ts +2 -3
  26. package/src/lib/constants/components.ts +7 -0
  27. package/src/lib/hooks/usePerformanceMonitor.ts +1 -1
  28. package/src/lib/hooks/useThemeTokens.ts +105 -0
  29. package/src/lib/theme/config/configLoader.ts +60 -219
  30. package/src/lib/theme/config/loader.ts +15 -21
  31. package/src/lib/theme/constants/constants.ts +1 -1
  32. package/src/lib/theme/core/ThemeRegistry.ts +75 -279
  33. package/src/lib/theme/core/composeTheme.ts +14 -64
  34. package/src/lib/theme/core/createTheme.ts +54 -40
  35. package/src/lib/theme/core/createThemeObject.ts +2 -2
  36. package/src/lib/theme/core/index.ts +15 -1
  37. package/src/lib/theme/errors/errors.ts +1 -1
  38. package/src/lib/theme/generators/generateCSSNested.ts +130 -0
  39. package/src/lib/theme/generators/index.ts +6 -0
  40. package/src/lib/theme/index.ts +35 -10
  41. package/src/lib/theme/runtime/ThemeApplicator.ts +1 -1
  42. package/src/lib/theme/runtime/ThemeErrorBoundary.tsx +4 -4
  43. package/src/lib/theme/runtime/ThemeProvider.tsx +261 -554
  44. package/src/lib/theme/runtime/index.ts +1 -0
  45. package/src/lib/theme/runtime/useThemeTokens.ts +131 -0
  46. package/src/lib/theme/utils/componentTheming.ts +132 -0
  47. package/src/lib/theme/utils/naming.ts +100 -0
  48. package/src/lib/theme/utils/themeUtils.ts +6 -6
  49. package/src/lib/utils/componentUtils.ts +1 -1
  50. package/src/lib/utils/memoryMonitor.ts +3 -3
  51. package/src/lib/utils/themeNaming.ts +135 -0
@@ -1,254 +1,95 @@
1
+
1
2
  /**
2
- * Config Loader
3
- *
4
- * Load design tokens from atomix.config.ts and convert to flat token format.
3
+ * Theme Configuration Loader
4
+ *
5
+ * Provides functions to load theme configurations from atomix.config.ts
6
+ * Includes both sync and async versions, with automatic fallbacks
5
7
  */
6
8
 
9
+ import type { Theme } from '../types';
7
10
  import type { DesignTokens } from '../tokens/tokens';
8
- import type { AtomixConfig, ThemeTokens } from '../../config';
11
+ import { createTokens } from '../tokens/tokens';
12
+ import { themeToDesignTokens, createDesignTokensFromTheme } from '../adapters/themeAdapter';
9
13
 
10
14
  /**
11
- * Convert nested config tokens to flat DesignTokens format
12
- *
13
- * Handles conversion from atomix.config.ts structure to flat tokens.
14
- * Maps config structure to actual DesignTokens key names.
15
+ * Load theme from config file (synchronous, Node.js only)
16
+ * @param configPath - Path to config file (default: atomix.config.ts)
17
+ * @returns DesignTokens from theme configuration
18
+ * @throws Error if config loading is not available in browser environment
15
19
  */
16
- function flattenConfigTokens(
17
- tokens: ThemeTokens,
18
- prefix: string = 'atomix'
19
- ): Partial<DesignTokens> {
20
- const flat: Partial<DesignTokens> = {};
21
-
22
- // Colors
23
- if (tokens.colors) {
24
- Object.entries(tokens.colors).forEach(([key, value]) => {
25
- if (typeof value === 'string') {
26
- // Simple color: 'primary': '#7AFFD7'
27
- // Map directly to DesignTokens keys (e.g., 'primary', 'secondary', 'error')
28
- // Only map if it's a valid semantic color key
29
- if (['primary', 'secondary', 'success', 'info', 'warning', 'error', 'light', 'dark'].includes(key)) {
30
- flat[key as keyof DesignTokens] = value;
31
- }
32
- } else if (value && typeof value === 'object') {
33
- // Color scale or palette
34
- if ('main' in value) {
35
- // PaletteColorOptions: { main: '#7AFFD7', light?: '#...', dark?: '#...' }
36
- const palette = value as { main: string; light?: string; dark?: string };
37
- const baseKey = key as keyof DesignTokens;
38
-
39
- // Map main to base color (e.g., primary, secondary, error)
40
- if (['primary', 'secondary', 'success', 'info', 'warning', 'error', 'light', 'dark'].includes(key)) {
41
- flat[baseKey] = palette.main;
42
-
43
- // Map light/dark to appropriate scale values
44
- // light typically maps to step 3, dark to step 9
45
- if (palette.light) {
46
- flat[`${key}-3` as keyof DesignTokens] = palette.light;
47
- }
48
- if (palette.dark) {
49
- flat[`${key}-9` as keyof DesignTokens] = palette.dark;
50
- }
51
- }
52
- } else {
53
- // Color scale: { 1: '#fff', 2: '#eee', ..., 6: '#main', ... }
54
- // Or full scale: { 1: '#...', 2: '#...', ..., 10: '#...' }
55
- Object.entries(value).forEach(([scaleKey, scaleValue]) => {
56
- if (typeof scaleValue === 'string') {
57
- // Map scale keys to DesignTokens format
58
- if (scaleKey === 'main' || scaleKey === '6') {
59
- // Main color maps to base key (e.g., 'primary')
60
- if (['primary', 'secondary', 'success', 'info', 'warning', 'error', 'light', 'dark'].includes(key)) {
61
- flat[key as keyof DesignTokens] = scaleValue;
62
- }
63
- // Also map to step 6 if it's a scale color
64
- if (['primary', 'red', 'green', 'blue', 'yellow', 'gray'].includes(key)) {
65
- flat[`${key}-6` as keyof DesignTokens] = scaleValue;
66
- }
67
- } else {
68
- // Map scale numbers (1-10) to DesignTokens format
69
- const scaleNum = parseInt(scaleKey, 10);
70
- if (!isNaN(scaleNum) && scaleNum >= 1 && scaleNum <= 10) {
71
- flat[`${key}-${scaleKey}` as keyof DesignTokens] = scaleValue;
72
- }
73
- }
74
- }
75
- });
76
- }
77
- }
78
- });
79
- }
80
-
81
- // Spacing
82
- if (tokens.spacing) {
83
- Object.entries(tokens.spacing).forEach(([key, value]) => {
84
- flat[`spacing-${key}` as keyof DesignTokens] = String(value);
85
- });
86
- }
87
-
88
- // Border Radius
89
- if (tokens.borderRadius) {
90
- Object.entries(tokens.borderRadius).forEach(([key, value]) => {
91
- // Map to DesignTokens format
92
- if (key === 'sm' || key === 'base' || key === '') {
93
- flat['border-radius-sm' as keyof DesignTokens] = String(value);
94
- } else if (key === 'md' || key === 'default') {
95
- flat['border-radius' as keyof DesignTokens] = String(value);
96
- } else if (key === 'lg') {
97
- flat['border-radius-lg' as keyof DesignTokens] = String(value);
98
- } else {
99
- flat[`border-radius-${key}` as keyof DesignTokens] = String(value);
100
- }
101
- });
20
+ export function loadThemeFromConfigSync(options?: { configPath?: string; required?: boolean }): DesignTokens {
21
+ // Check if we're in a browser environment
22
+ if (typeof window !== 'undefined') {
23
+ throw new Error('loadThemeFromConfigSync: Not available in browser environment. Config loading requires Node.js/SSR environment.');
102
24
  }
103
25
 
104
- // Typography
105
- if (tokens.typography) {
106
- // Font Families
107
- if (tokens.typography.fontFamilies) {
108
- Object.entries(tokens.typography.fontFamilies).forEach(([key, value]) => {
109
- // Map to DesignTokens format
110
- if (key === 'sans' || key === 'base') {
111
- flat['font-sans-serif' as keyof DesignTokens] = String(value);
112
- flat['body-font-family' as keyof DesignTokens] = String(value);
113
- } else if (key === 'mono') {
114
- flat['font-monospace' as keyof DesignTokens] = String(value);
115
- } else {
116
- flat[`font-family-${key}` as keyof DesignTokens] = String(value);
117
- }
118
- });
119
- }
120
-
121
- // Font Sizes
122
- if (tokens.typography.fontSizes) {
123
- Object.entries(tokens.typography.fontSizes).forEach(([key, value]) => {
124
- flat[`font-size-${key}` as keyof DesignTokens] = String(value);
125
- });
126
- }
127
-
128
- // Font Weights
129
- if (tokens.typography.fontWeights) {
130
- Object.entries(tokens.typography.fontWeights).forEach(([key, value]) => {
131
- flat[`font-weight-${key}` as keyof DesignTokens] = String(value);
132
- });
133
- }
134
-
135
- // Line Heights
136
- if (tokens.typography.lineHeights) {
137
- Object.entries(tokens.typography.lineHeights).forEach(([key, value]) => {
138
- if (key === 'base' || key === 'default') {
139
- flat['line-height-base' as keyof DesignTokens] = String(value);
140
- } else {
141
- flat[`line-height-${key}` as keyof DesignTokens] = String(value);
142
- }
143
- });
26
+ // Use dynamic import to load the config loader
27
+ // This allows bundlers to handle external dependencies properly
28
+ let loadAtomixConfig: any;
29
+
30
+ try {
31
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
32
+ const { loadAtomixConfig: loader } = require('../../config/loader');
33
+ loadAtomixConfig = loader;
34
+ } catch (error) {
35
+ if (options?.required !== false) {
36
+ throw new Error('Config loader module not available');
144
37
  }
38
+ // Return empty tokens if config is not required
39
+ return createTokens({});
145
40
  }
146
41
 
147
- // Shadows
148
- if (tokens.shadows) {
149
- Object.entries(tokens.shadows).forEach(([key, value]) => {
150
- flat[`shadow-${key}` as keyof DesignTokens] = String(value);
151
- });
152
- }
42
+ const config = loadAtomixConfig({
43
+ configPath: options?.configPath || 'atomix.config.ts',
44
+ required: options?.required !== false,
45
+ });
153
46
 
154
- // Z-Index
155
- if (tokens.zIndex) {
156
- Object.entries(tokens.zIndex).forEach(([key, value]) => {
157
- flat[`z-index-${key}` as keyof DesignTokens] = String(value);
158
- });
47
+ if (!config?.theme) {
48
+ return createTokens({});
159
49
  }
160
50
 
161
- // Transitions
162
- if (tokens.transitions) {
163
- if (tokens.transitions.durations) {
164
- Object.entries(tokens.transitions.durations).forEach(([key, value]) => {
165
- flat[`transition-${key}` as keyof DesignTokens] = String(value);
166
- });
167
- }
51
+ if (isThemeObject(config.theme)) {
52
+ return createDesignTokensFromTheme(config.theme);
168
53
  }
169
54
 
170
- return flat;
55
+ return createTokens(config.theme);
171
56
  }
172
57
 
173
58
  /**
174
- * Load theme tokens from atomix.config.ts
175
- *
176
- * Loads atomix.config.ts and extracts theme tokens.
177
- * Config file is required - throws error if not found.
178
- *
179
- * @param configPath - Optional custom config path (default: 'atomix.config.ts')
180
- * @returns Partial DesignTokens from config
181
- * @throws Error if config file is not found or cannot be loaded
182
- *
183
- * @example
184
- * ```typescript
185
- * const tokens = await loadThemeFromConfig();
186
- * const css = createTheme(tokens);
187
- * injectTheme(css);
188
- * ```
59
+ * Load theme from config file (asynchronous)
60
+ * @param configPath - Path to config file (default: atomix.config.ts)
61
+ * @returns Promise resolving to DesignTokens from theme configuration
189
62
  */
190
- export async function loadThemeFromConfig(
191
- configPath: string = 'atomix.config.ts'
192
- ): Promise<Partial<DesignTokens>> {
193
- // In browser environments, config loading is not supported
63
+ export async function loadThemeFromConfig(options?: { configPath?: string; required?: boolean }): Promise<DesignTokens> {
64
+ // Check if we're in a browser environment
194
65
  if (typeof window !== 'undefined') {
195
66
  throw new Error('loadThemeFromConfig: Not available in browser environment. Config loading requires Node.js/SSR environment.');
196
67
  }
197
68
 
198
- // Load config using the existing loader (required)
69
+ // Dynamic import for config loader
199
70
  const { loadAtomixConfig } = await import('../../config/loader');
200
- const config = loadAtomixConfig({ configPath, required: true });
201
-
202
- if (!config || !config.theme) {
203
- throw new Error(`Config file ${configPath} does not contain theme configuration.`);
71
+
72
+ const config = await loadAtomixConfig({
73
+ configPath: options?.configPath || 'atomix.config.ts',
74
+ required: options?.required !== false,
75
+ });
76
+
77
+ if (!config?.theme) {
78
+ return createTokens({});
204
79
  }
205
80
 
206
- // Extract tokens from config
207
- const tokens = config.theme.tokens || config.theme.extend || {};
208
-
209
- if (Object.keys(tokens).length === 0) {
210
- throw new Error(`Config file ${configPath} has empty theme configuration.`);
81
+ if (isThemeObject(config.theme)) {
82
+ return createDesignTokensFromTheme(config.theme);
211
83
  }
212
84
 
213
- // Convert nested structure to flat tokens
214
- return flattenConfigTokens(tokens, config.prefix || 'atomix');
85
+ return createTokens(config.theme);
215
86
  }
216
87
 
217
88
  /**
218
- * Load theme tokens from atomix.config.ts (synchronous version)
219
- *
220
- * Synchronous version that uses require() instead of dynamic import.
221
- * Only works in Node.js environment.
222
- * Config file is required - throws error if not found.
223
- *
224
- * @param configPath - Optional custom config path
225
- * @returns Partial DesignTokens from config
226
- * @throws Error if config file is not found or cannot be loaded
89
+ * Check if the provided object is a Theme object
90
+ * @param theme - Object to check
91
+ * @returns True if the object is a Theme object, false otherwise
227
92
  */
228
- export function loadThemeFromConfigSync(
229
- configPath: string = 'atomix.config.ts'
230
- ): Partial<DesignTokens> {
231
- // In browser environments, config loading is not supported
232
- if (typeof window !== 'undefined') {
233
- throw new Error('loadThemeFromConfigSync: Not available in browser environment. Config loading requires Node.js/SSR environment.');
234
- }
235
-
236
- // eslint-disable-next-line @typescript-eslint/no-require-imports
237
- const { loadAtomixConfig } = require('../../config/loader');
238
- const config = loadAtomixConfig({ configPath, required: true });
239
-
240
- if (!config || !config.theme) {
241
- throw new Error(`Config file ${configPath} does not contain theme configuration.`);
242
- }
243
-
244
- // Extract tokens from config
245
- const tokens = config.theme.tokens || config.theme.extend || {};
246
-
247
- if (Object.keys(tokens).length === 0) {
248
- throw new Error(`Config file ${configPath} has empty theme configuration.`);
249
- }
250
-
251
- // Convert nested structure to flat tokens
252
- return flattenConfigTokens(tokens, config.prefix || 'atomix');
93
+ function isThemeObject(theme: any): theme is Theme {
94
+ return typeof theme === 'object' && theme !== null;
253
95
  }
254
-
@@ -13,7 +13,6 @@ import { validateConfig } from './validator';
13
13
  import { ThemeError, ThemeErrorCode, getLogger } from '../errors/errors';
14
14
  import {
15
15
  DEFAULT_ATOMIX_CONFIG_PATH,
16
- DEFAULT_CONFIG_RELATIVE_PATH,
17
16
  DEFAULT_BASE_PATH,
18
17
  DEFAULT_STORAGE_KEY,
19
18
  DEFAULT_DATA_ATTRIBUTE,
@@ -90,31 +89,26 @@ export function loadThemeConfig(
90
89
  let configModule: ConfigModule;
91
90
 
92
91
  // Try require (Node.js/CommonJS)
92
+ // Use process.cwd() to resolve config path - avoids bundling issues with relative paths
93
93
  try {
94
- // Try relative path first
95
- try {
96
- configModule = nodeRequire(DEFAULT_CONFIG_RELATIVE_PATH) as ConfigModule;
97
- } catch {
98
- // If relative path fails, try to resolve from process.cwd()
99
- const path = nodeRequire('path') as typeof import('path');
100
- const fs = nodeRequire('fs') as typeof import('fs');
94
+ const path = nodeRequire('path') as typeof import('path');
95
+ const fs = nodeRequire('fs') as typeof import('fs');
101
96
 
102
- let configFilePath = path.resolve(process.cwd(), configPath);
97
+ let configFilePath = path.resolve(process.cwd(), configPath);
103
98
 
104
- // If atomix.config.ts not found at the root, use the default path
105
- if (!fs.existsSync(configFilePath) && configPath === DEFAULT_ATOMIX_CONFIG_PATH) {
106
- configFilePath = path.resolve(process.cwd(), DEFAULT_ATOMIX_CONFIG_PATH);
107
- }
99
+ // If atomix.config.ts not found at the root, use the default path
100
+ if (!fs.existsSync(configFilePath) && configPath === DEFAULT_ATOMIX_CONFIG_PATH) {
101
+ configFilePath = path.resolve(process.cwd(), DEFAULT_ATOMIX_CONFIG_PATH);
102
+ }
108
103
 
109
- if (fs.existsSync(configFilePath)) {
110
- const resolvedPath = nodeRequire.resolve(configFilePath);
111
- if (nodeRequire.cache && nodeRequire.cache[resolvedPath]) {
112
- delete nodeRequire.cache[resolvedPath];
113
- }
114
- configModule = nodeRequire(configFilePath) as ConfigModule;
115
- } else {
116
- throw new Error(`Config file not found: ${configFilePath}`);
104
+ if (fs.existsSync(configFilePath)) {
105
+ const resolvedPath = nodeRequire.resolve(configFilePath);
106
+ if (nodeRequire.cache && nodeRequire.cache[resolvedPath]) {
107
+ delete nodeRequire.cache[resolvedPath];
117
108
  }
109
+ configModule = nodeRequire(configFilePath) as ConfigModule;
110
+ } else {
111
+ throw new Error(`Config file not found: ${configFilePath}`);
118
112
  }
119
113
  } catch (requireError) {
120
114
  const errorMessage = requireError instanceof Error
@@ -121,7 +121,7 @@ export const DEFAULT_ANALYTICS_CONFIG = {
121
121
  * Logger default configuration
122
122
  */
123
123
  export const DEFAULT_LOGGER_CONFIG = {
124
- level: process.env.NODE_ENV === 'production' ? 1 : 2, // WARN in prod, INFO in dev
124
+ level: (typeof process !== 'undefined' && process.env?.NODE_ENV === 'production') ? 1 : 2, // WARN in prod, INFO in dev
125
125
  enableConsole: true,
126
126
  } as const;
127
127