@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,477 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Composable Hook Templates (TypeScript)
|
|
3
|
+
* Templates for generating React hooks following Atomix composable pattern
|
|
4
|
+
*
|
|
5
|
+
* @module templates/hooks
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { HTMLAttributes } from 'react';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Component size variants
|
|
12
|
+
*/
|
|
13
|
+
export type ComponentSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Component visual variants
|
|
17
|
+
*/
|
|
18
|
+
export type ComponentVariant = 'primary' | 'secondary' | 'outline' | 'ghost' | 'link' | 'success' | 'error' | 'warning';
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Options for customizing hook generation
|
|
22
|
+
*/
|
|
23
|
+
export interface HookGenerationOptions {
|
|
24
|
+
hasVariants?: boolean;
|
|
25
|
+
hasSizes?: boolean;
|
|
26
|
+
hasStates?: boolean;
|
|
27
|
+
hasCallbacks?: boolean;
|
|
28
|
+
hasControlledMode?: boolean;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Generates a standard composable hook for a component
|
|
33
|
+
*
|
|
34
|
+
* @param name - Component name (e.g., "Button", "Card")
|
|
35
|
+
* @param options - Hook generation options
|
|
36
|
+
* @returns TypeScript hook code string
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* ```typescript
|
|
40
|
+
* const hook = generateComposableHook('Button', { hasVariants: true });
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
43
|
+
export const generateComposableHook = (
|
|
44
|
+
name: string,
|
|
45
|
+
options: HookGenerationOptions = {}
|
|
46
|
+
): string => {
|
|
47
|
+
const {
|
|
48
|
+
hasVariants = true,
|
|
49
|
+
hasSizes = true,
|
|
50
|
+
hasStates = true,
|
|
51
|
+
hasCallbacks = true,
|
|
52
|
+
hasControlledMode = false,
|
|
53
|
+
} = options;
|
|
54
|
+
|
|
55
|
+
const hookName = `use${name}`;
|
|
56
|
+
const propsInterface = `${name}HookProps`;
|
|
57
|
+
const returnInterface = `${name}HookReturn`;
|
|
58
|
+
const componentPrefix = name
|
|
59
|
+
.toLowerCase()
|
|
60
|
+
.replace(/([A-Z])/g, '-$1')
|
|
61
|
+
.replace(/^-/, '');
|
|
62
|
+
|
|
63
|
+
// Build imports section
|
|
64
|
+
let imports = `import { useCallback, useMemo, useState } from 'react';`;
|
|
65
|
+
|
|
66
|
+
if (hasCallbacks) {
|
|
67
|
+
imports += `\nimport type { ${name}Props } from '../../types/components';`;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Build props interface
|
|
71
|
+
const propsFields = [];
|
|
72
|
+
|
|
73
|
+
if (hasVariants) {
|
|
74
|
+
propsFields.push(` /**\n * Component visual variant\n * @default 'primary'\n */\n variant?: ComponentVariant;`);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (hasSizes) {
|
|
78
|
+
propsFields.push(` /**\n * Component size\n * @default 'md'\n */\n size?: ComponentSize;`);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (hasStates) {
|
|
82
|
+
propsFields.push(` /**\n * Disabled state\n * @default false\n */\n disabled?: boolean;\n\n /**\n * Enable glass morphism effect\n * @default false\n */\n glass?: boolean | object;`);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (hasCallbacks) {
|
|
86
|
+
propsFields.push(` /**\n * Click event handler\n */\n onClick?: (event: React.MouseEvent<HTMLDivElement>) => void;\n\n /**\n * Hover/mouse enter event handler\n */\n onHover?: (event: React.MouseEvent<HTMLDivElement>) => void;\n\n /**\n * Focus event handler\n */\n onFocus?: (event: React.FocusEvent<HTMLDivElement>) => void;\n\n /**\n * Blur event handler\n */\n onBlur?: (event: React.FocusEvent<HTMLDivElement>) => void;\n\n /**\n * State change callback for controlled mode\n */\n onStateChange?: (state: ComponentState) => void;`);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const propsInterfaceContent = propsFields.length > 0
|
|
90
|
+
? `export interface ${propsInterface} {\n${propsFields.join('\n\n')}\n}\n\n`
|
|
91
|
+
: '';
|
|
92
|
+
|
|
93
|
+
// Build return interface
|
|
94
|
+
const returnFields = [
|
|
95
|
+
` /**\n * Generate BEM-compliant class names based on current state\n * @param className - Optional additional custom classes\n * @returns Space-separated class name string\n */\n generateClassNames: (className?: string) => string;`,
|
|
96
|
+
];
|
|
97
|
+
|
|
98
|
+
if (hasCallbacks) {
|
|
99
|
+
returnFields.push(
|
|
100
|
+
` /**\n * Click handler with disabled state check\n */\n handleClick: (event: React.MouseEvent<HTMLDivElement>) => void;\n\n /**\n * Mouse enter handler\n */\n handleMouseEnter: (event: React.MouseEvent<HTMLDivElement>) => void;\n\n /**\n * Focus handler\n */\n handleFocus: (event: React.FocusEvent<HTMLDivElement>) => void;\n\n /**\n * Blur handler\n */\n handleBlur: (event: React.FocusEvent<HTMLDivElement>) => void;`
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
returnFields.push(` /**\n * Current component state\n */\n state: ComponentState;`);
|
|
105
|
+
|
|
106
|
+
// Build hook implementation
|
|
107
|
+
const destructuredProps = [];
|
|
108
|
+
const defaultValues = [];
|
|
109
|
+
const useCallbackDeps = [];
|
|
110
|
+
|
|
111
|
+
if (hasVariants) {
|
|
112
|
+
destructuredProps.push(`variant = 'primary'`);
|
|
113
|
+
useCallbackDeps.push('variant');
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
if (hasSizes) {
|
|
117
|
+
destructuredProps.push(`size = 'md'`);
|
|
118
|
+
useCallbackDeps.push('size');
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if (hasStates) {
|
|
122
|
+
destructuredProps.push(`disabled = false`, `glass = false`);
|
|
123
|
+
useCallbackDeps.push('disabled', 'glass');
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
if (hasCallbacks) {
|
|
127
|
+
destructuredProps.push(
|
|
128
|
+
'onClick',
|
|
129
|
+
'onHover',
|
|
130
|
+
'onFocus',
|
|
131
|
+
'onBlur',
|
|
132
|
+
'onStateChange'
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
return `${imports}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Component State Interface
|
|
140
|
+
* Tracks internal component state for dynamic behavior
|
|
141
|
+
*/
|
|
142
|
+
export interface ComponentState {
|
|
143
|
+
isActive: boolean;
|
|
144
|
+
isHovered: boolean;
|
|
145
|
+
isFocused: boolean;
|
|
146
|
+
isLoading: boolean;
|
|
147
|
+
variant: ComponentVariant | string;
|
|
148
|
+
size: ComponentSize | string;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
${propsInterfaceContent.length > 0 ? propsInterfaceContent : ''}/**
|
|
152
|
+
* Hook Return Type
|
|
153
|
+
* Provides class name generation, event handlers, and state
|
|
154
|
+
*/
|
|
155
|
+
export interface ${returnInterface} {
|
|
156
|
+
${returnFields.join('\n')}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* ${hookName} - Composable Hook for ${name} Component
|
|
161
|
+
*
|
|
162
|
+
* Provides state management, BEM class name generation, and event handlers
|
|
163
|
+
* following the Atomix composable pattern. Supports both controlled and
|
|
164
|
+
* uncontrolled modes.
|
|
165
|
+
*
|
|
166
|
+
* @param props - Hook configuration props
|
|
167
|
+
* @returns Object with class names, handlers, and state
|
|
168
|
+
*
|
|
169
|
+
* @example
|
|
170
|
+
* \`\`\`tsx
|
|
171
|
+
* const { generateClassNames, handleClick, state } = ${hookName}({
|
|
172
|
+
* variant: 'primary',
|
|
173
|
+
* size: 'md',
|
|
174
|
+
* disabled: false,
|
|
175
|
+
* onClick: handleClick
|
|
176
|
+
* });
|
|
177
|
+
* \`\`\`
|
|
178
|
+
*/
|
|
179
|
+
export function ${hookName}(props: ${propsInterface}): ${returnInterface} {
|
|
180
|
+
const {
|
|
181
|
+
${destructuredProps.join(',\n ')}
|
|
182
|
+
} = props;
|
|
183
|
+
|
|
184
|
+
// Internal state tracking
|
|
185
|
+
const [isHovered, setIsHovered] = useState(false);
|
|
186
|
+
const [isFocused, setIsFocused] = useState(false);
|
|
187
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Generate component class names using BEM methodology
|
|
191
|
+
* Integrates with ThemeNaming utility for consistency
|
|
192
|
+
*/
|
|
193
|
+
const generateClassNames = useCallback(
|
|
194
|
+
(className?: string): string => {
|
|
195
|
+
const baseClasses = ['c-${componentPrefix}'];
|
|
196
|
+
|
|
197
|
+
// Add variant class
|
|
198
|
+
${hasVariants ? `baseClasses.push(\`c-${componentPrefix}--\${variant}\`);` : ''}
|
|
199
|
+
|
|
200
|
+
// Add size class (only if not default)
|
|
201
|
+
${hasSizes ? `if (size !== 'md') {\n baseClasses.push(\`c-${componentPrefix}--\${size}\`);\n }` : ''}
|
|
202
|
+
|
|
203
|
+
// Add state classes
|
|
204
|
+
${hasStates ? `if (disabled) {\n baseClasses.push('c-${componentPrefix}--disabled');\n }\n \n if (glass) {\n baseClasses.push('c-${componentPrefix}--glass');\n }` : ''}
|
|
205
|
+
|
|
206
|
+
// Add custom className
|
|
207
|
+
if (className) {
|
|
208
|
+
baseClasses.push(className);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
return baseClasses.filter(Boolean).join(' ');
|
|
212
|
+
},
|
|
213
|
+
[${useCallbackDeps.join(', ')}]
|
|
214
|
+
);
|
|
215
|
+
|
|
216
|
+
${hasCallbacks ? `/**
|
|
217
|
+
* Handle click event with disabled state check
|
|
218
|
+
*/
|
|
219
|
+
const handleClick = useCallback(
|
|
220
|
+
(event: React.MouseEvent<HTMLDivElement>) => {
|
|
221
|
+
if (disabled) {
|
|
222
|
+
event.preventDefault();
|
|
223
|
+
return;
|
|
224
|
+
}
|
|
225
|
+
onClick?.(event);
|
|
226
|
+
},
|
|
227
|
+
[disabled, onClick]
|
|
228
|
+
);
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Handle mouse enter (hover start)
|
|
232
|
+
*/
|
|
233
|
+
const handleMouseEnter = useCallback(
|
|
234
|
+
(event: React.MouseEvent<HTMLDivElement>) => {
|
|
235
|
+
if (!disabled) {
|
|
236
|
+
setIsHovered(true);
|
|
237
|
+
onHover?.(event);
|
|
238
|
+
}
|
|
239
|
+
},
|
|
240
|
+
[disabled, onHover]
|
|
241
|
+
);
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* Handle focus event
|
|
245
|
+
*/
|
|
246
|
+
const handleFocus = useCallback(
|
|
247
|
+
(event: React.FocusEvent<HTMLDivElement>) => {
|
|
248
|
+
if (!disabled) {
|
|
249
|
+
setIsFocused(true);
|
|
250
|
+
onFocus?.(event);
|
|
251
|
+
}
|
|
252
|
+
},
|
|
253
|
+
[disabled, onFocus]
|
|
254
|
+
);
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Handle blur event
|
|
258
|
+
*/
|
|
259
|
+
const handleBlur = useCallback(
|
|
260
|
+
(event: React.FocusEvent<HTMLDivElement>) => {
|
|
261
|
+
if (!disabled) {
|
|
262
|
+
setIsFocused(false);
|
|
263
|
+
onBlur?.(event);
|
|
264
|
+
}
|
|
265
|
+
},
|
|
266
|
+
[disabled, onBlur]
|
|
267
|
+
);` : ''}
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* Component state object
|
|
271
|
+
* Memoized to prevent unnecessary re-renders
|
|
272
|
+
*/
|
|
273
|
+
const state: ComponentState = useMemo(
|
|
274
|
+
() => ({
|
|
275
|
+
isActive: false,
|
|
276
|
+
isHovered,
|
|
277
|
+
isFocused,
|
|
278
|
+
isLoading,
|
|
279
|
+
variant,
|
|
280
|
+
size,
|
|
281
|
+
}),
|
|
282
|
+
[${hasVariants ? 'variant' : ''}${hasVariants && hasSizes ? ', ' : ''}${hasSizes ? 'size' : ''}]
|
|
283
|
+
);
|
|
284
|
+
|
|
285
|
+
${hasCallbacks && hasControlledMode ? `// Notify parent of state changes (controlled mode support)
|
|
286
|
+
useMemo(() => {
|
|
287
|
+
if (onStateChange && !disabled) {
|
|
288
|
+
onStateChange(state);
|
|
289
|
+
}
|
|
290
|
+
}, [state, onStateChange, disabled]);` : ''}
|
|
291
|
+
|
|
292
|
+
return {
|
|
293
|
+
generateClassNames,
|
|
294
|
+
${hasCallbacks ? `handleClick,
|
|
295
|
+
handleMouseEnter,
|
|
296
|
+
handleFocus,
|
|
297
|
+
handleBlur,` : ''}
|
|
298
|
+
state,
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
export default ${hookName};
|
|
303
|
+
`;
|
|
304
|
+
};
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* Generates a simple composable hook for basic components
|
|
308
|
+
*
|
|
309
|
+
* @param name - Component name
|
|
310
|
+
* @returns Simple hook code string
|
|
311
|
+
*/
|
|
312
|
+
export const generateSimpleHook = (name: string): string => {
|
|
313
|
+
const componentPrefix = name
|
|
314
|
+
.toLowerCase()
|
|
315
|
+
.replace(/([A-Z])/g, '-$1')
|
|
316
|
+
.replace(/^-/, '');
|
|
317
|
+
|
|
318
|
+
return `import { useState, useEffect, useCallback } from 'react';
|
|
319
|
+
import type { ${name}Props } from '../types/components';
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* Simple ${name} Hook
|
|
323
|
+
* Basic hook for presentational components
|
|
324
|
+
*/
|
|
325
|
+
export function use${name}(props?: Partial<${name}Props>) {
|
|
326
|
+
const [isReady, setIsReady] = useState(false);
|
|
327
|
+
|
|
328
|
+
useEffect(() => {
|
|
329
|
+
// Mark component as ready after mount
|
|
330
|
+
setIsReady(true);
|
|
331
|
+
}, []);
|
|
332
|
+
|
|
333
|
+
/**
|
|
334
|
+
* Generate class names
|
|
335
|
+
*/
|
|
336
|
+
const generateClassNames = useCallback(
|
|
337
|
+
(baseClassName = ''): string => {
|
|
338
|
+
return \`c-${componentPrefix} \${baseClassName}\`.trim();
|
|
339
|
+
},
|
|
340
|
+
[]
|
|
341
|
+
);
|
|
342
|
+
|
|
343
|
+
return {
|
|
344
|
+
isReady,
|
|
345
|
+
generateClassNames,
|
|
346
|
+
};
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
export default use${name};
|
|
350
|
+
`;
|
|
351
|
+
};
|
|
352
|
+
|
|
353
|
+
/**
|
|
354
|
+
* Generates a complex composable hook with advanced state management
|
|
355
|
+
*
|
|
356
|
+
* @param name - Component name
|
|
357
|
+
* @returns Complex hook code string with refs and methods
|
|
358
|
+
*/
|
|
359
|
+
export const generateComplexHook = (name: string): string => {
|
|
360
|
+
const componentPrefix = name
|
|
361
|
+
.toLowerCase()
|
|
362
|
+
.replace(/([A-Z])/g, '-$1')
|
|
363
|
+
.replace(/^-/, '');
|
|
364
|
+
|
|
365
|
+
return `import { useState, useEffect, useRef, useCallback, useMemo } from 'react';
|
|
366
|
+
import { ${name.toUpperCase()} } from '../constants/components';
|
|
367
|
+
import type { ${name}Props, ${name}State, ElementRefs } from '../types/components';
|
|
368
|
+
|
|
369
|
+
/**
|
|
370
|
+
* Complex ${name} Hook Return Type
|
|
371
|
+
*/
|
|
372
|
+
interface Use${name}Result {
|
|
373
|
+
state: ${name}State;
|
|
374
|
+
refs: ElementRefs;
|
|
375
|
+
methods: {
|
|
376
|
+
updateState: (newState: Partial<${name}State>) => void;
|
|
377
|
+
reset: () => void;
|
|
378
|
+
toggle: () => void;
|
|
379
|
+
};
|
|
380
|
+
generateClassNames: (baseClassName?: string) => string;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
/**
|
|
384
|
+
* use${name} - Complex Composable Hook
|
|
385
|
+
*
|
|
386
|
+
* Advanced hook for components with complex state and multiple DOM references
|
|
387
|
+
*/
|
|
388
|
+
export function use${name}(
|
|
389
|
+
initialProps?: Partial<${name}Props>
|
|
390
|
+
): Use${name}Result {
|
|
391
|
+
const defaultProps: Partial<${name}Props> = {
|
|
392
|
+
disabled: false,
|
|
393
|
+
...initialProps,
|
|
394
|
+
};
|
|
395
|
+
|
|
396
|
+
// Complex state management
|
|
397
|
+
const [state, setState] = useState<${name}State>({
|
|
398
|
+
isOpen: false,
|
|
399
|
+
isActive: false,
|
|
400
|
+
isAnimating: false,
|
|
401
|
+
error: null,
|
|
402
|
+
});
|
|
403
|
+
|
|
404
|
+
// DOM references
|
|
405
|
+
const panelRef = useRef<HTMLDivElement>(null);
|
|
406
|
+
const contentRef = useRef<HTMLDivElement>(null);
|
|
407
|
+
const buttonRef = useRef<HTMLButtonElement>(null);
|
|
408
|
+
const triggerRef = useRef<HTMLButtonElement>(null);
|
|
409
|
+
|
|
410
|
+
/**
|
|
411
|
+
* Update partial state
|
|
412
|
+
*/
|
|
413
|
+
const updateState = useCallback((newState: Partial<${name}State>) => {
|
|
414
|
+
setState(prev => ({ ...prev, ...newState }));
|
|
415
|
+
}, []);
|
|
416
|
+
|
|
417
|
+
/**
|
|
418
|
+
* Reset to initial state
|
|
419
|
+
*/
|
|
420
|
+
const reset = useCallback(() => {
|
|
421
|
+
setState({
|
|
422
|
+
isOpen: false,
|
|
423
|
+
isActive: false,
|
|
424
|
+
isAnimating: false,
|
|
425
|
+
error: null,
|
|
426
|
+
});
|
|
427
|
+
}, []);
|
|
428
|
+
|
|
429
|
+
/**
|
|
430
|
+
* Toggle open/close state
|
|
431
|
+
*/
|
|
432
|
+
const toggle = useCallback(() => {
|
|
433
|
+
setState(prev => ({ ...prev, isOpen: !prev.isOpen }));
|
|
434
|
+
}, []);
|
|
435
|
+
|
|
436
|
+
/**
|
|
437
|
+
* Generate BEM class names
|
|
438
|
+
*/
|
|
439
|
+
const generateClassNames = useCallback(
|
|
440
|
+
(baseClassName = ''): string => {
|
|
441
|
+
const baseClasses = [
|
|
442
|
+
${name.toUpperCase()}.SELECTORS.${name.toUpperCase().replace(/([A-Z])/g, '_').toUpperCase()}.replace('.', ''),
|
|
443
|
+
state.isOpen ? ${name.toUpperCase()}.CLASSES.IS_OPEN : '',
|
|
444
|
+
defaultProps.disabled ? ${name.toUpperCase()}.CLASSES.IS_DISABLED : '',
|
|
445
|
+
baseClassName,
|
|
446
|
+
].filter(Boolean).join(' ');
|
|
447
|
+
|
|
448
|
+
return baseClasses;
|
|
449
|
+
},
|
|
450
|
+
[state.isOpen, defaultProps.disabled]
|
|
451
|
+
);
|
|
452
|
+
|
|
453
|
+
return {
|
|
454
|
+
state,
|
|
455
|
+
refs: { panelRef, contentRef, buttonRef, triggerRef },
|
|
456
|
+
methods: { updateState, reset, toggle },
|
|
457
|
+
generateClassNames,
|
|
458
|
+
};
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
export default use${name};
|
|
462
|
+
`;
|
|
463
|
+
};
|
|
464
|
+
|
|
465
|
+
/**
|
|
466
|
+
* All composable hook templates
|
|
467
|
+
*/
|
|
468
|
+
export const composableHookTemplates = {
|
|
469
|
+
useHook: generateComposableHook,
|
|
470
|
+
simpleHook: generateSimpleHook,
|
|
471
|
+
complexHook: generateComplexHook,
|
|
472
|
+
};
|
|
473
|
+
|
|
474
|
+
/**
|
|
475
|
+
* Type for composable hook templates object
|
|
476
|
+
*/
|
|
477
|
+
export type ComposableHookTemplates = typeof composableHookTemplates;
|
|
@@ -1,10 +1,23 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Templates Index
|
|
3
|
-
*
|
|
2
|
+
* Templates Index - Backward Compatibility Layer
|
|
3
|
+
*
|
|
4
|
+
* This file maintains backward compatibility with existing code.
|
|
5
|
+
* The new organized TypeScript templates are available in:
|
|
6
|
+
* - components/react-component.ts
|
|
7
|
+
* - styles/scss-component.ts
|
|
8
|
+
* - stories/storybook-story.ts
|
|
9
|
+
* - tests/vitest-test.ts
|
|
10
|
+
* - types/component-types.ts
|
|
11
|
+
* - config/project-config.ts
|
|
12
|
+
* - utils/testing-utils.ts
|
|
13
|
+
*
|
|
14
|
+
* For new code, use the TypeScript modules directly or build the project.
|
|
4
15
|
*/
|
|
5
16
|
|
|
6
|
-
// Import template modules
|
|
17
|
+
// Import legacy template modules for backward compatibility
|
|
7
18
|
import { reactTemplates } from './react-templates.js';
|
|
19
|
+
import { nextTemplates } from './next-templates.js';
|
|
20
|
+
import { vanillaTemplates } from './vanilla-templates.js';
|
|
8
21
|
import { storybookTemplates } from './storybook-templates.js';
|
|
9
22
|
import { testingTemplates } from './testing-templates.js';
|
|
10
23
|
import { scssTemplates } from './scss-templates.js';
|
|
@@ -34,6 +47,8 @@ export const componentTemplates = {
|
|
|
34
47
|
types: typesTemplates.types,
|
|
35
48
|
constants: typesTemplates.constants,
|
|
36
49
|
},
|
|
50
|
+
next: nextTemplates,
|
|
51
|
+
vanilla: vanillaTemplates,
|
|
37
52
|
composable: composableTemplates,
|
|
38
53
|
storybook: storybookTemplates,
|
|
39
54
|
testing: testingTemplates,
|
|
@@ -50,7 +65,7 @@ export {
|
|
|
50
65
|
};
|
|
51
66
|
|
|
52
67
|
/**
|
|
53
|
-
* Get template by name and type
|
|
68
|
+
* Get template by name and type (legacy API)
|
|
54
69
|
* @param {string} type - Template type (react, composable, etc.)
|
|
55
70
|
* @param {string} name - Template name (simple, medium, complex, etc.)
|
|
56
71
|
* @returns {Function|null} Template function or null if not found
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Atomix CLI Templates
|
|
3
|
+
*
|
|
4
|
+
* A modular and organized collection of templates for generating
|
|
5
|
+
* components, styles, stories, tests, and configuration files.
|
|
6
|
+
*
|
|
7
|
+
* @module templates
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
// Component templates
|
|
11
|
+
export { reactComponentTemplates } from './components/react-component';
|
|
12
|
+
export type { ReactComponentTemplates } from './components/react-component';
|
|
13
|
+
|
|
14
|
+
// Style templates
|
|
15
|
+
export { scssComponentTemplates } from './styles/scss-component';
|
|
16
|
+
export type { ScssComponentTemplates } from './styles/scss-component';
|
|
17
|
+
|
|
18
|
+
// Story templates
|
|
19
|
+
export { storybookStoryTemplates } from './stories/storybook-story';
|
|
20
|
+
export type { StorybookStoryTemplates } from './stories/storybook-story';
|
|
21
|
+
|
|
22
|
+
// Test templates
|
|
23
|
+
export { vitestTestTemplates } from './tests/vitest-test';
|
|
24
|
+
export type { VitestTestTemplates } from './tests/vitest-test';
|
|
25
|
+
|
|
26
|
+
// Type templates
|
|
27
|
+
export { componentTypeTemplates } from './types/component-types';
|
|
28
|
+
export type { ComponentTypeTemplates } from './types/component-types';
|
|
29
|
+
|
|
30
|
+
// Config templates
|
|
31
|
+
export { projectConfigTemplates } from './config/project-config';
|
|
32
|
+
export type { ProjectConfigTemplates } from './config/project-config';
|
|
33
|
+
|
|
34
|
+
// Utility templates
|
|
35
|
+
export { testingUtilsTemplates } from './utils/testing-utils';
|
|
36
|
+
export type { TestingUtilsTemplates } from './utils/testing-utils';
|
|
37
|
+
|
|
38
|
+
// Hook templates
|
|
39
|
+
export { composableHookTemplates, generateComposableHook, generateSimpleHook, generateComplexHook } from './hooks/use-component';
|
|
40
|
+
export type { ComposableHookTemplates, HookGenerationOptions } from './hooks/use-component';
|
|
41
|
+
|
|
42
|
+
// Token templates
|
|
43
|
+
export { tokenGenerators, generateColorTokens, generateSpacingTokens, generateTypographyTokens, generateShadowTokens, generateRadiusTokens, generateAnimationTokens, generateBreakpointTokens, generateZIndexTokens, generateJSONTokens, generateCSSTokens } from './tokens/token-generators';
|
|
44
|
+
export type { TokenGenerators, TokenCategory, TokenFormat, ColorTokenConfig, SpacingTokenConfig, TypographyTokenConfig, ShadowTokenConfig, RadiusTokenConfig, AnimationTokenConfig, BreakpointTokenConfig, ZIndexTokenConfig } from './tokens/token-generators';
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Template categories
|
|
48
|
+
*/
|
|
49
|
+
export const templates = {
|
|
50
|
+
components: {
|
|
51
|
+
react: reactComponentTemplates,
|
|
52
|
+
},
|
|
53
|
+
styles: {
|
|
54
|
+
scss: scssComponentTemplates,
|
|
55
|
+
},
|
|
56
|
+
stories: {
|
|
57
|
+
storybook: storybookStoryTemplates,
|
|
58
|
+
},
|
|
59
|
+
tests: {
|
|
60
|
+
vitest: vitestTestTemplates,
|
|
61
|
+
utils: testingUtilsTemplates,
|
|
62
|
+
},
|
|
63
|
+
types: {
|
|
64
|
+
components: componentTypeTemplates,
|
|
65
|
+
},
|
|
66
|
+
config: {
|
|
67
|
+
project: projectConfigTemplates,
|
|
68
|
+
},
|
|
69
|
+
hooks: {
|
|
70
|
+
composable: composableHookTemplates,
|
|
71
|
+
},
|
|
72
|
+
tokens: {
|
|
73
|
+
generators: tokenGenerators,
|
|
74
|
+
},
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Get a template by category and name
|
|
79
|
+
* @param category - Template category (components, styles, stories, tests, types, config)
|
|
80
|
+
* @param type - Template type within category
|
|
81
|
+
* @param name - Template name
|
|
82
|
+
* @returns Template function or null if not found
|
|
83
|
+
*/
|
|
84
|
+
export function getTemplate<K extends keyof typeof templates>(
|
|
85
|
+
category: K,
|
|
86
|
+
type: keyof typeof templates[K],
|
|
87
|
+
name: string
|
|
88
|
+
): ((...args: any[]) => any) | null {
|
|
89
|
+
const categoryTemplatesObject = templates[category];
|
|
90
|
+
const typeTemplatesObject = categoryTemplatesObject?.[type as keyof typeof categoryTemplatesObject];
|
|
91
|
+
|
|
92
|
+
if (!typeTemplatesObject || typeof typeTemplatesObject !== 'object') {
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const template = (typeTemplatesObject as Record<string, any>)[name];
|
|
97
|
+
return typeof template === 'function' ? template : null;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Get all templates for a category
|
|
102
|
+
* @param category - Template category
|
|
103
|
+
* @returns All templates for the category or empty object
|
|
104
|
+
*/
|
|
105
|
+
export function getTemplatesByCategory<K extends keyof typeof templates>(
|
|
106
|
+
category: K
|
|
107
|
+
): typeof templates[K] {
|
|
108
|
+
return templates[category];
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Get all available template categories
|
|
113
|
+
* @returns Array of category names
|
|
114
|
+
*/
|
|
115
|
+
export function getTemplateCategories(): string[] {
|
|
116
|
+
return Object.keys(templates);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Backward compatibility exports
|
|
121
|
+
* These maintain compatibility with existing code
|
|
122
|
+
*/
|
|
123
|
+
import { reactComponentTemplates as reactTmpl } from './components/react-component';
|
|
124
|
+
import { storybookStoryTemplates as storyTmpl } from './stories/storybook-story';
|
|
125
|
+
import { vitestTestTemplates as testTmpl } from './tests/vitest-test';
|
|
126
|
+
import { scssComponentTemplates as scssTmpl } from './styles/scss-component';
|
|
127
|
+
import { componentTypeTemplates as typeTmpl } from './types/component-types';
|
|
128
|
+
import { composableHookTemplates as hookTmpl } from './hooks/use-component';
|
|
129
|
+
import { tokenGenerators as tokenGen } from './tokens/token-generators';
|
|
130
|
+
|
|
131
|
+
export const componentTemplates = {
|
|
132
|
+
react: {
|
|
133
|
+
component: reactTmpl.component,
|
|
134
|
+
simple: reactTmpl.simple,
|
|
135
|
+
medium: reactTmpl.medium,
|
|
136
|
+
complex: reactTmpl.complex,
|
|
137
|
+
index: reactTmpl.index,
|
|
138
|
+
story: storyTmpl.story,
|
|
139
|
+
test: testTmpl.test,
|
|
140
|
+
scss: scssTmpl.full,
|
|
141
|
+
settings: scssTmpl.settings,
|
|
142
|
+
componentStyles: scssTmpl.component,
|
|
143
|
+
types: typeTmpl.types,
|
|
144
|
+
constants: typeTmpl.constants,
|
|
145
|
+
composable: {
|
|
146
|
+
useHook: hookTmpl.useHook,
|
|
147
|
+
simpleHook: hookTmpl.simpleHook,
|
|
148
|
+
complexHook: hookTmpl.complexHook,
|
|
149
|
+
},
|
|
150
|
+
},
|
|
151
|
+
token: {
|
|
152
|
+
color: tokenGen.color,
|
|
153
|
+
spacing: tokenGen.spacing,
|
|
154
|
+
typography: tokenGen.typography,
|
|
155
|
+
shadow: tokenGen.shadow,
|
|
156
|
+
radius: tokenGen.radius,
|
|
157
|
+
animation: tokenGen.animation,
|
|
158
|
+
breakpoint: tokenGen.breakpoint,
|
|
159
|
+
zIndex: tokenGen.zIndex,
|
|
160
|
+
json: tokenGen.json,
|
|
161
|
+
css: tokenGen.css,
|
|
162
|
+
},
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
export default {
|
|
166
|
+
templates,
|
|
167
|
+
componentTemplates,
|
|
168
|
+
getTemplate,
|
|
169
|
+
getTemplatesByCategory,
|
|
170
|
+
getTemplateCategories,
|
|
171
|
+
};
|