@shohojdhara/atomix 0.4.7 → 0.4.9

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 (176) hide show
  1. package/atomix.config.ts +58 -1
  2. package/dist/atomix.css +172 -157
  3. package/dist/atomix.css.map +1 -1
  4. package/dist/atomix.min.css +4 -4
  5. package/dist/atomix.min.css.map +1 -1
  6. package/dist/charts.d.ts +33 -0
  7. package/dist/charts.js +1274 -164
  8. package/dist/charts.js.map +1 -1
  9. package/dist/core.d.ts +33 -10
  10. package/dist/core.js +1099 -83
  11. package/dist/core.js.map +1 -1
  12. package/dist/forms.d.ts +33 -0
  13. package/dist/forms.js +2106 -1050
  14. package/dist/forms.js.map +1 -1
  15. package/dist/heavy.d.ts +42 -1
  16. package/dist/heavy.js +1663 -638
  17. package/dist/heavy.js.map +1 -1
  18. package/dist/index.d.ts +442 -270
  19. package/dist/index.esm.js +1947 -680
  20. package/dist/index.esm.js.map +1 -1
  21. package/dist/index.js +1982 -712
  22. package/dist/index.js.map +1 -1
  23. package/dist/index.min.js +1 -1
  24. package/dist/index.min.js.map +1 -1
  25. package/package.json +6 -3
  26. package/scripts/atomix-cli.js +136 -1827
  27. package/scripts/cli/__tests__/basic.test.js +3 -2
  28. package/scripts/cli/__tests__/clean.test.js +278 -0
  29. package/scripts/cli/__tests__/component-validator.test.js +433 -0
  30. package/scripts/cli/__tests__/generator.test.js +613 -0
  31. package/scripts/cli/__tests__/glass-motion.test.js +256 -0
  32. package/scripts/cli/__tests__/integration.test.js +719 -108
  33. package/scripts/cli/__tests__/migrate.test.js +74 -0
  34. package/scripts/cli/__tests__/security.test.js +206 -0
  35. package/scripts/cli/__tests__/test-setup.js +3 -1
  36. package/scripts/cli/__tests__/theme-bridge.test.js +507 -0
  37. package/scripts/cli/__tests__/token-provider.test.js +361 -0
  38. package/scripts/cli/__tests__/utils.test.js +5 -5
  39. package/scripts/cli/commands/benchmark.js +105 -0
  40. package/scripts/cli/commands/build-theme.js +115 -0
  41. package/scripts/cli/commands/clean.js +109 -0
  42. package/scripts/cli/commands/doctor.js +88 -0
  43. package/scripts/cli/commands/generate.js +218 -0
  44. package/scripts/cli/commands/init.js +73 -0
  45. package/scripts/cli/commands/migrate.js +106 -0
  46. package/scripts/cli/commands/sync-tokens.js +206 -0
  47. package/scripts/cli/commands/theme-bridge.js +248 -0
  48. package/scripts/cli/commands/tokens.js +157 -0
  49. package/scripts/cli/commands/validate.js +194 -0
  50. package/scripts/cli/internal/ai-engine.js +156 -0
  51. package/scripts/cli/internal/compiler.js +114 -0
  52. package/scripts/cli/internal/component-validator.js +443 -0
  53. package/scripts/cli/internal/config-loader.js +162 -0
  54. package/scripts/cli/internal/filesystem.js +158 -0
  55. package/scripts/cli/internal/generator.js +430 -0
  56. package/scripts/cli/internal/glass-generator.js +398 -0
  57. package/scripts/cli/internal/hook-generator.js +369 -0
  58. package/scripts/cli/internal/hooks.js +61 -0
  59. package/scripts/cli/internal/itcss-generator.js +565 -0
  60. package/scripts/cli/internal/motion-generator.js +679 -0
  61. package/scripts/cli/internal/template-engine.js +301 -0
  62. package/scripts/cli/internal/theme-bridge.js +664 -0
  63. package/scripts/cli/internal/tokens/engine.js +122 -0
  64. package/scripts/cli/internal/tokens/provider.js +34 -0
  65. package/scripts/cli/internal/tokens/providers/figma.js +50 -0
  66. package/scripts/cli/internal/tokens/providers/style-dictionary.js +48 -0
  67. package/scripts/cli/internal/tokens/providers/w3c.js +48 -0
  68. package/scripts/cli/internal/tokens/token-provider.js +443 -0
  69. package/scripts/cli/internal/tokens/token-validator.js +513 -0
  70. package/scripts/cli/internal/validator.js +276 -0
  71. package/scripts/cli/internal/wizard.js +115 -0
  72. package/scripts/cli/mappings.js +23 -0
  73. package/scripts/cli/migration-tools.js +164 -94
  74. package/scripts/cli/plugins/style-dictionary.js +46 -0
  75. package/scripts/cli/templates/README.md +525 -95
  76. package/scripts/cli/templates/common-templates.js +40 -14
  77. package/scripts/cli/templates/components/react-component.ts +282 -0
  78. package/scripts/cli/templates/config/project-config.ts +112 -0
  79. package/scripts/cli/templates/hooks/use-component.ts +477 -0
  80. package/scripts/cli/templates/index.js +19 -4
  81. package/scripts/cli/templates/index.ts +171 -0
  82. package/scripts/cli/templates/next-templates.js +72 -0
  83. package/scripts/cli/templates/react-templates.js +70 -126
  84. package/scripts/cli/templates/scss-templates.js +35 -35
  85. package/scripts/cli/templates/stories/storybook-story.ts +241 -0
  86. package/scripts/cli/templates/styles/scss-component.ts +255 -0
  87. package/scripts/cli/templates/tests/vitest-test.ts +229 -0
  88. package/scripts/cli/templates/token-templates.js +337 -1
  89. package/scripts/cli/templates/tokens/token-generators.ts +1088 -0
  90. package/scripts/cli/templates/types/component-types.ts +145 -0
  91. package/scripts/cli/templates/utils/testing-utils.ts +144 -0
  92. package/scripts/cli/templates/vanilla-templates.js +39 -0
  93. package/scripts/cli/token-manager.js +8 -2
  94. package/scripts/cli/utils/cache-manager.js +240 -0
  95. package/scripts/cli/utils/detector.js +46 -0
  96. package/scripts/cli/utils/diagnostics.js +289 -0
  97. package/scripts/cli/utils/error.js +89 -0
  98. package/scripts/cli/utils/helpers.js +67 -0
  99. package/scripts/cli/utils/logger.js +75 -0
  100. package/scripts/cli/utils/security.js +302 -0
  101. package/scripts/cli/utils/telemetry.js +115 -0
  102. package/scripts/cli/utils/validation.js +37 -0
  103. package/scripts/cli/utils.js +28 -341
  104. package/src/components/Accordion/Accordion.stories.tsx +0 -18
  105. package/src/components/Accordion/Accordion.test.tsx +0 -17
  106. package/src/components/Accordion/Accordion.tsx +0 -4
  107. package/src/components/AtomixGlass/AtomixGlass.test.tsx +37 -3
  108. package/src/components/AtomixGlass/AtomixGlass.tsx +143 -31
  109. package/src/components/AtomixGlass/AtomixGlassContainer.tsx +129 -31
  110. package/src/components/AtomixGlass/PerformanceDashboard.tsx +219 -0
  111. package/src/components/AtomixGlass/README.md +25 -10
  112. package/src/components/AtomixGlass/__snapshots__/AtomixGlass.test.tsx.snap +216 -0
  113. package/src/components/AtomixGlass/animation-system.ts +578 -0
  114. package/src/components/AtomixGlass/shader-utils.ts +4 -1
  115. package/src/components/AtomixGlass/stories/Overview.stories.tsx +157 -6
  116. package/src/components/AtomixGlass/stories/Phase1-Animation.stories.tsx +653 -0
  117. package/src/components/AtomixGlass/stories/Phase1-Test.stories.tsx +95 -0
  118. package/src/components/AtomixGlass/stories/Playground.stories.tsx +51 -51
  119. package/src/components/AtomixGlass/stories/shared-components.tsx +6 -0
  120. package/src/components/Avatar/Avatar.tsx +1 -1
  121. package/src/components/Button/Button.stories.disabled-link.tsx +10 -0
  122. package/src/components/Button/Button.stories.tsx +10 -0
  123. package/src/components/Button/Button.test.tsx +16 -11
  124. package/src/components/Button/Button.tsx +4 -4
  125. package/src/components/Card/Card.tsx +1 -1
  126. package/src/components/Dropdown/Dropdown.tsx +12 -12
  127. package/src/components/Form/Select.tsx +62 -3
  128. package/src/components/Modal/Modal.tsx +14 -3
  129. package/src/components/Navigation/Navbar/Navbar.tsx +44 -0
  130. package/src/components/Slider/Slider.stories.tsx +3 -3
  131. package/src/components/Slider/Slider.tsx +38 -0
  132. package/src/components/Steps/Steps.tsx +3 -3
  133. package/src/components/Tabs/Tabs.tsx +77 -8
  134. package/src/components/Testimonial/Testimonial.tsx +1 -1
  135. package/src/components/TypedButton/TypedButton.stories.tsx +59 -0
  136. package/src/components/TypedButton/TypedButton.tsx +39 -0
  137. package/src/components/TypedButton/index.ts +2 -0
  138. package/src/components/VideoPlayer/VideoPlayer.tsx +11 -4
  139. package/src/lib/composables/index.ts +4 -7
  140. package/src/lib/composables/types.ts +45 -0
  141. package/src/lib/composables/useAccordion.ts +0 -7
  142. package/src/lib/composables/useAtomixGlass.ts +148 -6
  143. package/src/lib/composables/useAtomixGlassStyles.ts +9 -7
  144. package/src/lib/composables/useChartExport.ts +3 -13
  145. package/src/lib/composables/useDropdown.ts +66 -0
  146. package/src/lib/composables/useFocusTrap.ts +80 -0
  147. package/src/lib/composables/usePerformanceMonitor.ts +448 -0
  148. package/src/lib/composables/useResponsiveGlass.presets.ts +192 -0
  149. package/src/lib/composables/useResponsiveGlass.ts +441 -0
  150. package/src/lib/composables/useTooltip.ts +16 -0
  151. package/src/lib/composables/useTypedButton.ts +66 -0
  152. package/src/lib/config/index.ts +62 -5
  153. package/src/lib/constants/components.ts +62 -7
  154. package/src/lib/theme/devtools/__tests__/useHistory.test.tsx +150 -0
  155. package/src/lib/theme/tokens/centralized-tokens.ts +120 -0
  156. package/src/lib/theme/utils/__tests__/domUtils.test.ts +101 -0
  157. package/src/lib/types/components.ts +37 -11
  158. package/src/lib/types/glass.ts +35 -0
  159. package/src/lib/types/index.ts +1 -0
  160. package/src/lib/utils/displacement-generator.ts +1 -1
  161. package/src/styles/01-settings/_settings.testtypecheck.scss +53 -0
  162. package/src/styles/01-settings/_settings.typedbutton.scss +53 -0
  163. package/src/styles/06-components/_components.atomix-glass.scss +17 -21
  164. package/src/styles/06-components/_components.edge-panel.scss +1 -5
  165. package/src/styles/06-components/_components.modal.scss +1 -4
  166. package/src/styles/06-components/_components.navbar.scss +1 -1
  167. package/src/styles/06-components/_components.testbutton.scss +212 -0
  168. package/src/styles/06-components/_components.testtypecheck.scss +212 -0
  169. package/src/styles/06-components/_components.tooltip.scss +9 -5
  170. package/src/styles/06-components/_components.typedbutton.scss +212 -0
  171. package/src/styles/99-utilities/_index.scss +1 -0
  172. package/src/styles/99-utilities/_utilities.text.scss +1 -1
  173. package/src/styles/99-utilities/_utilities.touch-target.scss +36 -0
  174. package/scripts/cli/component-generator.js +0 -564
  175. package/scripts/cli/interactive-init.js +0 -357
  176. package/src/styles/06-components/old.chart.styles.scss +0 -2788
@@ -0,0 +1,206 @@
1
+ /**
2
+ * Sync Tokens Command
3
+ * Synchronizes design tokens from external sources (Figma, Style Dictionary, etc.)
4
+ */
5
+
6
+ import { existsSync } from 'fs';
7
+ import { join } from 'path';
8
+ import { logger } from '../utils/logger.js';
9
+ import { AtomixCLIError } from '../utils/error.js';
10
+ import { tokenProvider, TOKEN_FORMATS } from '../internal/tokens/token-provider.js';
11
+ import { tokenValidator } from '../internal/tokens/token-validator.js';
12
+ import { filesystem } from '../internal/filesystem.js';
13
+
14
+ /**
15
+ * Token source configurations
16
+ */
17
+ const TOKEN_SOURCES = {
18
+ FIGMA: {
19
+ name: 'Figma',
20
+ format: TOKEN_FORMATS.FIGMA,
21
+ defaultPath: './design-tokens/figma-tokens.json'
22
+ },
23
+ STYLE_DICTIONARY: {
24
+ name: 'Style Dictionary',
25
+ format: TOKEN_FORMATS.STYLE_DICTIONARY,
26
+ defaultPath: './design-tokens/style-dictionary.json'
27
+ },
28
+ W3C_DTCG: {
29
+ name: 'W3C DTCG',
30
+ format: TOKEN_FORMATS.W3C_DTCG,
31
+ defaultPath: './design-tokens/tokens.json'
32
+ }
33
+ };
34
+
35
+ /**
36
+ * Action logic for syncing tokens
37
+ * @param {string} source - Token source (figma, style-dictionary, w3c)
38
+ * @param {Object} options - CLI options
39
+ */
40
+ export async function syncTokensAction(source, options) {
41
+ const spinner = logger.spinner(`Syncing tokens from ${source}...`).start();
42
+
43
+ try {
44
+ // Determine source configuration
45
+ const sourceConfig = TOKEN_SOURCES[source.toUpperCase()];
46
+ if (!sourceConfig) {
47
+ throw new AtomixCLIError(
48
+ `Unknown token source: ${source}`,
49
+ 'UNKNOWN_SOURCE',
50
+ [
51
+ 'Available sources: figma, style-dictionary, w3c',
52
+ 'Use `atomix sync-tokens --help` for usage information'
53
+ ]
54
+ );
55
+ }
56
+
57
+ // Determine file path
58
+ const filePath = options.file || sourceConfig.defaultPath;
59
+ const absolutePath = join(process.cwd(), filePath);
60
+
61
+ if (!existsSync(absolutePath)) {
62
+ throw new AtomixCLIError(
63
+ `Token file not found: ${absolutePath}`,
64
+ 'TOKEN_FILE_NOT_FOUND',
65
+ [
66
+ 'Verify the file path is correct',
67
+ 'Export tokens from your design tool first',
68
+ 'Use --file flag to specify custom path'
69
+ ]
70
+ );
71
+ }
72
+
73
+ // Load tokens using provider
74
+ logger.debug(`Loading tokens from ${filePath}`);
75
+ const loadedTokens = await tokenProvider.loadTokens(filePath, {
76
+ format: sourceConfig.format
77
+ });
78
+
79
+ // Validate tokens
80
+ logger.debug('Validating tokens');
81
+ const validationResults = tokenValidator.validate(loadedTokens);
82
+
83
+ if (!validationResults.valid) {
84
+ spinner.warn('Token sync completed with validation issues');
85
+ logger.info(tokenValidator.getReport(validationResults));
86
+
87
+ if (!options.force && validationResults.summary.errors > 0) {
88
+ throw new AtomixCLIError(
89
+ 'Token validation failed with errors',
90
+ 'VALIDATION_FAILED',
91
+ [
92
+ 'Fix the validation errors listed above',
93
+ 'Use --force flag to sync anyway (not recommended)'
94
+ ]
95
+ );
96
+ }
97
+ } else {
98
+ spinner.succeed(`Successfully synced ${countTokens(loadedTokens)} tokens from ${sourceConfig.name}`);
99
+ }
100
+
101
+ // Export tokens to desired formats
102
+ if (options.output) {
103
+ await exportTokens(options.output, loadedTokens);
104
+ }
105
+
106
+ // Show summary
107
+ showSyncSummary(loadedTokens, validationResults, sourceConfig);
108
+
109
+ } catch (error) {
110
+ spinner.fail('Token sync failed');
111
+
112
+ if (error instanceof AtomixCLIError) {
113
+ throw error;
114
+ }
115
+
116
+ throw new AtomixCLIError(
117
+ `Failed to sync tokens: ${error.message}`,
118
+ 'SYNC_FAILED',
119
+ [
120
+ 'Check that the token file is valid JSON',
121
+ 'Ensure you have read permissions for the file',
122
+ 'Try validating the file manually'
123
+ ]
124
+ );
125
+ }
126
+ }
127
+
128
+ /**
129
+ * Export tokens to multiple formats
130
+ * @private
131
+ */
132
+ async function exportTokens(outputDir, tokens) {
133
+ const exports = [];
134
+
135
+ // Export to JSON
136
+ const jsonPath = join(outputDir, 'tokens.json');
137
+ const jsonContent = tokenProvider.exportTokens(TOKEN_FORMATS.JSON, { pretty: true });
138
+ await filesystem.writeFile(jsonPath, jsonContent, 'utf8');
139
+ exports.push(jsonPath);
140
+
141
+ // Export to CSS
142
+ const cssPath = join(outputDir, 'tokens.css');
143
+ const cssContent = tokenProvider.exportTokens(TOKEN_FORMATS.CSS, { selector: ':root' });
144
+ await filesystem.writeFile(cssPath, cssContent, 'utf8');
145
+ exports.push(cssPath);
146
+
147
+ logger.debug(`Exported tokens to: ${exports.join(', ')}`);
148
+ }
149
+
150
+ /**
151
+ * Count total tokens across all categories
152
+ * @private
153
+ */
154
+ function countTokens(tokens) {
155
+ let count = 0;
156
+ for (const category of Object.values(tokens)) {
157
+ count += Object.keys(category).length;
158
+ }
159
+ return count;
160
+ }
161
+
162
+ /**
163
+ * Display sync summary
164
+ * @private
165
+ */
166
+ function showSyncSummary(tokens, validation, source) {
167
+ const totalTokens = countTokens(tokens);
168
+ const categories = Object.keys(tokens);
169
+
170
+ const summary = `
171
+ ✅ Token Sync Complete
172
+
173
+ Source: ${source.name}
174
+ Total Tokens: ${totalTokens}
175
+ Categories: ${categories.join(', ')}
176
+
177
+ Validation:
178
+ Errors: ${validation.summary.errors}
179
+ Warnings: ${validation.summary.warnings}
180
+ Info: ${validation.summary.info}
181
+
182
+ Next Steps:
183
+ • Review validation warnings with \`atomix validate tokens\`
184
+ • Export tokens with \`atomix build-theme\`
185
+ • Use tokens in components with \`atomix generate component\`
186
+ `.trim();
187
+
188
+ logger.box(summary);
189
+ }
190
+
191
+ /**
192
+ * Interactive mode for token sync
193
+ * @private
194
+ */
195
+ export async function interactiveSync() {
196
+ logger.info('🔄 Interactive Token Sync\n');
197
+
198
+ // In a full implementation, this would use inquirer to prompt for:
199
+ // 1. Source selection (Figma, Style Dictionary, etc.)
200
+ // 2. File path
201
+ // 3. Export options
202
+ // 4. Validation preferences
203
+
204
+ logger.info('Interactive mode coming soon!');
205
+ logger.info('For now, use: atomix sync-tokens <source> --file <path>\n');
206
+ }
@@ -0,0 +1,248 @@
1
+ /**
2
+ * Atomix CLI Theme Bridge Command
3
+ * Syncs design tokens with theme providers (Tailwind, CSS-in-JS, CSS Variables)
4
+ */
5
+
6
+ import { join } from 'path';
7
+ import chalk from 'chalk';
8
+ import { Command } from 'commander';
9
+ import {
10
+ createThemePackage,
11
+ syncToTailwind,
12
+ syncToCssInJs,
13
+ syncToCssVariables,
14
+ validateThemeSync,
15
+ THEME_PROVIDERS
16
+ } from '../internal/theme-bridge.js';
17
+ import { filesystem } from '../internal/filesystem.js';
18
+ import { AtomixCLIError } from '../utils/error.js';
19
+ import { detectFramework } from '../utils/detector.js';
20
+
21
+ export const SYNC_PROVIDERS = {
22
+ TAILWIND: 'tailwind',
23
+ EMOTION: 'emotion',
24
+ STYLED_COMPONENTS: 'styled-components',
25
+ VANILLA_EXTRACT: 'vanilla-extract',
26
+ CSS_VARIABLES: 'css-variables'
27
+ };
28
+
29
+ /**
30
+ * Execute theme bridge synchronization (exported for CLI integration)
31
+ * @param {string} source - Source tokens file path
32
+ * @param {Object} options - Command options
33
+ */
34
+ export async function themeBridgeAction(source = './design-tokens/tokens.json', options = {}) {
35
+ await executeThemeBridge(source, options);
36
+ }
37
+
38
+ /**
39
+ * Creates the theme-bridge command
40
+ * @param {Command} program - Commander program instance
41
+ */
42
+ export function createThemeBridgeCommand(program) {
43
+ const cmd = program
44
+ .command('theme-bridge')
45
+ .description('Sync design tokens with theme providers')
46
+ .argument('[source]', 'Path to design tokens file', './design-tokens/tokens.json')
47
+ .option('-o, --output <dir>', 'Output directory for theme files', './src/theme')
48
+ .option('-f, --format <format>', 'Theme format (tailwind, emotion, styled-components, vanilla-extract, css-variables, all)', 'all')
49
+ .option('--prefix <prefix>', 'CSS variable prefix', 'atomix')
50
+ .option('--selector <selector>', 'CSS selector for variables', ':root')
51
+ .option('--no-typescript', 'Skip TypeScript type generation')
52
+ .option('--validate', 'Validate generated theme files')
53
+ .option('--dry-run', 'Show what would be generated without writing files')
54
+ .action(async (source, options) => {
55
+ try {
56
+ await executeThemeBridge(source, options);
57
+ } catch (error) {
58
+ if (error instanceof AtomixCLIError) {
59
+ console.error(chalk.red('\nTheme bridge failed:'));
60
+ console.error(chalk.yellow(error.message));
61
+ if (error.suggestions?.length) {
62
+ console.error(chalk.dim('\nSuggestions:'));
63
+ error.suggestions.forEach(s => console.error(` - ${s}`));
64
+ }
65
+ process.exit(1);
66
+ }
67
+ throw error;
68
+ }
69
+ });
70
+
71
+ return cmd;
72
+ }
73
+
74
+ /**
75
+ * Execute theme bridge synchronization
76
+ * @param {string} source - Source tokens file path
77
+ * @param {Object} options - Command options
78
+ */
79
+ async function executeThemeBridge(source, options) {
80
+ const { output, format, prefix, selector, typescript, validate, dryRun } = options;
81
+
82
+ // Set dry run mode
83
+ if (dryRun) {
84
+ process.env.ATOMIX_DRY_RUN = 'true';
85
+ }
86
+
87
+ console.log(chalk.cyan('\n🎨 Atomix Theme Bridge\n'));
88
+
89
+ // Resolve paths
90
+ const tokenPath = join(process.cwd(), source);
91
+ const outputDir = join(process.cwd(), output);
92
+
93
+ // Check if source file exists
94
+ const exists = await filesystem.exists(tokenPath);
95
+ if (!exists) {
96
+ throw new AtomixCLIError(
97
+ `Design tokens file not found: ${tokenPath}`,
98
+ 'TOKEN_FILE_NOT_FOUND',
99
+ [
100
+ 'Run `atomix init` to create design tokens',
101
+ 'Check the source path is correct',
102
+ 'Ensure tokens file has been created'
103
+ ]
104
+ );
105
+ }
106
+
107
+ console.log(chalk.bold('Source:'), tokenPath);
108
+ console.log(chalk.bold('Output:'), outputDir);
109
+ console.log(chalk.bold('Format:'), format);
110
+ console.log();
111
+
112
+ // Generate theme package or single format
113
+ let result;
114
+
115
+ if (format === 'all' || !format) {
116
+ result = await createThemePackage(tokenPath, outputDir, {
117
+ prefix,
118
+ selector,
119
+ typescript: typescript !== false
120
+ });
121
+ } else if (format === 'tailwind') {
122
+ const outputPath = join(outputDir, 'tailwind.theme.js');
123
+ result = await syncToTailwind(tokenPath, outputPath);
124
+ } else if (['emotion', 'styled-components'].includes(format)) {
125
+ const outputPath = join(outputDir, 'theme.ts');
126
+ result = await syncToCssInJs(tokenPath, outputPath, format);
127
+ } else if (format === 'vanilla-extract') {
128
+ const outputPath = join(outputDir, 'theme.ts');
129
+ result = await syncToCssInJs(tokenPath, outputPath, 'vanilla-extract');
130
+ } else if (format === 'css-variables') {
131
+ const outputPath = join(outputDir, 'variables.css');
132
+ result = await syncToCssVariables(tokenPath, outputPath, { prefix, selector });
133
+ } else {
134
+ throw new AtomixCLIError(
135
+ `Unknown format: ${format}`,
136
+ 'UNKNOWN_FORMAT',
137
+ ['Use: tailwind, emotion, styled-components, vanilla-extract, css-variables, or all']
138
+ );
139
+ }
140
+
141
+ // Display results
142
+ if (dryRun) {
143
+ console.log(chalk.yellow('\n[DRY RUN] Files that would be created:'));
144
+ result.created.forEach(file => console.log(` ${file}`));
145
+ } else {
146
+ console.log(chalk.green('\n✓ Theme synchronization complete!\n'));
147
+ console.log(chalk.bold('Created files:'));
148
+ result.created.forEach(file => console.log(` ${chalk.cyan(file)}`));
149
+
150
+ if (result.formats) {
151
+ console.log(chalk.bold('\nFormats generated:'));
152
+ result.formats.forEach(f => console.log(` ${chalk.cyan(f)}`));
153
+ }
154
+
155
+ console.log(chalk.bold('\nTokens synced:'), result.tokensSynced);
156
+ }
157
+
158
+ // Validate if requested
159
+ if (validate && !dryRun) {
160
+ console.log(chalk.cyan('\n🔍 Validating theme files...\n'));
161
+
162
+ for (const file of result.created) {
163
+ const provider = detectProviderFromFile(file);
164
+ const validation = await validateThemeSync(tokenPath, file, provider);
165
+
166
+ if (validation.valid) {
167
+ console.log(chalk.green(` ✓ ${file}`));
168
+ } else {
169
+ console.log(chalk.yellow(` ⚠ ${file}`));
170
+ validation.issues.forEach(issue => {
171
+ const icon = issue.severity === 'error' ? '✗' : '⚠';
172
+ console.log(chalk.dim(` ${icon} ${issue.message}`));
173
+ });
174
+ }
175
+ }
176
+
177
+ console.log();
178
+ }
179
+
180
+ // Show usage instructions
181
+ showUsageInstructions(format, outputDir);
182
+ }
183
+
184
+ /**
185
+ * Detect theme provider from file path/extension
186
+ * @param {string} filePath - Path to theme file
187
+ * @returns {string} Provider type
188
+ */
189
+ function detectProviderFromFile(filePath) {
190
+ if (filePath.includes('tailwind')) return 'tailwind';
191
+ if (filePath.endsWith('.css')) return 'css-variables';
192
+ if (filePath.includes('vanilla-extract')) return 'vanilla-extract';
193
+ if (filePath.includes('emotion')) return 'emotion';
194
+ if (filePath.includes('styled-components')) return 'styled-components';
195
+ return 'css-in-js';
196
+ }
197
+
198
+ /**
199
+ * Show usage instructions for different theme providers
200
+ * @param {string} format - Generated format
201
+ * @param {string} outputDir - Output directory
202
+ */
203
+ function showUsageInstructions(format, outputDir) {
204
+ console.log(chalk.bold('\n📚 Usage Instructions:\n'));
205
+
206
+ if (format === 'all' || format === 'tailwind') {
207
+ console.log(chalk.cyan('Tailwind CSS:'));
208
+ console.log(chalk.dim(' // tailwind.config.js'));
209
+ console.log(chalk.dim(' module.exports = {'));
210
+ console.log(chalk.dim(' presets: [require(\'./src/theme/tailwind.theme\')],'));
211
+ console.log(chalk.dim(' };'));
212
+ console.log();
213
+ }
214
+
215
+ if (format === 'all' || format === 'emotion') {
216
+ console.log(chalk.cyan('Emotion:'));
217
+ console.log(chalk.dim(' import { ThemeProvider } from \'@emotion/react\';'));
218
+ console.log(chalk.dim(' import { theme } from \'./src/theme/theme\';'));
219
+ console.log(chalk.dim(' '));
220
+ console.log(chalk.dim(' function App() {'));
221
+ console.log(chalk.dim(' return <ThemeProvider theme={theme}>...</ThemeProvider>;'));
222
+ console.log(chalk.dim(' }'));
223
+ console.log();
224
+ }
225
+
226
+ if (format === 'all' || format === 'css-variables') {
227
+ console.log(chalk.cyan('CSS Variables:'));
228
+ console.log(chalk.dim(' // Import in your main CSS file'));
229
+ console.log(chalk.dim(' @import \'./src/theme/variables.css\';'));
230
+ console.log(chalk.dim(' '));
231
+ console.log(chalk.dim(' // Use in components'));
232
+ console.log(chalk.dim(' color: var(--atomix-primary);'));
233
+ console.log(chalk.dim(' padding: var(--atomix-space-md);'));
234
+ console.log();
235
+ }
236
+
237
+ if (format === 'all' || format === 'vanilla-extract') {
238
+ console.log(chalk.cyan('Vanilla Extract:'));
239
+ console.log(chalk.dim(' import { style } from \'@vanilla-extract/css\';'));
240
+ console.log(chalk.dim(' import { theme } from \'./src/theme/theme.css\';'));
241
+ console.log(chalk.dim(' '));
242
+ console.log(chalk.dim(' const myStyle = style({'));
243
+ console.log(chalk.dim(' color: theme.colors.primary,'));
244
+ console.log(chalk.dim(' padding: theme.space.md'));
245
+ console.log(chalk.dim(' });'));
246
+ console.log();
247
+ }
248
+ }
@@ -0,0 +1,157 @@
1
+ /**
2
+ * Atomix CLI Tokens Command
3
+ * Design token management and export
4
+ */
5
+
6
+ import inquirer from 'inquirer';
7
+ import { logger } from '../utils/logger.js';
8
+ import { listTokens, exportTokens } from '../token-manager.js';
9
+ import { tokenEngine } from '../internal/tokens/engine.js';
10
+ import { isNonInteractive } from '../utils/helpers.js';
11
+ import { AtomixCLIError, ErrorCategory } from '../utils/error.js';
12
+ import chalk from 'chalk';
13
+
14
+ const SUPPORTED_PROVIDER_TYPES = 'figma, style-dictionary, w3c';
15
+
16
+ /**
17
+ * Get provider for pull/push: from options, or prompt in interactive mode, or throw
18
+ * @param {object} options - Command options
19
+ * @param {string} subcommand - 'pull' | 'push'
20
+ * @returns {Promise<string>} - Provider name
21
+ */
22
+ async function resolveProvider(options, subcommand) {
23
+ if (options.provider) return options.provider;
24
+
25
+ const names = tokenEngine.getProviderNames();
26
+ const message = names.length === 0
27
+ ? `No token providers configured. Add tokenEngine.providers in atomix.config. Supported types: ${SUPPORTED_PROVIDER_TYPES}.`
28
+ : `Missing required option: --provider. Supported (from config): ${names.join(', ')}. Use --provider <name>.`;
29
+
30
+ if (isNonInteractive() || !process.stdin.isTTY) {
31
+ throw new AtomixCLIError(message, ErrorCategory.CONFIG, [
32
+ 'Set --provider <name> or configure tokenEngine.providers in atomix.config.'
33
+ ]);
34
+ }
35
+
36
+ if (names.length === 0) {
37
+ throw new AtomixCLIError(message, ErrorCategory.CONFIG, [
38
+ 'Add tokenEngine.providers in atomix.config. Supported types: figma, style-dictionary, w3c.'
39
+ ]);
40
+ }
41
+
42
+ const { provider } = await inquirer.prompt([
43
+ {
44
+ type: 'list',
45
+ name: 'provider',
46
+ message: `Select provider for ${subcommand}:`,
47
+ choices: names
48
+ }
49
+ ]);
50
+ return provider;
51
+ }
52
+
53
+ /**
54
+ * Action for the `atomix tokens` command
55
+ * @param {string} subcommand - list | export | pull | push
56
+ * @param {object} options - Command options
57
+ */
58
+ export async function tokensAction(subcommand, options = {}) {
59
+ // Initialize token engine
60
+ await tokenEngine.initialize();
61
+
62
+ switch (subcommand) {
63
+ case 'list':
64
+ await listTokensAction(options);
65
+ break;
66
+ case 'export':
67
+ await exportTokensAction(options);
68
+ break;
69
+ case 'pull': {
70
+ const provider = await resolveProvider(options, 'pull');
71
+ if (!provider) break;
72
+ await pullTokensAction(provider, options);
73
+ break;
74
+ }
75
+ case 'push': {
76
+ const provider = await resolveProvider(options, 'push');
77
+ if (!provider) break;
78
+ await pushTokensAction(provider, options);
79
+ break;
80
+ }
81
+ default:
82
+ throw new AtomixCLIError(
83
+ `Unknown subcommand: ${subcommand}. Available: list, export, pull, push`,
84
+ ErrorCategory.VALIDATION,
85
+ ['Use one of: atomix tokens list | export | pull | push']
86
+ );
87
+ }
88
+ }
89
+
90
+ /**
91
+ * Pull tokens from a provider
92
+ */
93
+ async function pullTokensAction(provider, options) {
94
+ try {
95
+ const tokens = await tokenEngine.pull(provider);
96
+ logger.box(`Tokens pulled successfully from ${provider}!\nSource: ${tokens.source}\nTokens: ${Object.keys(tokens.tokens).join(', ')}`);
97
+ } catch (error) {
98
+ throw new AtomixCLIError(
99
+ error.message || `Token pull failed`,
100
+ ErrorCategory.CONFIG,
101
+ ['Check tokenEngine.providers in atomix.config and network access.']
102
+ );
103
+ }
104
+ }
105
+
106
+ /**
107
+ * Push tokens to a provider
108
+ */
109
+ async function pushTokensAction(provider, options) {
110
+ try {
111
+ const localTokens = {};
112
+ const success = await tokenEngine.push(provider, localTokens);
113
+ if (success) {
114
+ logger.succeed(`Tokens pushed successfully to ${provider}`);
115
+ } else {
116
+ throw new AtomixCLIError(
117
+ 'Token push failed',
118
+ ErrorCategory.CONFIG,
119
+ ['Check provider configuration and credentials.']
120
+ );
121
+ }
122
+ } catch (error) {
123
+ if (error instanceof AtomixCLIError) throw error;
124
+ throw new AtomixCLIError(
125
+ error.message || 'Token push failed',
126
+ ErrorCategory.CONFIG,
127
+ ['Check tokenEngine.providers in atomix.config.']
128
+ );
129
+ }
130
+ }
131
+
132
+ /**
133
+ * List all tokens
134
+ */
135
+ async function listTokensAction(options) {
136
+ try {
137
+ // listTokens already logs everything
138
+ await listTokens();
139
+ } catch (error) {
140
+ logger.error(`Failed to list tokens: ${error.message}`);
141
+ }
142
+ }
143
+
144
+ /**
145
+ * Export tokens
146
+ */
147
+ async function exportTokensAction(options) {
148
+ const format = options.format || 'css';
149
+ const outputPath = options.output || './tokens';
150
+
151
+ try {
152
+ // exportTokens already logs everything
153
+ await exportTokens(format, outputPath);
154
+ } catch (error) {
155
+ logger.error(`Token export failed: ${error.message}`);
156
+ }
157
+ }