@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,443 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Token Provider System
|
|
3
|
+
* Manages design token imports from multiple sources (Figma, Style Dictionary, W3C DTCG)
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { existsSync } from 'fs';
|
|
7
|
+
import { join } from 'path';
|
|
8
|
+
import { filesystem } from '../filesystem.js';
|
|
9
|
+
import { logger } from '../../utils/logger.js';
|
|
10
|
+
import { AtomixCLIError } from '../../utils/error.js';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Token format types supported by Atomix
|
|
14
|
+
*/
|
|
15
|
+
export const TOKEN_FORMATS = {
|
|
16
|
+
FIGMA: 'figma',
|
|
17
|
+
STYLE_DICTIONARY: 'style-dictionary',
|
|
18
|
+
W3C_DTCG: 'w3c-dtcg',
|
|
19
|
+
JSON: 'json',
|
|
20
|
+
CSS: 'css'
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Token categories for organization
|
|
25
|
+
*/
|
|
26
|
+
export const TOKEN_CATEGORIES = {
|
|
27
|
+
COLOR: 'color',
|
|
28
|
+
SPACING: 'spacing',
|
|
29
|
+
TYPOGRAPHY: 'typography',
|
|
30
|
+
SHADOW: 'shadow',
|
|
31
|
+
RADIUS: 'radius',
|
|
32
|
+
ANIMATION: 'animation',
|
|
33
|
+
BREAKPOINT: 'breakpoint',
|
|
34
|
+
Z_INDEX: 'zIndex'
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Token Provider class for managing design tokens
|
|
39
|
+
*/
|
|
40
|
+
export class TokenProvider {
|
|
41
|
+
constructor(options = {}) {
|
|
42
|
+
this.tokenPath = options.tokenPath || './design-tokens';
|
|
43
|
+
this.format = options.format || TOKEN_FORMATS.JSON;
|
|
44
|
+
this.tokens = {};
|
|
45
|
+
this.sources = new Map();
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Load tokens from a file path
|
|
50
|
+
* @param {string} filePath - Path to token file
|
|
51
|
+
* @param {Object} options - Load options
|
|
52
|
+
* @returns {Promise<Object>} Loaded tokens
|
|
53
|
+
*/
|
|
54
|
+
async loadTokens(filePath, options = {}) {
|
|
55
|
+
const absolutePath = join(process.cwd(), filePath);
|
|
56
|
+
|
|
57
|
+
if (!existsSync(absolutePath)) {
|
|
58
|
+
throw new AtomixCLIError(
|
|
59
|
+
`Token file not found: ${absolutePath}`,
|
|
60
|
+
'TOKEN_FILE_NOT_FOUND',
|
|
61
|
+
[
|
|
62
|
+
'Verify the token file path is correct',
|
|
63
|
+
'Run `atomix init` to create default token structure',
|
|
64
|
+
'Check file permissions'
|
|
65
|
+
]
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const ext = filePath.split('.').pop().toLowerCase();
|
|
70
|
+
let loadedTokens = {};
|
|
71
|
+
|
|
72
|
+
try {
|
|
73
|
+
switch (ext) {
|
|
74
|
+
case 'json':
|
|
75
|
+
loadedTokens = await this.loadJSONTokens(absolutePath);
|
|
76
|
+
break;
|
|
77
|
+
case 'css':
|
|
78
|
+
case 'scss':
|
|
79
|
+
loadedTokens = await this.loadCSSTokens(absolutePath);
|
|
80
|
+
break;
|
|
81
|
+
default:
|
|
82
|
+
throw new Error(`Unsupported token file format: ${ext}`);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Validate loaded tokens
|
|
86
|
+
this.validateTokenStructure(loadedTokens);
|
|
87
|
+
|
|
88
|
+
// Merge with existing tokens
|
|
89
|
+
this.tokens = this.mergeTokens(this.tokens, loadedTokens);
|
|
90
|
+
|
|
91
|
+
// Track source
|
|
92
|
+
this.sources.set(filePath, {
|
|
93
|
+
path: absolutePath,
|
|
94
|
+
format: this.detectFormat(ext),
|
|
95
|
+
loadedAt: new Date()
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
logger.debug(`Loaded ${Object.keys(loadedTokens).length} tokens from ${filePath}`);
|
|
99
|
+
|
|
100
|
+
return loadedTokens;
|
|
101
|
+
} catch (error) {
|
|
102
|
+
if (error instanceof AtomixCLIError) {
|
|
103
|
+
throw error;
|
|
104
|
+
}
|
|
105
|
+
throw new AtomixCLIError(
|
|
106
|
+
`Failed to load tokens from ${filePath}: ${error.message}`,
|
|
107
|
+
'TOKEN_LOAD_FAILED',
|
|
108
|
+
[
|
|
109
|
+
'Check token file syntax is valid JSON/CSS',
|
|
110
|
+
'Ensure file is not corrupted',
|
|
111
|
+
'Try validating tokens with `atomix validate tokens`'
|
|
112
|
+
]
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Load JSON format tokens
|
|
119
|
+
* @private
|
|
120
|
+
*/
|
|
121
|
+
async loadJSONTokens(filePath) {
|
|
122
|
+
const content = await filesystem.readFile(filePath, 'utf8');
|
|
123
|
+
const data = JSON.parse(content);
|
|
124
|
+
|
|
125
|
+
// Handle different JSON structures
|
|
126
|
+
if (data.$schema || data.tokens) {
|
|
127
|
+
// W3C DTCG format
|
|
128
|
+
return this.parseW3CDTCG(data);
|
|
129
|
+
} else if (data.props || data.properties) {
|
|
130
|
+
// Style Dictionary format
|
|
131
|
+
return this.parseStyleDictionary(data);
|
|
132
|
+
} else {
|
|
133
|
+
// Simple flat structure
|
|
134
|
+
return this.parseSimpleJSON(data);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Load CSS/SCSS format tokens
|
|
140
|
+
* @private
|
|
141
|
+
*/
|
|
142
|
+
async loadCSSTokens(filePath) {
|
|
143
|
+
const content = await filesystem.readFile(filePath, 'utf8');
|
|
144
|
+
return this.parseCSSVariables(content);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Parse W3C DTCG format tokens
|
|
149
|
+
* @private
|
|
150
|
+
*/
|
|
151
|
+
parseW3CDTCG(data) {
|
|
152
|
+
const tokens = {};
|
|
153
|
+
|
|
154
|
+
if (data.tokens) {
|
|
155
|
+
for (const [category, categoryData] of Object.entries(data.tokens)) {
|
|
156
|
+
tokens[category] = this.flattenTokenGroup(categoryData);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
return tokens;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Parse Style Dictionary format tokens
|
|
165
|
+
* @private
|
|
166
|
+
*/
|
|
167
|
+
parseStyleDictionary(data) {
|
|
168
|
+
const tokens = {};
|
|
169
|
+
const props = data.props || data.properties;
|
|
170
|
+
|
|
171
|
+
for (const [category, categoryData] of Object.entries(props)) {
|
|
172
|
+
tokens[category] = this.flattenTokenGroup(categoryData);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
return tokens;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Parse simple JSON tokens
|
|
180
|
+
* @private
|
|
181
|
+
*/
|
|
182
|
+
parseSimpleJSON(data) {
|
|
183
|
+
const tokens = {};
|
|
184
|
+
|
|
185
|
+
for (const [key, value] of Object.entries(data)) {
|
|
186
|
+
if (typeof value === 'object' && value !== null) {
|
|
187
|
+
tokens[key] = this.flattenTokenGroup(value);
|
|
188
|
+
} else {
|
|
189
|
+
tokens['custom'] = tokens['custom'] || {};
|
|
190
|
+
tokens['custom'][key] = value;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
return tokens;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Parse CSS custom properties
|
|
199
|
+
* @private
|
|
200
|
+
*/
|
|
201
|
+
parseCSSVariables(cssContent) {
|
|
202
|
+
const tokens = {};
|
|
203
|
+
const cssVarRegex = /--([a-zA-Z0-9-]+):\s*([^;]+);/g;
|
|
204
|
+
let match;
|
|
205
|
+
|
|
206
|
+
while ((match = cssVarRegex.exec(cssContent)) !== null) {
|
|
207
|
+
const [, name, value] = match;
|
|
208
|
+
const category = this.categorizeToken(name);
|
|
209
|
+
|
|
210
|
+
tokens[category] = tokens[category] || {};
|
|
211
|
+
tokens[category][name] = {
|
|
212
|
+
value: value.trim(),
|
|
213
|
+
type: this.inferTokenType(value.trim())
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
return tokens;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Flatten nested token groups
|
|
222
|
+
* @private
|
|
223
|
+
*/
|
|
224
|
+
flattenTokenGroup(group, prefix = '') {
|
|
225
|
+
const flattened = {};
|
|
226
|
+
|
|
227
|
+
for (const [key, value] of Object.entries(group)) {
|
|
228
|
+
const tokenKey = prefix ? `${prefix}-${key}` : key;
|
|
229
|
+
|
|
230
|
+
if (typeof value === 'object' && value !== null && !value.value) {
|
|
231
|
+
// Nested group
|
|
232
|
+
Object.assign(flattened, this.flattenTokenGroup(value, tokenKey));
|
|
233
|
+
} else {
|
|
234
|
+
// Actual token
|
|
235
|
+
flattened[tokenKey] = typeof value === 'object' ? value : { value };
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
return flattened;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Categorize token by name
|
|
244
|
+
* @private
|
|
245
|
+
*/
|
|
246
|
+
categorizeToken(name) {
|
|
247
|
+
const nameLower = name.toLowerCase();
|
|
248
|
+
|
|
249
|
+
if (nameLower.includes('color') || nameLower.includes('bg') || nameLower.includes('text')) {
|
|
250
|
+
return TOKEN_CATEGORIES.COLOR;
|
|
251
|
+
} else if (nameLower.includes('space') || nameLower.includes('margin') || nameLower.includes('padding')) {
|
|
252
|
+
return TOKEN_CATEGORIES.SPACING;
|
|
253
|
+
} else if (nameLower.includes('font') || nameLower.includes('type') || nameLower.includes('text')) {
|
|
254
|
+
return TOKEN_CATEGORIES.TYPOGRAPHY;
|
|
255
|
+
} else if (nameLower.includes('shadow') || nameLower.includes('elevation')) {
|
|
256
|
+
return TOKEN_CATEGORIES.SHADOW;
|
|
257
|
+
} else if (nameLower.includes('radius') || nameLower.includes('corner') || nameLower.includes('rounded')) {
|
|
258
|
+
return TOKEN_CATEGORIES.RADIUS;
|
|
259
|
+
} else if (nameLower.includes('duration') || nameLower.includes('transition') || nameLower.includes('animation')) {
|
|
260
|
+
return TOKEN_CATEGORIES.ANIMATION;
|
|
261
|
+
} else if (nameLower.includes('breakpoint') || nameLower.includes('screen')) {
|
|
262
|
+
return TOKEN_CATEGORIES.BREAKPOINT;
|
|
263
|
+
} else if (nameLower.includes('z-index') || nameLower.includes('layer')) {
|
|
264
|
+
return TOKEN_CATEGORIES.Z_INDEX;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
return 'other';
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Infer token type from value
|
|
272
|
+
* @private
|
|
273
|
+
*/
|
|
274
|
+
inferTokenType(value) {
|
|
275
|
+
if (typeof value === 'number') return 'number';
|
|
276
|
+
if (value.startsWith('#') || value.startsWith('rgb') || value.startsWith('hsl')) return 'color';
|
|
277
|
+
if (value.includes('px') || value.includes('rem') || value.includes('em')) return 'dimension';
|
|
278
|
+
if (value.includes('ms') || value.includes('s')) return 'duration';
|
|
279
|
+
if (value.match(/^\d+$/)) return 'number';
|
|
280
|
+
return 'string';
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Detect token format from extension
|
|
285
|
+
* @private
|
|
286
|
+
*/
|
|
287
|
+
detectFormat(ext) {
|
|
288
|
+
const formatMap = {
|
|
289
|
+
'json': TOKEN_FORMATS.JSON,
|
|
290
|
+
'css': TOKEN_FORMATS.CSS,
|
|
291
|
+
'scss': TOKEN_FORMATS.CSS,
|
|
292
|
+
};
|
|
293
|
+
return formatMap[ext] || TOKEN_FORMATS.JSON;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* Validate token structure
|
|
298
|
+
* @private
|
|
299
|
+
*/
|
|
300
|
+
validateTokenStructure(tokens) {
|
|
301
|
+
const issues = [];
|
|
302
|
+
|
|
303
|
+
for (const [category, categoryTokens] of Object.entries(tokens)) {
|
|
304
|
+
if (typeof categoryTokens !== 'object') {
|
|
305
|
+
issues.push(`Category "${category}" must be an object`);
|
|
306
|
+
continue;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
for (const [tokenName, tokenData] of Object.entries(categoryTokens)) {
|
|
310
|
+
if (!tokenData.value && typeof tokenData !== 'string' && typeof tokenData !== 'number') {
|
|
311
|
+
issues.push(`Token "${category}.${tokenName}" missing required "value" property`);
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
if (issues.length > 0) {
|
|
317
|
+
throw new AtomixCLIError(
|
|
318
|
+
`Token validation failed:\n${issues.join('\n')}`,
|
|
319
|
+
'TOKEN_VALIDATION_FAILED',
|
|
320
|
+
['Fix the listed token structure issues']
|
|
321
|
+
);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* Merge multiple token sets
|
|
327
|
+
* @private
|
|
328
|
+
*/
|
|
329
|
+
mergeTokens(existing, newTokens) {
|
|
330
|
+
const merged = { ...existing };
|
|
331
|
+
|
|
332
|
+
for (const [category, categoryTokens] of Object.entries(newTokens)) {
|
|
333
|
+
merged[category] = {
|
|
334
|
+
...(merged[category] || {}),
|
|
335
|
+
...categoryTokens
|
|
336
|
+
};
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
return merged;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
/**
|
|
343
|
+
* Get token by name
|
|
344
|
+
* @param {string} name - Token name (e.g., "color.primary.500")
|
|
345
|
+
* @returns {Object|null} Token data or null if not found
|
|
346
|
+
*/
|
|
347
|
+
getToken(name) {
|
|
348
|
+
const parts = name.split('.');
|
|
349
|
+
let current = this.tokens;
|
|
350
|
+
|
|
351
|
+
for (const part of parts) {
|
|
352
|
+
if (!current[part]) return null;
|
|
353
|
+
current = current[part];
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
return typeof current === 'object' ? current : { value: current };
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
/**
|
|
360
|
+
* Get all tokens in a category
|
|
361
|
+
* @param {string} category - Token category
|
|
362
|
+
* @returns {Object} Category tokens
|
|
363
|
+
*/
|
|
364
|
+
getCategoryTokens(category) {
|
|
365
|
+
return this.tokens[category] || {};
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
/**
|
|
369
|
+
* Get all loaded tokens
|
|
370
|
+
* @returns {Object} All tokens
|
|
371
|
+
*/
|
|
372
|
+
getAllTokens() {
|
|
373
|
+
return this.tokens;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
/**
|
|
377
|
+
* Export tokens to specified format
|
|
378
|
+
* @param {string} format - Export format
|
|
379
|
+
* @param {Object} options - Export options
|
|
380
|
+
* @returns {string} Exported tokens
|
|
381
|
+
*/
|
|
382
|
+
exportTokens(format, options = {}) {
|
|
383
|
+
switch (format) {
|
|
384
|
+
case TOKEN_FORMATS.JSON:
|
|
385
|
+
return this.exportToJSON(options);
|
|
386
|
+
case TOKEN_FORMATS.CSS:
|
|
387
|
+
return this.exportToCSS(options);
|
|
388
|
+
case TOKEN_FORMATS.W3C_DTCG:
|
|
389
|
+
return this.exportToW3CDTCG(options);
|
|
390
|
+
default:
|
|
391
|
+
throw new Error(`Unsupported export format: ${format}`);
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
/**
|
|
396
|
+
* Export to JSON format
|
|
397
|
+
* @private
|
|
398
|
+
*/
|
|
399
|
+
exportToJSON(options = {}) {
|
|
400
|
+
const { pretty = true } = options;
|
|
401
|
+
return pretty
|
|
402
|
+
? JSON.stringify(this.tokens, null, 2)
|
|
403
|
+
: JSON.stringify(this.tokens);
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
/**
|
|
407
|
+
* Export to CSS custom properties
|
|
408
|
+
* @private
|
|
409
|
+
*/
|
|
410
|
+
exportToCSS(options = {}) {
|
|
411
|
+
const { selector = ':root', prefix = '' } = options;
|
|
412
|
+
const lines = [`${selector} {`];
|
|
413
|
+
|
|
414
|
+
for (const [category, categoryTokens] of Object.entries(this.tokens)) {
|
|
415
|
+
for (const [tokenName, tokenData] of Object.entries(categoryTokens)) {
|
|
416
|
+
const value = typeof tokenData === 'object' ? tokenData.value : tokenData;
|
|
417
|
+
const varName = prefix ? `${prefix}-${category}-${tokenName}` : `${category}-${tokenName}`;
|
|
418
|
+
lines.push(` --${varName}: ${value};`);
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
lines.push('}');
|
|
423
|
+
return lines.join('\n');
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
/**
|
|
427
|
+
* Export to W3C DTCG format
|
|
428
|
+
* @private
|
|
429
|
+
*/
|
|
430
|
+
exportToW3CDTCG(options = {}) {
|
|
431
|
+
return {
|
|
432
|
+
$schema: 'https://design-tokens.org/schema.json',
|
|
433
|
+
tokens: this.tokens
|
|
434
|
+
};
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
/**
|
|
439
|
+
* Create a singleton token provider instance
|
|
440
|
+
*/
|
|
441
|
+
export const tokenProvider = new TokenProvider();
|
|
442
|
+
|
|
443
|
+
export default tokenProvider;
|