@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
@@ -19,6 +19,7 @@
19
19
  @forward 'utilities.visibility';
20
20
  @forward 'utilities.visually-hidden';
21
21
  @forward 'utilities.z-index';
22
+ @forward 'utilities.touch-target';
22
23
 
23
24
  // Forward the main utilities generator
24
25
  @forward 'utilities';
@@ -9,7 +9,7 @@ $utilities-text: (
9
9
  'font-size': (
10
10
  rfs: true,
11
11
  property: font-size,
12
- class: u-fs,
12
+ class: u-text,
13
13
  values: map.merge(
14
14
  color-maps.$font-sizes-extended,
15
15
  (
@@ -0,0 +1,36 @@
1
+ @use '../02-tools/tools.breakpoints' as *;
2
+ @use '../01-settings/settings.config' as config;
3
+
4
+ /**
5
+ * Touch Target Optimization
6
+ * Ensures interactive elements have a minimum touch target size of 44px
7
+ * as per WCAG 2.1 Success Criterion 2.5.5 (Target Size).
8
+ */
9
+
10
+ .u-touch-target {
11
+ @include media-breakpoint-down(md) {
12
+ min-height: 44px;
13
+ min-width: 44px;
14
+ display: inline-flex;
15
+ align-items: center;
16
+ justify-content: center;
17
+ }
18
+ }
19
+
20
+ // Apply to common interactive elements automatically on mobile
21
+ @include media-breakpoint-down(md) {
22
+ .c-btn--sm,
23
+ .c-form-check-input,
24
+ .c-form-select-sm,
25
+ .c-form-control-sm {
26
+ min-height: 44px;
27
+ min-width: 44px;
28
+ }
29
+
30
+ // Checkbox/Radio labels should also be part of the touch target
31
+ .c-form-check {
32
+ min-height: 44px;
33
+ display: flex;
34
+ align-items: center;
35
+ }
36
+ }
@@ -1,564 +0,0 @@
1
- /**
2
- * Enhanced Component Generator
3
- * Supports template variants, interactive generation, and validation
4
- */
5
-
6
- import inquirer from 'inquirer';
7
- import chalk from 'chalk';
8
- import { readFile, writeFile, mkdir } from 'fs/promises';
9
- import { existsSync } from 'fs';
10
- import { join } from 'path';
11
- import ora from 'ora';
12
- import boxen from 'boxen';
13
-
14
- import {
15
- validatePath,
16
- validateComponentName,
17
- sanitizeInput,
18
- AtomixCLIError
19
- } from './utils.js';
20
- import { componentTemplates } from './templates.js';
21
-
22
- /**
23
- * Component complexity levels
24
- */
25
- export const COMPLEXITY_LEVELS = {
26
- SIMPLE: {
27
- name: 'simple',
28
- description: 'Basic presentational component with minimal state',
29
- features: [
30
- 'Props interface',
31
- 'Basic styling',
32
- 'No internal state',
33
- 'No complex interactions'
34
- ],
35
- template: 'simple'
36
- },
37
- MEDIUM: {
38
- name: 'medium',
39
- description: 'Component with some state and interactions',
40
- features: [
41
- 'Props interface',
42
- 'Internal state management',
43
- 'Event handlers',
44
- 'Composable hook',
45
- 'Full styling system'
46
- ],
47
- template: 'medium'
48
- },
49
- COMPLEX: {
50
- name: 'complex',
51
- description: 'Advanced component with rich functionality',
52
- features: [
53
- 'All medium features',
54
- 'Context integration',
55
- 'Advanced interactions',
56
- 'Accessibility features',
57
- 'Validation logic',
58
- 'Animation support'
59
- ],
60
- template: 'complex'
61
- }
62
- };
63
-
64
- /**
65
- * Component feature options
66
- */
67
- export const COMPONENT_FEATURES = {
68
- TYPESCRIPT: {
69
- name: 'typescript',
70
- description: 'Include TypeScript definitions',
71
- default: true
72
- },
73
- STORYBOOK: {
74
- name: 'storybook',
75
- description: 'Generate Storybook stories',
76
- default: true
77
- },
78
- TESTS: {
79
- name: 'tests',
80
- description: 'Include unit tests',
81
- default: false
82
- },
83
- HOOK: {
84
- name: 'hook',
85
- description: 'Create composable hook',
86
- default: true
87
- },
88
- STYLES: {
89
- name: 'styles',
90
- description: 'Generate SCSS styles (ITCSS architecture)',
91
- default: true
92
- },
93
- ACCESSIBILITY: {
94
- name: 'accessibility',
95
- description: 'Include accessibility features (ARIA, keyboard)',
96
- default: true
97
- },
98
- ANIMATIONS: {
99
- name: 'animations',
100
- description: 'Add animation support',
101
- default: false
102
- },
103
- CONTEXT: {
104
- name: 'context',
105
- description: 'Support context integration',
106
- default: false
107
- }
108
- };
109
-
110
- /**
111
- * Simple component template
112
- */
113
- function getSimpleTemplate(name) {
114
- return componentTemplates.react.simple(name);
115
- }
116
-
117
- /**
118
- * Medium component template
119
- */
120
- function getMediumTemplate(name) {
121
- return componentTemplates.react.medium(name);
122
- }
123
-
124
- /**
125
- * Complex component template
126
- */
127
- function getComplexTemplate(name) {
128
- return componentTemplates.react.complex(name);
129
- }
130
-
131
- /**
132
- * Generate component based on complexity level
133
- */
134
- export function generateComponentByComplexity(name, complexity, options = {}) {
135
- const level = COMPLEXITY_LEVELS[complexity.toUpperCase()];
136
-
137
- if (!level) {
138
- throw new AtomixCLIError(
139
- `Unknown complexity level: ${complexity}`,
140
- 'INVALID_COMPLEXITY',
141
- [
142
- 'Valid levels: simple, medium, complex',
143
- 'Example: atomix generate component MyButton --complexity medium'
144
- ]
145
- );
146
- }
147
-
148
- switch (level.template) {
149
- case 'simple':
150
- return getSimpleTemplate(name);
151
- case 'medium':
152
- return getMediumTemplate(name);
153
- case 'complex':
154
- return getComplexTemplate(name);
155
- default:
156
- return componentTemplates.react.component(name, options);
157
- }
158
- }
159
-
160
- /**
161
- * Interactive component generation
162
- */
163
- export async function interactiveComponentGeneration() {
164
- try {
165
- console.log(boxen(
166
- chalk.bold.cyan('🎨 Interactive Component Generator\n\n') +
167
- chalk.gray('Let\'s create a new component for your design system'),
168
- {
169
- padding: 1,
170
- margin: 1,
171
- borderStyle: 'round',
172
- borderColor: 'cyan'
173
- }
174
- ));
175
-
176
- // Step 1: Component name
177
- const { componentName } = await inquirer.prompt([
178
- {
179
- type: 'input',
180
- name: 'componentName',
181
- message: 'What is your component name?',
182
- validate: (input) => {
183
- const validation = validateComponentName(input);
184
- return validation.isValid || validation.error;
185
- },
186
- filter: (input) => sanitizeInput(input)
187
- }
188
- ]);
189
-
190
- // Step 2: Complexity level
191
- const { complexity } = await inquirer.prompt([
192
- {
193
- type: 'list',
194
- name: 'complexity',
195
- message: 'What is the complexity level?',
196
- choices: Object.values(COMPLEXITY_LEVELS).map(level => ({
197
- name: `${chalk.bold(level.name.charAt(0).toUpperCase() + level.name.slice(1))} - ${level.description}`,
198
- value: level.name,
199
- short: level.name
200
- })),
201
- default: 'medium'
202
- }
203
- ]);
204
-
205
- // Step 3: Features
206
- const { features } = await inquirer.prompt([
207
- {
208
- type: 'checkbox',
209
- name: 'features',
210
- message: 'Select features to include:',
211
- choices: Object.values(COMPONENT_FEATURES).map(feature => ({
212
- name: `${feature.description}`,
213
- value: feature.name,
214
- checked: feature.default
215
- }))
216
- }
217
- ]);
218
-
219
- // Step 4: Output path
220
- const { outputPath } = await inquirer.prompt([
221
- {
222
- type: 'input',
223
- name: 'outputPath',
224
- message: 'Output directory:',
225
- default: './src/components',
226
- validate: (input) => {
227
- const validation = validatePath(sanitizeInput(input));
228
- return validation.isValid || validation.error;
229
- },
230
- filter: (input) => sanitizeInput(input)
231
- }
232
- ]);
233
-
234
- return {
235
- name: componentName,
236
- complexity,
237
- features,
238
- outputPath
239
- };
240
- } catch (error) {
241
- if (error.message === 'User cancelled') {
242
- return null;
243
- }
244
- throw error;
245
- }
246
- }
247
-
248
- /**
249
- * Generate all component files
250
- */
251
- export async function generateComponentFiles(name, options = {}) {
252
- const {
253
- outputPath = './src/components',
254
- complexity = 'medium',
255
- features = [],
256
- spinner
257
- } = options;
258
-
259
- const componentPath = join(outputPath, name);
260
-
261
- // Create component directory
262
- await mkdir(componentPath, { recursive: true });
263
-
264
- // Determine if we need to generate a composable hook
265
- const hasComposable = features.includes('HOOK') || COMPONENT_FEATURES.HOOK.default;
266
-
267
- // Determine if we need glass effect
268
- const hasGlass = features.includes('STYLES') || COMPONENT_FEATURES.STYLES.default;
269
-
270
- // Generate main component file
271
- const componentContent = generateComponentByComplexity(name, complexity, {
272
- hasComposable,
273
- hasGlass
274
- });
275
-
276
- await writeFile(
277
- join(componentPath, `${name}.tsx`),
278
- componentContent
279
- );
280
-
281
- if (spinner) spinner.text = `Generating ${name}.tsx...`;
282
-
283
- // Generate index file
284
- const indexContent = componentTemplates.react.index(name);
285
- await writeFile(
286
- join(componentPath, 'index.ts'),
287
- indexContent
288
- );
289
-
290
- if (spinner) spinner.text = `Generating index.ts...`;
291
-
292
- // Generate storybook file if feature is enabled
293
- if (features.includes('storybook') || COMPONENT_FEATURES.STORYBOOK.default) {
294
- const storyContent = componentTemplates.react.story(name);
295
- await writeFile(
296
- join(componentPath, `${name}.stories.tsx`),
297
- storyContent
298
- );
299
-
300
- if (spinner) spinner.text = `Generating ${name}.stories.tsx...`;
301
- }
302
-
303
- // Generate test file if feature is enabled
304
- if (features.includes('tests') || COMPONENT_FEATURES.TESTS.default) {
305
- const testContent = componentTemplates.react.test(name);
306
- await writeFile(
307
- join(componentPath, `${name}.test.tsx`),
308
- testContent
309
- );
310
-
311
- if (spinner) spinner.text = `Generating ${name}.test.tsx...`;
312
- }
313
-
314
- // Generate composable hook if feature is enabled
315
- if (hasComposable) {
316
- const composableDir = join(outputPath, '..', 'lib', 'composables');
317
- await mkdir(composableDir, { recursive: true });
318
-
319
- const composableContent = componentTemplates.composable.useHook(name);
320
- await writeFile(
321
- join(composableDir, `use${name}.ts`),
322
- composableContent
323
- );
324
-
325
- if (spinner) spinner.text = `Generating use${name}.ts...`;
326
- }
327
-
328
- // Generate constants and types if TypeScript feature is enabled
329
- if (features.includes('typescript') || COMPONENT_FEATURES.TYPESCRIPT.default) {
330
- // Note: In a real implementation, we'd append to existing files rather than overwrite
331
- // This is simplified for demonstration purposes
332
- const constantsContent = componentTemplates.types.constants(name);
333
- const typesContent = componentTemplates.types.types(name);
334
-
335
- // In a real scenario, these would be appended to existing files
336
- // For now, we'll just show what would be added
337
- console.log(chalk.blue(`\n💡 Remember to add these to the appropriate files:`));
338
- console.log(chalk.gray(`Constants to src/lib/constants/components.ts:`));
339
- console.log(chalk.gray(constantsContent.substring(0, 100) + '...'));
340
- console.log(chalk.gray(`Types to src/lib/types/components.ts:`));
341
- console.log(chalk.gray(typesContent.substring(0, 100) + '...'));
342
- }
343
-
344
- // Generate SCSS files if styles feature is enabled
345
- if (features.includes('styles') || COMPONENT_FEATURES.STYLES.default) {
346
- const stylesBasePath = join(outputPath, '..', 'styles');
347
-
348
- // Create settings file
349
- const settingsPath = join(stylesBasePath, '01-settings');
350
- await mkdir(settingsPath, { recursive: true });
351
-
352
- const settingsContent = componentTemplates.scss.settings(name);
353
- await writeFile(
354
- join(settingsPath, `_settings.${name.toLowerCase()}.scss`),
355
- settingsContent
356
- );
357
-
358
- if (spinner) spinner.text = `Generating _settings.${name.toLowerCase()}.scss...`;
359
-
360
- // Create components file
361
- const componentsPath = join(stylesBasePath, '06-components');
362
- await mkdir(componentsPath, { recursive: true });
363
-
364
- const componentStylesContent = componentTemplates.scss.component(name);
365
- await writeFile(
366
- join(componentsPath, `_components.${name.toLowerCase()}.scss`),
367
- componentStylesContent
368
- );
369
-
370
- if (spinner) spinner.text = `Generating _components.${name.toLowerCase()}.scss...`;
371
- }
372
-
373
- return componentPath;
374
- }
375
-
376
- /**
377
- * Generate a new component
378
- */
379
- export async function generateComponent(options) {
380
- const { name, complexity, features, outputPath } = options;
381
-
382
- const spinner = ora({
383
- text: chalk.blue('Generating component...'),
384
- spinner: 'clock'
385
- });
386
-
387
- try {
388
- spinner.start();
389
-
390
- const componentPath = await generateComponentFiles(name, {
391
- complexity,
392
- features,
393
- outputPath,
394
- spinner
395
- });
396
-
397
- spinner.succeed(chalk.green(`Component ${name} generated successfully!\n${chalk.gray('Location:')} ${componentPath}`));
398
-
399
- return componentPath;
400
- } catch (error) {
401
- spinner.fail(chalk.red(`Failed to generate component: ${error.message}`));
402
- throw error;
403
- }
404
- }
405
-
406
- /**
407
- * Validate generated component against guidelines
408
- */
409
- export async function validateGeneratedComponent(name, componentPath) {
410
- const issues = [];
411
- const warnings = [];
412
-
413
- // Check component file
414
- const componentFile = join(componentPath, `${name}.tsx`);
415
- if (existsSync(componentFile)) {
416
- const content = await readFile(componentFile, 'utf8');
417
-
418
- // Check for proper TypeScript types
419
- if (!content.includes('export interface') && !content.includes('export type')) {
420
- issues.push({
421
- file: `${name}.tsx`,
422
- issue: 'Missing TypeScript type definitions',
423
- suggestion: 'Add proper type interfaces for component props'
424
- });
425
- }
426
-
427
- // Check for displayName
428
- if (!content.includes('displayName')) {
429
- warnings.push({
430
- file: `${name}.tsx`,
431
- issue: 'Missing displayName property',
432
- suggestion: 'Add Component.displayName = "ComponentName" for better debugging'
433
- });
434
- }
435
-
436
- // Check for proper documentation
437
- if (!content.includes('/**') && !content.includes('*')) {
438
- warnings.push({
439
- file: `${name}.tsx`,
440
- issue: 'Missing JSDoc comments',
441
- suggestion: 'Add JSDoc comments to document the component API'
442
- });
443
- }
444
-
445
- // Check for accessibility features
446
- if (!content.includes('aria-') && !content.includes('role=')) {
447
- warnings.push({
448
- file: `${name}.tsx`,
449
- issue: 'Missing accessibility attributes',
450
- suggestion: 'Add ARIA attributes and roles for better accessibility'
451
- });
452
- }
453
-
454
- // Check for hardcoded styles
455
- if (content.match(/#[0-9a-fA-F]{3,6}|rgb\(|rgba\(/)) {
456
- warnings.push({
457
- file: `${name}.tsx`,
458
- issue: 'Using hardcoded values instead of design tokens',
459
- suggestion: 'Use design tokens (e.g., var(--color-primary)) or utility classes'
460
- });
461
- }
462
- } else {
463
- issues.push({
464
- file: `${name}.tsx`,
465
- issue: 'Component file not found',
466
- suggestion: 'Ensure the component was generated successfully'
467
- });
468
- }
469
-
470
- // Check for SCSS file
471
- if (existsSync(componentPath)) {
472
- // Check in styles directory
473
- const globalScss = join(process.cwd(), 'src/styles/06-components', `_components.${name.toLowerCase()}.scss`);
474
- if (!existsSync(globalScss)) {
475
- warnings.push({
476
- file: 'styles',
477
- issue: 'SCSS styles file not found',
478
- suggestion: 'Generate SCSS styles following ITCSS architecture'
479
- });
480
- }
481
- }
482
-
483
- // Check for Storybook story
484
- const storyFile = join(componentPath, `${name}.stories.tsx`);
485
- if (!existsSync(storyFile)) {
486
- warnings.push({
487
- file: `${name}.stories.tsx`,
488
- issue: 'Storybook story not found',
489
- suggestion: 'Generate Storybook stories for component documentation'
490
- });
491
- } else {
492
- const storyContent = await readFile(storyFile, 'utf8');
493
-
494
- if (!storyContent.includes('autodocs')) {
495
- warnings.push({
496
- file: `${name}.stories.tsx`,
497
- issue: 'Missing autodocs tag',
498
- suggestion: 'Add tags: [\'autodocs\'] for automatic documentation'
499
- });
500
- }
501
-
502
- if (!storyContent.match(/export const (Default|Primary|Basic)/)) {
503
- warnings.push({
504
- file: `${name}.stories.tsx`,
505
- issue: 'Missing default story',
506
- suggestion: 'Add a default story to showcase the basic component usage'
507
- });
508
- }
509
- }
510
-
511
- return {
512
- valid: issues.length === 0,
513
- issues,
514
- warnings
515
- };
516
- }
517
-
518
- /**
519
- * Display validation report
520
- */
521
- export function displayValidationReport(result) {
522
- if (result.valid && result.warnings.length === 0) {
523
- console.log(boxen(
524
- chalk.bold.green('✅ Component validation passed!\n\n') +
525
- chalk.gray('Your component follows all Atomix design system guidelines.'),
526
- {
527
- padding: 1,
528
- margin: 1,
529
- borderStyle: 'round',
530
- borderColor: 'green'
531
- }
532
- ));
533
- return true;
534
- }
535
-
536
- if (result.issues.length > 0) {
537
- console.log(chalk.bold.red(`\n❌ Found ${result.issues.length} issue(s):\n`));
538
- result.issues.forEach((issue, index) => {
539
- console.log(chalk.red(` ${index + 1}. ${issue.file}`));
540
- console.log(chalk.gray(` Issue: ${issue.issue}`));
541
- console.log(chalk.yellow(` Suggestion: ${issue.suggestion}\n`));
542
- });
543
- }
544
-
545
- if (result.warnings.length > 0) {
546
- console.log(chalk.bold.yellow(`\n⚠️ Found ${result.warnings.length} warning(s):\n`));
547
- result.warnings.forEach((warning, index) => {
548
- console.log(chalk.yellow(` ${index + 1}. ${warning.file}`));
549
- console.log(chalk.gray(` Warning: ${warning.issue}`));
550
- console.log(chalk.cyan(` Suggestion: ${warning.suggestion}\n`));
551
- });
552
- }
553
-
554
- return false;
555
- }
556
-
557
- export default {
558
- COMPLEXITY_LEVELS,
559
- COMPONENT_FEATURES,
560
- generateComponentByComplexity,
561
- interactiveComponentGeneration,
562
- validateGeneratedComponent,
563
- displayValidationReport
564
- };