@shohojdhara/atomix 0.3.14 → 0.3.15

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 (173) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/build-tools/EXAMPLES.md +372 -0
  3. package/build-tools/README.md +242 -0
  4. package/build-tools/__tests__/error-handler.test.js +230 -0
  5. package/build-tools/__tests__/index.test.js +141 -0
  6. package/build-tools/__tests__/rollup-plugin.test.js +194 -0
  7. package/build-tools/__tests__/utils.test.js +161 -0
  8. package/build-tools/__tests__/vite-plugin.test.js +129 -0
  9. package/build-tools/__tests__/webpack-loader.test.js +190 -0
  10. package/build-tools/error-handler.js +308 -0
  11. package/build-tools/index.d.ts +43 -0
  12. package/build-tools/index.js +88 -0
  13. package/build-tools/package.json +67 -0
  14. package/build-tools/rollup-plugin.js +236 -0
  15. package/build-tools/types.d.ts +163 -0
  16. package/build-tools/utils.js +203 -0
  17. package/build-tools/vite-plugin.js +161 -0
  18. package/build-tools/webpack-loader.js +123 -0
  19. package/dist/atomix.css +203 -90
  20. package/dist/atomix.css.map +1 -1
  21. package/dist/atomix.min.css +3 -3
  22. package/dist/atomix.min.css.map +1 -1
  23. package/dist/build-tools/EXAMPLES.md +372 -0
  24. package/dist/build-tools/README.md +242 -0
  25. package/dist/build-tools/__tests__/error-handler.test.js +230 -0
  26. package/dist/build-tools/__tests__/index.test.js +141 -0
  27. package/dist/build-tools/__tests__/rollup-plugin.test.js +194 -0
  28. package/dist/build-tools/__tests__/utils.test.js +161 -0
  29. package/dist/build-tools/__tests__/vite-plugin.test.js +129 -0
  30. package/dist/build-tools/__tests__/webpack-loader.test.js +190 -0
  31. package/dist/build-tools/error-handler.js +308 -0
  32. package/dist/build-tools/index.d.ts +43 -0
  33. package/dist/build-tools/index.js +88 -0
  34. package/dist/build-tools/package.json +67 -0
  35. package/dist/build-tools/rollup-plugin.js +236 -0
  36. package/dist/build-tools/types.d.ts +163 -0
  37. package/dist/build-tools/utils.js +203 -0
  38. package/dist/build-tools/vite-plugin.js +161 -0
  39. package/dist/build-tools/webpack-loader.js +123 -0
  40. package/dist/charts.d.ts +1 -1
  41. package/dist/charts.js +86 -57
  42. package/dist/charts.js.map +1 -1
  43. package/dist/core.d.ts +1 -1
  44. package/dist/core.js +136 -112
  45. package/dist/core.js.map +1 -1
  46. package/dist/forms.d.ts +2 -5
  47. package/dist/forms.js +140 -128
  48. package/dist/forms.js.map +1 -1
  49. package/dist/heavy.d.ts +1 -1
  50. package/dist/heavy.js +136 -112
  51. package/dist/heavy.js.map +1 -1
  52. package/dist/index.d.ts +9 -61
  53. package/dist/index.esm.js +237 -286
  54. package/dist/index.esm.js.map +1 -1
  55. package/dist/index.js +250 -299
  56. package/dist/index.js.map +1 -1
  57. package/dist/index.min.js +1 -1
  58. package/dist/index.min.js.map +1 -1
  59. package/package.json +23 -8
  60. package/scripts/atomix-cli.js +170 -73
  61. package/scripts/cli/__tests__/README.md +81 -0
  62. package/scripts/cli/__tests__/basic.test.js +115 -0
  63. package/scripts/cli/__tests__/component-generator.test.js +332 -0
  64. package/scripts/cli/__tests__/integration.test.js +327 -0
  65. package/scripts/cli/__tests__/test-setup.js +133 -0
  66. package/scripts/cli/__tests__/token-manager.test.js +251 -0
  67. package/scripts/cli/__tests__/utils.test.js +161 -0
  68. package/scripts/cli/component-generator.js +253 -299
  69. package/scripts/cli/dependency-checker.js +355 -0
  70. package/scripts/cli/interactive-init.js +46 -5
  71. package/scripts/cli/template-manager.js +0 -2
  72. package/scripts/cli/templates/common-templates.js +636 -0
  73. package/scripts/cli/templates/composable-templates.js +148 -126
  74. package/scripts/cli/templates/index.js +23 -16
  75. package/scripts/cli/templates/project-templates.js +151 -23
  76. package/scripts/cli/templates/react-templates.js +280 -210
  77. package/scripts/cli/templates/scss-templates.js +90 -91
  78. package/scripts/cli/templates/testing-templates.js +206 -27
  79. package/scripts/cli/templates/testing-utils.js +278 -0
  80. package/scripts/cli/templates/types-templates.js +70 -56
  81. package/scripts/cli/theme-bridge.js +8 -2
  82. package/scripts/cli/token-manager.js +318 -206
  83. package/scripts/cli/utils.js +0 -1
  84. package/src/components/Accordion/Accordion.stories.tsx +369 -870
  85. package/src/components/AtomixGlass/AtomixGlass.tsx +80 -39
  86. package/src/components/AtomixGlass/AtomixGlassContainer.tsx +103 -81
  87. package/src/components/AtomixGlass/__snapshots__/AtomixGlass.test.tsx.snap +8 -7
  88. package/src/components/AtomixGlass/glass-utils.ts +2 -2
  89. package/src/components/AtomixGlass/shader-utils.ts +5 -0
  90. package/src/components/AtomixGlass/stories/Customization.stories.tsx +131 -0
  91. package/src/components/AtomixGlass/stories/Examples.stories.tsx +2957 -2853
  92. package/src/components/AtomixGlass/stories/Modes.stories.tsx +1 -1
  93. package/src/components/AtomixGlass/stories/Overview.stories.tsx +348 -0
  94. package/src/components/AtomixGlass/stories/Performance.stories.tsx +103 -0
  95. package/src/components/AtomixGlass/stories/Playground.stories.tsx +50 -35
  96. package/src/components/AtomixGlass/stories/{ShaderVariants.stories.tsx → Shaders.stories.tsx} +1 -1
  97. package/src/components/AtomixGlass/stories/shared-components.tsx +90 -190
  98. package/src/components/Avatar/Avatar.stories.tsx +213 -1
  99. package/src/components/Badge/Badge.stories.tsx +121 -362
  100. package/src/components/Block/Block.stories.tsx +21 -12
  101. package/src/components/Breadcrumb/Breadcrumb.stories.tsx +141 -23
  102. package/src/components/Button/Button.stories.tsx +463 -1126
  103. package/src/components/Button/Button.test.tsx +107 -0
  104. package/src/components/Button/Button.tsx +46 -50
  105. package/src/components/Button/ButtonGroup.stories.tsx +373 -217
  106. package/src/components/Callout/Callout.stories.tsx +289 -634
  107. package/src/components/Card/Card.stories.tsx +248 -68
  108. package/src/components/Chart/Chart.stories.tsx +150 -8
  109. package/src/components/ColorModeToggle/ColorModeToggle.stories.tsx +151 -69
  110. package/src/components/Countdown/Countdown.stories.tsx +115 -8
  111. package/src/components/DataTable/DataTable.stories.tsx +346 -146
  112. package/src/components/DatePicker/DatePicker.stories.tsx +325 -1066
  113. package/src/components/Dropdown/Dropdown.stories.tsx +153 -33
  114. package/src/components/EdgePanel/EdgePanel.stories.tsx +230 -21
  115. package/src/components/Footer/Footer.stories.tsx +392 -328
  116. package/src/components/Form/Checkbox.stories.tsx +140 -6
  117. package/src/components/Form/Checkbox.test.tsx +63 -0
  118. package/src/components/Form/Checkbox.tsx +87 -51
  119. package/src/components/Form/Form.stories.tsx +119 -20
  120. package/src/components/Form/FormGroup.stories.tsx +127 -4
  121. package/src/components/Form/Radio.stories.tsx +140 -5
  122. package/src/components/Form/Select.stories.tsx +140 -8
  123. package/src/components/Form/Textarea.stories.tsx +149 -6
  124. package/src/components/Hero/Hero.stories.tsx +333 -32
  125. package/src/components/List/List.stories.tsx +141 -3
  126. package/src/components/Modal/Modal.stories.tsx +181 -42
  127. package/src/components/Popover/Popover.stories.tsx +448 -98
  128. package/src/components/Progress/Progress.stories.tsx +167 -5
  129. package/src/components/River/River.stories.tsx +1 -1
  130. package/src/components/SectionIntro/SectionIntro.stories.tsx +240 -48
  131. package/src/components/Spinner/Spinner.stories.tsx +102 -8
  132. package/src/components/Steps/Steps.stories.tsx +172 -43
  133. package/src/components/Tabs/Tabs.stories.tsx +136 -10
  134. package/src/components/Testimonial/Testimonial.stories.tsx +120 -3
  135. package/src/components/Todo/Todo.stories.tsx +198 -9
  136. package/src/components/Toggle/Toggle.stories.tsx +126 -39
  137. package/src/components/Tooltip/Tooltip.stories.tsx +194 -104
  138. package/src/components/Upload/Upload.stories.tsx +113 -24
  139. package/src/lib/README.md +2 -2
  140. package/src/lib/__tests__/theme-tools.test.ts +193 -0
  141. package/src/lib/composables/index.ts +2 -2
  142. package/src/lib/composables/useAtomixGlass.ts +28 -56
  143. package/src/lib/composables/useChartExport.ts +2 -7
  144. package/src/lib/composables/useDataTable.ts +46 -29
  145. package/src/lib/constants/components.ts +9 -32
  146. package/src/lib/theme/devtools/CLI.ts +1 -1
  147. package/src/lib/types/components.ts +1 -1
  148. package/src/lib/utils/__tests__/csv.test.ts +45 -0
  149. package/src/lib/utils/csv.ts +17 -0
  150. package/src/lib/utils/dataTableExport.ts +1 -10
  151. package/src/styles/01-settings/_index.scss +2 -1
  152. package/src/styles/01-settings/_settings.accordion.scss +28 -7
  153. package/src/styles/01-settings/_settings.colors.scss +11 -11
  154. package/src/styles/01-settings/_settings.typography.scss +5 -5
  155. package/src/styles/02-tools/_tools.utility-api.scss +14 -0
  156. package/src/styles/06-components/_components.accordion.scss +56 -14
  157. package/src/styles/06-components/_components.checkbox.scss +23 -17
  158. package/src/styles/99-utilities/_index.scss +2 -0
  159. package/src/styles/99-utilities/_utilities.scss +3 -1
  160. package/src/styles/99-utilities/_utilities.text-gradient.scss +45 -0
  161. package/themes/dark-complementary/README.md +98 -0
  162. package/themes/dark-complementary/index.scss +158 -0
  163. package/themes/default-light/README.md +81 -0
  164. package/themes/default-light/index.scss +154 -0
  165. package/themes/high-contrast/README.md +105 -0
  166. package/themes/high-contrast/index.scss +172 -0
  167. package/themes/test-theme/README.md +38 -0
  168. package/themes/test-theme/index.scss +47 -0
  169. package/scripts/cli/templates-original-backup.js +0 -1655
  170. package/scripts/cli/templates_backup.js +0 -684
  171. package/src/components/AtomixGlass/stories/AtomixGlass.stories.tsx +0 -1438
  172. package/src/lib/composables/useButton.ts +0 -93
  173. package/src/lib/composables/useCheckbox.ts +0 -70
@@ -5,9 +5,9 @@
5
5
 
6
6
  import inquirer from 'inquirer';
7
7
  import chalk from 'chalk';
8
- import { readFile, writeFile, mkdir, access } from 'fs/promises';
8
+ import { readFile, writeFile, mkdir } from 'fs/promises';
9
9
  import { existsSync } from 'fs';
10
- import { join, dirname, basename } from 'path';
10
+ import { join } from 'path';
11
11
  import ora from 'ora';
12
12
  import boxen from 'boxen';
13
13
 
@@ -15,7 +15,6 @@ import {
15
15
  validatePath,
16
16
  validateComponentName,
17
17
  sanitizeInput,
18
- fileExists,
19
18
  AtomixCLIError
20
19
  } from './utils.js';
21
20
  import { componentTemplates } from './templates.js';
@@ -112,239 +111,21 @@ export const COMPONENT_FEATURES = {
112
111
  * Simple component template
113
112
  */
114
113
  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
- `;
114
+ return componentTemplates.react.simple(name);
133
115
  }
134
116
 
135
117
  /**
136
118
  * Medium component template
137
119
  */
138
120
  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
- `;
121
+ return componentTemplates.react.medium(name);
208
122
  }
209
123
 
210
124
  /**
211
125
  * Complex component template
212
126
  */
213
127
  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
- `;
128
+ return componentTemplates.react.complex(name);
348
129
  }
349
130
 
350
131
  /**
@@ -380,81 +161,246 @@ export function generateComponentByComplexity(name, complexity, options = {}) {
380
161
  * Interactive component generation
381
162
  */
382
163
  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)
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;
449
243
  }
450
- ]);
244
+ throw error;
245
+ }
246
+ }
451
247
 
452
- return {
453
- name: componentName,
454
- complexity,
455
- features,
456
- outputPath
457
- };
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
+ }
458
404
  }
459
405
 
460
406
  /**
@@ -504,6 +450,15 @@ export async function validateGeneratedComponent(name, componentPath) {
504
450
  suggestion: 'Add ARIA attributes and roles for better accessibility'
505
451
  });
506
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
+ }
507
462
  } else {
508
463
  issues.push({
509
464
  file: `${name}.tsx`,
@@ -513,7 +468,6 @@ export async function validateGeneratedComponent(name, componentPath) {
513
468
  }
514
469
 
515
470
  // Check for SCSS file
516
- const scssFile = join(componentPath, `${name}.scss`);
517
471
  if (existsSync(componentPath)) {
518
472
  // Check in styles directory
519
473
  const globalScss = join(process.cwd(), 'src/styles/06-components', `_components.${name.toLowerCase()}.scss`);
@@ -592,7 +546,7 @@ export function displayValidationReport(result) {
592
546
  console.log(chalk.bold.yellow(`\n⚠️ Found ${result.warnings.length} warning(s):\n`));
593
547
  result.warnings.forEach((warning, index) => {
594
548
  console.log(chalk.yellow(` ${index + 1}. ${warning.file}`));
595
- console.log(chalk.gray(` Warning: ${warning.warning}`));
549
+ console.log(chalk.gray(` Warning: ${warning.issue}`));
596
550
  console.log(chalk.cyan(` Suggestion: ${warning.suggestion}\n`));
597
551
  });
598
552
  }