@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,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
|
-
};
|