@shohojdhara/atomix 0.3.9 → 0.3.11
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/CHANGELOG.md +14 -3
- package/dist/index.d.ts +2 -80
- package/dist/index.esm.js +14 -262
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +58 -303
- 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 +1 -32
- package/dist/theme.js +12 -159
- package/dist/theme.js.map +1 -1
- package/package.json +1 -1
- package/src/lib/config/index.ts +5 -5
- package/src/lib/theme/config/index.ts +1 -1
- package/src/lib/theme/core/createTheme.ts +11 -40
- package/src/lib/theme/generators/index.ts +1 -4
- package/src/lib/theme/index.ts +4 -16
- package/src/lib/theme/runtime/ThemeProvider.tsx +1 -16
- package/src/lib/config/loader.ts +0 -147
- package/src/lib/theme/config/__tests__/configLoader.test.ts +0 -207
- package/src/lib/theme/config/configLoader.ts +0 -113
- package/src/lib/theme/config/loader.ts +0 -293
- package/src/lib/theme/generators/cssFile.ts +0 -79
package/package.json
CHANGED
package/src/lib/config/index.ts
CHANGED
|
@@ -192,7 +192,7 @@ export interface AtomixConfig {
|
|
|
192
192
|
* Example: prefix: 'myapp' → --myapp-primary instead of --atomix-primary
|
|
193
193
|
*/
|
|
194
194
|
prefix?: string;
|
|
195
|
-
|
|
195
|
+
|
|
196
196
|
/**
|
|
197
197
|
* Theme customization (Tailwind-like)
|
|
198
198
|
*
|
|
@@ -207,7 +207,7 @@ export interface AtomixConfig {
|
|
|
207
207
|
* Your values will override or extend the base tokens.
|
|
208
208
|
*/
|
|
209
209
|
extend?: ThemeTokens;
|
|
210
|
-
|
|
210
|
+
|
|
211
211
|
/**
|
|
212
212
|
* Override the default tokens entirely (advanced)
|
|
213
213
|
*
|
|
@@ -215,7 +215,7 @@ export interface AtomixConfig {
|
|
|
215
215
|
* Most users should use `extend` instead.
|
|
216
216
|
*/
|
|
217
217
|
tokens?: ThemeTokens;
|
|
218
|
-
|
|
218
|
+
|
|
219
219
|
/**
|
|
220
220
|
* Register custom themes (optional)
|
|
221
221
|
*
|
|
@@ -223,7 +223,7 @@ export interface AtomixConfig {
|
|
|
223
223
|
*/
|
|
224
224
|
themes?: Record<string, ThemeDefinition>;
|
|
225
225
|
};
|
|
226
|
-
|
|
226
|
+
|
|
227
227
|
// Internal configurations (for library development only)
|
|
228
228
|
// These are not needed for external developers
|
|
229
229
|
/** @internal Build configuration (internal use only) */
|
|
@@ -270,6 +270,6 @@ export function defineConfig(config: AtomixConfig): AtomixConfig {
|
|
|
270
270
|
}
|
|
271
271
|
|
|
272
272
|
// Export loader functions
|
|
273
|
-
|
|
273
|
+
// Loader functions removed to prevent bundling Node.js modules in browser
|
|
274
274
|
|
|
275
275
|
export default AtomixConfig;
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Exports for theme configuration loading and validation
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
// Loader exports removed
|
|
8
8
|
export { validateConfig } from './validator';
|
|
9
9
|
export type {
|
|
10
10
|
ConfigLoaderOptions,
|
|
@@ -66,47 +66,18 @@ export function createTheme(
|
|
|
66
66
|
|
|
67
67
|
// Determine tokens based on input
|
|
68
68
|
let tokens: Partial<DesignTokens>;
|
|
69
|
-
|
|
69
|
+
|
|
70
70
|
if (!input) {
|
|
71
|
-
//
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
);
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
// Load from config when no input provided
|
|
81
|
-
let loadThemeFromConfigSync: any;
|
|
82
|
-
let loadAtomixConfig: any;
|
|
83
|
-
|
|
84
|
-
try {
|
|
85
|
-
const configLoaderModule = require('../config/configLoader');
|
|
86
|
-
const loaderModule = require('../../config/loader');
|
|
87
|
-
|
|
88
|
-
loadThemeFromConfigSync = configLoaderModule.loadThemeFromConfigSync;
|
|
89
|
-
loadAtomixConfig = loaderModule.loadAtomixConfig;
|
|
90
|
-
|
|
91
|
-
tokens = loadThemeFromConfigSync();
|
|
92
|
-
|
|
93
|
-
// Get prefix from config if needed
|
|
94
|
-
if (!options?.prefix) {
|
|
95
|
-
try {
|
|
96
|
-
const config = loadAtomixConfig({ configPath: 'atomix.config.ts', required: false });
|
|
97
|
-
options = { ...options, prefix: config?.prefix || 'atomix' };
|
|
98
|
-
} catch (error) {
|
|
99
|
-
// If config loading fails, use default prefix
|
|
100
|
-
options = { ...options, prefix: 'atomix' };
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
} catch (error) {
|
|
104
|
-
throw new ThemeError(
|
|
105
|
-
'No input provided and config loading is not available in this environment. Please provide tokens explicitly.',
|
|
106
|
-
ThemeErrorCode.CONFIG_LOAD_FAILED,
|
|
107
|
-
{ error: error instanceof Error ? error.message : String(error) }
|
|
108
|
-
);
|
|
71
|
+
// Auto-loading config from file system is removed for browser compatibility.
|
|
72
|
+
// If no input is provided, we return an empty theme (using defaults only) or user must provide tokens.
|
|
73
|
+
// This allows createTheme to be isomorphic.
|
|
74
|
+
|
|
75
|
+
// Warn in development if no input provided
|
|
76
|
+
if (process.env.NODE_ENV !== 'production' && typeof window !== 'undefined') {
|
|
77
|
+
console.warn('Atomix: createTheme() called without tokens. Using default tokens only.');
|
|
109
78
|
}
|
|
79
|
+
|
|
80
|
+
tokens = {};
|
|
110
81
|
} else {
|
|
111
82
|
// Validate input tokens structure
|
|
112
83
|
if (typeof input !== 'object' || input === null || Array.isArray(input)) {
|
|
@@ -116,7 +87,7 @@ export function createTheme(
|
|
|
116
87
|
{ inputType: typeof input }
|
|
117
88
|
);
|
|
118
89
|
}
|
|
119
|
-
|
|
90
|
+
|
|
120
91
|
// Use DesignTokens directly
|
|
121
92
|
tokens = input;
|
|
122
93
|
}
|
package/src/lib/theme/index.ts
CHANGED
|
@@ -29,7 +29,7 @@ export { createTheme } from './core';
|
|
|
29
29
|
export { deepMerge, mergeTheme, extendTheme } from './core';
|
|
30
30
|
|
|
31
31
|
// Simplified Theme Registry
|
|
32
|
-
export {
|
|
32
|
+
export {
|
|
33
33
|
createThemeRegistry,
|
|
34
34
|
registerTheme,
|
|
35
35
|
unregisterTheme,
|
|
@@ -46,7 +46,7 @@ export {
|
|
|
46
46
|
// ============================================================================
|
|
47
47
|
|
|
48
48
|
import { injectCSS, removeCSS, isCSSInjected } from './utils/injectCSS';
|
|
49
|
-
|
|
49
|
+
// File saving utilities removed to prevent bundling Node.js modules in browser
|
|
50
50
|
|
|
51
51
|
/**
|
|
52
52
|
* Inject theme CSS into DOM
|
|
@@ -62,12 +62,7 @@ export function removeTheme(id: string = 'atomix-theme'): void {
|
|
|
62
62
|
removeCSS(id);
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
-
|
|
66
|
-
* Save theme to CSS file
|
|
67
|
-
*/
|
|
68
|
-
export async function saveTheme(css: string, filePath: string): Promise<void> {
|
|
69
|
-
await saveCSSFile(css, filePath);
|
|
70
|
-
}
|
|
65
|
+
|
|
71
66
|
|
|
72
67
|
// ============================================================================
|
|
73
68
|
// Token Utilities
|
|
@@ -113,14 +108,7 @@ export {
|
|
|
113
108
|
export { injectCSS, removeCSS, isCSSInjected } from './utils/injectCSS';
|
|
114
109
|
|
|
115
110
|
|
|
116
|
-
//
|
|
117
|
-
// Config Loader
|
|
118
|
-
// ============================================================================
|
|
119
|
-
|
|
120
|
-
export {
|
|
121
|
-
loadThemeFromConfig,
|
|
122
|
-
loadThemeFromConfigSync,
|
|
123
|
-
} from './config/configLoader';
|
|
111
|
+
// Config loader removed to prevent bundling Node.js modules in browser
|
|
124
112
|
|
|
125
113
|
// ============================================================================
|
|
126
114
|
// React Integration
|
|
@@ -86,22 +86,7 @@ export const ThemeProvider: React.FC<ThemeProviderProps> = ({
|
|
|
86
86
|
return defaultTheme;
|
|
87
87
|
}
|
|
88
88
|
|
|
89
|
-
|
|
90
|
-
if (typeof window === 'undefined') {
|
|
91
|
-
try {
|
|
92
|
-
// Dynamically import the config loader to avoid bundling issues in browser
|
|
93
|
-
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
94
|
-
const { loadThemeFromConfigSync } = require('../config/configLoader');
|
|
95
|
-
|
|
96
|
-
const configTokens = loadThemeFromConfigSync();
|
|
97
|
-
if (configTokens && Object.keys(configTokens).length > 0) {
|
|
98
|
-
// For simplicity, we'll treat config tokens as a special theme name
|
|
99
|
-
return 'config-theme';
|
|
100
|
-
}
|
|
101
|
-
} catch (error) {
|
|
102
|
-
// Failed to load theme from config, using default
|
|
103
|
-
}
|
|
104
|
-
}
|
|
89
|
+
|
|
105
90
|
|
|
106
91
|
// Default fallback
|
|
107
92
|
return 'default';
|
package/src/lib/config/loader.ts
DELETED
|
@@ -1,147 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Atomix Config Loader
|
|
3
|
-
*
|
|
4
|
-
* Helper functions to load atomix.config.ts from external projects.
|
|
5
|
-
* Similar to how Tailwind loads tailwind.config.js
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import type { AtomixConfig } from './index';
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Load Atomix configuration from project root
|
|
12
|
-
*
|
|
13
|
-
* Attempts to load atomix.config.ts from the current working directory.
|
|
14
|
-
* Falls back to default config if file doesn't exist.
|
|
15
|
-
*
|
|
16
|
-
* @param options - Loader options
|
|
17
|
-
* @returns Loaded configuration or default
|
|
18
|
-
*
|
|
19
|
-
* @example
|
|
20
|
-
* ```typescript
|
|
21
|
-
* import { loadAtomixConfig } from '@shohojdhara/atomix/config';
|
|
22
|
-
* import { createTheme } from '@shohojdhara/atomix/theme';
|
|
23
|
-
*
|
|
24
|
-
* const config = loadAtomixConfig();
|
|
25
|
-
* const theme = createTheme(config.theme?.tokens || {});
|
|
26
|
-
* ```
|
|
27
|
-
*/
|
|
28
|
-
export function loadAtomixConfig(
|
|
29
|
-
options: {
|
|
30
|
-
/** Custom config path (default: 'atomix.config.ts') */
|
|
31
|
-
configPath?: string;
|
|
32
|
-
/** Whether to throw error if config not found (default: false) */
|
|
33
|
-
required?: boolean;
|
|
34
|
-
} = {}
|
|
35
|
-
): AtomixConfig {
|
|
36
|
-
const { configPath = 'atomix.config.ts', required = false } = options;
|
|
37
|
-
|
|
38
|
-
// Default config
|
|
39
|
-
const defaultConfig: AtomixConfig = {
|
|
40
|
-
prefix: 'atomix',
|
|
41
|
-
theme: {
|
|
42
|
-
extend: {},
|
|
43
|
-
},
|
|
44
|
-
};
|
|
45
|
-
|
|
46
|
-
// In browser environments, config loading is not supported
|
|
47
|
-
if (typeof window !== 'undefined') {
|
|
48
|
-
if (required) {
|
|
49
|
-
throw new Error('loadAtomixConfig: Not available in browser environment. Config loading requires Node.js/SSR environment.');
|
|
50
|
-
}
|
|
51
|
-
return defaultConfig;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
// Try to load config file
|
|
55
|
-
try {
|
|
56
|
-
// Use dynamic import for ESM compatibility
|
|
57
|
-
const configModule = require(configPath);
|
|
58
|
-
const config = configModule.default || configModule;
|
|
59
|
-
|
|
60
|
-
// Validate it's an AtomixConfig
|
|
61
|
-
if (config && typeof config === 'object') {
|
|
62
|
-
return config as AtomixConfig;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
throw new Error('Invalid config format');
|
|
66
|
-
} catch (error: any) {
|
|
67
|
-
if (required) {
|
|
68
|
-
throw new Error(`Failed to load config from ${configPath}: ${error.message}`);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
// Return default config if not required
|
|
72
|
-
return defaultConfig;
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
/**
|
|
77
|
-
* Resolve config path
|
|
78
|
-
*
|
|
79
|
-
* Finds atomix.config.ts in the project, checking common locations.
|
|
80
|
-
* Returns null in browser environments where file system access is not available.
|
|
81
|
-
*
|
|
82
|
-
* This function is designed to work in Node.js environments only.
|
|
83
|
-
* In browser builds, it will always return null without attempting to access Node.js modules.
|
|
84
|
-
*
|
|
85
|
-
* @internal This function uses Node.js modules and should not be called in browser environments.
|
|
86
|
-
*/
|
|
87
|
-
export function resolveConfigPath(): string | null {
|
|
88
|
-
// Early return for browser environments - prevents any Node.js module access
|
|
89
|
-
// This check happens before any require() calls, preventing bundlers from analyzing them
|
|
90
|
-
if (typeof window !== 'undefined' || typeof process === 'undefined' || !process.cwd) {
|
|
91
|
-
return null;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
// Only attempt to load Node.js modules in Node.js runtime
|
|
95
|
-
// Use a lazy-loading pattern that prevents static analysis by bundlers
|
|
96
|
-
try {
|
|
97
|
-
// Create a function that only executes in Node.js runtime
|
|
98
|
-
// Use string-based module names to prevent static analysis by bundlers
|
|
99
|
-
const loadNodeModules = () => {
|
|
100
|
-
// These requires are only executed at runtime in Node.js environments
|
|
101
|
-
// They are marked as external in Rollup config and should not be bundled
|
|
102
|
-
// Using string concatenation and computed property access to prevent static analysis
|
|
103
|
-
if (typeof require === 'undefined') {
|
|
104
|
-
return null;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
// Use a try-catch wrapper to safely access require
|
|
108
|
-
try {
|
|
109
|
-
// Build module names dynamically to prevent static analysis
|
|
110
|
-
const moduleNames: [string, string] = ['f' + 's', 'p' + 'a' + 't' + 'h'];
|
|
111
|
-
// eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires
|
|
112
|
-
const fs = require(moduleNames[0]);
|
|
113
|
-
// eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires
|
|
114
|
-
const path = require(moduleNames[1]);
|
|
115
|
-
return { fs, path };
|
|
116
|
-
} catch {
|
|
117
|
-
return null;
|
|
118
|
-
}
|
|
119
|
-
};
|
|
120
|
-
|
|
121
|
-
const modules = loadNodeModules();
|
|
122
|
-
if (!modules) {
|
|
123
|
-
return null;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
const { fs, path } = modules;
|
|
127
|
-
const cwd = process.cwd();
|
|
128
|
-
const possiblePaths = [
|
|
129
|
-
path.join(cwd, 'atomix.config.ts'),
|
|
130
|
-
path.join(cwd, 'atomix.config.js'),
|
|
131
|
-
path.join(cwd, 'atomix.config.mjs'),
|
|
132
|
-
];
|
|
133
|
-
|
|
134
|
-
for (const configPath of possiblePaths) {
|
|
135
|
-
if (fs.existsSync(configPath)) {
|
|
136
|
-
return configPath;
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
} catch (error) {
|
|
140
|
-
// Silently fail in browser environments or when modules are unavailable
|
|
141
|
-
return null;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
return null;
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
export default loadAtomixConfig;
|
|
@@ -1,207 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Config Loader Tests
|
|
3
|
-
*
|
|
4
|
-
* Tests for automatic config loading from atomix.config.ts
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
8
|
-
import { loadThemeFromConfigSync, loadThemeFromConfig } from '../configLoader';
|
|
9
|
-
import { createTheme } from '../../core/createTheme';
|
|
10
|
-
import type { DesignTokens } from '../../tokens/tokens';
|
|
11
|
-
|
|
12
|
-
describe('Config Loader', () => {
|
|
13
|
-
beforeEach(() => {
|
|
14
|
-
// Clear any cached configs
|
|
15
|
-
vi.clearAllMocks();
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
afterEach(() => {
|
|
19
|
-
vi.restoreAllMocks();
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
describe('loadThemeFromConfigSync', () => {
|
|
23
|
-
it('should return empty object in browser environment', () => {
|
|
24
|
-
// Mock window object
|
|
25
|
-
const originalWindow = global.window;
|
|
26
|
-
// @ts-expect-error - intentionally setting window for test
|
|
27
|
-
global.window = {};
|
|
28
|
-
|
|
29
|
-
const result = loadThemeFromConfigSync();
|
|
30
|
-
expect(result).toEqual({});
|
|
31
|
-
|
|
32
|
-
// Restore
|
|
33
|
-
global.window = originalWindow;
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
it('should handle missing config file gracefully', () => {
|
|
37
|
-
// In Node.js environment, if config doesn't exist, should return empty object
|
|
38
|
-
const result = loadThemeFromConfigSync('non-existent-config.ts');
|
|
39
|
-
expect(result).toEqual({});
|
|
40
|
-
});
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
describe('loadThemeFromConfig', () => {
|
|
44
|
-
it('should return empty object in browser environment', async () => {
|
|
45
|
-
// Mock window object
|
|
46
|
-
const originalWindow = global.window;
|
|
47
|
-
// @ts-expect-error - intentionally setting window for test
|
|
48
|
-
global.window = {};
|
|
49
|
-
|
|
50
|
-
const result = await loadThemeFromConfig();
|
|
51
|
-
expect(result).toEqual({});
|
|
52
|
-
|
|
53
|
-
// Restore
|
|
54
|
-
global.window = originalWindow;
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
it('should handle missing config file gracefully', async () => {
|
|
58
|
-
const result = await loadThemeFromConfig('non-existent-config.ts');
|
|
59
|
-
expect(result).toEqual({});
|
|
60
|
-
});
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
describe('Token Flattening', () => {
|
|
64
|
-
it('should correctly map simple color strings', () => {
|
|
65
|
-
// This tests the internal flattenConfigTokens function indirectly
|
|
66
|
-
// by checking that createTheme can handle config structure
|
|
67
|
-
const mockConfig = {
|
|
68
|
-
theme: {
|
|
69
|
-
extend: {
|
|
70
|
-
colors: {
|
|
71
|
-
primary: '#7AFFD7',
|
|
72
|
-
secondary: '#FF5733',
|
|
73
|
-
},
|
|
74
|
-
},
|
|
75
|
-
},
|
|
76
|
-
};
|
|
77
|
-
|
|
78
|
-
// Since we can't directly test the private function,
|
|
79
|
-
// we test through createTheme which uses it
|
|
80
|
-
// This is an integration test
|
|
81
|
-
expect(typeof createTheme).toBe('function');
|
|
82
|
-
});
|
|
83
|
-
|
|
84
|
-
it('should correctly map palette color objects', () => {
|
|
85
|
-
const mockConfig = {
|
|
86
|
-
theme: {
|
|
87
|
-
extend: {
|
|
88
|
-
colors: {
|
|
89
|
-
primary: {
|
|
90
|
-
main: '#7AFFD7',
|
|
91
|
-
light: '#B3FFE9',
|
|
92
|
-
dark: '#00E6C3',
|
|
93
|
-
},
|
|
94
|
-
},
|
|
95
|
-
},
|
|
96
|
-
},
|
|
97
|
-
};
|
|
98
|
-
|
|
99
|
-
// Integration test through createTheme
|
|
100
|
-
expect(typeof createTheme).toBe('function');
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
it('should correctly map color scales', () => {
|
|
104
|
-
const mockConfig = {
|
|
105
|
-
theme: {
|
|
106
|
-
extend: {
|
|
107
|
-
colors: {
|
|
108
|
-
primary: {
|
|
109
|
-
1: '#f0f9ff',
|
|
110
|
-
6: '#3b82f6',
|
|
111
|
-
10: '#1e3a8a',
|
|
112
|
-
},
|
|
113
|
-
},
|
|
114
|
-
},
|
|
115
|
-
},
|
|
116
|
-
};
|
|
117
|
-
|
|
118
|
-
// Integration test
|
|
119
|
-
expect(typeof createTheme).toBe('function');
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
it('should correctly map spacing tokens', () => {
|
|
123
|
-
const mockConfig = {
|
|
124
|
-
theme: {
|
|
125
|
-
extend: {
|
|
126
|
-
spacing: {
|
|
127
|
-
'4': '1rem',
|
|
128
|
-
'8': '2rem',
|
|
129
|
-
},
|
|
130
|
-
},
|
|
131
|
-
},
|
|
132
|
-
};
|
|
133
|
-
|
|
134
|
-
// Integration test
|
|
135
|
-
expect(typeof createTheme).toBe('function');
|
|
136
|
-
});
|
|
137
|
-
|
|
138
|
-
it('should correctly map typography tokens', () => {
|
|
139
|
-
const mockConfig = {
|
|
140
|
-
theme: {
|
|
141
|
-
extend: {
|
|
142
|
-
typography: {
|
|
143
|
-
fontFamilies: {
|
|
144
|
-
sans: ['Inter', 'sans-serif'],
|
|
145
|
-
},
|
|
146
|
-
fontSizes: {
|
|
147
|
-
'2xl': '1.5rem',
|
|
148
|
-
},
|
|
149
|
-
},
|
|
150
|
-
},
|
|
151
|
-
},
|
|
152
|
-
};
|
|
153
|
-
|
|
154
|
-
// Integration test
|
|
155
|
-
expect(typeof createTheme).toBe('function');
|
|
156
|
-
});
|
|
157
|
-
});
|
|
158
|
-
});
|
|
159
|
-
|
|
160
|
-
describe('createTheme with Config Loading', () => {
|
|
161
|
-
it('should work without input (will use defaults if config not available)', () => {
|
|
162
|
-
// createTheme() should work even if config is not available
|
|
163
|
-
// It will fall back to default tokens
|
|
164
|
-
const css = createTheme();
|
|
165
|
-
|
|
166
|
-
expect(typeof css).toBe('string');
|
|
167
|
-
expect(css).toContain(':root');
|
|
168
|
-
expect(css).toContain('--atomix');
|
|
169
|
-
});
|
|
170
|
-
|
|
171
|
-
it('should accept DesignTokens input', () => {
|
|
172
|
-
const tokens: Partial<DesignTokens> = {
|
|
173
|
-
'primary': '#7AFFD7',
|
|
174
|
-
'spacing-4': '1rem',
|
|
175
|
-
};
|
|
176
|
-
|
|
177
|
-
const css = createTheme(tokens);
|
|
178
|
-
|
|
179
|
-
expect(typeof css).toBe('string');
|
|
180
|
-
expect(css).toContain('--atomix-primary');
|
|
181
|
-
expect(css).toContain('#7AFFD7');
|
|
182
|
-
});
|
|
183
|
-
|
|
184
|
-
it('should respect prefix option', () => {
|
|
185
|
-
const tokens: Partial<DesignTokens> = {
|
|
186
|
-
'primary': '#7AFFD7',
|
|
187
|
-
};
|
|
188
|
-
|
|
189
|
-
const css = createTheme(tokens, { prefix: 'myapp' });
|
|
190
|
-
|
|
191
|
-
expect(css).toContain('--myapp-primary');
|
|
192
|
-
expect(css).not.toContain('--atomix-primary');
|
|
193
|
-
});
|
|
194
|
-
|
|
195
|
-
it('should respect selector option', () => {
|
|
196
|
-
const tokens: Partial<DesignTokens> = {
|
|
197
|
-
'primary': '#7AFFD7',
|
|
198
|
-
};
|
|
199
|
-
|
|
200
|
-
const css = createTheme(tokens, { selector: '[data-theme="dark"]' });
|
|
201
|
-
|
|
202
|
-
expect(css).toContain('[data-theme="dark"]');
|
|
203
|
-
expect(css).not.toContain(':root');
|
|
204
|
-
});
|
|
205
|
-
});
|
|
206
|
-
|
|
207
|
-
|
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
/**
|
|
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
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import type { DesignTokens } from '../tokens/tokens';
|
|
10
|
-
import { createTokens } from '../tokens/tokens';
|
|
11
|
-
import { loadAtomixConfig as loadAtomixConfigStatic } from '../../config/loader';
|
|
12
|
-
|
|
13
|
-
/**
|
|
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
|
|
18
|
-
*/
|
|
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.');
|
|
23
|
-
}
|
|
24
|
-
|
|
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,
|
|
32
|
-
});
|
|
33
|
-
} catch (error) {
|
|
34
|
-
if (options?.required !== false) {
|
|
35
|
-
throw new Error('Config loader module not available');
|
|
36
|
-
}
|
|
37
|
-
// Return empty tokens if config is not required
|
|
38
|
-
return createTokens({});
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
if (!config?.theme) {
|
|
42
|
-
return createTokens({});
|
|
43
|
-
}
|
|
44
|
-
|
|
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>);
|
|
55
|
-
}
|
|
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({});
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
/**
|
|
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
|
|
67
|
-
*/
|
|
68
|
-
export async function loadThemeFromConfig(options?: { configPath?: string; required?: boolean }): Promise<DesignTokens> {
|
|
69
|
-
// Check if we're in a browser environment
|
|
70
|
-
if (typeof window !== 'undefined') {
|
|
71
|
-
throw new Error('loadThemeFromConfig: Not available in browser environment. Config loading requires Node.js/SSR environment.');
|
|
72
|
-
}
|
|
73
|
-
|
|
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({});
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
if (!config?.theme) {
|
|
93
|
-
return createTokens({});
|
|
94
|
-
}
|
|
95
|
-
|
|
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>);
|
|
106
|
-
}
|
|
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({});
|
|
112
|
-
}
|
|
113
|
-
|