@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.
- package/atomix.config.ts +58 -1
- package/dist/atomix.css +172 -157
- package/dist/atomix.css.map +1 -1
- package/dist/atomix.min.css +4 -4
- package/dist/atomix.min.css.map +1 -1
- package/dist/charts.d.ts +33 -0
- package/dist/charts.js +1274 -164
- package/dist/charts.js.map +1 -1
- package/dist/core.d.ts +33 -10
- package/dist/core.js +1099 -83
- package/dist/core.js.map +1 -1
- package/dist/forms.d.ts +33 -0
- package/dist/forms.js +2106 -1050
- package/dist/forms.js.map +1 -1
- package/dist/heavy.d.ts +42 -1
- package/dist/heavy.js +1663 -638
- package/dist/heavy.js.map +1 -1
- package/dist/index.d.ts +442 -270
- package/dist/index.esm.js +1947 -680
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +1982 -712
- package/dist/index.js.map +1 -1
- package/dist/index.min.js +1 -1
- package/dist/index.min.js.map +1 -1
- package/package.json +6 -3
- package/scripts/atomix-cli.js +136 -1827
- package/scripts/cli/__tests__/basic.test.js +3 -2
- package/scripts/cli/__tests__/clean.test.js +278 -0
- package/scripts/cli/__tests__/component-validator.test.js +433 -0
- package/scripts/cli/__tests__/generator.test.js +613 -0
- package/scripts/cli/__tests__/glass-motion.test.js +256 -0
- package/scripts/cli/__tests__/integration.test.js +719 -108
- package/scripts/cli/__tests__/migrate.test.js +74 -0
- package/scripts/cli/__tests__/security.test.js +206 -0
- package/scripts/cli/__tests__/test-setup.js +3 -1
- package/scripts/cli/__tests__/theme-bridge.test.js +507 -0
- package/scripts/cli/__tests__/token-provider.test.js +361 -0
- package/scripts/cli/__tests__/utils.test.js +5 -5
- package/scripts/cli/commands/benchmark.js +105 -0
- package/scripts/cli/commands/build-theme.js +115 -0
- package/scripts/cli/commands/clean.js +109 -0
- package/scripts/cli/commands/doctor.js +88 -0
- package/scripts/cli/commands/generate.js +218 -0
- package/scripts/cli/commands/init.js +73 -0
- package/scripts/cli/commands/migrate.js +106 -0
- package/scripts/cli/commands/sync-tokens.js +206 -0
- package/scripts/cli/commands/theme-bridge.js +248 -0
- package/scripts/cli/commands/tokens.js +157 -0
- package/scripts/cli/commands/validate.js +194 -0
- package/scripts/cli/internal/ai-engine.js +156 -0
- package/scripts/cli/internal/compiler.js +114 -0
- package/scripts/cli/internal/component-validator.js +443 -0
- package/scripts/cli/internal/config-loader.js +162 -0
- package/scripts/cli/internal/filesystem.js +158 -0
- package/scripts/cli/internal/generator.js +430 -0
- package/scripts/cli/internal/glass-generator.js +398 -0
- package/scripts/cli/internal/hook-generator.js +369 -0
- package/scripts/cli/internal/hooks.js +61 -0
- package/scripts/cli/internal/itcss-generator.js +565 -0
- package/scripts/cli/internal/motion-generator.js +679 -0
- package/scripts/cli/internal/template-engine.js +301 -0
- package/scripts/cli/internal/theme-bridge.js +664 -0
- package/scripts/cli/internal/tokens/engine.js +122 -0
- package/scripts/cli/internal/tokens/provider.js +34 -0
- package/scripts/cli/internal/tokens/providers/figma.js +50 -0
- package/scripts/cli/internal/tokens/providers/style-dictionary.js +48 -0
- package/scripts/cli/internal/tokens/providers/w3c.js +48 -0
- package/scripts/cli/internal/tokens/token-provider.js +443 -0
- package/scripts/cli/internal/tokens/token-validator.js +513 -0
- package/scripts/cli/internal/validator.js +276 -0
- package/scripts/cli/internal/wizard.js +115 -0
- package/scripts/cli/mappings.js +23 -0
- package/scripts/cli/migration-tools.js +164 -94
- package/scripts/cli/plugins/style-dictionary.js +46 -0
- package/scripts/cli/templates/README.md +525 -95
- package/scripts/cli/templates/common-templates.js +40 -14
- package/scripts/cli/templates/components/react-component.ts +282 -0
- package/scripts/cli/templates/config/project-config.ts +112 -0
- package/scripts/cli/templates/hooks/use-component.ts +477 -0
- package/scripts/cli/templates/index.js +19 -4
- package/scripts/cli/templates/index.ts +171 -0
- package/scripts/cli/templates/next-templates.js +72 -0
- package/scripts/cli/templates/react-templates.js +70 -126
- package/scripts/cli/templates/scss-templates.js +35 -35
- package/scripts/cli/templates/stories/storybook-story.ts +241 -0
- package/scripts/cli/templates/styles/scss-component.ts +255 -0
- package/scripts/cli/templates/tests/vitest-test.ts +229 -0
- package/scripts/cli/templates/token-templates.js +337 -1
- package/scripts/cli/templates/tokens/token-generators.ts +1088 -0
- package/scripts/cli/templates/types/component-types.ts +145 -0
- package/scripts/cli/templates/utils/testing-utils.ts +144 -0
- package/scripts/cli/templates/vanilla-templates.js +39 -0
- package/scripts/cli/token-manager.js +8 -2
- package/scripts/cli/utils/cache-manager.js +240 -0
- package/scripts/cli/utils/detector.js +46 -0
- package/scripts/cli/utils/diagnostics.js +289 -0
- package/scripts/cli/utils/error.js +89 -0
- package/scripts/cli/utils/helpers.js +67 -0
- package/scripts/cli/utils/logger.js +75 -0
- package/scripts/cli/utils/security.js +302 -0
- package/scripts/cli/utils/telemetry.js +115 -0
- package/scripts/cli/utils/validation.js +37 -0
- package/scripts/cli/utils.js +28 -341
- package/src/components/Accordion/Accordion.stories.tsx +0 -18
- package/src/components/Accordion/Accordion.test.tsx +0 -17
- package/src/components/Accordion/Accordion.tsx +0 -4
- package/src/components/AtomixGlass/AtomixGlass.test.tsx +37 -3
- package/src/components/AtomixGlass/AtomixGlass.tsx +143 -31
- package/src/components/AtomixGlass/AtomixGlassContainer.tsx +129 -31
- package/src/components/AtomixGlass/PerformanceDashboard.tsx +219 -0
- package/src/components/AtomixGlass/README.md +25 -10
- package/src/components/AtomixGlass/__snapshots__/AtomixGlass.test.tsx.snap +216 -0
- package/src/components/AtomixGlass/animation-system.ts +578 -0
- package/src/components/AtomixGlass/shader-utils.ts +4 -1
- package/src/components/AtomixGlass/stories/Overview.stories.tsx +157 -6
- package/src/components/AtomixGlass/stories/Phase1-Animation.stories.tsx +653 -0
- package/src/components/AtomixGlass/stories/Phase1-Test.stories.tsx +95 -0
- package/src/components/AtomixGlass/stories/Playground.stories.tsx +51 -51
- package/src/components/AtomixGlass/stories/shared-components.tsx +6 -0
- package/src/components/Avatar/Avatar.tsx +1 -1
- package/src/components/Button/Button.stories.disabled-link.tsx +10 -0
- package/src/components/Button/Button.stories.tsx +10 -0
- package/src/components/Button/Button.test.tsx +16 -11
- package/src/components/Button/Button.tsx +4 -4
- package/src/components/Card/Card.tsx +1 -1
- package/src/components/Dropdown/Dropdown.tsx +12 -12
- package/src/components/Form/Select.tsx +62 -3
- package/src/components/Modal/Modal.tsx +14 -3
- package/src/components/Navigation/Navbar/Navbar.tsx +44 -0
- package/src/components/Slider/Slider.stories.tsx +3 -3
- package/src/components/Slider/Slider.tsx +38 -0
- package/src/components/Steps/Steps.tsx +3 -3
- package/src/components/Tabs/Tabs.tsx +77 -8
- package/src/components/Testimonial/Testimonial.tsx +1 -1
- package/src/components/TypedButton/TypedButton.stories.tsx +59 -0
- package/src/components/TypedButton/TypedButton.tsx +39 -0
- package/src/components/TypedButton/index.ts +2 -0
- package/src/components/VideoPlayer/VideoPlayer.tsx +11 -4
- package/src/lib/composables/index.ts +4 -7
- package/src/lib/composables/types.ts +45 -0
- package/src/lib/composables/useAccordion.ts +0 -7
- package/src/lib/composables/useAtomixGlass.ts +148 -6
- package/src/lib/composables/useAtomixGlassStyles.ts +9 -7
- package/src/lib/composables/useChartExport.ts +3 -13
- package/src/lib/composables/useDropdown.ts +66 -0
- package/src/lib/composables/useFocusTrap.ts +80 -0
- package/src/lib/composables/usePerformanceMonitor.ts +448 -0
- package/src/lib/composables/useResponsiveGlass.presets.ts +192 -0
- package/src/lib/composables/useResponsiveGlass.ts +441 -0
- package/src/lib/composables/useTooltip.ts +16 -0
- package/src/lib/composables/useTypedButton.ts +66 -0
- package/src/lib/config/index.ts +62 -5
- package/src/lib/constants/components.ts +62 -7
- package/src/lib/theme/devtools/__tests__/useHistory.test.tsx +150 -0
- package/src/lib/theme/tokens/centralized-tokens.ts +120 -0
- package/src/lib/theme/utils/__tests__/domUtils.test.ts +101 -0
- package/src/lib/types/components.ts +37 -11
- package/src/lib/types/glass.ts +35 -0
- package/src/lib/types/index.ts +1 -0
- package/src/lib/utils/displacement-generator.ts +1 -1
- package/src/styles/01-settings/_settings.testtypecheck.scss +53 -0
- package/src/styles/01-settings/_settings.typedbutton.scss +53 -0
- package/src/styles/06-components/_components.atomix-glass.scss +17 -21
- package/src/styles/06-components/_components.edge-panel.scss +1 -5
- package/src/styles/06-components/_components.modal.scss +1 -4
- package/src/styles/06-components/_components.navbar.scss +1 -1
- package/src/styles/06-components/_components.testbutton.scss +212 -0
- package/src/styles/06-components/_components.testtypecheck.scss +212 -0
- package/src/styles/06-components/_components.tooltip.scss +9 -5
- package/src/styles/06-components/_components.typedbutton.scss +212 -0
- package/src/styles/99-utilities/_index.scss +1 -0
- package/src/styles/99-utilities/_utilities.text.scss +1 -1
- package/src/styles/99-utilities/_utilities.touch-target.scss +36 -0
- package/scripts/cli/component-generator.js +0 -564
- package/scripts/cli/interactive-init.js +0 -357
- package/src/styles/06-components/old.chart.styles.scss +0 -2788
|
@@ -0,0 +1,664 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Atomix CLI Theme Bridge Generator
|
|
3
|
+
* Automatically syncs design tokens with theme providers (Tailwind, CSS-in-JS, etc.)
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { writeFile, mkdir } from 'fs/promises';
|
|
7
|
+
import { dirname, join } from 'path';
|
|
8
|
+
import { filesystem } from './filesystem.js';
|
|
9
|
+
import { tokenProvider } from './tokens/token-provider.js';
|
|
10
|
+
import { AtomixCLIError } from '../utils/error.js';
|
|
11
|
+
import chalk from 'chalk';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Theme provider types supported by Atomix
|
|
15
|
+
*/
|
|
16
|
+
export const THEME_PROVIDERS = {
|
|
17
|
+
TAILWIND: 'tailwind',
|
|
18
|
+
CSS_IN_JS: 'css-in-js',
|
|
19
|
+
EMOTION: 'emotion',
|
|
20
|
+
STYLED_COMPONENTS: 'styled-components',
|
|
21
|
+
VANILLA_EXTRACT: 'vanilla-extract',
|
|
22
|
+
CSS_VARIABLES: 'css-variables'
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Generates Tailwind theme configuration from design tokens
|
|
27
|
+
* @param {Object} tokens - Design tokens object
|
|
28
|
+
* @returns {string} Tailwind theme configuration
|
|
29
|
+
*/
|
|
30
|
+
export function generateTailwindTheme(tokens) {
|
|
31
|
+
const themeConfig = [];
|
|
32
|
+
|
|
33
|
+
// Colors
|
|
34
|
+
if (tokens.colors) {
|
|
35
|
+
themeConfig.push(' colors: {');
|
|
36
|
+
Object.entries(tokens.colors).forEach(([key, value]) => {
|
|
37
|
+
if (typeof value === 'object') {
|
|
38
|
+
// Handle nested color objects by expanding them
|
|
39
|
+
themeConfig.push(` ${key}: {`);
|
|
40
|
+
Object.entries(value).forEach(([variant, variantValue]) => {
|
|
41
|
+
themeConfig.push(` ${variant}: '${variantValue}',`);
|
|
42
|
+
});
|
|
43
|
+
themeConfig.push(' },');
|
|
44
|
+
} else {
|
|
45
|
+
themeConfig.push(` ${key}: '${value}',`);
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
themeConfig.push(' },');
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Spacing
|
|
52
|
+
if (tokens.spacing) {
|
|
53
|
+
themeConfig.push(' spacing: {');
|
|
54
|
+
Object.entries(tokens.spacing).forEach(([key, value]) => {
|
|
55
|
+
themeConfig.push(` ${key}: '${value}',`);
|
|
56
|
+
});
|
|
57
|
+
themeConfig.push(' },');
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Typography
|
|
61
|
+
if (tokens.typography) {
|
|
62
|
+
if (tokens.typography.fontSize) {
|
|
63
|
+
themeConfig.push(' fontSize: {');
|
|
64
|
+
Object.entries(tokens.typography.fontSize).forEach(([key, value]) => {
|
|
65
|
+
const size = typeof value === 'object' ? value.size : value;
|
|
66
|
+
themeConfig.push(` ${key}: '${size}',`);
|
|
67
|
+
});
|
|
68
|
+
themeConfig.push(' },');
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (tokens.typography.fontFamily) {
|
|
72
|
+
themeConfig.push(' fontFamily: {');
|
|
73
|
+
Object.entries(tokens.typography.fontFamily).forEach(([key, value]) => {
|
|
74
|
+
themeConfig.push(` ${key}: [${JSON.stringify(value)}],`);
|
|
75
|
+
});
|
|
76
|
+
themeConfig.push(' },');
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Breakpoints
|
|
81
|
+
if (tokens.breakpoints) {
|
|
82
|
+
themeConfig.push(' screens: {');
|
|
83
|
+
Object.entries(tokens.breakpoints).forEach(([key, value]) => {
|
|
84
|
+
themeConfig.push(` ${key}: '${value}',`);
|
|
85
|
+
});
|
|
86
|
+
themeConfig.push(' },');
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Shadows
|
|
90
|
+
if (tokens.shadows) {
|
|
91
|
+
themeConfig.push(' boxShadow: {');
|
|
92
|
+
Object.entries(tokens.shadows).forEach(([key, value]) => {
|
|
93
|
+
themeConfig.push(` ${key}: '${value}',`);
|
|
94
|
+
});
|
|
95
|
+
themeConfig.push(' },');
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Border Radius
|
|
99
|
+
if (tokens.radius) {
|
|
100
|
+
themeConfig.push(' borderRadius: {');
|
|
101
|
+
Object.entries(tokens.radius).forEach(([key, value]) => {
|
|
102
|
+
themeConfig.push(` ${key}: '${value}',`);
|
|
103
|
+
});
|
|
104
|
+
themeConfig.push(' },');
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Animation
|
|
108
|
+
if (tokens.animation) {
|
|
109
|
+
themeConfig.push(' animation: {');
|
|
110
|
+
Object.entries(tokens.animation).forEach(([key, value]) => {
|
|
111
|
+
if (typeof value === 'string') {
|
|
112
|
+
themeConfig.push(` ${key}: '${value}',`);
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
themeConfig.push(' },');
|
|
116
|
+
|
|
117
|
+
themeConfig.push(' keyframes: {');
|
|
118
|
+
Object.entries(tokens.animation).forEach(([key, value]) => {
|
|
119
|
+
if (typeof value === 'object' && value.keyframes) {
|
|
120
|
+
themeConfig.push(` ${key}: ${JSON.stringify(value.keyframes)},`);
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
themeConfig.push(' },');
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
themeConfig.push('}');
|
|
127
|
+
|
|
128
|
+
return `module.exports = {
|
|
129
|
+
theme: {
|
|
130
|
+
${themeConfig.join('\n')}
|
|
131
|
+
};
|
|
132
|
+
`;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Generates CSS-in-JS theme object from design tokens
|
|
137
|
+
* @param {Object} tokens - Design tokens object
|
|
138
|
+
* @param {string} provider - CSS-in-JS provider (emotion, styled-components, vanilla-extract)
|
|
139
|
+
* @returns {string} Theme configuration
|
|
140
|
+
*/
|
|
141
|
+
export function generateCssInJsTheme(tokens, provider = 'emotion') {
|
|
142
|
+
const lines = [];
|
|
143
|
+
|
|
144
|
+
if (provider === 'vanilla-extract') {
|
|
145
|
+
lines.push("import { createGlobalTheme } from '@vanilla-extract/css';\n");
|
|
146
|
+
lines.push('export const theme = createGlobalTheme(\':root\', {');
|
|
147
|
+
} else {
|
|
148
|
+
lines.push('export const theme = {');
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// Colors
|
|
152
|
+
if (tokens.colors) {
|
|
153
|
+
lines.push(' colors: {');
|
|
154
|
+
Object.entries(tokens.colors).forEach(([key, value]) => {
|
|
155
|
+
if (typeof value === 'object') {
|
|
156
|
+
// Expand nested color objects
|
|
157
|
+
lines.push(` ${key}: {`);
|
|
158
|
+
Object.entries(value).forEach(([variant, variantValue]) => {
|
|
159
|
+
lines.push(` ${variant}: '${variantValue}',`);
|
|
160
|
+
});
|
|
161
|
+
lines.push(' },');
|
|
162
|
+
} else {
|
|
163
|
+
lines.push(` ${key}: '${value}',`);
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
lines.push(' },');
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// Spacing
|
|
170
|
+
if (tokens.spacing) {
|
|
171
|
+
lines.push(' space: {');
|
|
172
|
+
Object.entries(tokens.spacing).forEach(([key, value]) => {
|
|
173
|
+
lines.push(` ${key}: '${value}',`);
|
|
174
|
+
});
|
|
175
|
+
lines.push(' },');
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// Typography
|
|
179
|
+
if (tokens.typography) {
|
|
180
|
+
lines.push(' fonts: {');
|
|
181
|
+
if (tokens.typography.fontFamily) {
|
|
182
|
+
Object.entries(tokens.typography.fontFamily).forEach(([key, value]) => {
|
|
183
|
+
lines.push(` ${key}: '${value}',`);
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
lines.push(' },');
|
|
187
|
+
|
|
188
|
+
if (tokens.typography.fontSize) {
|
|
189
|
+
lines.push(' fontSizes: {');
|
|
190
|
+
Object.entries(tokens.typography.fontSize).forEach(([key, value]) => {
|
|
191
|
+
const size = typeof value === 'object' ? value.size : value;
|
|
192
|
+
lines.push(` ${key}: '${size}',`);
|
|
193
|
+
});
|
|
194
|
+
lines.push(' },');
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// Breakpoints
|
|
199
|
+
if (tokens.breakpoints) {
|
|
200
|
+
lines.push(' breakpoints: {');
|
|
201
|
+
Object.entries(tokens.breakpoints).forEach(([key, value]) => {
|
|
202
|
+
lines.push(` ${key}: '${value}',`);
|
|
203
|
+
});
|
|
204
|
+
lines.push(' },');
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// Shadows
|
|
208
|
+
if (tokens.shadows) {
|
|
209
|
+
lines.push(' shadows: {');
|
|
210
|
+
Object.entries(tokens.shadows).forEach(([key, value]) => {
|
|
211
|
+
lines.push(` ${key}: '${value}',`);
|
|
212
|
+
});
|
|
213
|
+
lines.push(' },');
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// Border Radius
|
|
217
|
+
if (tokens.radius) {
|
|
218
|
+
lines.push(' radii: {');
|
|
219
|
+
Object.entries(tokens.radius).forEach(([key, value]) => {
|
|
220
|
+
lines.push(` ${key}: '${value}',`);
|
|
221
|
+
});
|
|
222
|
+
lines.push(' },');
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// Z-index
|
|
226
|
+
if (tokens.zIndex) {
|
|
227
|
+
lines.push(' zIndices: {');
|
|
228
|
+
Object.entries(tokens.zIndex).forEach(([key, value]) => {
|
|
229
|
+
lines.push(` ${key}: ${value},`);
|
|
230
|
+
});
|
|
231
|
+
lines.push(' },');
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
lines.push('};');
|
|
235
|
+
|
|
236
|
+
if (provider === 'vanilla-extract') {
|
|
237
|
+
lines.push('\nexport type Theme = typeof theme;');
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
return lines.join('\n');
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* Generates CSS custom properties from design tokens
|
|
245
|
+
* @param {Object} tokens - Design tokens object
|
|
246
|
+
* @param {Object} options - Generation options
|
|
247
|
+
* @returns {string} CSS custom properties
|
|
248
|
+
*/
|
|
249
|
+
export function generateCssVariables(tokens, options = {}) {
|
|
250
|
+
const { selector = ':root', prefix = 'atomix' } = options;
|
|
251
|
+
const lines = [`${selector} {`];
|
|
252
|
+
|
|
253
|
+
// Colors
|
|
254
|
+
if (tokens.colors) {
|
|
255
|
+
Object.entries(tokens.colors).forEach(([key, value]) => {
|
|
256
|
+
if (typeof value === 'object') {
|
|
257
|
+
// Handle color variants (light/dark mode)
|
|
258
|
+
if (value.base) {
|
|
259
|
+
lines.push(` --${prefix}-${key}: ${value.base};`);
|
|
260
|
+
}
|
|
261
|
+
if (value.light) {
|
|
262
|
+
lines.push(` --${prefix}-${key}-light: ${value.light};`);
|
|
263
|
+
}
|
|
264
|
+
if (value.dark) {
|
|
265
|
+
lines.push(` --${prefix}-${key}-dark: ${value.dark};`);
|
|
266
|
+
}
|
|
267
|
+
} else {
|
|
268
|
+
lines.push(` --${prefix}-${key}: ${value};`);
|
|
269
|
+
}
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
// Spacing
|
|
274
|
+
if (tokens.spacing) {
|
|
275
|
+
Object.entries(tokens.spacing).forEach(([key, value]) => {
|
|
276
|
+
lines.push(` --${prefix}-space-${key}: ${value};`);
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
// Typography
|
|
281
|
+
if (tokens.typography) {
|
|
282
|
+
if (tokens.typography.fontFamily) {
|
|
283
|
+
Object.entries(tokens.typography.fontFamily).forEach(([key, value]) => {
|
|
284
|
+
lines.push(` --${prefix}-font-${key}: ${value};`);
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
if (tokens.typography.fontSize) {
|
|
289
|
+
Object.entries(tokens.typography.fontSize).forEach(([key, value]) => {
|
|
290
|
+
const size = typeof value === 'object' ? value.size : value;
|
|
291
|
+
lines.push(` --${prefix}-text-${key}: ${size};`);
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
// Breakpoints
|
|
297
|
+
if (tokens.breakpoints) {
|
|
298
|
+
Object.entries(tokens.breakpoints).forEach(([key, value]) => {
|
|
299
|
+
lines.push(` --${prefix}-breakpoint-${key}: ${value};`);
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
// Shadows
|
|
304
|
+
if (tokens.shadows) {
|
|
305
|
+
Object.entries(tokens.shadows).forEach(([key, value]) => {
|
|
306
|
+
lines.push(` --${prefix}-shadow-${key}: ${value};`);
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
// Border Radius
|
|
311
|
+
if (tokens.radius) {
|
|
312
|
+
Object.entries(tokens.radius).forEach(([key, value]) => {
|
|
313
|
+
lines.push(` --${prefix}-radius-${key}: ${value};`);
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
// Z-index
|
|
318
|
+
if (tokens.zIndex) {
|
|
319
|
+
Object.entries(tokens.zIndex).forEach(([key, value]) => {
|
|
320
|
+
lines.push(` --${prefix}-z-${key}: ${value};`);
|
|
321
|
+
});
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
// Motion
|
|
325
|
+
if (tokens.motion) {
|
|
326
|
+
if (tokens.motion.duration) {
|
|
327
|
+
Object.entries(tokens.motion.duration).forEach(([key, value]) => {
|
|
328
|
+
lines.push(` --${prefix}-duration-${key}: ${value};`);
|
|
329
|
+
});
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
if (tokens.motion.easing) {
|
|
333
|
+
Object.entries(tokens.motion.easing).forEach(([key, value]) => {
|
|
334
|
+
lines.push(` --${prefix}-easing-${key}: ${value};`);
|
|
335
|
+
});
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
lines.push('}');
|
|
340
|
+
|
|
341
|
+
return lines.join('\n');
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
/**
|
|
345
|
+
* Syncs design tokens to Tailwind config
|
|
346
|
+
* @param {string} tokenPath - Path to design tokens file
|
|
347
|
+
* @param {string} outputPath - Path to output Tailwind config
|
|
348
|
+
* @param {Object} options - Sync options
|
|
349
|
+
* @returns {Promise<Object>} Result with created files
|
|
350
|
+
*/
|
|
351
|
+
export async function syncToTailwind(tokenPath, outputPath, options = {}) {
|
|
352
|
+
try {
|
|
353
|
+
const tokens = await tokenProvider.loadTokens(tokenPath);
|
|
354
|
+
const tailwindConfig = generateTailwindTheme(tokens);
|
|
355
|
+
|
|
356
|
+
await filesystem.writeFile(outputPath, tailwindConfig, 'utf8');
|
|
357
|
+
|
|
358
|
+
return {
|
|
359
|
+
success: true,
|
|
360
|
+
created: [outputPath],
|
|
361
|
+
tokensSynced: Object.keys(tokens).length
|
|
362
|
+
};
|
|
363
|
+
} catch (error) {
|
|
364
|
+
throw new AtomixCLIError(
|
|
365
|
+
`Failed to sync to Tailwind: ${error.message}`,
|
|
366
|
+
'TAILWIND_SYNC_FAILED',
|
|
367
|
+
[
|
|
368
|
+
'Verify design tokens file exists and is valid',
|
|
369
|
+
'Check output path is writable',
|
|
370
|
+
'Ensure tokens follow expected structure'
|
|
371
|
+
]
|
|
372
|
+
);
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
/**
|
|
377
|
+
* Syncs design tokens to CSS-in-JS theme
|
|
378
|
+
* @param {string} tokenPath - Path to design tokens file
|
|
379
|
+
* @param {string} outputPath - Path to output theme file
|
|
380
|
+
* @param {string} provider - CSS-in-JS provider
|
|
381
|
+
* @param {Object} options - Sync options
|
|
382
|
+
* @returns {Promise<Object>} Result with created files
|
|
383
|
+
*/
|
|
384
|
+
export async function syncToCssInJs(tokenPath, outputPath, provider = 'emotion', options = {}) {
|
|
385
|
+
try {
|
|
386
|
+
const tokens = await tokenProvider.loadTokens(tokenPath);
|
|
387
|
+
const themeContent = generateCssInJsTheme(tokens, provider);
|
|
388
|
+
|
|
389
|
+
await filesystem.writeFile(outputPath, themeContent, 'utf8');
|
|
390
|
+
|
|
391
|
+
return {
|
|
392
|
+
success: true,
|
|
393
|
+
created: [outputPath],
|
|
394
|
+
tokensSynced: Object.keys(tokens).length,
|
|
395
|
+
provider
|
|
396
|
+
};
|
|
397
|
+
} catch (error) {
|
|
398
|
+
throw new AtomixCLIError(
|
|
399
|
+
`Failed to sync to CSS-in-JS: ${error.message}`,
|
|
400
|
+
'CSS_IN_JS_SYNC_FAILED',
|
|
401
|
+
[
|
|
402
|
+
'Verify design tokens file exists',
|
|
403
|
+
'Check provider is supported (emotion, styled-components, vanilla-extract)',
|
|
404
|
+
'Ensure output directory is writable'
|
|
405
|
+
]
|
|
406
|
+
);
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
/**
|
|
411
|
+
* Syncs design tokens to CSS variables
|
|
412
|
+
* @param {string} tokenPath - Path to design tokens file
|
|
413
|
+
* @param {string} outputPath - Path to output CSS file
|
|
414
|
+
* @param {Object} options - Sync options
|
|
415
|
+
* @returns {Promise<Object>} Result with created files
|
|
416
|
+
*/
|
|
417
|
+
export async function syncToCssVariables(tokenPath, outputPath, options = {}) {
|
|
418
|
+
try {
|
|
419
|
+
const tokens = await tokenProvider.loadTokens(tokenPath);
|
|
420
|
+
const cssContent = generateCssVariables(tokens, options);
|
|
421
|
+
|
|
422
|
+
await filesystem.writeFile(outputPath, cssContent, 'utf8');
|
|
423
|
+
|
|
424
|
+
return {
|
|
425
|
+
success: true,
|
|
426
|
+
created: [outputPath],
|
|
427
|
+
tokensSynced: Object.keys(tokens).length
|
|
428
|
+
};
|
|
429
|
+
} catch (error) {
|
|
430
|
+
throw new AtomixCLIError(
|
|
431
|
+
`Failed to sync to CSS variables: ${error.message}`,
|
|
432
|
+
'CSS_VARIABLES_SYNC_FAILED',
|
|
433
|
+
[
|
|
434
|
+
'Verify design tokens file exists',
|
|
435
|
+
'Check output path is writable',
|
|
436
|
+
'Ensure tokens have valid values'
|
|
437
|
+
]
|
|
438
|
+
);
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
/**
|
|
443
|
+
* Creates a complete theme package with all formats
|
|
444
|
+
* @param {string} tokenPath - Path to design tokens file
|
|
445
|
+
* @param {string} outputDir - Output directory for theme files
|
|
446
|
+
* @param {Object} options - Generation options
|
|
447
|
+
* @returns {Promise<Object>} Result with all created files
|
|
448
|
+
*/
|
|
449
|
+
export async function createThemePackage(tokenPath, outputDir, options = {}) {
|
|
450
|
+
const results = {
|
|
451
|
+
success: true,
|
|
452
|
+
created: [],
|
|
453
|
+
tokensSynced: 0,
|
|
454
|
+
formats: []
|
|
455
|
+
};
|
|
456
|
+
|
|
457
|
+
try {
|
|
458
|
+
const tokens = await tokenProvider.loadTokens(tokenPath);
|
|
459
|
+
results.tokensSynced = Object.keys(tokens).length;
|
|
460
|
+
|
|
461
|
+
// Ensure output directory exists
|
|
462
|
+
await filesystem.createDirectory(outputDir);
|
|
463
|
+
|
|
464
|
+
// Generate Tailwind config
|
|
465
|
+
if (options.formats?.includes('tailwind') || !options.formats) {
|
|
466
|
+
const tailwindPath = join(outputDir, 'tailwind.theme.js');
|
|
467
|
+
const tailwindResult = await syncToTailwind(tokenPath, tailwindPath);
|
|
468
|
+
results.created.push(...tailwindResult.created);
|
|
469
|
+
results.formats.push('tailwind');
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
// Generate CSS-in-JS theme
|
|
473
|
+
if (options.formats?.includes('css-in-js') || !options.formats) {
|
|
474
|
+
const themePath = join(outputDir, 'theme.ts');
|
|
475
|
+
const themeResult = await syncToCssInJs(tokenPath, themePath, 'emotion');
|
|
476
|
+
results.created.push(...themeResult.created);
|
|
477
|
+
results.formats.push('css-in-js');
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
// Generate CSS variables
|
|
481
|
+
if (options.formats?.includes('css-variables') || !options.formats) {
|
|
482
|
+
const cssPath = join(outputDir, 'variables.css');
|
|
483
|
+
const cssResult = await syncToCssVariables(tokenPath, cssPath, options);
|
|
484
|
+
results.created.push(...cssResult.created);
|
|
485
|
+
results.formats.push('css-variables');
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
// Generate TypeScript types
|
|
489
|
+
if (options.typescript !== false) {
|
|
490
|
+
const typesPath = join(outputDir, 'theme.types.ts');
|
|
491
|
+
const typesContent = generateTypeScriptTypes(tokens);
|
|
492
|
+
await filesystem.writeFile(typesPath, typesContent, 'utf8');
|
|
493
|
+
results.created.push(typesPath);
|
|
494
|
+
results.formats.push('typescript');
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
return results;
|
|
498
|
+
} catch (error) {
|
|
499
|
+
throw new AtomixCLIError(
|
|
500
|
+
`Failed to create theme package: ${error.message}`,
|
|
501
|
+
'THEME_PACKAGE_CREATION_FAILED',
|
|
502
|
+
[
|
|
503
|
+
'Verify design tokens file exists and is valid',
|
|
504
|
+
'Check output directory is writable',
|
|
505
|
+
'Ensure all required dependencies are installed'
|
|
506
|
+
]
|
|
507
|
+
);
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
/**
|
|
512
|
+
* Generates TypeScript type definitions for theme
|
|
513
|
+
* @param {Object} tokens - Design tokens object
|
|
514
|
+
* @returns {string} TypeScript type definitions
|
|
515
|
+
*/
|
|
516
|
+
export function generateTypeScriptTypes(tokens) {
|
|
517
|
+
const lines = [
|
|
518
|
+
'/**',
|
|
519
|
+
' * Atomix Theme Type Definitions',
|
|
520
|
+
' * Auto-generated from design tokens',
|
|
521
|
+
' */\n',
|
|
522
|
+
'export interface AtomixTheme {',
|
|
523
|
+
];
|
|
524
|
+
|
|
525
|
+
if (tokens.colors) {
|
|
526
|
+
lines.push(' colors: {');
|
|
527
|
+
Object.keys(tokens.colors).forEach(key => {
|
|
528
|
+
lines.push(` ${key}: string;`);
|
|
529
|
+
});
|
|
530
|
+
lines.push(' };');
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
if (tokens.spacing) {
|
|
534
|
+
lines.push(' space: {');
|
|
535
|
+
Object.keys(tokens.spacing).forEach(key => {
|
|
536
|
+
lines.push(` ${key}: string;`);
|
|
537
|
+
});
|
|
538
|
+
lines.push(' };');
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
if (tokens.typography) {
|
|
542
|
+
lines.push(' fonts: {');
|
|
543
|
+
if (tokens.typography.fontFamily) {
|
|
544
|
+
Object.keys(tokens.typography.fontFamily).forEach(key => {
|
|
545
|
+
lines.push(` ${key}: string;`);
|
|
546
|
+
});
|
|
547
|
+
}
|
|
548
|
+
lines.push(' };');
|
|
549
|
+
|
|
550
|
+
lines.push(' fontSizes: {');
|
|
551
|
+
if (tokens.typography.fontSize) {
|
|
552
|
+
Object.keys(tokens.typography.fontSize).forEach(key => {
|
|
553
|
+
lines.push(` ${key}: string;`);
|
|
554
|
+
});
|
|
555
|
+
}
|
|
556
|
+
lines.push(' };');
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
if (tokens.breakpoints) {
|
|
560
|
+
lines.push(' breakpoints: {');
|
|
561
|
+
Object.keys(tokens.breakpoints).forEach(key => {
|
|
562
|
+
lines.push(` ${key}: string;`);
|
|
563
|
+
});
|
|
564
|
+
lines.push(' };');
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
if (tokens.shadows) {
|
|
568
|
+
lines.push(' shadows: {');
|
|
569
|
+
Object.keys(tokens.shadows).forEach(key => {
|
|
570
|
+
lines.push(` ${key}: string;`);
|
|
571
|
+
});
|
|
572
|
+
lines.push(' };');
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
if (tokens.radius) {
|
|
576
|
+
lines.push(' radii: {');
|
|
577
|
+
Object.keys(tokens.radius).forEach(key => {
|
|
578
|
+
lines.push(` ${key}: string;`);
|
|
579
|
+
});
|
|
580
|
+
lines.push(' };');
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
if (tokens.zIndex) {
|
|
584
|
+
lines.push(' zIndices: {');
|
|
585
|
+
Object.keys(tokens.zIndex).forEach(key => {
|
|
586
|
+
lines.push(` ${key}: number;`);
|
|
587
|
+
});
|
|
588
|
+
lines.push(' };');
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
lines.push('}\n');
|
|
592
|
+
lines.push('export type ThemeColor = keyof AtomixTheme[\'colors\'];');
|
|
593
|
+
lines.push('export type ThemeSpacing = keyof AtomixTheme[\'space\'];');
|
|
594
|
+
lines.push('export type ThemeFontSize = keyof AtomixTheme[\'fontSizes\'];');
|
|
595
|
+
|
|
596
|
+
return lines.join('\n');
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
/**
|
|
600
|
+
* Validates theme synchronization
|
|
601
|
+
* @param {string} tokenPath - Path to design tokens
|
|
602
|
+
* @param {string} themePath - Path to generated theme
|
|
603
|
+
* @param {string} provider - Theme provider type
|
|
604
|
+
* @returns {Promise<Object>} Validation result
|
|
605
|
+
*/
|
|
606
|
+
export async function validateThemeSync(tokenPath, themePath, provider) {
|
|
607
|
+
try {
|
|
608
|
+
const tokens = await tokenProvider.loadTokens(tokenPath);
|
|
609
|
+
const themeContent = await filesystem.readFile(themePath, 'utf8');
|
|
610
|
+
|
|
611
|
+
const issues = [];
|
|
612
|
+
let valid = true;
|
|
613
|
+
|
|
614
|
+
// Check if all token keys are present in theme
|
|
615
|
+
for (const category of Object.keys(tokens)) {
|
|
616
|
+
const tokenKeys = Object.keys(tokens[category]);
|
|
617
|
+
const missingKeys = tokenKeys.filter(key => !themeContent.includes(key));
|
|
618
|
+
|
|
619
|
+
if (missingKeys.length > 0) {
|
|
620
|
+
valid = false;
|
|
621
|
+
issues.push({
|
|
622
|
+
severity: 'warning',
|
|
623
|
+
message: `Missing tokens in theme: ${missingKeys.join(', ')}`,
|
|
624
|
+
category
|
|
625
|
+
});
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
// Provider-specific validation
|
|
630
|
+
if (provider === 'tailwind') {
|
|
631
|
+
if (!themeContent.includes('module.exports')) {
|
|
632
|
+
valid = false;
|
|
633
|
+
issues.push({
|
|
634
|
+
severity: 'error',
|
|
635
|
+
message: 'Tailwind config must use CommonJS exports'
|
|
636
|
+
});
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
if (provider === 'css-variables') {
|
|
641
|
+
if (!themeContent.includes(':root')) {
|
|
642
|
+
valid = false;
|
|
643
|
+
issues.push({
|
|
644
|
+
severity: 'error',
|
|
645
|
+
message: 'CSS variables must be defined in :root selector'
|
|
646
|
+
});
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
return {
|
|
651
|
+
valid,
|
|
652
|
+
issues,
|
|
653
|
+
tokensChecked: Object.keys(tokens).length
|
|
654
|
+
};
|
|
655
|
+
} catch (error) {
|
|
656
|
+
return {
|
|
657
|
+
valid: false,
|
|
658
|
+
issues: [{
|
|
659
|
+
severity: 'error',
|
|
660
|
+
message: `Validation failed: ${error.message}`
|
|
661
|
+
}]
|
|
662
|
+
};
|
|
663
|
+
}
|
|
664
|
+
}
|