@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,507 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for Theme Bridge Generator
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
|
6
|
+
import {
|
|
7
|
+
generateTailwindTheme,
|
|
8
|
+
generateCssInJsTheme,
|
|
9
|
+
generateCssVariables,
|
|
10
|
+
generateTypeScriptTypes,
|
|
11
|
+
validateThemeSync
|
|
12
|
+
} from '../internal/theme-bridge.js';
|
|
13
|
+
import { tokenProvider } from '../internal/tokens/token-provider.js';
|
|
14
|
+
|
|
15
|
+
// Mock filesystem
|
|
16
|
+
vi.mock('../internal/filesystem.js', () => ({
|
|
17
|
+
filesystem: {
|
|
18
|
+
writeFile: vi.fn().mockResolvedValue(true),
|
|
19
|
+
readFile: vi.fn().mockResolvedValue('mock content'),
|
|
20
|
+
createDirectory: vi.fn().mockResolvedValue(true)
|
|
21
|
+
}
|
|
22
|
+
}));
|
|
23
|
+
|
|
24
|
+
describe('Theme Bridge Generator', () => {
|
|
25
|
+
// Sample tokens for testing
|
|
26
|
+
const sampleTokens = {
|
|
27
|
+
colors: {
|
|
28
|
+
primary: '#3B82F6',
|
|
29
|
+
secondary: '#10B981',
|
|
30
|
+
brand: {
|
|
31
|
+
base: '#6366F1',
|
|
32
|
+
light: '#818CF8',
|
|
33
|
+
dark: '#4F46E5'
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
spacing: {
|
|
37
|
+
xs: '0.25rem',
|
|
38
|
+
sm: '0.5rem',
|
|
39
|
+
md: '1rem',
|
|
40
|
+
lg: '1.5rem',
|
|
41
|
+
xl: '2rem'
|
|
42
|
+
},
|
|
43
|
+
typography: {
|
|
44
|
+
fontFamily: {
|
|
45
|
+
sans: 'Inter, system-ui, sans-serif',
|
|
46
|
+
mono: 'Fira Code, monospace'
|
|
47
|
+
},
|
|
48
|
+
fontSize: {
|
|
49
|
+
sm: '0.875rem',
|
|
50
|
+
base: '1rem',
|
|
51
|
+
lg: '1.125rem',
|
|
52
|
+
xl: '1.25rem'
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
breakpoints: {
|
|
56
|
+
sm: '640px',
|
|
57
|
+
md: '768px',
|
|
58
|
+
lg: '1024px',
|
|
59
|
+
xl: '1280px'
|
|
60
|
+
},
|
|
61
|
+
shadows: {
|
|
62
|
+
sm: '0 1px 2px rgba(0, 0, 0, 0.05)',
|
|
63
|
+
md: '0 4px 6px rgba(0, 0, 0, 0.1)',
|
|
64
|
+
lg: '0 10px 15px rgba(0, 0, 0, 0.1)'
|
|
65
|
+
},
|
|
66
|
+
radius: {
|
|
67
|
+
sm: '0.25rem',
|
|
68
|
+
md: '0.375rem',
|
|
69
|
+
lg: '0.5rem',
|
|
70
|
+
full: '9999px'
|
|
71
|
+
},
|
|
72
|
+
zIndex: {
|
|
73
|
+
hidden: -1,
|
|
74
|
+
base: 0,
|
|
75
|
+
dropdown: 1000,
|
|
76
|
+
modal: 1500,
|
|
77
|
+
popover: 2000
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
describe('generateTailwindTheme', () => {
|
|
82
|
+
it('should generate valid Tailwind theme config', () => {
|
|
83
|
+
const config = generateTailwindTheme(sampleTokens);
|
|
84
|
+
|
|
85
|
+
expect(config).toContain('module.exports');
|
|
86
|
+
expect(config).toContain('theme:');
|
|
87
|
+
expect(config).toContain('colors:');
|
|
88
|
+
expect(config).toContain('spacing:');
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it('should include all color tokens', () => {
|
|
92
|
+
const config = generateTailwindTheme(sampleTokens);
|
|
93
|
+
|
|
94
|
+
expect(config).toContain('primary:');
|
|
95
|
+
expect(config).toContain('secondary:');
|
|
96
|
+
expect(config).toContain('brand:');
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it('should handle nested color objects', () => {
|
|
100
|
+
const config = generateTailwindTheme(sampleTokens);
|
|
101
|
+
|
|
102
|
+
expect(config).toContain('#6366F1'); // brand.base
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
it('should include spacing tokens', () => {
|
|
106
|
+
const config = generateTailwindTheme(sampleTokens);
|
|
107
|
+
|
|
108
|
+
expect(config).toContain('xs:');
|
|
109
|
+
expect(config).toContain('sm:');
|
|
110
|
+
expect(config).toContain('md:');
|
|
111
|
+
expect(config).toContain('lg:');
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
it('should include typography tokens', () => {
|
|
115
|
+
const config = generateTailwindTheme(sampleTokens);
|
|
116
|
+
|
|
117
|
+
expect(config).toContain('fontSize:');
|
|
118
|
+
expect(config).toContain('fontFamily:');
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
it('should include breakpoint tokens as screens', () => {
|
|
122
|
+
const config = generateTailwindTheme(sampleTokens);
|
|
123
|
+
|
|
124
|
+
expect(config).toContain('screens:');
|
|
125
|
+
expect(config).toContain('sm:');
|
|
126
|
+
expect(config).toContain('md:');
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
it('should include shadow tokens', () => {
|
|
130
|
+
const config = generateTailwindTheme(sampleTokens);
|
|
131
|
+
|
|
132
|
+
expect(config).toContain('boxShadow:');
|
|
133
|
+
expect(config).toContain('sm:');
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
it('should include border radius tokens', () => {
|
|
137
|
+
const config = generateTailwindTheme(sampleTokens);
|
|
138
|
+
|
|
139
|
+
expect(config).toContain('borderRadius:');
|
|
140
|
+
expect(config).toContain('full:');
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
it('should generate valid JavaScript syntax', () => {
|
|
144
|
+
const config = generateTailwindTheme(sampleTokens);
|
|
145
|
+
|
|
146
|
+
// Basic syntax validation
|
|
147
|
+
expect(config).toContain('{');
|
|
148
|
+
expect(config).toContain('}');
|
|
149
|
+
expect(config.split('{').length).toBeGreaterThan(1);
|
|
150
|
+
});
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
describe('generateCssInJsTheme', () => {
|
|
154
|
+
it('should generate emotion theme by default', () => {
|
|
155
|
+
const theme = generateCssInJsTheme(sampleTokens, 'emotion');
|
|
156
|
+
|
|
157
|
+
expect(theme).toContain('export const theme');
|
|
158
|
+
expect(theme).toContain('colors:');
|
|
159
|
+
expect(theme).toContain('space:');
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
it('should generate styled-components theme', () => {
|
|
163
|
+
const theme = generateCssInJsTheme(sampleTokens, 'styled-components');
|
|
164
|
+
|
|
165
|
+
expect(theme).toContain('export const theme');
|
|
166
|
+
expect(theme).toContain('fonts:');
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
it('should generate vanilla-extract theme with imports', () => {
|
|
170
|
+
const theme = generateCssInJsTheme(sampleTokens, 'vanilla-extract');
|
|
171
|
+
|
|
172
|
+
expect(theme).toContain("import { createGlobalTheme }");
|
|
173
|
+
expect(theme).toContain('createGlobalTheme');
|
|
174
|
+
expect(theme).toContain('export type Theme');
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
it('should include all token categories', () => {
|
|
178
|
+
const theme = generateCssInJsTheme(sampleTokens, 'emotion');
|
|
179
|
+
|
|
180
|
+
expect(theme).toContain('colors:');
|
|
181
|
+
expect(theme).toContain('space:');
|
|
182
|
+
expect(theme).toContain('fonts:');
|
|
183
|
+
expect(theme).toContain('fontSizes:');
|
|
184
|
+
expect(theme).toContain('breakpoints:');
|
|
185
|
+
expect(theme).toContain('shadows:');
|
|
186
|
+
expect(theme).toContain('radii:');
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
it('should handle nested color values', () => {
|
|
190
|
+
const theme = generateCssInJsTheme(sampleTokens, 'emotion');
|
|
191
|
+
|
|
192
|
+
expect(theme).toContain('base:');
|
|
193
|
+
expect(theme).toContain('light:');
|
|
194
|
+
expect(theme).toContain('dark:');
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
it('should include z-index tokens', () => {
|
|
198
|
+
const theme = generateCssInJsTheme(sampleTokens, 'emotion');
|
|
199
|
+
|
|
200
|
+
expect(theme).toContain('zIndices:');
|
|
201
|
+
expect(theme).toContain('modal:');
|
|
202
|
+
});
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
describe('generateCssVariables', () => {
|
|
206
|
+
it('should generate CSS custom properties in :root', () => {
|
|
207
|
+
const css = generateCssVariables(sampleTokens);
|
|
208
|
+
|
|
209
|
+
expect(css).toContain(':root {');
|
|
210
|
+
expect(css).toContain('--atomix-');
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
it('should use custom selector when provided', () => {
|
|
214
|
+
const css = generateCssVariables(sampleTokens, { selector: '[data-theme]' });
|
|
215
|
+
|
|
216
|
+
expect(css).toContain('[data-theme] {');
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
it('should use custom prefix when provided', () => {
|
|
220
|
+
const css = generateCssVariables(sampleTokens, { prefix: 'custom' });
|
|
221
|
+
|
|
222
|
+
expect(css).toContain('--custom-');
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
it('should generate color variables', () => {
|
|
226
|
+
const css = generateCssVariables(sampleTokens);
|
|
227
|
+
|
|
228
|
+
expect(css).toContain('--atomix-primary:');
|
|
229
|
+
expect(css).toContain('--atomix-secondary:');
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
it('should handle nested color objects', () => {
|
|
233
|
+
const css = generateCssVariables(sampleTokens);
|
|
234
|
+
|
|
235
|
+
expect(css).toContain('--atomix-brand:'); // Uses base value for main variable
|
|
236
|
+
expect(css).toContain('--atomix-brand-light:');
|
|
237
|
+
expect(css).toContain('--atomix-brand-dark:');
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
it('should generate spacing variables', () => {
|
|
241
|
+
const css = generateCssVariables(sampleTokens);
|
|
242
|
+
|
|
243
|
+
expect(css).toContain('--atomix-space-xs:');
|
|
244
|
+
expect(css).toContain('--atomix-space-sm:');
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
it('should generate font variables', () => {
|
|
248
|
+
const css = generateCssVariables(sampleTokens);
|
|
249
|
+
|
|
250
|
+
expect(css).toContain('--atomix-font-sans:');
|
|
251
|
+
expect(css).toContain('--atomix-text-base:');
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
it('should generate breakpoint variables', () => {
|
|
255
|
+
const css = generateCssVariables(sampleTokens);
|
|
256
|
+
|
|
257
|
+
expect(css).toContain('--atomix-breakpoint-sm:');
|
|
258
|
+
expect(css).toContain('--atomix-breakpoint-md:');
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
it('should generate shadow variables', () => {
|
|
262
|
+
const css = generateCssVariables(sampleTokens);
|
|
263
|
+
|
|
264
|
+
expect(css).toContain('--atomix-shadow-sm:');
|
|
265
|
+
expect(css).toContain('--atomix-shadow-md:');
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
it('should generate radius variables', () => {
|
|
269
|
+
const css = generateCssVariables(sampleTokens);
|
|
270
|
+
|
|
271
|
+
expect(css).toContain('--atomix-radius-sm:');
|
|
272
|
+
expect(css).toContain('--atomix-radius-full:');
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
it('should generate z-index variables', () => {
|
|
276
|
+
const css = generateCssVariables(sampleTokens);
|
|
277
|
+
|
|
278
|
+
expect(css).toContain('--atomix-z-modal:');
|
|
279
|
+
expect(css).toContain('--atomix-z-popover:');
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
it('should close the selector block', () => {
|
|
283
|
+
const css = generateCssVariables(sampleTokens);
|
|
284
|
+
|
|
285
|
+
expect(css).toMatch(/\}$/);
|
|
286
|
+
});
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
describe('generateTypeScriptTypes', () => {
|
|
290
|
+
it('should generate TypeScript interface', () => {
|
|
291
|
+
const types = generateTypeScriptTypes(sampleTokens);
|
|
292
|
+
|
|
293
|
+
expect(types).toContain('export interface AtomixTheme');
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
it('should include JSDoc header', () => {
|
|
297
|
+
const types = generateTypeScriptTypes(sampleTokens);
|
|
298
|
+
|
|
299
|
+
expect(types).toContain('/**');
|
|
300
|
+
expect(types).toContain('Auto-generated from design tokens');
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
it('should generate color type definitions', () => {
|
|
304
|
+
const types = generateTypeScriptTypes(sampleTokens);
|
|
305
|
+
|
|
306
|
+
expect(types).toContain('colors:');
|
|
307
|
+
expect(types).toContain('primary: string;');
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
it('should generate spacing type definitions', () => {
|
|
311
|
+
const types = generateTypeScriptTypes(sampleTokens);
|
|
312
|
+
|
|
313
|
+
expect(types).toContain('space:');
|
|
314
|
+
expect(types).toContain('sm: string;');
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
it('should generate utility type aliases', () => {
|
|
318
|
+
const types = generateTypeScriptTypes(sampleTokens);
|
|
319
|
+
|
|
320
|
+
expect(types).toContain('export type ThemeColor');
|
|
321
|
+
expect(types).toContain('export type ThemeSpacing');
|
|
322
|
+
expect(types).toContain('export type ThemeFontSize');
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
it('should use correct types for different token categories', () => {
|
|
326
|
+
const types = generateTypeScriptTypes(sampleTokens);
|
|
327
|
+
|
|
328
|
+
// String types
|
|
329
|
+
expect(types).toContain(': string;');
|
|
330
|
+
|
|
331
|
+
// Number types for zIndex
|
|
332
|
+
expect(types).toContain(': number;');
|
|
333
|
+
});
|
|
334
|
+
});
|
|
335
|
+
|
|
336
|
+
describe('validateThemeSync', () => {
|
|
337
|
+
it('should return valid when all tokens are present', async () => {
|
|
338
|
+
// Mock tokenProvider.loadTokens
|
|
339
|
+
const loadTokensSpy = vi.spyOn(tokenProvider, 'loadTokens').mockResolvedValue({
|
|
340
|
+
colors: { primary: '#3B82F6', secondary: '#10B981' },
|
|
341
|
+
spacing: { sm: '0.5rem', md: '1rem' }
|
|
342
|
+
});
|
|
343
|
+
|
|
344
|
+
const mockThemeContent = `
|
|
345
|
+
export const theme = {
|
|
346
|
+
colors: { primary: '#3B82F6', secondary: '#10B981' },
|
|
347
|
+
space: { sm: '0.5rem', md: '1rem' }
|
|
348
|
+
};
|
|
349
|
+
`;
|
|
350
|
+
|
|
351
|
+
// Mock filesystem.readFile
|
|
352
|
+
const { filesystem } = await import('../internal/filesystem.js');
|
|
353
|
+
const readFileSpy = vi.spyOn(filesystem, 'readFile').mockResolvedValue(mockThemeContent);
|
|
354
|
+
|
|
355
|
+
const result = await validateThemeSync(
|
|
356
|
+
'./tokens.json',
|
|
357
|
+
'./theme.ts',
|
|
358
|
+
'css-in-js'
|
|
359
|
+
);
|
|
360
|
+
|
|
361
|
+
expect(result.valid).toBe(true);
|
|
362
|
+
expect(result.issues).toEqual([]);
|
|
363
|
+
expect(result.tokensChecked).toBeGreaterThan(0);
|
|
364
|
+
|
|
365
|
+
loadTokensSpy.mockRestore();
|
|
366
|
+
readFileSpy.mockRestore();
|
|
367
|
+
});
|
|
368
|
+
|
|
369
|
+
it('should detect missing tokens', async () => {
|
|
370
|
+
const loadTokensSpy = vi.spyOn(tokenProvider, 'loadTokens').mockResolvedValue({
|
|
371
|
+
colors: { primary: '#3B82F6', secondary: '#10B981' },
|
|
372
|
+
spacing: { sm: '0.5rem', md: '1rem' }
|
|
373
|
+
});
|
|
374
|
+
|
|
375
|
+
const mockThemeContent = `
|
|
376
|
+
export const theme = {
|
|
377
|
+
colors: { primary: '#3B82F6' }
|
|
378
|
+
};
|
|
379
|
+
`;
|
|
380
|
+
|
|
381
|
+
const { filesystem } = await import('../internal/filesystem.js');
|
|
382
|
+
const readFileSpy = vi.spyOn(filesystem, 'readFile').mockResolvedValue(mockThemeContent);
|
|
383
|
+
|
|
384
|
+
const result = await validateThemeSync(
|
|
385
|
+
'./tokens.json',
|
|
386
|
+
'./theme.ts',
|
|
387
|
+
'css-in-js'
|
|
388
|
+
);
|
|
389
|
+
|
|
390
|
+
// Should have issues for missing tokens
|
|
391
|
+
expect(result.issues).toBeDefined();
|
|
392
|
+
expect(result.issues.length).toBeGreaterThan(0);
|
|
393
|
+
|
|
394
|
+
loadTokensSpy.mockRestore();
|
|
395
|
+
readFileSpy.mockRestore();
|
|
396
|
+
});
|
|
397
|
+
|
|
398
|
+
it('should validate Tailwind CommonJS exports', async () => {
|
|
399
|
+
const loadTokensSpy = vi.spyOn(tokenProvider, 'loadTokens').mockResolvedValue({
|
|
400
|
+
colors: { primary: '#3B82F6' }
|
|
401
|
+
});
|
|
402
|
+
|
|
403
|
+
const invalidTailwind = `
|
|
404
|
+
export default { theme: {} };
|
|
405
|
+
`;
|
|
406
|
+
|
|
407
|
+
const { filesystem } = await import('../internal/filesystem.js');
|
|
408
|
+
const readFileSpy = vi.spyOn(filesystem, 'readFile').mockResolvedValue(invalidTailwind);
|
|
409
|
+
|
|
410
|
+
const result = await validateThemeSync(
|
|
411
|
+
'./tokens.json',
|
|
412
|
+
'./tailwind.config.js',
|
|
413
|
+
'tailwind'
|
|
414
|
+
);
|
|
415
|
+
|
|
416
|
+
expect(result.valid).toBe(false);
|
|
417
|
+
expect(result.issues.some(i => i.severity === 'error')).toBe(true);
|
|
418
|
+
|
|
419
|
+
loadTokensSpy.mockRestore();
|
|
420
|
+
readFileSpy.mockRestore();
|
|
421
|
+
});
|
|
422
|
+
|
|
423
|
+
it('should validate CSS variables :root selector', async () => {
|
|
424
|
+
const loadTokensSpy = vi.spyOn(tokenProvider, 'loadTokens').mockResolvedValue({
|
|
425
|
+
colors: { primary: '#3B82F6' }
|
|
426
|
+
});
|
|
427
|
+
|
|
428
|
+
const invalidCss = `
|
|
429
|
+
.theme { --atomix-primary: #3B82F6; }
|
|
430
|
+
`;
|
|
431
|
+
|
|
432
|
+
const { filesystem } = await import('../internal/filesystem.js');
|
|
433
|
+
const readFileSpy = vi.spyOn(filesystem, 'readFile').mockResolvedValue(invalidCss);
|
|
434
|
+
|
|
435
|
+
const result = await validateThemeSync(
|
|
436
|
+
'./tokens.json',
|
|
437
|
+
'./variables.css',
|
|
438
|
+
'css-variables'
|
|
439
|
+
);
|
|
440
|
+
|
|
441
|
+
expect(result.valid).toBe(false);
|
|
442
|
+
expect(result.issues.some(i => i.severity === 'error')).toBe(true);
|
|
443
|
+
|
|
444
|
+
loadTokensSpy.mockRestore();
|
|
445
|
+
readFileSpy.mockRestore();
|
|
446
|
+
});
|
|
447
|
+
|
|
448
|
+
it('should handle validation errors gracefully', async () => {
|
|
449
|
+
const loadTokensSpy = vi.spyOn(tokenProvider, 'loadTokens').mockRejectedValue(
|
|
450
|
+
new Error('File not found')
|
|
451
|
+
);
|
|
452
|
+
|
|
453
|
+
const result = await validateThemeSync(
|
|
454
|
+
'./nonexistent.json',
|
|
455
|
+
'./nonexistent.ts',
|
|
456
|
+
'css-in-js'
|
|
457
|
+
);
|
|
458
|
+
|
|
459
|
+
expect(result.valid).toBe(false);
|
|
460
|
+
expect(result.issues).toBeDefined();
|
|
461
|
+
expect(result.issues.length).toBeGreaterThan(0);
|
|
462
|
+
|
|
463
|
+
loadTokensSpy.mockRestore();
|
|
464
|
+
});
|
|
465
|
+
});
|
|
466
|
+
|
|
467
|
+
describe('Integration Scenarios', () => {
|
|
468
|
+
it('should handle empty tokens object', () => {
|
|
469
|
+
const emptyTokens = {};
|
|
470
|
+
|
|
471
|
+
const tailwind = generateTailwindTheme(emptyTokens);
|
|
472
|
+
const cssInJs = generateCssInJsTheme(emptyTokens, 'emotion');
|
|
473
|
+
const cssVars = generateCssVariables(emptyTokens);
|
|
474
|
+
|
|
475
|
+
expect(tailwind).toBeDefined();
|
|
476
|
+
expect(cssInJs).toBeDefined();
|
|
477
|
+
expect(cssVars).toBeDefined();
|
|
478
|
+
});
|
|
479
|
+
|
|
480
|
+
it('should handle partial tokens (missing categories)', () => {
|
|
481
|
+
const partialTokens = {
|
|
482
|
+
colors: { primary: '#FF0000' }
|
|
483
|
+
// Missing other categories
|
|
484
|
+
};
|
|
485
|
+
|
|
486
|
+
const tailwind = generateTailwindTheme(partialTokens);
|
|
487
|
+
|
|
488
|
+
expect(tailwind).toContain('colors:');
|
|
489
|
+
expect(tailwind).not.toContain('spacing:');
|
|
490
|
+
});
|
|
491
|
+
|
|
492
|
+
it('should preserve token naming conventions', () => {
|
|
493
|
+
const semanticTokens = {
|
|
494
|
+
colors: {
|
|
495
|
+
'button-primary': '#3B82F6',
|
|
496
|
+
'text-muted': '#6B7280',
|
|
497
|
+
'bg-surface': '#FFFFFF'
|
|
498
|
+
}
|
|
499
|
+
};
|
|
500
|
+
|
|
501
|
+
const css = generateCssVariables(semanticTokens);
|
|
502
|
+
|
|
503
|
+
expect(css).toContain('--atomix-button-primary');
|
|
504
|
+
expect(css).toContain('--atomix-text-muted');
|
|
505
|
+
});
|
|
506
|
+
});
|
|
507
|
+
});
|