@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,369 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Composable Hook Generator
|
|
3
|
+
* Generates React hooks following Atomix composable pattern
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { join } from 'path';
|
|
7
|
+
import { existsSync } from 'fs';
|
|
8
|
+
import { filesystem } from './filesystem.js';
|
|
9
|
+
import { logger } from '../utils/logger.js';
|
|
10
|
+
import { AtomixCLIError } from '../utils/error.js';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Generate a composable hook for a component
|
|
14
|
+
*/
|
|
15
|
+
export function generateComposableHook(componentName, options = {}) {
|
|
16
|
+
const {
|
|
17
|
+
hasVariants = true,
|
|
18
|
+
hasSizes = true,
|
|
19
|
+
hasStates = true,
|
|
20
|
+
hasCallbacks = true
|
|
21
|
+
} = options;
|
|
22
|
+
|
|
23
|
+
const hookName = `use${componentName}`;
|
|
24
|
+
const propsInterface = `${componentName}HookProps`;
|
|
25
|
+
const returnInterface = `${componentName}HookReturn`;
|
|
26
|
+
|
|
27
|
+
let imports = `import { useCallback, useMemo } from 'react';`;
|
|
28
|
+
|
|
29
|
+
if (hasCallbacks) {
|
|
30
|
+
imports += `\nimport type { ${componentName}Props } from '../../types/components';`;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return `${imports}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* ${hookName} Props Interface
|
|
37
|
+
*/
|
|
38
|
+
export interface ${propsInterface} {
|
|
39
|
+
${hasVariants ? "variant?: 'primary' | 'secondary' | 'outline';\n " : ""}${hasSizes ? "size?: 'sm' | 'md' | 'lg';\n " : ""}${hasStates ? "disabled?: boolean;\n glass?: boolean | object;\n " : ""}${hasCallbacks ? "onClick?: (event: React.MouseEvent<HTMLDivElement>) => void;\n onHover?: (event: React.MouseEvent<HTMLDivElement>) => void;\n onFocus?: (event: React.FocusEvent<HTMLDivElement>) => void;\n onBlur?: (event: React.FocusEvent<HTMLDivElement>) => void;\n onStateChange?: (state: ComponentState) => void;" : ""}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* ${hookName} Return Type
|
|
44
|
+
*/
|
|
45
|
+
export interface ${returnInterface} {
|
|
46
|
+
generateClassNames: (className?: string) => string;
|
|
47
|
+
${hasCallbacks ? "handleClick: (event: React.MouseEvent<HTMLDivElement>) => void;\n handleMouseEnter: (event: React.MouseEvent<HTMLDivElement>) => void;\n handleFocus: (event: React.FocusEvent<HTMLDivElement>) => void;\n handleBlur: (event: React.FocusEvent<HTMLDivElement>) => void;" : ""}
|
|
48
|
+
state: ComponentState;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Component State Type
|
|
53
|
+
*/
|
|
54
|
+
type ComponentState = {
|
|
55
|
+
isActive: boolean;
|
|
56
|
+
isHovered: boolean;
|
|
57
|
+
isFocused: boolean;
|
|
58
|
+
isLoading: boolean;
|
|
59
|
+
variant: string;
|
|
60
|
+
size: string;
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* ${hookName} - Composable Hook for ${componentName} Component
|
|
65
|
+
*
|
|
66
|
+
* Provides state management, class name generation, and event handlers
|
|
67
|
+
* following the Atomix composable pattern.
|
|
68
|
+
*
|
|
69
|
+
* @param props - Hook configuration props
|
|
70
|
+
* @returns Object with class names, handlers, and state
|
|
71
|
+
*
|
|
72
|
+
* @example
|
|
73
|
+
* \`\`\`tsx
|
|
74
|
+
* const { generateClassNames, handleClick, state } = use${componentName}({
|
|
75
|
+
* variant: 'primary',
|
|
76
|
+
* size: 'md',
|
|
77
|
+
* disabled: false,
|
|
78
|
+
* onClick: handleClick
|
|
79
|
+
* });
|
|
80
|
+
* \`\`\`
|
|
81
|
+
*/
|
|
82
|
+
export function ${hookName}(props: ${propsInterface}): ${returnInterface} {
|
|
83
|
+
const {
|
|
84
|
+
${hasVariants ? "variant = 'primary'," : ""}
|
|
85
|
+
${hasSizes ? "size = 'md'," : ""}
|
|
86
|
+
${hasStates ? "disabled = false,\n glass = false," : ""}
|
|
87
|
+
${hasCallbacks ? "onClick,\n onHover,\n onFocus,\n onBlur,\n onStateChange" : ""}
|
|
88
|
+
} = props;
|
|
89
|
+
|
|
90
|
+
// Internal state
|
|
91
|
+
const isHovered = false;
|
|
92
|
+
const isFocused = false;
|
|
93
|
+
const isLoading = false;
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Generate component class names
|
|
97
|
+
* Uses ThemeNaming utility for consistency
|
|
98
|
+
*/
|
|
99
|
+
const generateClassNames = useCallback(
|
|
100
|
+
(className?: string): string => {
|
|
101
|
+
const baseClasses = ['c-${componentName.toLowerCase().replace(/([A-Z])/g, '-$1').replace(/^-/, '')}'];
|
|
102
|
+
|
|
103
|
+
// Add variant class
|
|
104
|
+
${hasVariants ? "baseClasses.push(\`c-${componentName.toLowerCase().replace(/([A-Z])/g, '-$1').replace(/^-/, '')}--variant-\${variant}\`);" : ""}
|
|
105
|
+
|
|
106
|
+
// Add size class
|
|
107
|
+
${hasSizes ? "if (size !== 'md') {\n baseClasses.push(\`c-${componentName.toLowerCase().replace(/([A-Z])/g, '-$1').replace(/^-/, '')}--size-\${size}\`);\n }" : ""}
|
|
108
|
+
|
|
109
|
+
// Add state classes
|
|
110
|
+
${hasStates ? "if (disabled) {\n baseClasses.push(\`c-${componentName.toLowerCase().replace(/([A-Z])/g, '-$1').replace(/^-/, '')}--state-disabled\`);\n }\n \n if (glass) {\n baseClasses.push(\`c-${componentName.toLowerCase().replace(/([A-Z])/g, '-$1').replace(/^-/, '')}--state-glass\`);\n }" : ""}
|
|
111
|
+
|
|
112
|
+
// Add custom className
|
|
113
|
+
if (className) {
|
|
114
|
+
baseClasses.push(className);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return baseClasses.filter(Boolean).join(' ');
|
|
118
|
+
},
|
|
119
|
+
[${hasVariants ? 'variant' : ''}${hasVariants && hasSizes ? ', ' : ''}${hasSizes ? 'size' : ''}${hasStates ? ', disabled, glass' : ''}]
|
|
120
|
+
);
|
|
121
|
+
|
|
122
|
+
${hasCallbacks ? `/**
|
|
123
|
+
* Handle click event
|
|
124
|
+
*/
|
|
125
|
+
const handleClick = useCallback(
|
|
126
|
+
(event: React.MouseEvent<HTMLDivElement>) => {
|
|
127
|
+
if (disabled) {
|
|
128
|
+
event.preventDefault();
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
onClick?.(event);
|
|
132
|
+
},
|
|
133
|
+
[disabled, onClick]
|
|
134
|
+
);
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Handle mouse enter (hover)
|
|
138
|
+
*/
|
|
139
|
+
const handleMouseEnter = useCallback(
|
|
140
|
+
(event: React.MouseEvent<HTMLDivElement>) => {
|
|
141
|
+
if (!disabled) {
|
|
142
|
+
onHover?.(event);
|
|
143
|
+
}
|
|
144
|
+
},
|
|
145
|
+
[disabled, onHover]
|
|
146
|
+
);
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Handle focus
|
|
150
|
+
*/
|
|
151
|
+
const handleFocus = useCallback(
|
|
152
|
+
(event: React.FocusEvent<HTMLDivElement>) => {
|
|
153
|
+
if (!disabled) {
|
|
154
|
+
onFocus?.(event);
|
|
155
|
+
}
|
|
156
|
+
},
|
|
157
|
+
[disabled, onFocus]
|
|
158
|
+
);
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Handle blur
|
|
162
|
+
*/
|
|
163
|
+
const handleBlur = useCallback(
|
|
164
|
+
(event: React.FocusEvent<HTMLDivElement>) => {
|
|
165
|
+
if (!disabled) {
|
|
166
|
+
onBlur?.(event);
|
|
167
|
+
}
|
|
168
|
+
},
|
|
169
|
+
[disabled, onBlur]
|
|
170
|
+
);` : ""}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Component state object
|
|
174
|
+
*/
|
|
175
|
+
const state: ComponentState = useMemo(
|
|
176
|
+
() => ({
|
|
177
|
+
isActive: false,
|
|
178
|
+
isHovered,
|
|
179
|
+
isFocused,
|
|
180
|
+
isLoading,
|
|
181
|
+
variant,
|
|
182
|
+
size,
|
|
183
|
+
}),
|
|
184
|
+
[${hasVariants ? 'variant' : ''}${hasVariants && hasSizes ? ', ' : ''}${hasSizes ? 'size' : ''}]
|
|
185
|
+
);
|
|
186
|
+
|
|
187
|
+
${hasCallbacks ? `// Notify parent of state changes
|
|
188
|
+
useMemo(() => {
|
|
189
|
+
if (onStateChange) {
|
|
190
|
+
onStateChange(state);
|
|
191
|
+
}
|
|
192
|
+
}, [state, onStateChange]);` : ""}
|
|
193
|
+
|
|
194
|
+
return {
|
|
195
|
+
generateClassNames,
|
|
196
|
+
${hasCallbacks ? "handleClick,\n handleMouseEnter,\n handleFocus,\n handleBlur," : ""}
|
|
197
|
+
state,
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
export default ${hookName};
|
|
202
|
+
`;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Generate TypeScript types for the hook
|
|
207
|
+
*/
|
|
208
|
+
export function generateHookTypes(componentName) {
|
|
209
|
+
return `/**
|
|
210
|
+
* ${componentName} Hook Types
|
|
211
|
+
* Generated by Atomix CLI
|
|
212
|
+
*/
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Component State Interface
|
|
216
|
+
*/
|
|
217
|
+
export interface ComponentState {
|
|
218
|
+
isActive: boolean;
|
|
219
|
+
isHovered: boolean;
|
|
220
|
+
isFocused: boolean;
|
|
221
|
+
isLoading: boolean;
|
|
222
|
+
variant: 'primary' | 'secondary' | 'outline' | string;
|
|
223
|
+
size: 'sm' | 'md' | 'lg' | string;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Event Handler Types
|
|
228
|
+
*/
|
|
229
|
+
export type ClickHandler = (event: React.MouseEvent<HTMLDivElement>) => void;
|
|
230
|
+
export type HoverHandler = (event: React.MouseEvent<HTMLDivElement>) => void;
|
|
231
|
+
export type FocusHandler = (event: React.FocusEvent<HTMLDivElement>) => void;
|
|
232
|
+
export type BlurHandler = (event: React.FocusEvent<HTMLDivElement>) => void;
|
|
233
|
+
export type StateChangeHandler = (state: ComponentState) => void;
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* Variant Configuration
|
|
237
|
+
*/
|
|
238
|
+
export type VariantType = 'primary' | 'secondary' | 'outline' | 'ghost' | 'link';
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Size Configuration
|
|
242
|
+
*/
|
|
243
|
+
export type SizeType = 'xs' | 'sm' | 'md' | 'lg' | 'xl';
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Glass Effect Configuration
|
|
247
|
+
*/
|
|
248
|
+
export interface GlassConfig {
|
|
249
|
+
displacementScale?: number;
|
|
250
|
+
blurAmount?: number;
|
|
251
|
+
saturation?: number;
|
|
252
|
+
elasticity?: number;
|
|
253
|
+
}
|
|
254
|
+
`;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* Generate index file for composables directory
|
|
259
|
+
*/
|
|
260
|
+
export function generateComposablesIndex() {
|
|
261
|
+
return `/**
|
|
262
|
+
* Composable Hooks Index
|
|
263
|
+
* Auto-generated by Atomix CLI
|
|
264
|
+
*
|
|
265
|
+
* All component hooks are exported here for easy importing
|
|
266
|
+
*/
|
|
267
|
+
|
|
268
|
+
// Component Hooks
|
|
269
|
+
// These are auto-generated when you create components
|
|
270
|
+
// Example:
|
|
271
|
+
// export { useButton } from './useButton';
|
|
272
|
+
// export { useCard } from './useCard';
|
|
273
|
+
// export { useInput } from './useInput';
|
|
274
|
+
|
|
275
|
+
// Re-export all hooks
|
|
276
|
+
export * from './useButton';
|
|
277
|
+
export * from './useCard';
|
|
278
|
+
export * from './useInput';
|
|
279
|
+
|
|
280
|
+
// Types
|
|
281
|
+
export type { ComponentState, VariantType, SizeType } from './types';
|
|
282
|
+
`;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* Create composable hook file
|
|
287
|
+
*/
|
|
288
|
+
export async function generateHookFile(componentName, projectRoot, options = {}) {
|
|
289
|
+
const {
|
|
290
|
+
outputDir = 'src/lib/composables',
|
|
291
|
+
generateTypes = true,
|
|
292
|
+
force = false
|
|
293
|
+
} = options;
|
|
294
|
+
|
|
295
|
+
const created = [];
|
|
296
|
+
const hookName = `use${componentName}`;
|
|
297
|
+
|
|
298
|
+
try {
|
|
299
|
+
// Create composables directory
|
|
300
|
+
const composablesPath = join(projectRoot, outputDir);
|
|
301
|
+
await filesystem.createDirectory(composablesPath);
|
|
302
|
+
|
|
303
|
+
// Generate hook file
|
|
304
|
+
const hookFile = join(composablesPath, `${hookName}.ts`);
|
|
305
|
+
|
|
306
|
+
if (force || !existsSync(hookFile)) {
|
|
307
|
+
const hookContent = generateComposableHook(componentName);
|
|
308
|
+
await filesystem.writeFile(hookFile, hookContent, 'utf8');
|
|
309
|
+
created.push(`${outputDir}/${hookName}.ts`);
|
|
310
|
+
logger.debug(`Created hook: ${hookFile}`);
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
// Generate types file
|
|
314
|
+
if (generateTypes) {
|
|
315
|
+
const typesFile = join(composablesPath, 'types.ts');
|
|
316
|
+
|
|
317
|
+
if (!existsSync(typesFile)) {
|
|
318
|
+
const typesContent = generateHookTypes(componentName);
|
|
319
|
+
await filesystem.writeFile(typesFile, typesContent, 'utf8');
|
|
320
|
+
created.push(`${outputDir}/types.ts`);
|
|
321
|
+
logger.debug(`Created types: ${typesFile}`);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
// Update or create index file
|
|
326
|
+
const indexFile = join(composablesPath, 'index.ts');
|
|
327
|
+
const exportLine = `export { ${hookName} } from './${hookName}';`;
|
|
328
|
+
|
|
329
|
+
if (existsSync(indexFile)) {
|
|
330
|
+
// Append to existing index
|
|
331
|
+
const existingContent = await filesystem.readFile(indexFile, 'utf8');
|
|
332
|
+
if (existingContent && !existingContent.includes(exportLine)) {
|
|
333
|
+
const updatedContent = `${existingContent}\n${exportLine}`;
|
|
334
|
+
await filesystem.writeFile(indexFile, updatedContent, 'utf8');
|
|
335
|
+
}
|
|
336
|
+
} else {
|
|
337
|
+
// Create new index
|
|
338
|
+
const indexContent = generateComposablesIndex();
|
|
339
|
+
await filesystem.writeFile(indexFile, indexContent, 'utf8');
|
|
340
|
+
created.push(`${outputDir}/index.ts`);
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
return {
|
|
344
|
+
success: true,
|
|
345
|
+
created,
|
|
346
|
+
message: `Generated composable hook ${hookName} with ${created.length} files`
|
|
347
|
+
};
|
|
348
|
+
|
|
349
|
+
} catch (error) {
|
|
350
|
+
throw new AtomixCLIError(
|
|
351
|
+
`Failed to generate composable hook: ${error.message}`,
|
|
352
|
+
'HOOK_GENERATION_FAILED',
|
|
353
|
+
[
|
|
354
|
+
'Check you have write permissions for src/lib/composables',
|
|
355
|
+
'Verify TypeScript is configured in your project',
|
|
356
|
+
'Try running with --force flag to overwrite existing files'
|
|
357
|
+
]
|
|
358
|
+
);
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
/**
|
|
363
|
+
* Check if composable hook exists
|
|
364
|
+
*/
|
|
365
|
+
export function checkHookExists(componentName, projectRoot, outputDir = 'src/lib/composables') {
|
|
366
|
+
const hookName = `use${componentName}`;
|
|
367
|
+
const hookFile = join(projectRoot, outputDir, `${hookName}.ts`);
|
|
368
|
+
return existsSync(hookFile);
|
|
369
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Atomix CLI Hook Manager
|
|
3
|
+
* Central event bus for handling CLI lifecycle hooks
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { logger } from '../utils/logger.js';
|
|
7
|
+
|
|
8
|
+
export class HookManager {
|
|
9
|
+
constructor() {
|
|
10
|
+
this.hooks = {
|
|
11
|
+
preGenerate: [],
|
|
12
|
+
postBuild: [],
|
|
13
|
+
onValidate: []
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Registers a callback for a specific hook
|
|
19
|
+
* @param {string} hookName - Name of the hook
|
|
20
|
+
* @param {Function} callback - Async function to execute
|
|
21
|
+
*/
|
|
22
|
+
register(hookName, callback) {
|
|
23
|
+
if (!this.hooks[hookName]) {
|
|
24
|
+
logger.warn(`Attempted to register unknown hook: ${hookName}`);
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
this.hooks[hookName].push(callback);
|
|
28
|
+
logger.debug(`Registered hook: ${hookName}`);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Triggers all callbacks for a specific hook
|
|
33
|
+
* @param {string} hookName - Name of the hook
|
|
34
|
+
* @param {any} data - Data to pass to callbacks
|
|
35
|
+
* @returns {Promise<any>} - Modified data after all hooks have run
|
|
36
|
+
*/
|
|
37
|
+
async trigger(hookName, data) {
|
|
38
|
+
if (!this.hooks[hookName]) {
|
|
39
|
+
return data;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
let result = data;
|
|
43
|
+
for (const callback of this.hooks[hookName]) {
|
|
44
|
+
try {
|
|
45
|
+
const nextResult = await callback(result);
|
|
46
|
+
// Hooks can optionally return modified data
|
|
47
|
+
if (nextResult !== undefined) {
|
|
48
|
+
result = nextResult;
|
|
49
|
+
}
|
|
50
|
+
} catch (error) {
|
|
51
|
+
logger.error(`Error in hook ${hookName}: ${error.message}`);
|
|
52
|
+
if (process.env.ATOMIX_DEBUG) {
|
|
53
|
+
console.error(error);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return result;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export const hookManager = new HookManager();
|