@shohojdhara/atomix 0.3.6 → 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 (74) hide show
  1. package/README.md +3 -3
  2. package/dist/atomix.css +77 -0
  3. package/dist/atomix.css.map +1 -1
  4. package/dist/atomix.min.css +77 -0
  5. package/dist/atomix.min.css.map +1 -1
  6. package/dist/charts.js +50 -142
  7. package/dist/charts.js.map +1 -1
  8. package/dist/core.d.ts +2 -2
  9. package/dist/core.js +179 -274
  10. package/dist/core.js.map +1 -1
  11. package/dist/forms.js +50 -142
  12. package/dist/forms.js.map +1 -1
  13. package/dist/heavy.js +179 -274
  14. package/dist/heavy.js.map +1 -1
  15. package/dist/index.d.ts +1255 -1226
  16. package/dist/index.esm.js +2806 -2958
  17. package/dist/index.esm.js.map +1 -1
  18. package/dist/index.js +3113 -3269
  19. package/dist/index.js.map +1 -1
  20. package/dist/index.min.js +1 -1
  21. package/dist/index.min.js.map +1 -1
  22. package/dist/theme.d.ts +313 -667
  23. package/dist/theme.js +1818 -2589
  24. package/dist/theme.js.map +1 -1
  25. package/package.json +1 -1
  26. package/src/components/AtomixGlass/AtomixGlass.tsx +128 -356
  27. package/src/components/AtomixGlass/AtomixGlassContainer.tsx +1 -1
  28. package/src/components/Button/Button.tsx +85 -167
  29. package/src/components/DataTable/DataTable.stories.tsx +238 -0
  30. package/src/components/DataTable/DataTable.test.tsx +450 -0
  31. package/src/components/DataTable/DataTable.tsx +384 -61
  32. package/src/components/DatePicker/DatePicker.tsx +29 -38
  33. package/src/components/Upload/Upload.tsx +539 -40
  34. package/src/lib/composables/useAtomixGlass.ts +7 -7
  35. package/src/lib/composables/useDataTable.ts +355 -15
  36. package/src/lib/composables/useDatePicker.ts +19 -0
  37. package/src/lib/config/loader.ts +2 -3
  38. package/src/lib/constants/components.ts +17 -0
  39. package/src/lib/hooks/usePerformanceMonitor.ts +1 -1
  40. package/src/lib/theme/adapters/cssVariableMapper.ts +29 -14
  41. package/src/lib/theme/adapters/index.ts +1 -4
  42. package/src/lib/theme/config/configLoader.ts +82 -223
  43. package/src/lib/theme/config/loader.ts +15 -21
  44. package/src/lib/theme/constants/constants.ts +1 -1
  45. package/src/lib/theme/core/ThemeRegistry.ts +75 -279
  46. package/src/lib/theme/core/composeTheme.ts +30 -88
  47. package/src/lib/theme/core/createTheme.ts +88 -51
  48. package/src/lib/theme/core/createThemeObject.ts +2 -2
  49. package/src/lib/theme/core/index.ts +15 -2
  50. package/src/lib/theme/errors/errors.ts +1 -1
  51. package/src/lib/theme/generators/generateCSSNested.ts +131 -0
  52. package/src/lib/theme/generators/generateCSSVariables.ts +24 -16
  53. package/src/lib/theme/generators/index.ts +6 -0
  54. package/src/lib/theme/index.ts +45 -27
  55. package/src/lib/theme/runtime/ThemeApplicator.ts +6 -109
  56. package/src/lib/theme/runtime/ThemeErrorBoundary.tsx +1 -1
  57. package/src/lib/theme/runtime/ThemeProvider.tsx +393 -544
  58. package/src/lib/theme/runtime/index.ts +1 -0
  59. package/src/lib/theme/runtime/useTheme.ts +1 -1
  60. package/src/lib/theme/runtime/useThemeTokens.ts +122 -0
  61. package/src/lib/theme/test/testTheme.ts +2 -1
  62. package/src/lib/theme/types.ts +14 -14
  63. package/src/lib/theme/utils/componentTheming.ts +140 -0
  64. package/src/lib/theme/utils/domUtils.ts +57 -15
  65. package/src/lib/theme/utils/injectCSS.ts +0 -1
  66. package/src/lib/theme/utils/naming.ts +100 -0
  67. package/src/lib/theme/utils/themeHelpers.ts +1 -39
  68. package/src/lib/theme/utils/themeUtils.ts +1 -170
  69. package/src/lib/types/components.ts +145 -0
  70. package/src/lib/utils/componentUtils.ts +1 -1
  71. package/src/lib/utils/dataTableExport.ts +143 -0
  72. package/src/lib/utils/memoryMonitor.ts +3 -3
  73. package/src/lib/utils/themeNaming.ts +135 -0
  74. package/src/styles/06-components/_components.data-table.scss +95 -0
@@ -1,254 +1,113 @@
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
 
7
9
  import type { DesignTokens } from '../tokens/tokens';
8
- import type { AtomixConfig, ThemeTokens } from '../../config';
10
+ import { createTokens } from '../tokens/tokens';
11
+ import { loadAtomixConfig as loadAtomixConfigStatic } from '../../config/loader';
9
12
 
10
13
  /**
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.
14
+ * Load theme from config file (synchronous, Node.js only)
15
+ * @param configPath - Path to config file (default: atomix.config.ts)
16
+ * @returns DesignTokens from theme configuration
17
+ * @throws Error if config loading is not available in browser environment
15
18
  */
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
- });
19
+ export function loadThemeFromConfigSync(options?: { configPath?: string; required?: boolean }): DesignTokens {
20
+ // Check if we're in a browser environment
21
+ if (typeof window !== 'undefined') {
22
+ throw new Error('loadThemeFromConfigSync: Not available in browser environment. Config loading requires Node.js/SSR environment.');
86
23
  }
87
24
 
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
- }
25
+ // Use static import - the function handles browser environment checks internally
26
+ let config;
27
+
28
+ try {
29
+ config = loadAtomixConfigStatic({
30
+ configPath: options?.configPath || 'atomix.config.ts',
31
+ required: options?.required !== false,
101
32
  });
102
- }
103
-
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
- });
33
+ } catch (error) {
34
+ if (options?.required !== false) {
35
+ throw new Error('Config loader module not available');
144
36
  }
37
+ // Return empty tokens if config is not required
38
+ return createTokens({});
145
39
  }
146
40
 
147
- // Shadows
148
- if (tokens.shadows) {
149
- Object.entries(tokens.shadows).forEach(([key, value]) => {
150
- flat[`shadow-${key}` as keyof DesignTokens] = String(value);
151
- });
41
+ if (!config?.theme) {
42
+ return createTokens({});
152
43
  }
153
44
 
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
- });
45
+ // Extract tokens from config.theme structure
46
+ // config.theme can have: { extend?: ThemeTokens, tokens?: ThemeTokens, themes?: ... }
47
+ // We need to extract the actual DesignTokens (flat structure)
48
+ const themeConfig = config.theme;
49
+
50
+ // Check if theme is directly a flat object (DesignTokens format)
51
+ // This handles the case where config.theme might be passed as DesignTokens directly
52
+ if (themeConfig && typeof themeConfig === 'object' && !('extend' in themeConfig) && !('tokens' in themeConfig) && !('themes' in themeConfig)) {
53
+ // It's likely already a flat DesignTokens object
54
+ return createTokens(themeConfig as Partial<DesignTokens>);
159
55
  }
160
-
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
- }
168
- }
169
-
170
- return flat;
56
+
57
+ // If theme has nested structure (extend/tokens/themes), we can't directly use it
58
+ // Return empty tokens - the theme system will use defaults
59
+ // TODO: Add proper conversion from ThemeTokens to DesignTokens if needed
60
+ return createTokens({});
171
61
  }
172
62
 
173
63
  /**
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
- * ```
64
+ * Load theme from config file (asynchronous)
65
+ * @param configPath - Path to config file (default: atomix.config.ts)
66
+ * @returns Promise resolving to DesignTokens from theme configuration
189
67
  */
190
- export async function loadThemeFromConfig(
191
- configPath: string = 'atomix.config.ts'
192
- ): Promise<Partial<DesignTokens>> {
193
- // In browser environments, config loading is not supported
68
+ export async function loadThemeFromConfig(options?: { configPath?: string; required?: boolean }): Promise<DesignTokens> {
69
+ // Check if we're in a browser environment
194
70
  if (typeof window !== 'undefined') {
195
71
  throw new Error('loadThemeFromConfig: Not available in browser environment. Config loading requires Node.js/SSR environment.');
196
72
  }
197
73
 
198
- // Load config using the existing loader (required)
199
- 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.`);
204
- }
205
-
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.`);
211
- }
212
-
213
- // Convert nested structure to flat tokens
214
- return flattenConfigTokens(tokens, config.prefix || 'atomix');
215
- }
216
-
217
- /**
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
227
- */
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.');
74
+ // Use static import with runtime check
75
+ // The function will handle browser environment checks internally
76
+ let config;
77
+
78
+ try {
79
+ // loadAtomixConfig is synchronous, not async
80
+ config = loadAtomixConfigStatic({
81
+ configPath: options?.configPath || 'atomix.config.ts',
82
+ required: options?.required !== false,
83
+ });
84
+ } catch (error) {
85
+ if (options?.required !== false) {
86
+ throw new Error('Config loader module not available');
87
+ }
88
+ // Return empty tokens if config is not required
89
+ return createTokens({});
234
90
  }
235
91
 
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.`);
92
+ if (!config?.theme) {
93
+ return createTokens({});
242
94
  }
243
95
 
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.`);
96
+ // Extract tokens from config.theme structure
97
+ // config.theme can have: { extend?: ThemeTokens, tokens?: ThemeTokens, themes?: ... }
98
+ // We need to extract the actual DesignTokens (flat structure)
99
+ const themeConfig = config.theme;
100
+
101
+ // Check if theme is directly a flat object (DesignTokens format)
102
+ // This handles the case where config.theme might be passed as DesignTokens directly
103
+ if (themeConfig && typeof themeConfig === 'object' && !('extend' in themeConfig) && !('tokens' in themeConfig) && !('themes' in themeConfig)) {
104
+ // It's likely already a flat DesignTokens object
105
+ return createTokens(themeConfig as Partial<DesignTokens>);
249
106
  }
250
-
251
- // Convert nested structure to flat tokens
252
- return flattenConfigTokens(tokens, config.prefix || 'atomix');
107
+
108
+ // If theme has nested structure (extend/tokens/themes), we can't directly use it
109
+ // Return empty tokens - the theme system will use defaults
110
+ // TODO: Add proper conversion from ThemeTokens to DesignTokens if needed
111
+ return createTokens({});
253
112
  }
254
113
 
@@ -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