@shohojdhara/atomix 0.3.12 → 0.3.14
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 +19 -0
- package/README.md +2 -0
- package/dist/atomix.css +101 -88
- package/dist/atomix.css.map +1 -1
- package/dist/atomix.min.css +5 -15258
- package/dist/atomix.min.css.map +1 -1
- package/dist/charts.d.ts +1 -1
- package/dist/charts.js +17 -19
- package/dist/charts.js.map +1 -1
- package/dist/core.d.ts +41 -11
- package/dist/core.js +55 -41
- package/dist/core.js.map +1 -1
- package/dist/forms.d.ts +28 -11
- package/dist/forms.js +25 -24
- package/dist/forms.js.map +1 -1
- package/dist/heavy.d.ts +1 -1
- package/dist/heavy.js +32 -25
- package/dist/heavy.js.map +1 -1
- package/dist/index.d.ts +122 -46
- package/dist/index.esm.js +865 -200
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +870 -204
- 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 +27 -2
- package/dist/theme.js +721 -108
- package/dist/theme.js.map +1 -1
- package/package.json +1 -1
- package/scripts/atomix-cli.js +610 -1111
- package/scripts/cli/component-generator.js +610 -0
- package/scripts/cli/documentation-sync.js +542 -0
- package/scripts/cli/interactive-init.js +84 -288
- package/scripts/cli/mappings.js +211 -0
- package/scripts/cli/migration-tools.js +95 -288
- package/scripts/cli/template-manager.js +107 -0
- package/scripts/cli/templates/README.md +123 -0
- package/scripts/cli/templates/composable-templates.js +149 -0
- package/scripts/cli/templates/config-templates.js +126 -0
- package/scripts/cli/templates/index.js +95 -0
- package/scripts/cli/templates/project-templates.js +214 -0
- package/scripts/cli/templates/react-templates.js +261 -0
- package/scripts/cli/templates/scss-templates.js +156 -0
- package/scripts/cli/templates/storybook-templates.js +236 -0
- package/scripts/cli/templates/testing-templates.js +45 -0
- package/scripts/cli/templates/token-templates.js +447 -0
- package/scripts/cli/templates/types-templates.js +133 -0
- package/scripts/cli/templates-original-backup.js +1655 -0
- package/scripts/cli/templates.js +35 -0
- package/scripts/cli/templates_backup.js +684 -0
- package/scripts/cli/theme-bridge.js +20 -14
- package/scripts/cli/token-manager.js +150 -77
- package/scripts/cli/utils.js +37 -25
- package/src/components/Accordion/Accordion.stories.tsx +5 -5
- package/src/components/Accordion/Accordion.test.tsx +57 -0
- package/src/components/Accordion/Accordion.tsx +4 -0
- package/src/components/AtomixGlass/AtomixGlassContainer.tsx +41 -44
- package/src/components/AtomixGlass/stories/AtomixGlass.stories.tsx +1 -1
- package/src/components/AtomixGlass/stories/Examples.stories.tsx +37 -37
- package/src/components/AtomixGlass/stories/Modes.stories.tsx +1 -2
- package/src/components/AtomixGlass/stories/Playground.stories.tsx +50 -51
- package/src/components/Avatar/Avatar.stories.tsx +26 -26
- package/src/components/Badge/Badge.stories.tsx +31 -31
- package/src/components/Badge/Badge.test.tsx +51 -0
- package/src/components/Badge/Badge.tsx +20 -1
- package/src/components/Block/Block.stories.tsx +5 -5
- package/src/components/Breadcrumb/Breadcrumb.stories.tsx +1 -1
- package/src/components/Breadcrumb/Breadcrumb.tsx +2 -2
- package/src/components/Button/Button.stories.tsx +13 -13
- package/src/components/Button/Button.tsx +4 -4
- package/src/components/Button/ButtonGroup.stories.tsx +2 -2
- package/src/components/Button/README.md +5 -0
- package/src/components/Callout/Callout.stories.tsx +11 -11
- package/src/components/Callout/Callout.test.tsx +10 -10
- package/src/components/Callout/Callout.tsx +7 -7
- package/src/components/Callout/README.md +9 -8
- package/src/components/Card/Card.tsx +2 -2
- package/src/components/Chart/Chart.stories.tsx +6 -6
- package/src/components/Chart/Chart.tsx +1 -1
- package/src/components/ColorModeToggle/ColorModeToggle.stories.tsx +1 -1
- package/src/components/DataTable/DataTable.tsx +14 -12
- package/src/components/DatePicker/DatePicker.stories.tsx +6 -6
- package/src/components/Dropdown/Dropdown.stories.tsx +4 -4
- package/src/components/Form/Checkbox.stories.tsx +3 -3
- package/src/components/Form/Checkbox.tsx +4 -2
- package/src/components/Form/Form.stories.tsx +3 -3
- package/src/components/Form/FormGroup.stories.tsx +1 -1
- package/src/components/Form/Input.stories.tsx +28 -16
- package/src/components/Form/Input.test.tsx +59 -0
- package/src/components/Form/Input.tsx +97 -95
- package/src/components/Form/Radio.stories.tsx +94 -94
- package/src/components/Form/Radio.tsx +2 -2
- package/src/components/Form/Select.stories.tsx +4 -4
- package/src/components/Form/Select.tsx +2 -2
- package/src/components/Form/Textarea.stories.tsx +22 -7
- package/src/components/Form/Textarea.test.tsx +45 -0
- package/src/components/Form/Textarea.tsx +88 -86
- package/src/components/List/List.stories.tsx +2 -2
- package/src/components/Modal/Modal.stories.tsx +4 -4
- package/src/components/Navigation/Navbar/Navbar.stories.tsx +5 -5
- package/src/components/Navigation/Navbar/Navbar.tsx +1 -1
- package/src/components/Navigation/README.md +1 -1
- package/src/components/Pagination/Pagination.stories.tsx +5 -2
- package/src/components/Pagination/Pagination.tsx +1 -1
- package/src/components/PhotoViewer/PhotoViewer.stories.tsx +10 -10
- package/src/components/Popover/Popover.stories.tsx +1 -1
- package/src/components/ProductReview/ProductReview.tsx +1 -1
- package/src/components/Progress/Progress.tsx +46 -46
- package/src/components/Rating/Rating.stories.tsx +4 -4
- package/src/components/Rating/Rating.tsx +8 -8
- package/src/components/Slider/Slider.stories.tsx +63 -63
- package/src/components/Spinner/Spinner.stories.tsx +2 -2
- package/src/components/Spinner/Spinner.test.tsx +35 -0
- package/src/components/Spinner/Spinner.tsx +9 -2
- package/src/components/Testimonial/Testimonial.stories.tsx +1 -1
- package/src/components/Toggle/Toggle.stories.tsx +32 -9
- package/src/components/Toggle/Toggle.test.tsx +91 -0
- package/src/components/Toggle/Toggle.tsx +44 -27
- package/src/components/Tooltip/Tooltip.tsx +1 -1
- package/src/layouts/Grid/Grid.stories.tsx +49 -49
- package/src/layouts/MasonryGrid/MasonryGrid.stories.tsx +2 -2
- package/src/lib/composables/useAccordion.ts +12 -3
- package/src/lib/composables/useBreadcrumb.ts +2 -2
- package/src/lib/composables/useCallout.ts +7 -7
- package/src/lib/composables/useNavbar.ts +1 -1
- package/src/lib/constants/components.ts +1 -1
- package/src/lib/storybook/InteractiveDemo.tsx +113 -0
- package/src/lib/storybook/PreviewContainer.tsx +36 -0
- package/src/lib/storybook/VariantsGrid.tsx +21 -0
- package/src/lib/storybook/index.ts +3 -0
- package/src/lib/theme/core/createThemeObject.ts +9 -5
- package/src/lib/theme/devtools/CLI.ts +155 -0
- package/src/lib/theme/devtools/DesignTokensCustomizer.stories.tsx +213 -0
- package/src/lib/theme/devtools/DesignTokensCustomizer.tsx +566 -0
- package/src/lib/theme/devtools/LiveEditor.tsx +2 -1
- package/src/lib/theme/devtools/index.ts +3 -0
- package/src/lib/theme/errors/errors.ts +8 -0
- package/src/lib/theme/runtime/ThemeProvider.tsx +117 -57
- package/src/lib/theme/runtime/__tests__/ThemeProvider.integration.test.tsx +305 -0
- package/src/lib/theme/runtime/__tests__/ThemeProvider.test.tsx +588 -0
- package/src/lib/theme/utils/__tests__/themeValidation.test.ts +264 -0
- package/src/lib/theme/utils/index.ts +1 -0
- package/src/lib/theme/utils/themeValidation.ts +501 -0
- package/src/lib/theme-tools.ts +32 -3
- package/src/lib/types/components.ts +81 -26
- package/src/lib/utils/themeNaming.ts +1 -1
- package/src/styles/06-components/_components.atomix-glass.scss +14 -15
- package/src/styles/06-components/_components.callout.scss +29 -33
- package/src/styles/06-components/_index.scss +1 -1
- package/src/styles/99-utilities/_utilities.display.scss +14 -3
- package/src/styles/99-utilities/_utilities.flex.scss +10 -10
- package/src/styles/99-utilities/_utilities.text.scss +28 -8
- package/scripts/cli/__tests__/cli-commands.test.js +0 -204
- package/scripts/cli/__tests__/utils.test.js +0 -201
- package/scripts/cli/__tests__/vitest.config.js +0 -26
|
@@ -18,20 +18,26 @@ const __dirname = dirname(__filename);
|
|
|
18
18
|
*/
|
|
19
19
|
export async function executeThemeCommand(command, args = [], options = {}) {
|
|
20
20
|
const spinner = options.spinner || ora(`Running theme ${command}...`).start();
|
|
21
|
-
|
|
21
|
+
|
|
22
22
|
try {
|
|
23
23
|
// Path to the theme CLI
|
|
24
24
|
const themeCliPath = join(__dirname, '../../src/lib/theme/devtools/CLI.ts');
|
|
25
|
-
|
|
25
|
+
|
|
26
26
|
// Use ts-node to execute TypeScript CLI
|
|
27
27
|
const tsNodePath = join(__dirname, '../../node_modules/.bin/ts-node');
|
|
28
|
-
|
|
28
|
+
|
|
29
29
|
return new Promise((resolve, reject) => {
|
|
30
|
-
const child = spawn(tsNodePath, [
|
|
30
|
+
const child = spawn(tsNodePath, [
|
|
31
|
+
'--esm',
|
|
32
|
+
'--experimental-specifier-resolution=node',
|
|
33
|
+
themeCliPath,
|
|
34
|
+
command,
|
|
35
|
+
...args
|
|
36
|
+
], {
|
|
31
37
|
stdio: 'inherit',
|
|
32
38
|
cwd: process.cwd(),
|
|
33
39
|
});
|
|
34
|
-
|
|
40
|
+
|
|
35
41
|
child.on('close', (code) => {
|
|
36
42
|
if (code === 0) {
|
|
37
43
|
spinner.succeed(chalk.green(`✓ Theme ${command} completed`));
|
|
@@ -41,7 +47,7 @@ export async function executeThemeCommand(command, args = [], options = {}) {
|
|
|
41
47
|
reject(new Error(`Theme command failed with code ${code}`));
|
|
42
48
|
}
|
|
43
49
|
});
|
|
44
|
-
|
|
50
|
+
|
|
45
51
|
child.on('error', (error) => {
|
|
46
52
|
spinner.fail(chalk.red(`✗ Theme ${command} failed`));
|
|
47
53
|
reject(error);
|
|
@@ -65,43 +71,43 @@ export function createThemeCLIBridge() {
|
|
|
65
71
|
const args = [];
|
|
66
72
|
if (options.config) args.push('--config', options.config);
|
|
67
73
|
if (options.strict) args.push('--strict');
|
|
68
|
-
|
|
74
|
+
|
|
69
75
|
return executeThemeCommand('validate', args, options);
|
|
70
76
|
},
|
|
71
|
-
|
|
77
|
+
|
|
72
78
|
/**
|
|
73
79
|
* List all themes
|
|
74
80
|
*/
|
|
75
81
|
async list(options = {}) {
|
|
76
82
|
return executeThemeCommand('list', [], options);
|
|
77
83
|
},
|
|
78
|
-
|
|
84
|
+
|
|
79
85
|
/**
|
|
80
86
|
* Inspect a theme
|
|
81
87
|
*/
|
|
82
88
|
async inspect(themeName, options = {}) {
|
|
83
89
|
const args = ['--theme', themeName];
|
|
84
90
|
if (options.json) args.push('--json');
|
|
85
|
-
|
|
91
|
+
|
|
86
92
|
return executeThemeCommand('inspect', args, options);
|
|
87
93
|
},
|
|
88
|
-
|
|
94
|
+
|
|
89
95
|
/**
|
|
90
96
|
* Compare two themes
|
|
91
97
|
*/
|
|
92
98
|
async compare(theme1, theme2, options = {}) {
|
|
93
99
|
const args = ['--theme1', theme1, '--theme2', theme2];
|
|
94
|
-
|
|
100
|
+
|
|
95
101
|
return executeThemeCommand('compare', args, options);
|
|
96
102
|
},
|
|
97
|
-
|
|
103
|
+
|
|
98
104
|
/**
|
|
99
105
|
* Export a theme
|
|
100
106
|
*/
|
|
101
107
|
async export(themeName, options = {}) {
|
|
102
108
|
const args = ['--theme', themeName];
|
|
103
109
|
if (options.output) args.push('--output', options.output);
|
|
104
|
-
|
|
110
|
+
|
|
105
111
|
return executeThemeCommand('export', args, options);
|
|
106
112
|
},
|
|
107
113
|
};
|
|
@@ -52,10 +52,10 @@ async function extractTokensFromFile(filePath) {
|
|
|
52
52
|
if (!existsSync(filePath)) {
|
|
53
53
|
return null;
|
|
54
54
|
}
|
|
55
|
-
|
|
55
|
+
|
|
56
56
|
const content = await readFile(filePath, 'utf8');
|
|
57
57
|
const tokens = {};
|
|
58
|
-
|
|
58
|
+
|
|
59
59
|
// Extract SCSS variables
|
|
60
60
|
const scssVarPattern = /\$([a-z-]+):\s*([^;!]+)(?:\s*!default)?;/gi;
|
|
61
61
|
let match;
|
|
@@ -67,7 +67,7 @@ async function extractTokensFromFile(filePath) {
|
|
|
67
67
|
line: content.substring(0, match.index).split('\n').length
|
|
68
68
|
};
|
|
69
69
|
}
|
|
70
|
-
|
|
70
|
+
|
|
71
71
|
// Extract CSS custom properties
|
|
72
72
|
const cssVarPattern = /--(atomix-[a-z-]+):\s*([^;]+);/gi;
|
|
73
73
|
while ((match = cssVarPattern.exec(content)) !== null) {
|
|
@@ -78,7 +78,7 @@ async function extractTokensFromFile(filePath) {
|
|
|
78
78
|
line: content.substring(0, match.index).split('\n').length
|
|
79
79
|
};
|
|
80
80
|
}
|
|
81
|
-
|
|
81
|
+
|
|
82
82
|
return tokens;
|
|
83
83
|
}
|
|
84
84
|
|
|
@@ -87,25 +87,25 @@ async function extractTokensFromFile(filePath) {
|
|
|
87
87
|
*/
|
|
88
88
|
export async function listTokens(category = null) {
|
|
89
89
|
const spinner = ora('Loading design tokens...').start();
|
|
90
|
-
|
|
90
|
+
|
|
91
91
|
try {
|
|
92
92
|
const results = {};
|
|
93
|
-
|
|
93
|
+
|
|
94
94
|
// Get tokens from specified category or all categories
|
|
95
|
-
const categories = category
|
|
96
|
-
? [category]
|
|
95
|
+
const categories = category
|
|
96
|
+
? [category]
|
|
97
97
|
: Object.keys(tokenCategories);
|
|
98
|
-
|
|
98
|
+
|
|
99
99
|
for (const cat of categories) {
|
|
100
100
|
if (!tokenCategories[cat]) {
|
|
101
101
|
spinner.warn(chalk.yellow(`Unknown category: ${cat}`));
|
|
102
102
|
continue;
|
|
103
103
|
}
|
|
104
|
-
|
|
104
|
+
|
|
105
105
|
const { path, description } = tokenCategories[cat];
|
|
106
106
|
const fullPath = join(process.cwd(), path);
|
|
107
107
|
const tokens = await extractTokensFromFile(fullPath);
|
|
108
|
-
|
|
108
|
+
|
|
109
109
|
if (tokens) {
|
|
110
110
|
results[cat] = {
|
|
111
111
|
description,
|
|
@@ -115,18 +115,18 @@ export async function listTokens(category = null) {
|
|
|
115
115
|
};
|
|
116
116
|
}
|
|
117
117
|
}
|
|
118
|
-
|
|
118
|
+
|
|
119
119
|
spinner.stop();
|
|
120
|
-
|
|
120
|
+
|
|
121
121
|
// Display results
|
|
122
122
|
if (Object.keys(results).length === 0) {
|
|
123
123
|
console.log(chalk.yellow('\n⚠️ No design tokens found'));
|
|
124
124
|
console.log(chalk.gray('Make sure you are in an Atomix project directory'));
|
|
125
125
|
return;
|
|
126
126
|
}
|
|
127
|
-
|
|
127
|
+
|
|
128
128
|
console.log(chalk.bold.cyan('\n📐 Design Tokens\n'));
|
|
129
|
-
|
|
129
|
+
|
|
130
130
|
for (const [category, data] of Object.entries(results)) {
|
|
131
131
|
console.log(boxen(
|
|
132
132
|
chalk.bold(category.toUpperCase()) + '\n' +
|
|
@@ -140,25 +140,25 @@ export async function listTokens(category = null) {
|
|
|
140
140
|
borderColor: 'gray'
|
|
141
141
|
}
|
|
142
142
|
));
|
|
143
|
-
|
|
143
|
+
|
|
144
144
|
// Show first 5 tokens as examples
|
|
145
145
|
const tokenEntries = Object.entries(data.tokens).slice(0, 5);
|
|
146
146
|
tokenEntries.forEach(([name, info]) => {
|
|
147
|
-
const value = info.value.length > 30
|
|
148
|
-
? info.value.substring(0, 30) + '...'
|
|
147
|
+
const value = info.value.length > 30
|
|
148
|
+
? info.value.substring(0, 30) + '...'
|
|
149
149
|
: info.value;
|
|
150
150
|
console.log(` ${chalk.green(name)}: ${chalk.white(value)}`);
|
|
151
151
|
});
|
|
152
|
-
|
|
152
|
+
|
|
153
153
|
if (Object.keys(data.tokens).length > 5) {
|
|
154
154
|
console.log(chalk.gray(` ... and ${Object.keys(data.tokens).length - 5} more\n`));
|
|
155
155
|
} else {
|
|
156
156
|
console.log();
|
|
157
157
|
}
|
|
158
158
|
}
|
|
159
|
-
|
|
159
|
+
|
|
160
160
|
return results;
|
|
161
|
-
|
|
161
|
+
|
|
162
162
|
} catch (error) {
|
|
163
163
|
spinner.fail(chalk.red('Failed to load tokens'));
|
|
164
164
|
throw error;
|
|
@@ -170,15 +170,15 @@ export async function listTokens(category = null) {
|
|
|
170
170
|
*/
|
|
171
171
|
export async function validateTokens(options = {}) {
|
|
172
172
|
const spinner = ora('Validating design tokens...').start();
|
|
173
|
-
|
|
173
|
+
|
|
174
174
|
try {
|
|
175
175
|
const issues = [];
|
|
176
176
|
const warnings = [];
|
|
177
177
|
let totalTokens = 0;
|
|
178
|
-
|
|
178
|
+
|
|
179
179
|
for (const [category, config] of Object.entries(tokenCategories)) {
|
|
180
180
|
const fullPath = join(process.cwd(), config.path);
|
|
181
|
-
|
|
181
|
+
|
|
182
182
|
if (!existsSync(fullPath)) {
|
|
183
183
|
issues.push({
|
|
184
184
|
category,
|
|
@@ -188,14 +188,14 @@ export async function validateTokens(options = {}) {
|
|
|
188
188
|
});
|
|
189
189
|
continue;
|
|
190
190
|
}
|
|
191
|
-
|
|
191
|
+
|
|
192
192
|
const tokens = await extractTokensFromFile(fullPath);
|
|
193
193
|
if (tokens) {
|
|
194
194
|
totalTokens += Object.keys(tokens).length;
|
|
195
|
-
|
|
195
|
+
|
|
196
196
|
// Check for hardcoded values
|
|
197
197
|
const content = await readFile(fullPath, 'utf8');
|
|
198
|
-
|
|
198
|
+
|
|
199
199
|
// Check for hardcoded colors
|
|
200
200
|
if (category === 'colors') {
|
|
201
201
|
const hardcodedColors = content.match(/#[0-9a-fA-F]{3,8}(?![0-9a-fA-F])/g);
|
|
@@ -209,7 +209,7 @@ export async function validateTokens(options = {}) {
|
|
|
209
209
|
});
|
|
210
210
|
}
|
|
211
211
|
}
|
|
212
|
-
|
|
212
|
+
|
|
213
213
|
// Check for hardcoded pixel values
|
|
214
214
|
if (category === 'spacing' || category === 'typography') {
|
|
215
215
|
const hardcodedPixels = content.match(/\d+px/g);
|
|
@@ -223,7 +223,7 @@ export async function validateTokens(options = {}) {
|
|
|
223
223
|
});
|
|
224
224
|
}
|
|
225
225
|
}
|
|
226
|
-
|
|
226
|
+
|
|
227
227
|
// Check for missing !default flags
|
|
228
228
|
const scssVars = content.match(/\$[a-z-]+:\s*[^;]+;/gi);
|
|
229
229
|
const defaultFlags = content.match(/!default/g);
|
|
@@ -234,7 +234,7 @@ export async function validateTokens(options = {}) {
|
|
|
234
234
|
fix: 'Add !default to allow theme overrides'
|
|
235
235
|
});
|
|
236
236
|
}
|
|
237
|
-
|
|
237
|
+
|
|
238
238
|
// Check naming conventions
|
|
239
239
|
for (const [name, info] of Object.entries(tokens)) {
|
|
240
240
|
if (info.type === 'css' && !name.startsWith(config.prefix)) {
|
|
@@ -247,12 +247,12 @@ export async function validateTokens(options = {}) {
|
|
|
247
247
|
}
|
|
248
248
|
}
|
|
249
249
|
}
|
|
250
|
-
|
|
250
|
+
|
|
251
251
|
spinner.stop();
|
|
252
|
-
|
|
252
|
+
|
|
253
253
|
// Display validation results
|
|
254
254
|
console.log(chalk.bold.cyan('\n🔍 Token Validation Report\n'));
|
|
255
|
-
|
|
255
|
+
|
|
256
256
|
if (issues.length === 0 && warnings.length === 0) {
|
|
257
257
|
console.log(boxen(
|
|
258
258
|
chalk.bold.green('✅ All tokens valid!\n\n') +
|
|
@@ -274,7 +274,7 @@ export async function validateTokens(options = {}) {
|
|
|
274
274
|
console.log(chalk.yellow(` Fix: ${issue.fix}\n`));
|
|
275
275
|
});
|
|
276
276
|
}
|
|
277
|
-
|
|
277
|
+
|
|
278
278
|
if (warnings.length > 0) {
|
|
279
279
|
console.log(chalk.bold.yellow(`⚠️ Warnings (${warnings.length}):\n`));
|
|
280
280
|
warnings.forEach((warning, i) => {
|
|
@@ -285,13 +285,13 @@ export async function validateTokens(options = {}) {
|
|
|
285
285
|
console.log(chalk.cyan(` Fix: ${warning.fix}\n`));
|
|
286
286
|
});
|
|
287
287
|
}
|
|
288
|
-
|
|
288
|
+
|
|
289
289
|
console.log(chalk.gray('─'.repeat(50)));
|
|
290
290
|
console.log(chalk.cyan('\n💡 Run with --fix to attempt automatic fixes'));
|
|
291
291
|
}
|
|
292
|
-
|
|
292
|
+
|
|
293
293
|
return { issues, warnings, totalTokens };
|
|
294
|
-
|
|
294
|
+
|
|
295
295
|
} catch (error) {
|
|
296
296
|
spinner.fail(chalk.red('Validation failed'));
|
|
297
297
|
throw error;
|
|
@@ -303,15 +303,15 @@ export async function validateTokens(options = {}) {
|
|
|
303
303
|
*/
|
|
304
304
|
export async function exportTokens(format = 'json', outputPath = null) {
|
|
305
305
|
const spinner = ora(`Exporting tokens as ${format.toUpperCase()}...`).start();
|
|
306
|
-
|
|
306
|
+
|
|
307
307
|
try {
|
|
308
308
|
const allTokens = {};
|
|
309
|
-
|
|
309
|
+
|
|
310
310
|
// Collect all tokens
|
|
311
311
|
for (const [category, config] of Object.entries(tokenCategories)) {
|
|
312
312
|
const fullPath = join(process.cwd(), config.path);
|
|
313
313
|
const tokens = await extractTokensFromFile(fullPath);
|
|
314
|
-
|
|
314
|
+
|
|
315
315
|
if (tokens) {
|
|
316
316
|
allTokens[category] = {};
|
|
317
317
|
for (const [name, info] of Object.entries(tokens)) {
|
|
@@ -319,16 +319,16 @@ export async function exportTokens(format = 'json', outputPath = null) {
|
|
|
319
319
|
}
|
|
320
320
|
}
|
|
321
321
|
}
|
|
322
|
-
|
|
322
|
+
|
|
323
323
|
let output;
|
|
324
324
|
let filename;
|
|
325
|
-
|
|
325
|
+
|
|
326
326
|
switch (format.toLowerCase()) {
|
|
327
327
|
case 'json':
|
|
328
328
|
output = JSON.stringify(allTokens, null, 2);
|
|
329
329
|
filename = 'atomix-tokens.json';
|
|
330
330
|
break;
|
|
331
|
-
|
|
331
|
+
|
|
332
332
|
case 'css':
|
|
333
333
|
output = ':root {\n';
|
|
334
334
|
for (const [category, tokens] of Object.entries(allTokens)) {
|
|
@@ -342,7 +342,7 @@ export async function exportTokens(format = 'json', outputPath = null) {
|
|
|
342
342
|
output += '}';
|
|
343
343
|
filename = 'atomix-tokens.css';
|
|
344
344
|
break;
|
|
345
|
-
|
|
345
|
+
|
|
346
346
|
case 'scss':
|
|
347
347
|
output = '// Atomix Design Tokens\n\n';
|
|
348
348
|
for (const [category, tokens] of Object.entries(allTokens)) {
|
|
@@ -356,7 +356,7 @@ export async function exportTokens(format = 'json', outputPath = null) {
|
|
|
356
356
|
}
|
|
357
357
|
filename = 'atomix-tokens.scss';
|
|
358
358
|
break;
|
|
359
|
-
|
|
359
|
+
|
|
360
360
|
case 'js':
|
|
361
361
|
case 'javascript':
|
|
362
362
|
output = '// Atomix Design Tokens\n';
|
|
@@ -365,7 +365,7 @@ export async function exportTokens(format = 'json', outputPath = null) {
|
|
|
365
365
|
output += ';\n\nexport default tokens;';
|
|
366
366
|
filename = 'atomix-tokens.js';
|
|
367
367
|
break;
|
|
368
|
-
|
|
368
|
+
|
|
369
369
|
case 'ts':
|
|
370
370
|
case 'typescript':
|
|
371
371
|
output = '// Atomix Design Tokens\n\n';
|
|
@@ -379,30 +379,30 @@ export async function exportTokens(format = 'json', outputPath = null) {
|
|
|
379
379
|
output += ';\n\nexport default tokens;';
|
|
380
380
|
filename = 'atomix-tokens.ts';
|
|
381
381
|
break;
|
|
382
|
-
|
|
382
|
+
|
|
383
383
|
default:
|
|
384
384
|
throw new Error(`Unsupported format: ${format}`);
|
|
385
385
|
}
|
|
386
|
-
|
|
386
|
+
|
|
387
387
|
// Write to file
|
|
388
388
|
const finalPath = outputPath || filename;
|
|
389
389
|
await writeFile(finalPath, output, 'utf8');
|
|
390
|
-
|
|
390
|
+
|
|
391
391
|
spinner.succeed(chalk.green(`✓ Exported tokens to ${finalPath}`));
|
|
392
|
-
|
|
392
|
+
|
|
393
393
|
// Show summary
|
|
394
394
|
const categoryCount = Object.keys(allTokens).length;
|
|
395
395
|
const tokenCount = Object.values(allTokens).reduce(
|
|
396
|
-
(sum, cat) => sum + Object.keys(cat).length,
|
|
396
|
+
(sum, cat) => sum + Object.keys(cat).length,
|
|
397
397
|
0
|
|
398
398
|
);
|
|
399
|
-
|
|
399
|
+
|
|
400
400
|
console.log(chalk.gray(`\n Categories: ${categoryCount}`));
|
|
401
401
|
console.log(chalk.gray(` Total tokens: ${tokenCount}`));
|
|
402
402
|
console.log(chalk.gray(` Format: ${format.toUpperCase()}`));
|
|
403
|
-
|
|
403
|
+
|
|
404
404
|
return { path: finalPath, tokens: allTokens };
|
|
405
|
-
|
|
405
|
+
|
|
406
406
|
} catch (error) {
|
|
407
407
|
spinner.fail(chalk.red('Export failed'));
|
|
408
408
|
throw error;
|
|
@@ -414,23 +414,23 @@ export async function exportTokens(format = 'json', outputPath = null) {
|
|
|
414
414
|
*/
|
|
415
415
|
export async function importTokens(filePath, options = {}) {
|
|
416
416
|
const spinner = ora('Importing design tokens...').start();
|
|
417
|
-
|
|
417
|
+
|
|
418
418
|
try {
|
|
419
419
|
if (!existsSync(filePath)) {
|
|
420
420
|
throw new Error(`File not found: ${filePath}`);
|
|
421
421
|
}
|
|
422
|
-
|
|
422
|
+
|
|
423
423
|
const content = await readFile(filePath, 'utf8');
|
|
424
424
|
const extension = filePath.split('.').pop().toLowerCase();
|
|
425
|
-
|
|
425
|
+
|
|
426
426
|
let tokens;
|
|
427
|
-
|
|
427
|
+
|
|
428
428
|
// Parse tokens based on file type
|
|
429
429
|
switch (extension) {
|
|
430
430
|
case 'json':
|
|
431
431
|
tokens = JSON.parse(content);
|
|
432
432
|
break;
|
|
433
|
-
|
|
433
|
+
|
|
434
434
|
case 'js':
|
|
435
435
|
case 'ts':
|
|
436
436
|
// Parse tokens safely without eval
|
|
@@ -440,10 +440,10 @@ export async function importTokens(filePath, options = {}) {
|
|
|
440
440
|
if (jsonMatch) {
|
|
441
441
|
// Extract the object literal and clean it up
|
|
442
442
|
let objectStr = jsonMatch[1];
|
|
443
|
-
|
|
443
|
+
|
|
444
444
|
// Remove trailing semicolon if present
|
|
445
445
|
objectStr = objectStr.replace(/;\s*$/, '');
|
|
446
|
-
|
|
446
|
+
|
|
447
447
|
// Try direct JSON parsing first
|
|
448
448
|
try {
|
|
449
449
|
tokens = JSON.parse(objectStr);
|
|
@@ -457,7 +457,7 @@ export async function importTokens(filePath, options = {}) {
|
|
|
457
457
|
.replace(/(\s*)([a-zA-Z_$][a-zA-Z0-9_$]*)\s*:/g, '$1"$2":')
|
|
458
458
|
// Handle trailing commas
|
|
459
459
|
.replace(/,(\s*[}\]])/g, '$1');
|
|
460
|
-
|
|
460
|
+
|
|
461
461
|
tokens = JSON.parse(objectStr);
|
|
462
462
|
}
|
|
463
463
|
} else {
|
|
@@ -467,28 +467,28 @@ export async function importTokens(filePath, options = {}) {
|
|
|
467
467
|
throw new Error(`Could not parse JavaScript/TypeScript tokens: ${error.message}`);
|
|
468
468
|
}
|
|
469
469
|
break;
|
|
470
|
-
|
|
470
|
+
|
|
471
471
|
default:
|
|
472
472
|
throw new Error(`Unsupported file type: ${extension}`);
|
|
473
473
|
}
|
|
474
|
-
|
|
474
|
+
|
|
475
475
|
spinner.text = 'Updating token files...';
|
|
476
|
-
|
|
476
|
+
|
|
477
477
|
// Update token files
|
|
478
478
|
for (const [category, categoryTokens] of Object.entries(tokens)) {
|
|
479
479
|
if (!tokenCategories[category]) {
|
|
480
480
|
console.warn(chalk.yellow(`\n⚠️ Unknown category: ${category} (skipped)`));
|
|
481
481
|
continue;
|
|
482
482
|
}
|
|
483
|
-
|
|
483
|
+
|
|
484
484
|
const config = tokenCategories[category];
|
|
485
485
|
const fullPath = join(process.cwd(), config.path);
|
|
486
|
-
|
|
486
|
+
|
|
487
487
|
// Generate SCSS content
|
|
488
488
|
let scssContent = `// ${config.description}\n`;
|
|
489
489
|
scssContent += `// Imported from: ${basename(filePath)}\n`;
|
|
490
490
|
scssContent += `// Date: ${new Date().toISOString()}\n\n`;
|
|
491
|
-
|
|
491
|
+
|
|
492
492
|
for (const [name, value] of Object.entries(categoryTokens)) {
|
|
493
493
|
if (name.startsWith('$')) {
|
|
494
494
|
scssContent += `${name}: ${value} !default;\n`;
|
|
@@ -499,7 +499,7 @@ export async function importTokens(filePath, options = {}) {
|
|
|
499
499
|
scssContent += `$${name}: ${value} !default;\n`;
|
|
500
500
|
}
|
|
501
501
|
}
|
|
502
|
-
|
|
502
|
+
|
|
503
503
|
if (options.dryRun) {
|
|
504
504
|
console.log(chalk.yellow(`\n Would update: ${config.path}`));
|
|
505
505
|
console.log(chalk.gray(scssContent.substring(0, 200) + '...'));
|
|
@@ -508,37 +508,110 @@ export async function importTokens(filePath, options = {}) {
|
|
|
508
508
|
console.log(chalk.green(` ✓ Updated ${config.path}`));
|
|
509
509
|
}
|
|
510
510
|
}
|
|
511
|
-
|
|
511
|
+
|
|
512
512
|
spinner.succeed(chalk.green('✓ Tokens imported successfully'));
|
|
513
|
-
|
|
513
|
+
|
|
514
514
|
// Show summary
|
|
515
515
|
const categoryCount = Object.keys(tokens).length;
|
|
516
516
|
const tokenCount = Object.values(tokens).reduce(
|
|
517
|
-
(sum, cat) => sum + Object.keys(cat).length,
|
|
517
|
+
(sum, cat) => sum + Object.keys(cat).length,
|
|
518
518
|
0
|
|
519
519
|
);
|
|
520
|
-
|
|
520
|
+
|
|
521
521
|
console.log(chalk.gray(`\n Categories imported: ${categoryCount}`));
|
|
522
522
|
console.log(chalk.gray(` Total tokens: ${tokenCount}`));
|
|
523
|
-
|
|
523
|
+
|
|
524
524
|
if (!options.dryRun) {
|
|
525
525
|
console.log(chalk.cyan('\n💡 Next steps:'));
|
|
526
526
|
console.log(chalk.gray(' 1. Review the updated token files'));
|
|
527
527
|
console.log(chalk.gray(' 2. Rebuild your themes: atomix build-theme <theme>'));
|
|
528
528
|
console.log(chalk.gray(' 3. Test your components with new tokens'));
|
|
529
529
|
}
|
|
530
|
-
|
|
530
|
+
|
|
531
531
|
return { tokens, categoryCount, tokenCount };
|
|
532
|
-
|
|
532
|
+
|
|
533
533
|
} catch (error) {
|
|
534
534
|
spinner.fail(chalk.red('Import failed'));
|
|
535
535
|
throw error;
|
|
536
536
|
}
|
|
537
537
|
}
|
|
538
538
|
|
|
539
|
+
/**
|
|
540
|
+
* Automatically fix issues in token files
|
|
541
|
+
*/
|
|
542
|
+
export async function fixTokens(options = {}) {
|
|
543
|
+
const spinner = ora('Attempting to fix design tokens...').start();
|
|
544
|
+
let totalFixed = 0;
|
|
545
|
+
|
|
546
|
+
try {
|
|
547
|
+
for (const [category, config] of Object.entries(tokenCategories)) {
|
|
548
|
+
const fullPath = join(process.cwd(), config.path);
|
|
549
|
+
|
|
550
|
+
if (!existsSync(fullPath)) continue;
|
|
551
|
+
|
|
552
|
+
let content = await readFile(fullPath, 'utf8');
|
|
553
|
+
let originalContent = content;
|
|
554
|
+
let fileFixedCount = 0;
|
|
555
|
+
|
|
556
|
+
// 1. Fix missing !default flags
|
|
557
|
+
const defaultFixed = content.replace(/(\$[a-z-]+:\s*[^;!]+)(;)/gi, (match, p1, p2) => {
|
|
558
|
+
fileFixedCount++;
|
|
559
|
+
return `${p1} !default${p2}`;
|
|
560
|
+
});
|
|
561
|
+
content = defaultFixed;
|
|
562
|
+
|
|
563
|
+
// 2. Fix hardcoded colors (exact matches for basic tokens)
|
|
564
|
+
if (category === 'colors') {
|
|
565
|
+
const colorMappings = {
|
|
566
|
+
'#7AFFD7': 'var(--atomix-color-primary)',
|
|
567
|
+
'#FF5733': 'var(--atomix-color-secondary)',
|
|
568
|
+
'#000000': 'var(--atomix-color-background)',
|
|
569
|
+
'#FFFFFF': 'var(--atomix-color-text)'
|
|
570
|
+
};
|
|
571
|
+
|
|
572
|
+
for (const [hex, token] of Object.entries(colorMappings)) {
|
|
573
|
+
const regex = new RegExp(hex, 'gi');
|
|
574
|
+
if (regex.test(content)) {
|
|
575
|
+
content = content.replace(regex, token);
|
|
576
|
+
fileFixedCount++;
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
// 3. Fix hardcoded spacing (rem preferred)
|
|
582
|
+
if (category === 'spacing') {
|
|
583
|
+
content = content.replace(/(\d+)px/g, (match, pixels) => {
|
|
584
|
+
const px = parseInt(pixels);
|
|
585
|
+
if (px % 4 === 0) {
|
|
586
|
+
fileFixedCount++;
|
|
587
|
+
return `var(--atomix-space-${px / 4})`;
|
|
588
|
+
}
|
|
589
|
+
return match;
|
|
590
|
+
});
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
if (content !== originalContent) {
|
|
594
|
+
if (!options.dryRun) {
|
|
595
|
+
await writeFile(fullPath, content, 'utf8');
|
|
596
|
+
}
|
|
597
|
+
totalFixed += fileFixedCount;
|
|
598
|
+
console.log(chalk.green(` ✓ Fixed ${fileFixedCount} issues in ${config.path}`));
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
spinner.succeed(chalk.green(`✓ Successfully fixed ${totalFixed} issues!`));
|
|
603
|
+
return { totalFixed };
|
|
604
|
+
|
|
605
|
+
} catch (error) {
|
|
606
|
+
spinner.fail(chalk.red('Fix operation failed'));
|
|
607
|
+
throw error;
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
|
|
539
611
|
export default {
|
|
540
612
|
listTokens,
|
|
541
613
|
validateTokens,
|
|
542
614
|
exportTokens,
|
|
543
|
-
importTokens
|
|
615
|
+
importTokens,
|
|
616
|
+
fixTokens
|
|
544
617
|
};
|