@shohojdhara/atomix 0.4.7 → 0.4.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (176) hide show
  1. package/atomix.config.ts +58 -1
  2. package/dist/atomix.css +172 -157
  3. package/dist/atomix.css.map +1 -1
  4. package/dist/atomix.min.css +4 -4
  5. package/dist/atomix.min.css.map +1 -1
  6. package/dist/charts.d.ts +33 -0
  7. package/dist/charts.js +1274 -164
  8. package/dist/charts.js.map +1 -1
  9. package/dist/core.d.ts +33 -10
  10. package/dist/core.js +1099 -83
  11. package/dist/core.js.map +1 -1
  12. package/dist/forms.d.ts +33 -0
  13. package/dist/forms.js +2106 -1050
  14. package/dist/forms.js.map +1 -1
  15. package/dist/heavy.d.ts +42 -1
  16. package/dist/heavy.js +1663 -638
  17. package/dist/heavy.js.map +1 -1
  18. package/dist/index.d.ts +442 -270
  19. package/dist/index.esm.js +1947 -680
  20. package/dist/index.esm.js.map +1 -1
  21. package/dist/index.js +1982 -712
  22. package/dist/index.js.map +1 -1
  23. package/dist/index.min.js +1 -1
  24. package/dist/index.min.js.map +1 -1
  25. package/package.json +6 -3
  26. package/scripts/atomix-cli.js +136 -1827
  27. package/scripts/cli/__tests__/basic.test.js +3 -2
  28. package/scripts/cli/__tests__/clean.test.js +278 -0
  29. package/scripts/cli/__tests__/component-validator.test.js +433 -0
  30. package/scripts/cli/__tests__/generator.test.js +613 -0
  31. package/scripts/cli/__tests__/glass-motion.test.js +256 -0
  32. package/scripts/cli/__tests__/integration.test.js +719 -108
  33. package/scripts/cli/__tests__/migrate.test.js +74 -0
  34. package/scripts/cli/__tests__/security.test.js +206 -0
  35. package/scripts/cli/__tests__/test-setup.js +3 -1
  36. package/scripts/cli/__tests__/theme-bridge.test.js +507 -0
  37. package/scripts/cli/__tests__/token-provider.test.js +361 -0
  38. package/scripts/cli/__tests__/utils.test.js +5 -5
  39. package/scripts/cli/commands/benchmark.js +105 -0
  40. package/scripts/cli/commands/build-theme.js +115 -0
  41. package/scripts/cli/commands/clean.js +109 -0
  42. package/scripts/cli/commands/doctor.js +88 -0
  43. package/scripts/cli/commands/generate.js +218 -0
  44. package/scripts/cli/commands/init.js +73 -0
  45. package/scripts/cli/commands/migrate.js +106 -0
  46. package/scripts/cli/commands/sync-tokens.js +206 -0
  47. package/scripts/cli/commands/theme-bridge.js +248 -0
  48. package/scripts/cli/commands/tokens.js +157 -0
  49. package/scripts/cli/commands/validate.js +194 -0
  50. package/scripts/cli/internal/ai-engine.js +156 -0
  51. package/scripts/cli/internal/compiler.js +114 -0
  52. package/scripts/cli/internal/component-validator.js +443 -0
  53. package/scripts/cli/internal/config-loader.js +162 -0
  54. package/scripts/cli/internal/filesystem.js +158 -0
  55. package/scripts/cli/internal/generator.js +430 -0
  56. package/scripts/cli/internal/glass-generator.js +398 -0
  57. package/scripts/cli/internal/hook-generator.js +369 -0
  58. package/scripts/cli/internal/hooks.js +61 -0
  59. package/scripts/cli/internal/itcss-generator.js +565 -0
  60. package/scripts/cli/internal/motion-generator.js +679 -0
  61. package/scripts/cli/internal/template-engine.js +301 -0
  62. package/scripts/cli/internal/theme-bridge.js +664 -0
  63. package/scripts/cli/internal/tokens/engine.js +122 -0
  64. package/scripts/cli/internal/tokens/provider.js +34 -0
  65. package/scripts/cli/internal/tokens/providers/figma.js +50 -0
  66. package/scripts/cli/internal/tokens/providers/style-dictionary.js +48 -0
  67. package/scripts/cli/internal/tokens/providers/w3c.js +48 -0
  68. package/scripts/cli/internal/tokens/token-provider.js +443 -0
  69. package/scripts/cli/internal/tokens/token-validator.js +513 -0
  70. package/scripts/cli/internal/validator.js +276 -0
  71. package/scripts/cli/internal/wizard.js +115 -0
  72. package/scripts/cli/mappings.js +23 -0
  73. package/scripts/cli/migration-tools.js +164 -94
  74. package/scripts/cli/plugins/style-dictionary.js +46 -0
  75. package/scripts/cli/templates/README.md +525 -95
  76. package/scripts/cli/templates/common-templates.js +40 -14
  77. package/scripts/cli/templates/components/react-component.ts +282 -0
  78. package/scripts/cli/templates/config/project-config.ts +112 -0
  79. package/scripts/cli/templates/hooks/use-component.ts +477 -0
  80. package/scripts/cli/templates/index.js +19 -4
  81. package/scripts/cli/templates/index.ts +171 -0
  82. package/scripts/cli/templates/next-templates.js +72 -0
  83. package/scripts/cli/templates/react-templates.js +70 -126
  84. package/scripts/cli/templates/scss-templates.js +35 -35
  85. package/scripts/cli/templates/stories/storybook-story.ts +241 -0
  86. package/scripts/cli/templates/styles/scss-component.ts +255 -0
  87. package/scripts/cli/templates/tests/vitest-test.ts +229 -0
  88. package/scripts/cli/templates/token-templates.js +337 -1
  89. package/scripts/cli/templates/tokens/token-generators.ts +1088 -0
  90. package/scripts/cli/templates/types/component-types.ts +145 -0
  91. package/scripts/cli/templates/utils/testing-utils.ts +144 -0
  92. package/scripts/cli/templates/vanilla-templates.js +39 -0
  93. package/scripts/cli/token-manager.js +8 -2
  94. package/scripts/cli/utils/cache-manager.js +240 -0
  95. package/scripts/cli/utils/detector.js +46 -0
  96. package/scripts/cli/utils/diagnostics.js +289 -0
  97. package/scripts/cli/utils/error.js +89 -0
  98. package/scripts/cli/utils/helpers.js +67 -0
  99. package/scripts/cli/utils/logger.js +75 -0
  100. package/scripts/cli/utils/security.js +302 -0
  101. package/scripts/cli/utils/telemetry.js +115 -0
  102. package/scripts/cli/utils/validation.js +37 -0
  103. package/scripts/cli/utils.js +28 -341
  104. package/src/components/Accordion/Accordion.stories.tsx +0 -18
  105. package/src/components/Accordion/Accordion.test.tsx +0 -17
  106. package/src/components/Accordion/Accordion.tsx +0 -4
  107. package/src/components/AtomixGlass/AtomixGlass.test.tsx +37 -3
  108. package/src/components/AtomixGlass/AtomixGlass.tsx +143 -31
  109. package/src/components/AtomixGlass/AtomixGlassContainer.tsx +129 -31
  110. package/src/components/AtomixGlass/PerformanceDashboard.tsx +219 -0
  111. package/src/components/AtomixGlass/README.md +25 -10
  112. package/src/components/AtomixGlass/__snapshots__/AtomixGlass.test.tsx.snap +216 -0
  113. package/src/components/AtomixGlass/animation-system.ts +578 -0
  114. package/src/components/AtomixGlass/shader-utils.ts +4 -1
  115. package/src/components/AtomixGlass/stories/Overview.stories.tsx +157 -6
  116. package/src/components/AtomixGlass/stories/Phase1-Animation.stories.tsx +653 -0
  117. package/src/components/AtomixGlass/stories/Phase1-Test.stories.tsx +95 -0
  118. package/src/components/AtomixGlass/stories/Playground.stories.tsx +51 -51
  119. package/src/components/AtomixGlass/stories/shared-components.tsx +6 -0
  120. package/src/components/Avatar/Avatar.tsx +1 -1
  121. package/src/components/Button/Button.stories.disabled-link.tsx +10 -0
  122. package/src/components/Button/Button.stories.tsx +10 -0
  123. package/src/components/Button/Button.test.tsx +16 -11
  124. package/src/components/Button/Button.tsx +4 -4
  125. package/src/components/Card/Card.tsx +1 -1
  126. package/src/components/Dropdown/Dropdown.tsx +12 -12
  127. package/src/components/Form/Select.tsx +62 -3
  128. package/src/components/Modal/Modal.tsx +14 -3
  129. package/src/components/Navigation/Navbar/Navbar.tsx +44 -0
  130. package/src/components/Slider/Slider.stories.tsx +3 -3
  131. package/src/components/Slider/Slider.tsx +38 -0
  132. package/src/components/Steps/Steps.tsx +3 -3
  133. package/src/components/Tabs/Tabs.tsx +77 -8
  134. package/src/components/Testimonial/Testimonial.tsx +1 -1
  135. package/src/components/TypedButton/TypedButton.stories.tsx +59 -0
  136. package/src/components/TypedButton/TypedButton.tsx +39 -0
  137. package/src/components/TypedButton/index.ts +2 -0
  138. package/src/components/VideoPlayer/VideoPlayer.tsx +11 -4
  139. package/src/lib/composables/index.ts +4 -7
  140. package/src/lib/composables/types.ts +45 -0
  141. package/src/lib/composables/useAccordion.ts +0 -7
  142. package/src/lib/composables/useAtomixGlass.ts +148 -6
  143. package/src/lib/composables/useAtomixGlassStyles.ts +9 -7
  144. package/src/lib/composables/useChartExport.ts +3 -13
  145. package/src/lib/composables/useDropdown.ts +66 -0
  146. package/src/lib/composables/useFocusTrap.ts +80 -0
  147. package/src/lib/composables/usePerformanceMonitor.ts +448 -0
  148. package/src/lib/composables/useResponsiveGlass.presets.ts +192 -0
  149. package/src/lib/composables/useResponsiveGlass.ts +441 -0
  150. package/src/lib/composables/useTooltip.ts +16 -0
  151. package/src/lib/composables/useTypedButton.ts +66 -0
  152. package/src/lib/config/index.ts +62 -5
  153. package/src/lib/constants/components.ts +62 -7
  154. package/src/lib/theme/devtools/__tests__/useHistory.test.tsx +150 -0
  155. package/src/lib/theme/tokens/centralized-tokens.ts +120 -0
  156. package/src/lib/theme/utils/__tests__/domUtils.test.ts +101 -0
  157. package/src/lib/types/components.ts +37 -11
  158. package/src/lib/types/glass.ts +35 -0
  159. package/src/lib/types/index.ts +1 -0
  160. package/src/lib/utils/displacement-generator.ts +1 -1
  161. package/src/styles/01-settings/_settings.testtypecheck.scss +53 -0
  162. package/src/styles/01-settings/_settings.typedbutton.scss +53 -0
  163. package/src/styles/06-components/_components.atomix-glass.scss +17 -21
  164. package/src/styles/06-components/_components.edge-panel.scss +1 -5
  165. package/src/styles/06-components/_components.modal.scss +1 -4
  166. package/src/styles/06-components/_components.navbar.scss +1 -1
  167. package/src/styles/06-components/_components.testbutton.scss +212 -0
  168. package/src/styles/06-components/_components.testtypecheck.scss +212 -0
  169. package/src/styles/06-components/_components.tooltip.scss +9 -5
  170. package/src/styles/06-components/_components.typedbutton.scss +212 -0
  171. package/src/styles/99-utilities/_index.scss +1 -0
  172. package/src/styles/99-utilities/_utilities.text.scss +1 -1
  173. package/src/styles/99-utilities/_utilities.touch-target.scss +36 -0
  174. package/scripts/cli/component-generator.js +0 -564
  175. package/scripts/cli/interactive-init.js +0 -357
  176. package/src/styles/06-components/old.chart.styles.scss +0 -2788
@@ -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();