@shohojdhara/atomix 0.3.12 → 0.3.14

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 (155) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/README.md +2 -0
  3. package/dist/atomix.css +101 -88
  4. package/dist/atomix.css.map +1 -1
  5. package/dist/atomix.min.css +5 -15258
  6. package/dist/atomix.min.css.map +1 -1
  7. package/dist/charts.d.ts +1 -1
  8. package/dist/charts.js +17 -19
  9. package/dist/charts.js.map +1 -1
  10. package/dist/core.d.ts +41 -11
  11. package/dist/core.js +55 -41
  12. package/dist/core.js.map +1 -1
  13. package/dist/forms.d.ts +28 -11
  14. package/dist/forms.js +25 -24
  15. package/dist/forms.js.map +1 -1
  16. package/dist/heavy.d.ts +1 -1
  17. package/dist/heavy.js +32 -25
  18. package/dist/heavy.js.map +1 -1
  19. package/dist/index.d.ts +122 -46
  20. package/dist/index.esm.js +865 -200
  21. package/dist/index.esm.js.map +1 -1
  22. package/dist/index.js +870 -204
  23. package/dist/index.js.map +1 -1
  24. package/dist/index.min.js +1 -1
  25. package/dist/index.min.js.map +1 -1
  26. package/dist/theme.d.ts +27 -2
  27. package/dist/theme.js +721 -108
  28. package/dist/theme.js.map +1 -1
  29. package/package.json +1 -1
  30. package/scripts/atomix-cli.js +610 -1111
  31. package/scripts/cli/component-generator.js +610 -0
  32. package/scripts/cli/documentation-sync.js +542 -0
  33. package/scripts/cli/interactive-init.js +84 -288
  34. package/scripts/cli/mappings.js +211 -0
  35. package/scripts/cli/migration-tools.js +95 -288
  36. package/scripts/cli/template-manager.js +107 -0
  37. package/scripts/cli/templates/README.md +123 -0
  38. package/scripts/cli/templates/composable-templates.js +149 -0
  39. package/scripts/cli/templates/config-templates.js +126 -0
  40. package/scripts/cli/templates/index.js +95 -0
  41. package/scripts/cli/templates/project-templates.js +214 -0
  42. package/scripts/cli/templates/react-templates.js +261 -0
  43. package/scripts/cli/templates/scss-templates.js +156 -0
  44. package/scripts/cli/templates/storybook-templates.js +236 -0
  45. package/scripts/cli/templates/testing-templates.js +45 -0
  46. package/scripts/cli/templates/token-templates.js +447 -0
  47. package/scripts/cli/templates/types-templates.js +133 -0
  48. package/scripts/cli/templates-original-backup.js +1655 -0
  49. package/scripts/cli/templates.js +35 -0
  50. package/scripts/cli/templates_backup.js +684 -0
  51. package/scripts/cli/theme-bridge.js +20 -14
  52. package/scripts/cli/token-manager.js +150 -77
  53. package/scripts/cli/utils.js +37 -25
  54. package/src/components/Accordion/Accordion.stories.tsx +5 -5
  55. package/src/components/Accordion/Accordion.test.tsx +57 -0
  56. package/src/components/Accordion/Accordion.tsx +4 -0
  57. package/src/components/AtomixGlass/AtomixGlassContainer.tsx +41 -44
  58. package/src/components/AtomixGlass/stories/AtomixGlass.stories.tsx +1 -1
  59. package/src/components/AtomixGlass/stories/Examples.stories.tsx +37 -37
  60. package/src/components/AtomixGlass/stories/Modes.stories.tsx +1 -2
  61. package/src/components/AtomixGlass/stories/Playground.stories.tsx +50 -51
  62. package/src/components/Avatar/Avatar.stories.tsx +26 -26
  63. package/src/components/Badge/Badge.stories.tsx +31 -31
  64. package/src/components/Badge/Badge.test.tsx +51 -0
  65. package/src/components/Badge/Badge.tsx +20 -1
  66. package/src/components/Block/Block.stories.tsx +5 -5
  67. package/src/components/Breadcrumb/Breadcrumb.stories.tsx +1 -1
  68. package/src/components/Breadcrumb/Breadcrumb.tsx +2 -2
  69. package/src/components/Button/Button.stories.tsx +13 -13
  70. package/src/components/Button/Button.tsx +4 -4
  71. package/src/components/Button/ButtonGroup.stories.tsx +2 -2
  72. package/src/components/Button/README.md +5 -0
  73. package/src/components/Callout/Callout.stories.tsx +11 -11
  74. package/src/components/Callout/Callout.test.tsx +10 -10
  75. package/src/components/Callout/Callout.tsx +7 -7
  76. package/src/components/Callout/README.md +9 -8
  77. package/src/components/Card/Card.tsx +2 -2
  78. package/src/components/Chart/Chart.stories.tsx +6 -6
  79. package/src/components/Chart/Chart.tsx +1 -1
  80. package/src/components/ColorModeToggle/ColorModeToggle.stories.tsx +1 -1
  81. package/src/components/DataTable/DataTable.tsx +14 -12
  82. package/src/components/DatePicker/DatePicker.stories.tsx +6 -6
  83. package/src/components/Dropdown/Dropdown.stories.tsx +4 -4
  84. package/src/components/Form/Checkbox.stories.tsx +3 -3
  85. package/src/components/Form/Checkbox.tsx +4 -2
  86. package/src/components/Form/Form.stories.tsx +3 -3
  87. package/src/components/Form/FormGroup.stories.tsx +1 -1
  88. package/src/components/Form/Input.stories.tsx +28 -16
  89. package/src/components/Form/Input.test.tsx +59 -0
  90. package/src/components/Form/Input.tsx +97 -95
  91. package/src/components/Form/Radio.stories.tsx +94 -94
  92. package/src/components/Form/Radio.tsx +2 -2
  93. package/src/components/Form/Select.stories.tsx +4 -4
  94. package/src/components/Form/Select.tsx +2 -2
  95. package/src/components/Form/Textarea.stories.tsx +22 -7
  96. package/src/components/Form/Textarea.test.tsx +45 -0
  97. package/src/components/Form/Textarea.tsx +88 -86
  98. package/src/components/List/List.stories.tsx +2 -2
  99. package/src/components/Modal/Modal.stories.tsx +4 -4
  100. package/src/components/Navigation/Navbar/Navbar.stories.tsx +5 -5
  101. package/src/components/Navigation/Navbar/Navbar.tsx +1 -1
  102. package/src/components/Navigation/README.md +1 -1
  103. package/src/components/Pagination/Pagination.stories.tsx +5 -2
  104. package/src/components/Pagination/Pagination.tsx +1 -1
  105. package/src/components/PhotoViewer/PhotoViewer.stories.tsx +10 -10
  106. package/src/components/Popover/Popover.stories.tsx +1 -1
  107. package/src/components/ProductReview/ProductReview.tsx +1 -1
  108. package/src/components/Progress/Progress.tsx +46 -46
  109. package/src/components/Rating/Rating.stories.tsx +4 -4
  110. package/src/components/Rating/Rating.tsx +8 -8
  111. package/src/components/Slider/Slider.stories.tsx +63 -63
  112. package/src/components/Spinner/Spinner.stories.tsx +2 -2
  113. package/src/components/Spinner/Spinner.test.tsx +35 -0
  114. package/src/components/Spinner/Spinner.tsx +9 -2
  115. package/src/components/Testimonial/Testimonial.stories.tsx +1 -1
  116. package/src/components/Toggle/Toggle.stories.tsx +32 -9
  117. package/src/components/Toggle/Toggle.test.tsx +91 -0
  118. package/src/components/Toggle/Toggle.tsx +44 -27
  119. package/src/components/Tooltip/Tooltip.tsx +1 -1
  120. package/src/layouts/Grid/Grid.stories.tsx +49 -49
  121. package/src/layouts/MasonryGrid/MasonryGrid.stories.tsx +2 -2
  122. package/src/lib/composables/useAccordion.ts +12 -3
  123. package/src/lib/composables/useBreadcrumb.ts +2 -2
  124. package/src/lib/composables/useCallout.ts +7 -7
  125. package/src/lib/composables/useNavbar.ts +1 -1
  126. package/src/lib/constants/components.ts +1 -1
  127. package/src/lib/storybook/InteractiveDemo.tsx +113 -0
  128. package/src/lib/storybook/PreviewContainer.tsx +36 -0
  129. package/src/lib/storybook/VariantsGrid.tsx +21 -0
  130. package/src/lib/storybook/index.ts +3 -0
  131. package/src/lib/theme/core/createThemeObject.ts +9 -5
  132. package/src/lib/theme/devtools/CLI.ts +155 -0
  133. package/src/lib/theme/devtools/DesignTokensCustomizer.stories.tsx +213 -0
  134. package/src/lib/theme/devtools/DesignTokensCustomizer.tsx +566 -0
  135. package/src/lib/theme/devtools/LiveEditor.tsx +2 -1
  136. package/src/lib/theme/devtools/index.ts +3 -0
  137. package/src/lib/theme/errors/errors.ts +8 -0
  138. package/src/lib/theme/runtime/ThemeProvider.tsx +117 -57
  139. package/src/lib/theme/runtime/__tests__/ThemeProvider.integration.test.tsx +305 -0
  140. package/src/lib/theme/runtime/__tests__/ThemeProvider.test.tsx +588 -0
  141. package/src/lib/theme/utils/__tests__/themeValidation.test.ts +264 -0
  142. package/src/lib/theme/utils/index.ts +1 -0
  143. package/src/lib/theme/utils/themeValidation.ts +501 -0
  144. package/src/lib/theme-tools.ts +32 -3
  145. package/src/lib/types/components.ts +81 -26
  146. package/src/lib/utils/themeNaming.ts +1 -1
  147. package/src/styles/06-components/_components.atomix-glass.scss +14 -15
  148. package/src/styles/06-components/_components.callout.scss +29 -33
  149. package/src/styles/06-components/_index.scss +1 -1
  150. package/src/styles/99-utilities/_utilities.display.scss +14 -3
  151. package/src/styles/99-utilities/_utilities.flex.scss +10 -10
  152. package/src/styles/99-utilities/_utilities.text.scss +28 -8
  153. package/scripts/cli/__tests__/cli-commands.test.js +0 -204
  154. package/scripts/cli/__tests__/utils.test.js +0 -201
  155. package/scripts/cli/__tests__/vitest.config.js +0 -26
@@ -0,0 +1,610 @@
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, access } from 'fs/promises';
9
+ import { existsSync } from 'fs';
10
+ import { join, dirname, basename } from 'path';
11
+ import ora from 'ora';
12
+ import boxen from 'boxen';
13
+
14
+ import {
15
+ validatePath,
16
+ validateComponentName,
17
+ sanitizeInput,
18
+ fileExists,
19
+ AtomixCLIError
20
+ } from './utils.js';
21
+ import { componentTemplates } from './templates.js';
22
+
23
+ /**
24
+ * Component complexity levels
25
+ */
26
+ export const COMPLEXITY_LEVELS = {
27
+ SIMPLE: {
28
+ name: 'simple',
29
+ description: 'Basic presentational component with minimal state',
30
+ features: [
31
+ 'Props interface',
32
+ 'Basic styling',
33
+ 'No internal state',
34
+ 'No complex interactions'
35
+ ],
36
+ template: 'simple'
37
+ },
38
+ MEDIUM: {
39
+ name: 'medium',
40
+ description: 'Component with some state and interactions',
41
+ features: [
42
+ 'Props interface',
43
+ 'Internal state management',
44
+ 'Event handlers',
45
+ 'Composable hook',
46
+ 'Full styling system'
47
+ ],
48
+ template: 'medium'
49
+ },
50
+ COMPLEX: {
51
+ name: 'complex',
52
+ description: 'Advanced component with rich functionality',
53
+ features: [
54
+ 'All medium features',
55
+ 'Context integration',
56
+ 'Advanced interactions',
57
+ 'Accessibility features',
58
+ 'Validation logic',
59
+ 'Animation support'
60
+ ],
61
+ template: 'complex'
62
+ }
63
+ };
64
+
65
+ /**
66
+ * Component feature options
67
+ */
68
+ export const COMPONENT_FEATURES = {
69
+ TYPESCRIPT: {
70
+ name: 'typescript',
71
+ description: 'Include TypeScript definitions',
72
+ default: true
73
+ },
74
+ STORYBOOK: {
75
+ name: 'storybook',
76
+ description: 'Generate Storybook stories',
77
+ default: true
78
+ },
79
+ TESTS: {
80
+ name: 'tests',
81
+ description: 'Include unit tests',
82
+ default: false
83
+ },
84
+ HOOK: {
85
+ name: 'hook',
86
+ description: 'Create composable hook',
87
+ default: true
88
+ },
89
+ STYLES: {
90
+ name: 'styles',
91
+ description: 'Generate SCSS styles (ITCSS architecture)',
92
+ default: true
93
+ },
94
+ ACCESSIBILITY: {
95
+ name: 'accessibility',
96
+ description: 'Include accessibility features (ARIA, keyboard)',
97
+ default: true
98
+ },
99
+ ANIMATIONS: {
100
+ name: 'animations',
101
+ description: 'Add animation support',
102
+ default: false
103
+ },
104
+ CONTEXT: {
105
+ name: 'context',
106
+ description: 'Support context integration',
107
+ default: false
108
+ }
109
+ };
110
+
111
+ /**
112
+ * Simple component template
113
+ */
114
+ function getSimpleTemplate(name) {
115
+ return `import React from 'react';
116
+ import type { ${name}Props } from './${name}.types';
117
+
118
+ /**
119
+ * ${name} - Simple Presentational Component
120
+ *
121
+ * A basic component for rendering content with minimal overhead.
122
+ */
123
+ export const ${name} = ({ children, className, ...props }: ${name}Props) => {
124
+ return (
125
+ <div className={\`c-${name.toLowerCase()} \${className || ''}\`} {...props}>
126
+ {children}
127
+ </div>
128
+ );
129
+ };
130
+
131
+ ${name}.displayName = '${name}';
132
+ `;
133
+ }
134
+
135
+ /**
136
+ * Medium component template
137
+ */
138
+ function getMediumTemplate(name) {
139
+ return `import React, { useState, useCallback } from 'react';
140
+ import { cn } from '../../lib/utils';
141
+ import type { ${name}Props, ${name}State } from './${name}.types';
142
+ import { use${name} } from '../../lib/composables/use${name}';
143
+
144
+ /**
145
+ * ${name} - Component with State and Interactions
146
+ *
147
+ * A component with internal state management and event handling.
148
+ */
149
+ export const ${name} = React.forwardRef<HTMLDivElement, ${name}Props>(
150
+ ({
151
+ children,
152
+ className,
153
+ defaultOpen = false,
154
+ onOpenChange,
155
+ disabled = false,
156
+ ...props
157
+ }, ref) => {
158
+ const {
159
+ isOpen,
160
+ toggle,
161
+ setIsOpen
162
+ } = use${name}({
163
+ defaultOpen,
164
+ onOpenChange
165
+ });
166
+
167
+ const handleKeyDown = useCallback((e: React.KeyboardEvent) => {
168
+ if (disabled) return;
169
+
170
+ switch (e.key) {
171
+ case 'Enter':
172
+ case ' ':
173
+ e.preventDefault();
174
+ toggle();
175
+ break;
176
+ case 'Escape':
177
+ setIsOpen(false);
178
+ break;
179
+ }
180
+ }, [disabled, toggle, setIsOpen]);
181
+
182
+ return (
183
+ <div
184
+ ref={ref}
185
+ className={cn(
186
+ 'c-' + '${name.toLowerCase()}',
187
+ isOpen && 'is-open',
188
+ disabled && 'is-disabled',
189
+ className
190
+ )}
191
+ data-state={isOpen ? 'open' : 'closed'}
192
+ data-disabled={disabled}
193
+ onKeyDown={handleKeyDown}
194
+ tabIndex={disabled ? -1 : 0}
195
+ role="button"
196
+ aria-pressed={isOpen}
197
+ aria-disabled={disabled}
198
+ {...props}
199
+ >
200
+ {children}
201
+ </div>
202
+ );
203
+ }
204
+ );
205
+
206
+ ${name}.displayName = '${name}';
207
+ `;
208
+ }
209
+
210
+ /**
211
+ * Complex component template
212
+ */
213
+ function getComplexTemplate(name) {
214
+ return `import React, { useState, useCallback, useEffect, useRef } from 'react';
215
+ import { cn } from '../../lib/utils';
216
+ import type { ${name}Props, ${name}ContextValue } from './${name}.types';
217
+ import { use${name} } from '../../lib/composables/use${name}';
218
+ import { ${name}Context } from './${name}.context';
219
+
220
+ /**
221
+ * ${name} - Advanced Component with Context and Animations
222
+ *
223
+ * A feature-rich component with context integration, animations,
224
+ * accessibility, and validation.
225
+ */
226
+
227
+ // Root Component
228
+ export const ${name} = React.forwardRef<HTMLDivElement, ${name}Props>(
229
+ ({
230
+ children,
231
+ className,
232
+ defaultOpen = false,
233
+ onOpenChange,
234
+ disabled = false,
235
+ required = false,
236
+ validate,
237
+ animation = true,
238
+ ...props
239
+ }, ref) => {
240
+ const [isOpen, setIsOpen] = useState(defaultOpen);
241
+ const [isValid, setIsValid] = useState(true);
242
+ const [validationMessage, setValidationMessage] = useState('');
243
+ const elementRef = useRef<HTMLDivElement>(null);
244
+
245
+ const toggle = useCallback(() => {
246
+ if (disabled) return;
247
+
248
+ const newState = !isOpen;
249
+
250
+ // Validation before opening
251
+ if (newState && validate) {
252
+ const result = validate();
253
+ setIsValid(result.valid);
254
+ setValidationMessage(result.message || '');
255
+
256
+ if (!result.valid) {
257
+ return;
258
+ }
259
+ }
260
+
261
+ setIsOpen(newState);
262
+ onOpenChange?.(newState);
263
+ }, [isOpen, disabled, validate, onOpenChange]);
264
+
265
+ const contextValue: ${name}ContextValue = React.useMemo(() => ({
266
+ isOpen,
267
+ toggle,
268
+ setIsOpen,
269
+ disabled,
270
+ required,
271
+ isValid,
272
+ validationMessage
273
+ }), [isOpen, toggle, disabled, required, isValid, validationMessage]);
274
+
275
+ // Focus management
276
+ useEffect(() => {
277
+ if (isOpen && elementRef.current) {
278
+ elementRef.current.focus();
279
+ }
280
+ }, [isOpen]);
281
+
282
+ // Keyboard navigation
283
+ const handleKeyDown = useCallback((e: React.KeyboardEvent) => {
284
+ if (disabled) return;
285
+
286
+ switch (e.key) {
287
+ case 'Enter':
288
+ case ' ':
289
+ e.preventDefault();
290
+ toggle();
291
+ break;
292
+ case 'Escape':
293
+ setIsOpen(false);
294
+ break;
295
+ case 'ArrowDown':
296
+ if (isOpen) e.preventDefault();
297
+ break;
298
+ }
299
+ }, [disabled, isOpen, toggle]);
300
+
301
+ return (
302
+ <${name}Context.Provider value={contextValue}>
303
+ <div
304
+ ref={(node) => {
305
+ elementRef.current = node;
306
+ if (typeof ref === 'function') ref(node);
307
+ else if (ref) ref.current = node;
308
+ }}
309
+ className={cn(
310
+ 'c-${name.toLowerCase()}',
311
+ isOpen && 'is-open',
312
+ disabled && 'is-disabled',
313
+ !isValid && 'is-invalid',
314
+ animation && 'has-animation',
315
+ className
316
+ )}
317
+ data-state={isOpen ? 'open' : 'closed'}
318
+ data-disabled={disabled}
319
+ data-valid={isValid}
320
+ onKeyDown={handleKeyDown}
321
+ role="region"
322
+ aria-expanded={isOpen}
323
+ aria-disabled={disabled}
324
+ aria-invalid={!isValid}
325
+ aria-describedby={!isValid ? \`${name.toLowerCase()}-error\` : undefined}
326
+ {...props}
327
+ >
328
+ {children}
329
+
330
+ {!isValid && validationMessage && (
331
+ <div
332
+ id={\`${name.toLowerCase()}-error\`}
333
+ className="c-${name.toLowerCase()}__error"
334
+ role="alert"
335
+ aria-live="polite"
336
+ >
337
+ {validationMessage}
338
+ </div>
339
+ )}
340
+ </div>
341
+ </${name}Context.Provider>
342
+ );
343
+ }
344
+ );
345
+
346
+ ${name}.displayName = '${name}';
347
+ `;
348
+ }
349
+
350
+ /**
351
+ * Generate component based on complexity level
352
+ */
353
+ export function generateComponentByComplexity(name, complexity, options = {}) {
354
+ const level = COMPLEXITY_LEVELS[complexity.toUpperCase()];
355
+
356
+ if (!level) {
357
+ throw new AtomixCLIError(
358
+ `Unknown complexity level: ${complexity}`,
359
+ 'INVALID_COMPLEXITY',
360
+ [
361
+ 'Valid levels: simple, medium, complex',
362
+ 'Example: atomix generate component MyButton --complexity medium'
363
+ ]
364
+ );
365
+ }
366
+
367
+ switch (level.template) {
368
+ case 'simple':
369
+ return getSimpleTemplate(name);
370
+ case 'medium':
371
+ return getMediumTemplate(name);
372
+ case 'complex':
373
+ return getComplexTemplate(name);
374
+ default:
375
+ return componentTemplates.react.component(name, options);
376
+ }
377
+ }
378
+
379
+ /**
380
+ * Interactive component generation
381
+ */
382
+ export async function interactiveComponentGeneration() {
383
+ console.log(boxen(
384
+ chalk.bold.cyan('🎨 Interactive Component Generator\n\n') +
385
+ chalk.gray('Let\'s create a new component for your design system'),
386
+ {
387
+ padding: 1,
388
+ margin: 1,
389
+ borderStyle: 'round',
390
+ borderColor: 'cyan'
391
+ }
392
+ ));
393
+
394
+ // Step 1: Component name
395
+ const { componentName } = await inquirer.prompt([
396
+ {
397
+ type: 'input',
398
+ name: 'componentName',
399
+ message: 'What is your component name?',
400
+ validate: (input) => {
401
+ const validation = validateComponentName(input);
402
+ return validation.isValid || validation.error;
403
+ },
404
+ filter: (input) => sanitizeInput(input)
405
+ }
406
+ ]);
407
+
408
+ // Step 2: Complexity level
409
+ const { complexity } = await inquirer.prompt([
410
+ {
411
+ type: 'list',
412
+ name: 'complexity',
413
+ message: 'What is the complexity level?',
414
+ choices: Object.values(COMPLEXITY_LEVELS).map(level => ({
415
+ name: `${chalk.bold(level.name.charAt(0).toUpperCase() + level.name.slice(1))} - ${level.description}`,
416
+ value: level.name,
417
+ short: level.name
418
+ })),
419
+ default: 'medium'
420
+ }
421
+ ]);
422
+
423
+ // Step 3: Features
424
+ const { features } = await inquirer.prompt([
425
+ {
426
+ type: 'checkbox',
427
+ name: 'features',
428
+ message: 'Select features to include:',
429
+ choices: Object.values(COMPONENT_FEATURES).map(feature => ({
430
+ name: `${feature.description}`,
431
+ value: feature.name,
432
+ checked: feature.default
433
+ }))
434
+ }
435
+ ]);
436
+
437
+ // Step 4: Output path
438
+ const { outputPath } = await inquirer.prompt([
439
+ {
440
+ type: 'input',
441
+ name: 'outputPath',
442
+ message: 'Output directory:',
443
+ default: './src/components',
444
+ validate: (input) => {
445
+ const validation = validatePath(sanitizeInput(input));
446
+ return validation.isValid || validation.error;
447
+ },
448
+ filter: (input) => sanitizeInput(input)
449
+ }
450
+ ]);
451
+
452
+ return {
453
+ name: componentName,
454
+ complexity,
455
+ features,
456
+ outputPath
457
+ };
458
+ }
459
+
460
+ /**
461
+ * Validate generated component against guidelines
462
+ */
463
+ export async function validateGeneratedComponent(name, componentPath) {
464
+ const issues = [];
465
+ const warnings = [];
466
+
467
+ // Check component file
468
+ const componentFile = join(componentPath, `${name}.tsx`);
469
+ if (existsSync(componentFile)) {
470
+ const content = await readFile(componentFile, 'utf8');
471
+
472
+ // Check for proper TypeScript types
473
+ if (!content.includes('export interface') && !content.includes('export type')) {
474
+ issues.push({
475
+ file: `${name}.tsx`,
476
+ issue: 'Missing TypeScript type definitions',
477
+ suggestion: 'Add proper type interfaces for component props'
478
+ });
479
+ }
480
+
481
+ // Check for displayName
482
+ if (!content.includes('displayName')) {
483
+ warnings.push({
484
+ file: `${name}.tsx`,
485
+ issue: 'Missing displayName property',
486
+ suggestion: 'Add Component.displayName = "ComponentName" for better debugging'
487
+ });
488
+ }
489
+
490
+ // Check for proper documentation
491
+ if (!content.includes('/**') && !content.includes('*')) {
492
+ warnings.push({
493
+ file: `${name}.tsx`,
494
+ issue: 'Missing JSDoc comments',
495
+ suggestion: 'Add JSDoc comments to document the component API'
496
+ });
497
+ }
498
+
499
+ // Check for accessibility features
500
+ if (!content.includes('aria-') && !content.includes('role=')) {
501
+ warnings.push({
502
+ file: `${name}.tsx`,
503
+ issue: 'Missing accessibility attributes',
504
+ suggestion: 'Add ARIA attributes and roles for better accessibility'
505
+ });
506
+ }
507
+ } else {
508
+ issues.push({
509
+ file: `${name}.tsx`,
510
+ issue: 'Component file not found',
511
+ suggestion: 'Ensure the component was generated successfully'
512
+ });
513
+ }
514
+
515
+ // Check for SCSS file
516
+ const scssFile = join(componentPath, `${name}.scss`);
517
+ if (existsSync(componentPath)) {
518
+ // Check in styles directory
519
+ const globalScss = join(process.cwd(), 'src/styles/06-components', `_components.${name.toLowerCase()}.scss`);
520
+ if (!existsSync(globalScss)) {
521
+ warnings.push({
522
+ file: 'styles',
523
+ issue: 'SCSS styles file not found',
524
+ suggestion: 'Generate SCSS styles following ITCSS architecture'
525
+ });
526
+ }
527
+ }
528
+
529
+ // Check for Storybook story
530
+ const storyFile = join(componentPath, `${name}.stories.tsx`);
531
+ if (!existsSync(storyFile)) {
532
+ warnings.push({
533
+ file: `${name}.stories.tsx`,
534
+ issue: 'Storybook story not found',
535
+ suggestion: 'Generate Storybook stories for component documentation'
536
+ });
537
+ } else {
538
+ const storyContent = await readFile(storyFile, 'utf8');
539
+
540
+ if (!storyContent.includes('autodocs')) {
541
+ warnings.push({
542
+ file: `${name}.stories.tsx`,
543
+ issue: 'Missing autodocs tag',
544
+ suggestion: 'Add tags: [\'autodocs\'] for automatic documentation'
545
+ });
546
+ }
547
+
548
+ if (!storyContent.match(/export const (Default|Primary|Basic)/)) {
549
+ warnings.push({
550
+ file: `${name}.stories.tsx`,
551
+ issue: 'Missing default story',
552
+ suggestion: 'Add a default story to showcase the basic component usage'
553
+ });
554
+ }
555
+ }
556
+
557
+ return {
558
+ valid: issues.length === 0,
559
+ issues,
560
+ warnings
561
+ };
562
+ }
563
+
564
+ /**
565
+ * Display validation report
566
+ */
567
+ export function displayValidationReport(result) {
568
+ if (result.valid && result.warnings.length === 0) {
569
+ console.log(boxen(
570
+ chalk.bold.green('✅ Component validation passed!\n\n') +
571
+ chalk.gray('Your component follows all Atomix design system guidelines.'),
572
+ {
573
+ padding: 1,
574
+ margin: 1,
575
+ borderStyle: 'round',
576
+ borderColor: 'green'
577
+ }
578
+ ));
579
+ return true;
580
+ }
581
+
582
+ if (result.issues.length > 0) {
583
+ console.log(chalk.bold.red(`\n❌ Found ${result.issues.length} issue(s):\n`));
584
+ result.issues.forEach((issue, index) => {
585
+ console.log(chalk.red(` ${index + 1}. ${issue.file}`));
586
+ console.log(chalk.gray(` Issue: ${issue.issue}`));
587
+ console.log(chalk.yellow(` Suggestion: ${issue.suggestion}\n`));
588
+ });
589
+ }
590
+
591
+ if (result.warnings.length > 0) {
592
+ console.log(chalk.bold.yellow(`\n⚠️ Found ${result.warnings.length} warning(s):\n`));
593
+ result.warnings.forEach((warning, index) => {
594
+ console.log(chalk.yellow(` ${index + 1}. ${warning.file}`));
595
+ console.log(chalk.gray(` Warning: ${warning.warning}`));
596
+ console.log(chalk.cyan(` Suggestion: ${warning.suggestion}\n`));
597
+ });
598
+ }
599
+
600
+ return false;
601
+ }
602
+
603
+ export default {
604
+ COMPLEXITY_LEVELS,
605
+ COMPONENT_FEATURES,
606
+ generateComponentByComplexity,
607
+ interactiveComponentGeneration,
608
+ validateGeneratedComponent,
609
+ displayValidationReport
610
+ };