@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.
- package/README.md +3 -3
- package/dist/charts.js +50 -142
- package/dist/charts.js.map +1 -1
- package/dist/core.js +179 -274
- package/dist/core.js.map +1 -1
- package/dist/forms.js +50 -142
- package/dist/forms.js.map +1 -1
- package/dist/heavy.js +179 -274
- package/dist/heavy.js.map +1 -1
- package/dist/index.d.ts +669 -703
- package/dist/index.esm.js +966 -1649
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +1211 -1890
- package/dist/index.js.map +1 -1
- package/dist/index.min.js +1 -1
- package/dist/index.min.js.map +1 -1
- package/dist/theme.d.ts +163 -334
- package/dist/theme.js +774 -1473
- package/dist/theme.js.map +1 -1
- package/package.json +1 -1
- package/src/components/AtomixGlass/AtomixGlass.tsx +128 -356
- package/src/components/AtomixGlass/AtomixGlassContainer.tsx +1 -1
- package/src/components/Button/Button.tsx +85 -167
- package/src/lib/composables/useAtomixGlass.ts +7 -7
- package/src/lib/config/loader.ts +2 -3
- package/src/lib/constants/components.ts +7 -0
- package/src/lib/hooks/usePerformanceMonitor.ts +1 -1
- package/src/lib/hooks/useThemeTokens.ts +105 -0
- package/src/lib/theme/config/configLoader.ts +60 -219
- package/src/lib/theme/config/loader.ts +15 -21
- package/src/lib/theme/constants/constants.ts +1 -1
- package/src/lib/theme/core/ThemeRegistry.ts +75 -279
- package/src/lib/theme/core/composeTheme.ts +14 -64
- package/src/lib/theme/core/createTheme.ts +54 -40
- package/src/lib/theme/core/createThemeObject.ts +2 -2
- package/src/lib/theme/core/index.ts +15 -1
- package/src/lib/theme/errors/errors.ts +1 -1
- package/src/lib/theme/generators/generateCSSNested.ts +130 -0
- package/src/lib/theme/generators/index.ts +6 -0
- package/src/lib/theme/index.ts +35 -10
- package/src/lib/theme/runtime/ThemeApplicator.ts +1 -1
- package/src/lib/theme/runtime/ThemeErrorBoundary.tsx +4 -4
- package/src/lib/theme/runtime/ThemeProvider.tsx +261 -554
- package/src/lib/theme/runtime/index.ts +1 -0
- package/src/lib/theme/runtime/useThemeTokens.ts +131 -0
- package/src/lib/theme/utils/componentTheming.ts +132 -0
- package/src/lib/theme/utils/naming.ts +100 -0
- package/src/lib/theme/utils/themeUtils.ts +6 -6
- package/src/lib/utils/componentUtils.ts +1 -1
- package/src/lib/utils/memoryMonitor.ts +3 -3
- package/src/lib/utils/themeNaming.ts +135 -0
|
@@ -1,254 +1,95 @@
|
|
|
1
|
+
|
|
1
2
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
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
|
|
11
|
+
import { createTokens } from '../tokens/tokens';
|
|
12
|
+
import { themeToDesignTokens, createDesignTokensFromTheme } from '../adapters/themeAdapter';
|
|
9
13
|
|
|
10
14
|
/**
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
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
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
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
|
-
//
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
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
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
});
|
|
152
|
-
}
|
|
42
|
+
const config = loadAtomixConfig({
|
|
43
|
+
configPath: options?.configPath || 'atomix.config.ts',
|
|
44
|
+
required: options?.required !== false,
|
|
45
|
+
});
|
|
153
46
|
|
|
154
|
-
|
|
155
|
-
|
|
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
|
-
|
|
162
|
-
|
|
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
|
|
55
|
+
return createTokens(config.theme);
|
|
171
56
|
}
|
|
172
57
|
|
|
173
58
|
/**
|
|
174
|
-
* Load theme
|
|
175
|
-
*
|
|
176
|
-
*
|
|
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
|
-
|
|
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
|
-
//
|
|
69
|
+
// Dynamic import for config loader
|
|
199
70
|
const { loadAtomixConfig } = await import('../../config/loader');
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
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
|
-
|
|
207
|
-
|
|
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
|
-
|
|
214
|
-
return flattenConfigTokens(tokens, config.prefix || 'atomix');
|
|
85
|
+
return createTokens(config.theme);
|
|
215
86
|
}
|
|
216
87
|
|
|
217
88
|
/**
|
|
218
|
-
*
|
|
219
|
-
*
|
|
220
|
-
*
|
|
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
|
-
|
|
229
|
-
|
|
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
|
-
|
|
95
|
-
|
|
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
|
-
|
|
97
|
+
let configFilePath = path.resolve(process.cwd(), configPath);
|
|
103
98
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
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
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
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
|
|
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
|
|