@shohojdhara/atomix 0.3.12 → 0.3.14
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/CHANGELOG.md +19 -0
- package/README.md +2 -0
- package/dist/atomix.css +101 -88
- package/dist/atomix.css.map +1 -1
- package/dist/atomix.min.css +5 -15258
- package/dist/atomix.min.css.map +1 -1
- package/dist/charts.d.ts +1 -1
- package/dist/charts.js +17 -19
- package/dist/charts.js.map +1 -1
- package/dist/core.d.ts +41 -11
- package/dist/core.js +55 -41
- package/dist/core.js.map +1 -1
- package/dist/forms.d.ts +28 -11
- package/dist/forms.js +25 -24
- package/dist/forms.js.map +1 -1
- package/dist/heavy.d.ts +1 -1
- package/dist/heavy.js +32 -25
- package/dist/heavy.js.map +1 -1
- package/dist/index.d.ts +122 -46
- package/dist/index.esm.js +865 -200
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +870 -204
- package/dist/index.js.map +1 -1
- package/dist/index.min.js +1 -1
- package/dist/index.min.js.map +1 -1
- package/dist/theme.d.ts +27 -2
- package/dist/theme.js +721 -108
- package/dist/theme.js.map +1 -1
- package/package.json +1 -1
- package/scripts/atomix-cli.js +610 -1111
- package/scripts/cli/component-generator.js +610 -0
- package/scripts/cli/documentation-sync.js +542 -0
- package/scripts/cli/interactive-init.js +84 -288
- package/scripts/cli/mappings.js +211 -0
- package/scripts/cli/migration-tools.js +95 -288
- package/scripts/cli/template-manager.js +107 -0
- package/scripts/cli/templates/README.md +123 -0
- package/scripts/cli/templates/composable-templates.js +149 -0
- package/scripts/cli/templates/config-templates.js +126 -0
- package/scripts/cli/templates/index.js +95 -0
- package/scripts/cli/templates/project-templates.js +214 -0
- package/scripts/cli/templates/react-templates.js +261 -0
- package/scripts/cli/templates/scss-templates.js +156 -0
- package/scripts/cli/templates/storybook-templates.js +236 -0
- package/scripts/cli/templates/testing-templates.js +45 -0
- package/scripts/cli/templates/token-templates.js +447 -0
- package/scripts/cli/templates/types-templates.js +133 -0
- package/scripts/cli/templates-original-backup.js +1655 -0
- package/scripts/cli/templates.js +35 -0
- package/scripts/cli/templates_backup.js +684 -0
- package/scripts/cli/theme-bridge.js +20 -14
- package/scripts/cli/token-manager.js +150 -77
- package/scripts/cli/utils.js +37 -25
- package/src/components/Accordion/Accordion.stories.tsx +5 -5
- package/src/components/Accordion/Accordion.test.tsx +57 -0
- package/src/components/Accordion/Accordion.tsx +4 -0
- package/src/components/AtomixGlass/AtomixGlassContainer.tsx +41 -44
- package/src/components/AtomixGlass/stories/AtomixGlass.stories.tsx +1 -1
- package/src/components/AtomixGlass/stories/Examples.stories.tsx +37 -37
- package/src/components/AtomixGlass/stories/Modes.stories.tsx +1 -2
- package/src/components/AtomixGlass/stories/Playground.stories.tsx +50 -51
- package/src/components/Avatar/Avatar.stories.tsx +26 -26
- package/src/components/Badge/Badge.stories.tsx +31 -31
- package/src/components/Badge/Badge.test.tsx +51 -0
- package/src/components/Badge/Badge.tsx +20 -1
- package/src/components/Block/Block.stories.tsx +5 -5
- package/src/components/Breadcrumb/Breadcrumb.stories.tsx +1 -1
- package/src/components/Breadcrumb/Breadcrumb.tsx +2 -2
- package/src/components/Button/Button.stories.tsx +13 -13
- package/src/components/Button/Button.tsx +4 -4
- package/src/components/Button/ButtonGroup.stories.tsx +2 -2
- package/src/components/Button/README.md +5 -0
- package/src/components/Callout/Callout.stories.tsx +11 -11
- package/src/components/Callout/Callout.test.tsx +10 -10
- package/src/components/Callout/Callout.tsx +7 -7
- package/src/components/Callout/README.md +9 -8
- package/src/components/Card/Card.tsx +2 -2
- package/src/components/Chart/Chart.stories.tsx +6 -6
- package/src/components/Chart/Chart.tsx +1 -1
- package/src/components/ColorModeToggle/ColorModeToggle.stories.tsx +1 -1
- package/src/components/DataTable/DataTable.tsx +14 -12
- package/src/components/DatePicker/DatePicker.stories.tsx +6 -6
- package/src/components/Dropdown/Dropdown.stories.tsx +4 -4
- package/src/components/Form/Checkbox.stories.tsx +3 -3
- package/src/components/Form/Checkbox.tsx +4 -2
- package/src/components/Form/Form.stories.tsx +3 -3
- package/src/components/Form/FormGroup.stories.tsx +1 -1
- package/src/components/Form/Input.stories.tsx +28 -16
- package/src/components/Form/Input.test.tsx +59 -0
- package/src/components/Form/Input.tsx +97 -95
- package/src/components/Form/Radio.stories.tsx +94 -94
- package/src/components/Form/Radio.tsx +2 -2
- package/src/components/Form/Select.stories.tsx +4 -4
- package/src/components/Form/Select.tsx +2 -2
- package/src/components/Form/Textarea.stories.tsx +22 -7
- package/src/components/Form/Textarea.test.tsx +45 -0
- package/src/components/Form/Textarea.tsx +88 -86
- package/src/components/List/List.stories.tsx +2 -2
- package/src/components/Modal/Modal.stories.tsx +4 -4
- package/src/components/Navigation/Navbar/Navbar.stories.tsx +5 -5
- package/src/components/Navigation/Navbar/Navbar.tsx +1 -1
- package/src/components/Navigation/README.md +1 -1
- package/src/components/Pagination/Pagination.stories.tsx +5 -2
- package/src/components/Pagination/Pagination.tsx +1 -1
- package/src/components/PhotoViewer/PhotoViewer.stories.tsx +10 -10
- package/src/components/Popover/Popover.stories.tsx +1 -1
- package/src/components/ProductReview/ProductReview.tsx +1 -1
- package/src/components/Progress/Progress.tsx +46 -46
- package/src/components/Rating/Rating.stories.tsx +4 -4
- package/src/components/Rating/Rating.tsx +8 -8
- package/src/components/Slider/Slider.stories.tsx +63 -63
- package/src/components/Spinner/Spinner.stories.tsx +2 -2
- package/src/components/Spinner/Spinner.test.tsx +35 -0
- package/src/components/Spinner/Spinner.tsx +9 -2
- package/src/components/Testimonial/Testimonial.stories.tsx +1 -1
- package/src/components/Toggle/Toggle.stories.tsx +32 -9
- package/src/components/Toggle/Toggle.test.tsx +91 -0
- package/src/components/Toggle/Toggle.tsx +44 -27
- package/src/components/Tooltip/Tooltip.tsx +1 -1
- package/src/layouts/Grid/Grid.stories.tsx +49 -49
- package/src/layouts/MasonryGrid/MasonryGrid.stories.tsx +2 -2
- package/src/lib/composables/useAccordion.ts +12 -3
- package/src/lib/composables/useBreadcrumb.ts +2 -2
- package/src/lib/composables/useCallout.ts +7 -7
- package/src/lib/composables/useNavbar.ts +1 -1
- package/src/lib/constants/components.ts +1 -1
- package/src/lib/storybook/InteractiveDemo.tsx +113 -0
- package/src/lib/storybook/PreviewContainer.tsx +36 -0
- package/src/lib/storybook/VariantsGrid.tsx +21 -0
- package/src/lib/storybook/index.ts +3 -0
- package/src/lib/theme/core/createThemeObject.ts +9 -5
- package/src/lib/theme/devtools/CLI.ts +155 -0
- package/src/lib/theme/devtools/DesignTokensCustomizer.stories.tsx +213 -0
- package/src/lib/theme/devtools/DesignTokensCustomizer.tsx +566 -0
- package/src/lib/theme/devtools/LiveEditor.tsx +2 -1
- package/src/lib/theme/devtools/index.ts +3 -0
- package/src/lib/theme/errors/errors.ts +8 -0
- package/src/lib/theme/runtime/ThemeProvider.tsx +117 -57
- package/src/lib/theme/runtime/__tests__/ThemeProvider.integration.test.tsx +305 -0
- package/src/lib/theme/runtime/__tests__/ThemeProvider.test.tsx +588 -0
- package/src/lib/theme/utils/__tests__/themeValidation.test.ts +264 -0
- package/src/lib/theme/utils/index.ts +1 -0
- package/src/lib/theme/utils/themeValidation.ts +501 -0
- package/src/lib/theme-tools.ts +32 -3
- package/src/lib/types/components.ts +81 -26
- package/src/lib/utils/themeNaming.ts +1 -1
- package/src/styles/06-components/_components.atomix-glass.scss +14 -15
- package/src/styles/06-components/_components.callout.scss +29 -33
- package/src/styles/06-components/_index.scss +1 -1
- package/src/styles/99-utilities/_utilities.display.scss +14 -3
- package/src/styles/99-utilities/_utilities.flex.scss +10 -10
- package/src/styles/99-utilities/_utilities.text.scss +28 -8
- package/scripts/cli/__tests__/cli-commands.test.js +0 -204
- package/scripts/cli/__tests__/utils.test.js +0 -201
- package/scripts/cli/__tests__/vitest.config.js +0 -26
|
@@ -0,0 +1,1655 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Atomix CLI - Templates and Data
|
|
3
|
+
* Stores component templates and token generation functions
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Component templates for design system
|
|
8
|
+
*/
|
|
9
|
+
export const componentTemplates = {
|
|
10
|
+
react: {
|
|
11
|
+
// Simple template variant
|
|
12
|
+
simple: (name) => `import React, { memo, forwardRef } from 'react';
|
|
13
|
+
import { cn } from '../../lib/utils';
|
|
14
|
+
import { ACCORDION } from '../../lib/constants/components';
|
|
15
|
+
import type { ${name}Props } from '../../lib/types/components';
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* ${name} component - Simple variant
|
|
19
|
+
* Basic presentational component with minimal state
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* \`\`\`tsx
|
|
23
|
+
* <${name}>Hello World</${name}>
|
|
24
|
+
* \`\`\`
|
|
25
|
+
*/
|
|
26
|
+
export const ${name} = memo(
|
|
27
|
+
forwardRef<HTMLDivElement, ${name}Props>(
|
|
28
|
+
({
|
|
29
|
+
children,
|
|
30
|
+
className,
|
|
31
|
+
...props
|
|
32
|
+
}, ref) => {
|
|
33
|
+
const componentClass = cn(
|
|
34
|
+
ACCORDION.SELECTORS.ACCORDION.replace('.', ''),
|
|
35
|
+
className
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
return (
|
|
39
|
+
<div
|
|
40
|
+
ref={ref}
|
|
41
|
+
className={componentClass}
|
|
42
|
+
{...props}
|
|
43
|
+
>
|
|
44
|
+
{children}
|
|
45
|
+
</div>
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
)
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
${name}.displayName = '${name}';`,
|
|
52
|
+
|
|
53
|
+
// Medium template variant
|
|
54
|
+
medium: (name) => `import React, { memo, forwardRef } from 'react';
|
|
55
|
+
import { cn } from '../../lib/utils';
|
|
56
|
+
import { ACCORDION } from '../../lib/constants/components';
|
|
57
|
+
import type { ${name}Props } from '../../lib/types/components';
|
|
58
|
+
import { use${name} } from '../../lib/composables/use${name}';
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* ${name} component - Medium variant
|
|
62
|
+
* Component with state management and interactions
|
|
63
|
+
*
|
|
64
|
+
* @example
|
|
65
|
+
* \`\`\`tsx
|
|
66
|
+
* <${name}>Hello World</${name}>
|
|
67
|
+
* \`\`\`
|
|
68
|
+
*/
|
|
69
|
+
export const ${name} = memo(
|
|
70
|
+
forwardRef<HTMLDivElement, ${name}Props>(
|
|
71
|
+
({
|
|
72
|
+
children,
|
|
73
|
+
className,
|
|
74
|
+
...props
|
|
75
|
+
}, ref) => {
|
|
76
|
+
const {
|
|
77
|
+
state,
|
|
78
|
+
toggle,
|
|
79
|
+
isOpen,
|
|
80
|
+
setIsOpen,
|
|
81
|
+
getTriggerProps,
|
|
82
|
+
getPanelProps
|
|
83
|
+
} = use${name}({
|
|
84
|
+
// Initial props can be passed here
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
const componentClass = cn(
|
|
88
|
+
ACCORDION.SELECTORS.ACCORDION.replace('.', ''),
|
|
89
|
+
className
|
|
90
|
+
);
|
|
91
|
+
|
|
92
|
+
return (
|
|
93
|
+
<div
|
|
94
|
+
ref={ref}
|
|
95
|
+
className={componentClass}
|
|
96
|
+
data-state={state}
|
|
97
|
+
{...props}
|
|
98
|
+
>
|
|
99
|
+
{children}
|
|
100
|
+
</div>
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
)
|
|
104
|
+
);
|
|
105
|
+
|
|
106
|
+
${name}.displayName = '${name}';`,
|
|
107
|
+
|
|
108
|
+
// Complex template variant
|
|
109
|
+
complex: (name) => `import React, { memo, forwardRef } from 'react';
|
|
110
|
+
import { cn } from '../../lib/utils';
|
|
111
|
+
import { ACCORDION } from '../../lib/constants/components';
|
|
112
|
+
import type { ${name}Props, ${name}State } from '../../lib/types/components';
|
|
113
|
+
import { use${name} } from '../../lib/composables/use${name}';
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* ${name} component - Complex variant
|
|
117
|
+
* Advanced component with validation, accessibility, and state management
|
|
118
|
+
*
|
|
119
|
+
* @example
|
|
120
|
+
* \`\`\`tsx
|
|
121
|
+
* <${name} validationRules={rules}>
|
|
122
|
+
* Trigger content
|
|
123
|
+
* <${name}.Panel>Panel content</${name}.Panel>
|
|
124
|
+
* </${name}>
|
|
125
|
+
* \`\`\`
|
|
126
|
+
*/
|
|
127
|
+
export const ${name} = memo(
|
|
128
|
+
forwardRef<HTMLDivElement, ${name}Props>(
|
|
129
|
+
({
|
|
130
|
+
children,
|
|
131
|
+
className,
|
|
132
|
+
validationRules,
|
|
133
|
+
onValidationChange,
|
|
134
|
+
...props
|
|
135
|
+
}, ref) => {
|
|
136
|
+
const {
|
|
137
|
+
state,
|
|
138
|
+
toggle,
|
|
139
|
+
isOpen,
|
|
140
|
+
setIsOpen,
|
|
141
|
+
isControlled,
|
|
142
|
+
isValid,
|
|
143
|
+
validationMessage,
|
|
144
|
+
getTriggerProps,
|
|
145
|
+
getPanelProps,
|
|
146
|
+
getHeaderProps,
|
|
147
|
+
getContentProps
|
|
148
|
+
} = use${name}({
|
|
149
|
+
validationRules,
|
|
150
|
+
onValidationChange
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
const componentClass = cn(
|
|
154
|
+
ACCORDION.SELECTORS.ACCORDION.replace('.', ''),
|
|
155
|
+
{
|
|
156
|
+
'is-valid': isValid,
|
|
157
|
+
'is-invalid': !isValid && validationMessage,
|
|
158
|
+
'is-controlled': isControlled
|
|
159
|
+
},
|
|
160
|
+
className
|
|
161
|
+
);
|
|
162
|
+
|
|
163
|
+
return (
|
|
164
|
+
<div
|
|
165
|
+
ref={ref}
|
|
166
|
+
className={componentClass}
|
|
167
|
+
data-state={state}
|
|
168
|
+
data-valid={isValid}
|
|
169
|
+
{...getTriggerProps()}
|
|
170
|
+
>
|
|
171
|
+
{children}
|
|
172
|
+
|
|
173
|
+
{!isValid && validationMessage && (
|
|
174
|
+
<div
|
|
175
|
+
id={\`${name.toLowerCase()}-error\`}
|
|
176
|
+
className="c-${name.toLowerCase()}__error"
|
|
177
|
+
role="alert"
|
|
178
|
+
aria-live="polite"
|
|
179
|
+
>
|
|
180
|
+
{validationMessage}
|
|
181
|
+
</div>
|
|
182
|
+
)}
|
|
183
|
+
</div>
|
|
184
|
+
);
|
|
185
|
+
}
|
|
186
|
+
)
|
|
187
|
+
);
|
|
188
|
+
|
|
189
|
+
${name}.displayName = '${name}';`,
|
|
190
|
+
|
|
191
|
+
// Default component template (backward compatibility)
|
|
192
|
+
component: (name) => `import React, { memo, forwardRef } from 'react';
|
|
193
|
+
import { cn } from '../../lib/utils';
|
|
194
|
+
import { ACCORDION } from '../../lib/constants/components';
|
|
195
|
+
import type { ${name}Props } from '../../lib/types/components';
|
|
196
|
+
import { use${name} } from '../../lib/composables/use${name}';
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* ${name} component
|
|
200
|
+
*
|
|
201
|
+
* @example
|
|
202
|
+
* \`\`\`tsx
|
|
203
|
+
* <${name}>Hello World</${name}>
|
|
204
|
+
* \`\`\`
|
|
205
|
+
*/
|
|
206
|
+
export const ${name} = memo(
|
|
207
|
+
forwardRef<HTMLDivElement, ${name}Props>(
|
|
208
|
+
({
|
|
209
|
+
children,
|
|
210
|
+
className,
|
|
211
|
+
...props
|
|
212
|
+
}, ref) => {
|
|
213
|
+
const {
|
|
214
|
+
state,
|
|
215
|
+
toggle,
|
|
216
|
+
isOpen,
|
|
217
|
+
setIsOpen,
|
|
218
|
+
getTriggerProps,
|
|
219
|
+
getPanelProps,
|
|
220
|
+
getHeaderProps,
|
|
221
|
+
getContentProps
|
|
222
|
+
} = use${name}({
|
|
223
|
+
// Initial props can be passed here
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
const componentClass = cn(
|
|
227
|
+
ACCORDION.SELECTORS.ACCORDION.replace('.', ''),
|
|
228
|
+
className
|
|
229
|
+
);
|
|
230
|
+
|
|
231
|
+
return (
|
|
232
|
+
<div
|
|
233
|
+
ref={ref}
|
|
234
|
+
className={componentClass}
|
|
235
|
+
data-state={state}
|
|
236
|
+
{...props}
|
|
237
|
+
>
|
|
238
|
+
{children}
|
|
239
|
+
</div>
|
|
240
|
+
);
|
|
241
|
+
}
|
|
242
|
+
)
|
|
243
|
+
);
|
|
244
|
+
|
|
245
|
+
${name}.displayName = '${name}';`
|
|
246
|
+
import { cn } from '../../lib/utils';
|
|
247
|
+
import { ACCORDION } from '../../lib/constants/components';
|
|
248
|
+
import type { ${name}Props } from '../../lib/types/components';
|
|
249
|
+
import { use${name} } from '../../lib/composables/use${name}';
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* ${name} component
|
|
253
|
+
*
|
|
254
|
+
* @example
|
|
255
|
+
* \`\`\`tsx
|
|
256
|
+
* <${name}>Hello World</${name}>
|
|
257
|
+
* \`\`\`
|
|
258
|
+
*/
|
|
259
|
+
export const ${name} = memo(
|
|
260
|
+
forwardRef<HTMLDivElement, ${name}Props>(
|
|
261
|
+
({
|
|
262
|
+
children,
|
|
263
|
+
className,
|
|
264
|
+
...props
|
|
265
|
+
}, ref) => {
|
|
266
|
+
const {
|
|
267
|
+
state,
|
|
268
|
+
toggle,
|
|
269
|
+
isOpen,
|
|
270
|
+
setIsOpen,
|
|
271
|
+
getTriggerProps,
|
|
272
|
+
getPanelProps,
|
|
273
|
+
getHeaderProps,
|
|
274
|
+
getContentProps
|
|
275
|
+
} = use${name}({
|
|
276
|
+
// Initial props can be passed here
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
const componentClass = cn(
|
|
280
|
+
ACCORDION.SELECTORS.ACCORDION.replace('.', ''),
|
|
281
|
+
className
|
|
282
|
+
);
|
|
283
|
+
|
|
284
|
+
return (
|
|
285
|
+
<div
|
|
286
|
+
ref={ref}
|
|
287
|
+
className={componentClass}
|
|
288
|
+
data-state={state}
|
|
289
|
+
{...props}
|
|
290
|
+
>
|
|
291
|
+
{children}
|
|
292
|
+
</div>
|
|
293
|
+
);
|
|
294
|
+
}
|
|
295
|
+
)
|
|
296
|
+
);
|
|
297
|
+
|
|
298
|
+
${name}.displayName = '${name}';`,
|
|
299
|
+
|
|
300
|
+
index: (name) => `export { default as ${name} } from './${name}';
|
|
301
|
+
export type { ${name}Props } from '../../lib/types/components';`,
|
|
302
|
+
|
|
303
|
+
story: (name) => `import type { Meta, StoryObj } from '@storybook/react';
|
|
304
|
+
import { ${name} } from './${name}';
|
|
305
|
+
|
|
306
|
+
const meta: Meta<typeof ${name}> = {
|
|
307
|
+
title: 'Components/${name}',
|
|
308
|
+
component: ${name},
|
|
309
|
+
parameters: {
|
|
310
|
+
layout: 'centered',
|
|
311
|
+
},
|
|
312
|
+
tags: ['autodocs'],
|
|
313
|
+
argTypes: {
|
|
314
|
+
size: {
|
|
315
|
+
control: 'select',
|
|
316
|
+
options: ['sm', 'md', 'lg'],
|
|
317
|
+
},
|
|
318
|
+
variant: {
|
|
319
|
+
control: 'select',
|
|
320
|
+
options: ['primary', 'secondary', 'success', 'error'],
|
|
321
|
+
},
|
|
322
|
+
disabled: {
|
|
323
|
+
control: 'boolean',
|
|
324
|
+
},
|
|
325
|
+
glass: {
|
|
326
|
+
control: 'boolean',
|
|
327
|
+
},
|
|
328
|
+
},
|
|
329
|
+
};
|
|
330
|
+
|
|
331
|
+
export default meta;
|
|
332
|
+
type Story = StoryObj<typeof meta>;
|
|
333
|
+
|
|
334
|
+
export const Default: Story = {
|
|
335
|
+
args: {
|
|
336
|
+
children: '${name} Component',
|
|
337
|
+
size: 'md',
|
|
338
|
+
variant: 'primary',
|
|
339
|
+
},
|
|
340
|
+
};
|
|
341
|
+
|
|
342
|
+
export const Small: Story = {
|
|
343
|
+
args: {
|
|
344
|
+
...Default.args,
|
|
345
|
+
size: 'sm',
|
|
346
|
+
},
|
|
347
|
+
};
|
|
348
|
+
|
|
349
|
+
export const Large: Story = {
|
|
350
|
+
args: {
|
|
351
|
+
...Default.args,
|
|
352
|
+
size: 'lg',
|
|
353
|
+
},
|
|
354
|
+
};
|
|
355
|
+
|
|
356
|
+
export const Glass: Story = {
|
|
357
|
+
args: {
|
|
358
|
+
...Default.args,
|
|
359
|
+
glass: true,
|
|
360
|
+
},
|
|
361
|
+
};
|
|
362
|
+
`,
|
|
363
|
+
|
|
364
|
+
storyEnhanced: (name) => `import type { Meta, StoryObj } from '@storybook/react';
|
|
365
|
+
import { ${name} } from './${name}';
|
|
366
|
+
|
|
367
|
+
const meta: Meta<typeof ${name}> = {
|
|
368
|
+
title: 'Components/${name}',
|
|
369
|
+
component: ${name},
|
|
370
|
+
parameters: {
|
|
371
|
+
layout: 'centered',
|
|
372
|
+
docs: {
|
|
373
|
+
description: {
|
|
374
|
+
component: 'A versatile ${name.toLowerCase()} component built with Atomix Design System.',
|
|
375
|
+
},
|
|
376
|
+
},
|
|
377
|
+
},
|
|
378
|
+
tags: ['autodocs'],
|
|
379
|
+
argTypes: {
|
|
380
|
+
children: {
|
|
381
|
+
control: 'text',
|
|
382
|
+
description: 'Content to be rendered inside the component',
|
|
383
|
+
},
|
|
384
|
+
size: {
|
|
385
|
+
control: 'select',
|
|
386
|
+
options: ['sm', 'md', 'lg'],
|
|
387
|
+
description: 'Size variant of the component',
|
|
388
|
+
},
|
|
389
|
+
variant: {
|
|
390
|
+
control: 'select',
|
|
391
|
+
options: ['primary', 'secondary', 'success', 'error'],
|
|
392
|
+
description: 'Color variant of the component',
|
|
393
|
+
},
|
|
394
|
+
disabled: {
|
|
395
|
+
control: 'boolean',
|
|
396
|
+
description: 'Whether the component is disabled',
|
|
397
|
+
},
|
|
398
|
+
glass: {
|
|
399
|
+
control: 'boolean',
|
|
400
|
+
description: 'Whether to apply glass effect',
|
|
401
|
+
},
|
|
402
|
+
className: {
|
|
403
|
+
control: 'text',
|
|
404
|
+
description: 'Additional CSS classes',
|
|
405
|
+
},
|
|
406
|
+
},
|
|
407
|
+
};
|
|
408
|
+
|
|
409
|
+
export default meta;
|
|
410
|
+
type Story = StoryObj<typeof meta>;
|
|
411
|
+
|
|
412
|
+
export const Default: Story = {
|
|
413
|
+
args: {
|
|
414
|
+
children: '${name} Component',
|
|
415
|
+
size: 'md',
|
|
416
|
+
variant: 'primary',
|
|
417
|
+
},
|
|
418
|
+
parameters: {
|
|
419
|
+
docs: {
|
|
420
|
+
description: {
|
|
421
|
+
story: 'Default ${name.toLowerCase()} component with primary variant and medium size.',
|
|
422
|
+
},
|
|
423
|
+
},
|
|
424
|
+
},
|
|
425
|
+
};
|
|
426
|
+
|
|
427
|
+
export const Playground: Story = {
|
|
428
|
+
args: {
|
|
429
|
+
children: 'Interactive ${name}',
|
|
430
|
+
size: 'md',
|
|
431
|
+
variant: 'primary',
|
|
432
|
+
},
|
|
433
|
+
parameters: {
|
|
434
|
+
docs: {
|
|
435
|
+
description: {
|
|
436
|
+
story: 'Interactive playground to test different combinations of props.',
|
|
437
|
+
},
|
|
438
|
+
},
|
|
439
|
+
},
|
|
440
|
+
};
|
|
441
|
+
|
|
442
|
+
export const Small: Story = {
|
|
443
|
+
args: {
|
|
444
|
+
...Default.args,
|
|
445
|
+
size: 'sm',
|
|
446
|
+
children: 'Small ${name}',
|
|
447
|
+
},
|
|
448
|
+
};
|
|
449
|
+
|
|
450
|
+
export const Large: Story = {
|
|
451
|
+
args: {
|
|
452
|
+
...Default.args,
|
|
453
|
+
size: 'lg',
|
|
454
|
+
children: 'Large ${name}',
|
|
455
|
+
},
|
|
456
|
+
};
|
|
457
|
+
|
|
458
|
+
export const Secondary: Story = {
|
|
459
|
+
args: {
|
|
460
|
+
...Default.args,
|
|
461
|
+
variant: 'secondary',
|
|
462
|
+
},
|
|
463
|
+
};
|
|
464
|
+
|
|
465
|
+
export const Success: Story = {
|
|
466
|
+
args: {
|
|
467
|
+
...Default.args,
|
|
468
|
+
variant: 'success',
|
|
469
|
+
},
|
|
470
|
+
};
|
|
471
|
+
|
|
472
|
+
export const Error: Story = {
|
|
473
|
+
args: {
|
|
474
|
+
...Default.args,
|
|
475
|
+
variant: 'error',
|
|
476
|
+
},
|
|
477
|
+
};
|
|
478
|
+
|
|
479
|
+
export const Disabled: Story = {
|
|
480
|
+
args: {
|
|
481
|
+
...Default.args,
|
|
482
|
+
disabled: true,
|
|
483
|
+
},
|
|
484
|
+
};
|
|
485
|
+
|
|
486
|
+
export const Glass: Story = {
|
|
487
|
+
args: {
|
|
488
|
+
...Default.args,
|
|
489
|
+
glass: true,
|
|
490
|
+
},
|
|
491
|
+
parameters: {
|
|
492
|
+
docs: {
|
|
493
|
+
description: {
|
|
494
|
+
story: '${name} with glass morphism effect applied.',
|
|
495
|
+
},
|
|
496
|
+
},
|
|
497
|
+
},
|
|
498
|
+
};
|
|
499
|
+
|
|
500
|
+
export const CustomContent: Story = {
|
|
501
|
+
args: {
|
|
502
|
+
children: (
|
|
503
|
+
<div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
|
|
504
|
+
<span>🎨</span>
|
|
505
|
+
<span>Custom ${name} Content</span>
|
|
506
|
+
</div>
|
|
507
|
+
),
|
|
508
|
+
size: 'lg',
|
|
509
|
+
variant: 'primary',
|
|
510
|
+
},
|
|
511
|
+
parameters: {
|
|
512
|
+
docs: {
|
|
513
|
+
description: {
|
|
514
|
+
story: 'Example with custom content including icons and complex markup.',
|
|
515
|
+
},
|
|
516
|
+
},
|
|
517
|
+
},
|
|
518
|
+
};
|
|
519
|
+
`,
|
|
520
|
+
|
|
521
|
+
test: (name) => `import { describe, it, expect } from 'vitest';
|
|
522
|
+
import { render, screen } from '@testing-library/react';
|
|
523
|
+
import { ${name} } from './${name}';
|
|
524
|
+
|
|
525
|
+
describe('${name}', () => {
|
|
526
|
+
it('renders children correctly', () => {
|
|
527
|
+
render(<${name}>Test Content</${name}>);
|
|
528
|
+
expect(screen.getByText('Test Content')).toBeInTheDocument();
|
|
529
|
+
});
|
|
530
|
+
|
|
531
|
+
it('applies size variant classes', () => {
|
|
532
|
+
const { container } = render(<${name} size="lg">Content</${name}>);
|
|
533
|
+
const element = container.firstChild;
|
|
534
|
+
expect(element).toHaveClass('c-${name.toLowerCase()}--lg');
|
|
535
|
+
});
|
|
536
|
+
|
|
537
|
+
it('handles disabled state', () => {
|
|
538
|
+
const { container } = render(<${name} disabled>Content</${name}>);
|
|
539
|
+
const element = container.firstChild;
|
|
540
|
+
expect(element).toHaveAttribute('aria-disabled', 'true');
|
|
541
|
+
expect(element).toHaveClass('is-disabled');
|
|
542
|
+
});
|
|
543
|
+
|
|
544
|
+
it('forwards ref correctly', () => {
|
|
545
|
+
const ref = React.createRef<HTMLDivElement>();
|
|
546
|
+
render(<${name} ref={ref}>Content</${name}>);
|
|
547
|
+
expect(ref.current).toBeInstanceOf(HTMLDivElement);
|
|
548
|
+
});
|
|
549
|
+
});`,
|
|
550
|
+
|
|
551
|
+
scss: (name) => `// =============================================================================
|
|
552
|
+
// ${name.toUpperCase()}
|
|
553
|
+
// =============================================================================
|
|
554
|
+
|
|
555
|
+
@use '../01-settings/settings.${name.toLowerCase()}' as ${name.toLowerCase()};
|
|
556
|
+
|
|
557
|
+
.c-${name.toLowerCase()} {
|
|
558
|
+
// CSS Custom Properties (from settings)
|
|
559
|
+
--#{config.$prefix}${name.toLowerCase()}-width: #{${name.toLowerCase()}.$${name.toLowerCase()}-width};
|
|
560
|
+
--#{config.$prefix}${name.toLowerCase()}-padding-x: #{${name.toLowerCase()}.$${name.toLowerCase()}-padding-x};
|
|
561
|
+
--#{config.$prefix}${name.toLowerCase()}-padding-y: #{${name.toLowerCase()}.$${name.toLowerCase()}-padding-y};
|
|
562
|
+
--#{config.$prefix}${name.toLowerCase()}-bg: #{${name.toLowerCase()}.$${name.toLowerCase()}-bg};
|
|
563
|
+
--#{config.$prefix}${name.toLowerCase()}-color: #{${name.toLowerCase()}.$${name.toLowerCase()}-color};
|
|
564
|
+
--#{config.$prefix}${name.toLowerCase()}-border: #{${name.toLowerCase()}.$${name.toLowerCase()}-border};
|
|
565
|
+
--#{config.$prefix}${name.toLowerCase()}-border-radius: #{${name.toLowerCase()}.$${name.toLowerCase()}-border-radius};
|
|
566
|
+
--#{config.$prefix}${name.toLowerCase()}-transition: #{${name.toLowerCase()}.$${name.toLowerCase()}-transition};
|
|
567
|
+
|
|
568
|
+
// Base styles
|
|
569
|
+
width: var(#{config.$prefix}${name.toLowerCase()}-width);
|
|
570
|
+
padding: var(#{config.$prefix}${name.toLowerCase()}-padding-y) var(#{config.$prefix}${name.toLowerCase()}-padding-x);
|
|
571
|
+
background-color: var(#{config.$prefix}${name.toLowerCase()}-bg);
|
|
572
|
+
color: var(#{config.$prefix}${name.toLowerCase()}-color);
|
|
573
|
+
border: var(#{config.$prefix}${name.toLowerCase()}-border);
|
|
574
|
+
border-radius: var(#{config.$prefix}${name.toLowerCase()}-border-radius);
|
|
575
|
+
transition: var(#{config.$prefix}${name.toLowerCase()}-transition);
|
|
576
|
+
|
|
577
|
+
// Reset and base
|
|
578
|
+
box-sizing: border-box;
|
|
579
|
+
margin: 0;
|
|
580
|
+
font-family: inherit;
|
|
581
|
+
font-size: var(#{config.$prefix}${name.toLowerCase()}-font-size);
|
|
582
|
+
line-height: var(#{config.$prefix}${name.toLowerCase()}-line-height);
|
|
583
|
+
font-weight: var(#{config.$prefix}${name.toLowerCase()}-font-weight);
|
|
584
|
+
|
|
585
|
+
// Size variants
|
|
586
|
+
&--sm {
|
|
587
|
+
--#{config.$prefix}${name.toLowerCase()}-padding-x: #{${name.toLowerCase()}.$${name.toLowerCase()}-sm-padding-x};
|
|
588
|
+
--#{config.$prefix}${name.toLowerCase()}-padding-y: #{${name.toLowerCase()}.$${name.toLowerCase()}-sm-padding-y};
|
|
589
|
+
--#{config.$prefix}${name.toLowerCase()}-font-size: #{${name.toLowerCase()}.$${name.toLowerCase()}-sm-font-size};
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
&--lg {
|
|
593
|
+
--#{config.$prefix}${name.toLowerCase()}-padding-x: #{${name.toLowerCase()}.$${name.toLowerCase()}-lg-padding-x};
|
|
594
|
+
--#{config.$prefix}${name.toLowerCase()}-padding-y: #{${name.toLowerCase()}.$${name.toLowerCase()}-lg-padding-y};
|
|
595
|
+
--#{config.$prefix}${name.toLowerCase()}-font-size: #{${name.toLowerCase()}.$${name.toLowerCase()}-lg-font-size};
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
// Interactive states
|
|
599
|
+
&:hover {
|
|
600
|
+
--#{config.$prefix}${name.toLowerCase()}-bg: #{${name.toLowerCase()}.$${name.toLowerCase()}-hover-bg};
|
|
601
|
+
cursor: pointer;
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
&:focus {
|
|
605
|
+
--#{config.$prefix}${name.toLowerCase()}-bg: #{${name.toLowerCase()}.$${name.toLowerCase()}-focus-bg};
|
|
606
|
+
outline: 2px solid var(--atomix-focus-color);
|
|
607
|
+
outline-offset: 2px;
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
// Disabled state
|
|
611
|
+
&.is-disabled {
|
|
612
|
+
--#{config.$prefix}${name.toLowerCase()}-bg: #{${name.toLowerCase()}.$${name.toLowerCase()}-disabled-bg};
|
|
613
|
+
--#{config.$prefix}${name.toLowerCase()}-color: #{${name.toLowerCase()}.$${name.toLowerCase()}-disabled-color};
|
|
614
|
+
opacity: var(#{config.$prefix}${name.toLowerCase()}-disabled-opacity);
|
|
615
|
+
cursor: not-allowed;
|
|
616
|
+
pointer-events: none;
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
// Glass variant
|
|
620
|
+
&--glass {
|
|
621
|
+
background: #{${name.toLowerCase()}.$${name.toLowerCase()}-glass-bg};
|
|
622
|
+
backdrop-filter: #{${name.toLowerCase()}.$${name.toLowerCase()}-glass-backdrop};
|
|
623
|
+
border-color: #{${name.toLowerCase()}.$${name.toLowerCase()}-glass-border};
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
// Data states for JavaScript interaction
|
|
627
|
+
&[data-state="open"] {
|
|
628
|
+
// Styles for open state
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
&[data-state="closed"] {
|
|
632
|
+
// Styles for closed state
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
`,
|
|
636
|
+
|
|
637
|
+
scssModule: () => ``, // Disabled/Empty as we prefer global SCSS
|
|
638
|
+
|
|
639
|
+
types: (name) => `// ${name} Component Types
|
|
640
|
+
// Generated by Atomix CLI
|
|
641
|
+
// These should be added to src/lib/types/components.ts
|
|
642
|
+
|
|
643
|
+
import type { BaseComponentProps } from './base';
|
|
644
|
+
|
|
645
|
+
/**
|
|
646
|
+
* ${name} component props
|
|
647
|
+
*/
|
|
648
|
+
export interface ${name}Props extends BaseComponentProps {
|
|
649
|
+
/**
|
|
650
|
+
* Whether the ${name.toLowerCase()} is open
|
|
651
|
+
*/
|
|
652
|
+
isOpen?: boolean;
|
|
653
|
+
|
|
654
|
+
/**
|
|
655
|
+
* Whether the ${name.toLowerCase()} is open by default (uncontrolled mode)
|
|
656
|
+
*/
|
|
657
|
+
defaultIsOpen?: boolean;
|
|
658
|
+
|
|
659
|
+
/**
|
|
660
|
+
* Callback fired when ${name.toLowerCase()} is toggled
|
|
661
|
+
*/
|
|
662
|
+
onToggle?: (isOpen: boolean) => void;
|
|
663
|
+
|
|
664
|
+
/**
|
|
665
|
+
* Content to be rendered inside the ${name.toLowerCase()}
|
|
666
|
+
*/
|
|
667
|
+
children?: React.ReactNode;
|
|
668
|
+
|
|
669
|
+
/**
|
|
670
|
+
* Size variant
|
|
671
|
+
*/
|
|
672
|
+
size?: 'sm' | 'md' | 'lg';
|
|
673
|
+
|
|
674
|
+
/**
|
|
675
|
+
* Visual variant
|
|
676
|
+
*/
|
|
677
|
+
variant?: 'primary' | 'secondary';
|
|
678
|
+
|
|
679
|
+
/**
|
|
680
|
+
* Whether the ${name.toLowerCase()} is disabled
|
|
681
|
+
*/
|
|
682
|
+
disabled?: boolean;
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
/**
|
|
686
|
+
* ${name} component state type
|
|
687
|
+
*/
|
|
688
|
+
export type ${name}State = {
|
|
689
|
+
isOpen: boolean;
|
|
690
|
+
isControlled: boolean;
|
|
691
|
+
};
|
|
692
|
+
|
|
693
|
+
/**
|
|
694
|
+
* ${name} context interface
|
|
695
|
+
*/
|
|
696
|
+
export interface ${name}Context {
|
|
697
|
+
component?: ${name}Props;
|
|
698
|
+
state: ${name}State;
|
|
699
|
+
actions: {
|
|
700
|
+
toggle: () => void;
|
|
701
|
+
open: () => void;
|
|
702
|
+
close: () => void;
|
|
703
|
+
setIsOpen: (isOpen: boolean) => void;
|
|
704
|
+
};
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
// Legacy types for backward compatibility
|
|
708
|
+
export type ${name}Ref = HTMLDivElement;`,
|
|
709
|
+
|
|
710
|
+
constants: (name) => `// ${name} Component Constants
|
|
711
|
+
// Generated by Atomix CLI
|
|
712
|
+
// These should be added to src/lib/constants/components.ts
|
|
713
|
+
|
|
714
|
+
export const ${name.toUpperCase()} = {
|
|
715
|
+
SELECTORS: {
|
|
716
|
+
${name.toUpperCase()}: '.c-${name.toLowerCase()}',
|
|
717
|
+
HEADER: '.c-${name.toLowerCase()}__header',
|
|
718
|
+
PANEL: '.c-${name.toLowerCase()}__panel',
|
|
719
|
+
CONTENT: '.c-${name.toLowerCase()}__content',
|
|
720
|
+
},
|
|
721
|
+
CLASSES: {
|
|
722
|
+
IS_OPEN: 'is-open',
|
|
723
|
+
IS_DISABLED: 'is-disabled',
|
|
724
|
+
IS_ANIMATED: 'is-animated',
|
|
725
|
+
},
|
|
726
|
+
DATA_ATTRIBUTES: {
|
|
727
|
+
COMPONENT: 'data-${name.toLowerCase()}',
|
|
728
|
+
STATE: 'data-state',
|
|
729
|
+
DISABLED: 'data-disabled',
|
|
730
|
+
},
|
|
731
|
+
DEFAULT_PROPS: {
|
|
732
|
+
// Add default props specific to ${name}
|
|
733
|
+
},
|
|
734
|
+
ANIMATIONS: {
|
|
735
|
+
DURATION: '200ms',
|
|
736
|
+
EASING: 'cubic-bezier(0.4, 0, 0.2, 1)',
|
|
737
|
+
},
|
|
738
|
+
} as const;
|
|
739
|
+
|
|
740
|
+
// Type exports for ${name} component
|
|
741
|
+
export type ${name}State = 'open' | 'closed';
|
|
742
|
+
export type ${name}Size = 'sm' | 'md' | 'lg';
|
|
743
|
+
export type ${name}Variant = 'primary' | 'secondary';`,
|
|
744
|
+
|
|
745
|
+
scssSettings: (name) => `// ${name} Component Settings
|
|
746
|
+
// Generated by Atomix CLI
|
|
747
|
+
|
|
748
|
+
// Core component dimensions
|
|
749
|
+
$${name.toLowerCase()}-width: 100% !default;
|
|
750
|
+
$${name.toLowerCase()}-padding-x: map.get($spacing-sizes, 5) !default;
|
|
751
|
+
$${name.toLowerCase()}-padding-y: map.get($spacing-sizes, 3) !default;
|
|
752
|
+
$${name.toLowerCase()}-margin-bottom: map.get($spacing-sizes, 2) !default;
|
|
753
|
+
|
|
754
|
+
// Typography settings
|
|
755
|
+
$${name.toLowerCase()}-font-size: map.get($font-sizes, base) !default;
|
|
756
|
+
$${name.toLowerCase()}-font-weight: map.get($font-weights, normal) !default;
|
|
757
|
+
$${name.toLowerCase()}-line-height: map.get($line-heights, base) !default;
|
|
758
|
+
|
|
759
|
+
// Border and radius
|
|
760
|
+
$${name.toLowerCase()}-border: 1px solid var(--atomix-border-default) !default;
|
|
761
|
+
$${name.toLowerCase()}-border-radius: var(--atomix-border-radius-md) !default;
|
|
762
|
+
$${name.toLowerCase()}-border-style: solid !default;
|
|
763
|
+
|
|
764
|
+
// Colors (using CSS custom properties)
|
|
765
|
+
$${name.toLowerCase()}-bg: var(--atomix-bg-surface) !default;
|
|
766
|
+
$${name.toLowerCase()}-color: var(--atomix-text-primary) !default;
|
|
767
|
+
$${name.toLowerCase()}-border-color: var(--atomix-border-default) !default;
|
|
768
|
+
|
|
769
|
+
// Transitions
|
|
770
|
+
$${name.toLowerCase()}-transition: var(--atomix-transition-all) !default;
|
|
771
|
+
$${name.toLowerCase()}-transition-duration: var(--atomix-duration-base) !default;
|
|
772
|
+
$${name.toLowerCase()}-transition-timing: var(--atomix-easing-smooth) !default;
|
|
773
|
+
|
|
774
|
+
// State-specific settings
|
|
775
|
+
$${name.toLowerCase()}-hover-bg: var(--atomix-bg-surface-hover) !default;
|
|
776
|
+
$${name.toLowerCase()}-focus-bg: var(--atomix-bg-surface-focus) !default;
|
|
777
|
+
$${name.toLowerCase()}-disabled-bg: var(--atomix-bg-surface-disabled) !default;
|
|
778
|
+
$${name.toLowerCase()}-disabled-color: var(--atomix-text-disabled) !default;
|
|
779
|
+
$${name.toLowerCase()}-disabled-opacity: var(--atomix-opacity-disabled) !default;
|
|
780
|
+
|
|
781
|
+
// Size variants
|
|
782
|
+
$${name.toLowerCase()}-sm-padding-x: map.get($spacing-sizes, 3) !default;
|
|
783
|
+
$${name.toLowerCase()}-sm-padding-y: map.get($spacing-sizes, 2) !default;
|
|
784
|
+
$${name.toLowerCase()}-sm-font-size: map.get($font-sizes, sm) !default;
|
|
785
|
+
|
|
786
|
+
$${name.toLowerCase()}-lg-padding-x: map.get($spacing-sizes, 7) !default;
|
|
787
|
+
$${name.toLowerCase()}-lg-padding-y: map.get($spacing-sizes, 4) !default;
|
|
788
|
+
$${name.toLowerCase()}-lg-font-size: map.get($font-sizes, lg) !default;
|
|
789
|
+
|
|
790
|
+
// Glass variant settings
|
|
791
|
+
$${name.toLowerCase()}-glass-bg: rgba(255, 255, 255, 0.1) !default;
|
|
792
|
+
$${name.toLowerCase()}-glass-backdrop: blur(10px) !default;
|
|
793
|
+
$${name.toLowerCase()}-glass-border: rgba(255, 255, 255, 0.2) !default;`
|
|
794
|
+
},
|
|
795
|
+
|
|
796
|
+
composable: {
|
|
797
|
+
hook: (name) => `import { useState, useCallback, useRef, useEffect } from 'react';
|
|
798
|
+
import type { ${name}Props } from '../../lib/types/components';
|
|
799
|
+
|
|
800
|
+
/**
|
|
801
|
+
* Custom hook for ${name.toLowerCase()} component
|
|
802
|
+
* Provides controlled/uncontrolled state management and accessibility
|
|
803
|
+
*/
|
|
804
|
+
export function use${name}(initialProps?: Partial<${name}Props>) {
|
|
805
|
+
const {
|
|
806
|
+
isOpen: controlledIsOpen,
|
|
807
|
+
defaultIsOpen = false,
|
|
808
|
+
onToggle,
|
|
809
|
+
...props
|
|
810
|
+
} = initialProps || {};
|
|
811
|
+
|
|
812
|
+
// State management for controlled/uncontrolled pattern
|
|
813
|
+
const [internalIsOpen, setInternalIsOpen] = useState(defaultIsOpen);
|
|
814
|
+
const isControlled = typeof controlledIsOpen === 'boolean';
|
|
815
|
+
const isOpen = isControlled ? controlledIsOpen : internalIsOpen;
|
|
816
|
+
|
|
817
|
+
// Refs for DOM elements
|
|
818
|
+
const triggerRef = useRef<HTMLButtonElement>(null);
|
|
819
|
+
const panelRef = useRef<HTMLDivElement>(null);
|
|
820
|
+
|
|
821
|
+
// Toggle function with controlled support
|
|
822
|
+
const toggle = useCallback(() => {
|
|
823
|
+
if (isControlled) {
|
|
824
|
+
onToggle?.(!isOpen);
|
|
825
|
+
} else {
|
|
826
|
+
setInternalIsOpen(!isOpen);
|
|
827
|
+
onToggle?.(!isOpen);
|
|
828
|
+
}
|
|
829
|
+
}, [isOpen, isControlled, onToggle]);
|
|
830
|
+
|
|
831
|
+
// Open function
|
|
832
|
+
const open = useCallback(() => {
|
|
833
|
+
if (isControlled) {
|
|
834
|
+
onToggle?.(true);
|
|
835
|
+
} else {
|
|
836
|
+
setInternalIsOpen(true);
|
|
837
|
+
onToggle?.(true);
|
|
838
|
+
}
|
|
839
|
+
}, [isControlled, onToggle]);
|
|
840
|
+
|
|
841
|
+
// Close function
|
|
842
|
+
const close = useCallback(() => {
|
|
843
|
+
if (isControlled) {
|
|
844
|
+
onToggle?.(false);
|
|
845
|
+
} else {
|
|
846
|
+
setInternalIsOpen(false);
|
|
847
|
+
onToggle?.(false);
|
|
848
|
+
}
|
|
849
|
+
}, [isControlled, onToggle]);
|
|
850
|
+
|
|
851
|
+
// Keyboard navigation
|
|
852
|
+
const handleKeyDown = useCallback((event: KeyboardEvent) => {
|
|
853
|
+
switch (event.key) {
|
|
854
|
+
case 'Enter':
|
|
855
|
+
case ' ':
|
|
856
|
+
event.preventDefault();
|
|
857
|
+
toggle();
|
|
858
|
+
break;
|
|
859
|
+
case 'Escape':
|
|
860
|
+
if (isOpen) {
|
|
861
|
+
close();
|
|
862
|
+
triggerRef.current?.focus();
|
|
863
|
+
}
|
|
864
|
+
break;
|
|
865
|
+
}
|
|
866
|
+
}, [isOpen, toggle, close]);
|
|
867
|
+
|
|
868
|
+
// Accessibility helpers
|
|
869
|
+
const getTriggerProps = useCallback(() => ({
|
|
870
|
+
ref: triggerRef,
|
|
871
|
+
'aria-expanded': isOpen,
|
|
872
|
+
'aria-controls': panelRef.current?.id,
|
|
873
|
+
onKeyDown: handleKeyDown,
|
|
874
|
+
onClick: toggle,
|
|
875
|
+
}), [isOpen, handleKeyDown, toggle]);
|
|
876
|
+
|
|
877
|
+
const getPanelProps = useCallback(() => ({
|
|
878
|
+
ref: panelRef,
|
|
879
|
+
'aria-hidden': !isOpen,
|
|
880
|
+
role: 'region',
|
|
881
|
+
}), [isOpen]);
|
|
882
|
+
|
|
883
|
+
const getHeaderProps = useCallback(() => ({
|
|
884
|
+
role: 'heading',
|
|
885
|
+
'aria-level': 3,
|
|
886
|
+
}), []);
|
|
887
|
+
|
|
888
|
+
const getContentProps = useCallback(() => ({
|
|
889
|
+
// Content-specific props
|
|
890
|
+
}), []);
|
|
891
|
+
|
|
892
|
+
// State object for external access
|
|
893
|
+
const state = {
|
|
894
|
+
isOpen,
|
|
895
|
+
isControlled,
|
|
896
|
+
};
|
|
897
|
+
|
|
898
|
+
// Set controlled state from external updates
|
|
899
|
+
const setIsOpen = useCallback((newIsOpen: boolean) => {
|
|
900
|
+
if (!isControlled) {
|
|
901
|
+
setInternalIsOpen(newIsOpen);
|
|
902
|
+
}
|
|
903
|
+
}, [isControlled]);
|
|
904
|
+
|
|
905
|
+
return {
|
|
906
|
+
// State
|
|
907
|
+
state,
|
|
908
|
+
isOpen,
|
|
909
|
+
isControlled,
|
|
910
|
+
|
|
911
|
+
// Actions
|
|
912
|
+
toggle,
|
|
913
|
+
open,
|
|
914
|
+
close,
|
|
915
|
+
setIsOpen,
|
|
916
|
+
|
|
917
|
+
// Props helpers
|
|
918
|
+
getTriggerProps,
|
|
919
|
+
getPanelProps,
|
|
920
|
+
getHeaderProps,
|
|
921
|
+
getContentProps,
|
|
922
|
+
|
|
923
|
+
// Refs
|
|
924
|
+
triggerRef,
|
|
925
|
+
panelRef,
|
|
926
|
+
};
|
|
927
|
+
}
|
|
928
|
+
|
|
929
|
+
export default use${name};`
|
|
930
|
+
}
|
|
931
|
+
};
|
|
932
|
+
|
|
933
|
+
// Token generation functions
|
|
934
|
+
export function generateColorTokens() {
|
|
935
|
+
return `// Custom Color Tokens
|
|
936
|
+
// Generated by Atomix CLI
|
|
937
|
+
// =============================================================================
|
|
938
|
+
|
|
939
|
+
// Brand Colors
|
|
940
|
+
// Customize these to match your brand identity
|
|
941
|
+
$custom-primary-1: #fff9e6 !default;
|
|
942
|
+
$custom-primary-2: #fff4cc !default;
|
|
943
|
+
$custom-primary-3: #ffe699 !default;
|
|
944
|
+
$custom-primary-4: #ffd966 !default;
|
|
945
|
+
$custom-primary-5: #ffcc33 !default;
|
|
946
|
+
$custom-primary-6: #ffb800 !default; // Main brand color
|
|
947
|
+
$custom-primary-7: #e6a600 !default;
|
|
948
|
+
$custom-primary-8: #cc9400 !default;
|
|
949
|
+
$custom-primary-9: #b38200 !default;
|
|
950
|
+
$custom-primary-10: #997000 !default;
|
|
951
|
+
|
|
952
|
+
// Semantic Colors
|
|
953
|
+
$custom-success: #22c55e !default;
|
|
954
|
+
$custom-warning: #eab308 !default;
|
|
955
|
+
$custom-error: #ef4444 !default;
|
|
956
|
+
$custom-info: #3b82f6 !default;
|
|
957
|
+
|
|
958
|
+
// Neutral Colors
|
|
959
|
+
$custom-gray-1: #f9fafb !default;
|
|
960
|
+
$custom-gray-2: #f3f4f6 !default;
|
|
961
|
+
$custom-gray-3: #e5e7eb !default;
|
|
962
|
+
$custom-gray-4: #d1d5db !default;
|
|
963
|
+
$custom-gray-5: #9ca3af !default;
|
|
964
|
+
$custom-gray-6: #6b7280 !default;
|
|
965
|
+
$custom-gray-7: #4b5563 !default;
|
|
966
|
+
$custom-gray-8: #374151 !default;
|
|
967
|
+
$custom-gray-9: #1f2937 !default;
|
|
968
|
+
$custom-gray-10: #111827 !default;
|
|
969
|
+
|
|
970
|
+
// Background Colors
|
|
971
|
+
$custom-body-bg: #ffffff !default;
|
|
972
|
+
$custom-body-bg-dark: #1f2937 !default;
|
|
973
|
+
|
|
974
|
+
// Text Colors
|
|
975
|
+
$custom-body-color: $custom-gray-10 !default;
|
|
976
|
+
$custom-body-color-dark: #ffffff !default;
|
|
977
|
+
|
|
978
|
+
// Link Colors
|
|
979
|
+
$custom-link-color: $custom-primary-6 !default;
|
|
980
|
+
$custom-link-hover-color: $custom-primary-7 !default;
|
|
981
|
+
|
|
982
|
+
// Border Colors
|
|
983
|
+
$custom-border-color: $custom-gray-3 !default;
|
|
984
|
+
$custom-border-color-dark: $custom-gray-7 !default;
|
|
985
|
+
|
|
986
|
+
// Focus Colors
|
|
987
|
+
$custom-focus-color: $custom-primary-5 !default;
|
|
988
|
+
$custom-focus-color-dark: $custom-primary-4 !default;
|
|
989
|
+
|
|
990
|
+
// Export custom colors to override defaults
|
|
991
|
+
$primary: $custom-primary-6 !default;
|
|
992
|
+
$success: $custom-success !default;
|
|
993
|
+
$warning: $custom-warning !default;
|
|
994
|
+
$error: $custom-error !default;
|
|
995
|
+
$info: $custom-info !default;
|
|
996
|
+
|
|
997
|
+
// Dark mode overrides
|
|
998
|
+
$body-bg-dark: $custom-body-bg-dark !default;
|
|
999
|
+
$body-color-dark: $custom-body-color-dark !default;
|
|
1000
|
+
$border-color-dark: $custom-border-color-dark !default;
|
|
1001
|
+
`;
|
|
1002
|
+
}
|
|
1003
|
+
|
|
1004
|
+
export function generateSpacingTokens() {
|
|
1005
|
+
return `// Custom Spacing Tokens
|
|
1006
|
+
// Generated by Atomix CLI
|
|
1007
|
+
// =============================================================================
|
|
1008
|
+
|
|
1009
|
+
// Base spacing unit (change this to scale all spacing)
|
|
1010
|
+
$custom-spacing-base: 0.25rem !default; // 4px
|
|
1011
|
+
|
|
1012
|
+
// Spacing scale
|
|
1013
|
+
$custom-spacing-0: 0 !default;
|
|
1014
|
+
$custom-spacing-1: $custom-spacing-base !default; // 4px
|
|
1015
|
+
$custom-spacing-2: calc($custom-spacing-base * 2) !default; // 8px
|
|
1016
|
+
$custom-spacing-3: calc($custom-spacing-base * 3) !default; // 12px
|
|
1017
|
+
$custom-spacing-4: calc($custom-spacing-base * 4) !default; // 16px
|
|
1018
|
+
$custom-spacing-5: calc($custom-spacing-base * 5) !default; // 20px
|
|
1019
|
+
$custom-spacing-6: calc($custom-spacing-base * 6) !default; // 24px
|
|
1020
|
+
$custom-spacing-7: calc($custom-spacing-base * 7) !default; // 28px
|
|
1021
|
+
$custom-spacing-8: calc($custom-spacing-base * 8) !default; // 32px
|
|
1022
|
+
$custom-spacing-9: calc($custom-spacing-base * 9) !default; // 36px
|
|
1023
|
+
$custom-spacing-10: calc($custom-spacing-base * 10) !default; // 40px
|
|
1024
|
+
$custom-spacing-11: calc($custom-spacing-base * 11) !default; // 44px
|
|
1025
|
+
$custom-spacing-12: calc($custom-spacing-base * 12) !default; // 48px
|
|
1026
|
+
$custom-spacing-14: calc($custom-spacing-base * 14) !default; // 56px
|
|
1027
|
+
$custom-spacing-16: calc($custom-spacing-base * 16) !default; // 64px
|
|
1028
|
+
$custom-spacing-20: calc($custom-spacing-base * 20) !default; // 80px
|
|
1029
|
+
$custom-spacing-24: calc($custom-spacing-base * 24) !default; // 96px
|
|
1030
|
+
$custom-spacing-28: calc($custom-spacing-base * 28) !default; // 112px
|
|
1031
|
+
$custom-spacing-32: calc($custom-spacing-base * 32) !default; // 128px
|
|
1032
|
+
$custom-spacing-36: calc($custom-spacing-base * 36) !default; // 144px
|
|
1033
|
+
$custom-spacing-40: calc($custom-spacing-base * 40) !default; // 160px
|
|
1034
|
+
$custom-spacing-44: calc($custom-spacing-base * 44) !default; // 176px
|
|
1035
|
+
$custom-spacing-48: calc($custom-spacing-base * 48) !default; // 192px
|
|
1036
|
+
$custom-spacing-52: calc($custom-spacing-base * 52) !default; // 208px
|
|
1037
|
+
$custom-spacing-56: calc($custom-spacing-base * 56) !default; // 224px
|
|
1038
|
+
$custom-spacing-60: calc($custom-spacing-base * 60) !default; // 240px
|
|
1039
|
+
$custom-spacing-64: calc($custom-spacing-base * 64) !default; // 256px
|
|
1040
|
+
|
|
1041
|
+
// Component-specific spacing
|
|
1042
|
+
$custom-button-padding-x: $custom-spacing-4 !default;
|
|
1043
|
+
$custom-button-padding-y: $custom-spacing-2 !default;
|
|
1044
|
+
$custom-card-padding: $custom-spacing-6 !default;
|
|
1045
|
+
$custom-modal-padding: $custom-spacing-8 !default;
|
|
1046
|
+
|
|
1047
|
+
// Layout spacing
|
|
1048
|
+
$custom-container-padding: $custom-spacing-4 !default;
|
|
1049
|
+
$custom-grid-gap: $custom-spacing-6 !default;
|
|
1050
|
+
$custom-section-spacing: $custom-spacing-16 !default;
|
|
1051
|
+
|
|
1052
|
+
// Export to override defaults
|
|
1053
|
+
$spacing-sizes: (
|
|
1054
|
+
0: $custom-spacing-0,
|
|
1055
|
+
1: $custom-spacing-1,
|
|
1056
|
+
2: $custom-spacing-2,
|
|
1057
|
+
3: $custom-spacing-3,
|
|
1058
|
+
4: $custom-spacing-4,
|
|
1059
|
+
5: $custom-spacing-5,
|
|
1060
|
+
6: $custom-spacing-6,
|
|
1061
|
+
7: $custom-spacing-7,
|
|
1062
|
+
8: $custom-spacing-8,
|
|
1063
|
+
9: $custom-spacing-9,
|
|
1064
|
+
10: $custom-spacing-10,
|
|
1065
|
+
12: $custom-spacing-12,
|
|
1066
|
+
16: $custom-spacing-16,
|
|
1067
|
+
20: $custom-spacing-20,
|
|
1068
|
+
24: $custom-spacing-24,
|
|
1069
|
+
32: $custom-spacing-32,
|
|
1070
|
+
40: $custom-spacing-40,
|
|
1071
|
+
48: $custom-spacing-48,
|
|
1072
|
+
56: $custom-spacing-56,
|
|
1073
|
+
64: $custom-spacing-64,
|
|
1074
|
+
) !default;
|
|
1075
|
+
`;
|
|
1076
|
+
}
|
|
1077
|
+
|
|
1078
|
+
export function generateTypographyTokens() {
|
|
1079
|
+
return `// Custom Typography Tokens
|
|
1080
|
+
// Generated by Atomix CLI
|
|
1081
|
+
// =============================================================================
|
|
1082
|
+
|
|
1083
|
+
// Font Families
|
|
1084
|
+
$custom-font-family-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif !default;
|
|
1085
|
+
$custom-font-family-serif: Georgia, "Times New Roman", Times, serif !default;
|
|
1086
|
+
$custom-font-family-mono: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace !default;
|
|
1087
|
+
|
|
1088
|
+
// Font Size Scale
|
|
1089
|
+
$custom-font-size-xs: 0.75rem !default; // 12px
|
|
1090
|
+
$custom-font-size-sm: 0.875rem !default; // 14px
|
|
1091
|
+
$custom-font-size-base: 1rem !default; // 16px
|
|
1092
|
+
$custom-font-size-lg: 1.125rem !default; // 18px
|
|
1093
|
+
$custom-font-size-xl: 1.25rem !default; // 20px
|
|
1094
|
+
$custom-font-size-2xl: 1.5rem !default; // 24px
|
|
1095
|
+
$custom-font-size-3xl: 1.875rem !default; // 30px
|
|
1096
|
+
$custom-font-size-4xl: 2.25rem !default; // 36px
|
|
1097
|
+
$custom-font-size-5xl: 3rem !default; // 48px
|
|
1098
|
+
$custom-font-size-6xl: 3.75rem !default; // 60px
|
|
1099
|
+
$custom-font-size-7xl: 4.5rem !default; // 72px
|
|
1100
|
+
$custom-font-size-8xl: 6rem !default; // 96px
|
|
1101
|
+
|
|
1102
|
+
// Line Heights
|
|
1103
|
+
$custom-line-height-tight: 1.2 !default;
|
|
1104
|
+
$custom-line-height-base: 1.5 !default;
|
|
1105
|
+
$custom-line-height-relaxed: 1.75 !default;
|
|
1106
|
+
$custom-line-height-loose: 2 !default;
|
|
1107
|
+
|
|
1108
|
+
// Font Weights
|
|
1109
|
+
$custom-font-weight-light: 300 !default;
|
|
1110
|
+
$custom-font-weight-normal: 400 !default;
|
|
1111
|
+
$custom-font-weight-medium: 500 !default;
|
|
1112
|
+
$custom-font-weight-semibold: 600 !default;
|
|
1113
|
+
$custom-font-weight-bold: 700 !default;
|
|
1114
|
+
$custom-font-weight-heavy: 800 !default;
|
|
1115
|
+
$custom-font-weight-black: 900 !default;
|
|
1116
|
+
|
|
1117
|
+
// Letter Spacing
|
|
1118
|
+
$custom-letter-spacing-tight: -0.05em !default;
|
|
1119
|
+
$custom-letter-spacing-normal: 0 !default;
|
|
1120
|
+
$custom-letter-spacing-wide: 0.025em !default;
|
|
1121
|
+
$custom-letter-spacing-wider: 0.05em !default;
|
|
1122
|
+
$custom-letter-spacing-widest: 0.1em !default;
|
|
1123
|
+
|
|
1124
|
+
// Heading Sizes
|
|
1125
|
+
$custom-h1-font-size: $custom-font-size-5xl !default;
|
|
1126
|
+
$custom-h2-font-size: $custom-font-size-4xl !default;
|
|
1127
|
+
$custom-h3-font-size: $custom-font-size-3xl !default;
|
|
1128
|
+
$custom-h4-font-size: $custom-font-size-2xl !default;
|
|
1129
|
+
$custom-h5-font-size: $custom-font-size-xl !default;
|
|
1130
|
+
$custom-h6-font-size: $custom-font-size-lg !default;
|
|
1131
|
+
|
|
1132
|
+
// Export to override defaults
|
|
1133
|
+
$font-family-base: $custom-font-family-sans !default;
|
|
1134
|
+
$font-family-monospace: $custom-font-family-mono !default;
|
|
1135
|
+
$font-size-base: $custom-font-size-base !default;
|
|
1136
|
+
$font-size-sm: $custom-font-size-sm !default;
|
|
1137
|
+
$font-size-lg: $custom-font-size-lg !default;
|
|
1138
|
+
$line-height-base: $custom-line-height-base !default;
|
|
1139
|
+
$font-weight-base: $custom-font-weight-normal !default;
|
|
1140
|
+
|
|
1141
|
+
// Heading overrides
|
|
1142
|
+
$h1-font-size: $custom-h1-font-size !default;
|
|
1143
|
+
$h2-font-size: $custom-h2-font-size !default;
|
|
1144
|
+
$h3-font-size: $custom-h3-font-size !default;
|
|
1145
|
+
$h4-font-size: $custom-h4-font-size !default;
|
|
1146
|
+
$h5-font-size: $custom-h5-font-size !default;
|
|
1147
|
+
$h6-font-size: $custom-h6-font-size !default;
|
|
1148
|
+
`;
|
|
1149
|
+
}
|
|
1150
|
+
|
|
1151
|
+
export function generateShadowTokens() {
|
|
1152
|
+
return `// Custom Box Shadow Tokens
|
|
1153
|
+
// Generated by Atomix CLI
|
|
1154
|
+
// =============================================================================
|
|
1155
|
+
|
|
1156
|
+
// Shadow Colors
|
|
1157
|
+
$custom-shadow-color: rgba(0, 0, 0, 0.1) !default;
|
|
1158
|
+
$custom-shadow-color-dark: rgba(0, 0, 0, 0.2) !default;
|
|
1159
|
+
|
|
1160
|
+
// Shadow Sizes
|
|
1161
|
+
$custom-shadow-xs: 0 1px 2px 0 rgba(0, 0, 0, 0.05) !default;
|
|
1162
|
+
$custom-shadow-sm: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06) !default;
|
|
1163
|
+
$custom-shadow-base: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06) !default;
|
|
1164
|
+
$custom-shadow-md: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05) !default;
|
|
1165
|
+
$custom-shadow-lg: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04) !default;
|
|
1166
|
+
$custom-shadow-xl: 0 25px 50px -12px rgba(0, 0, 0, 0.25) !default;
|
|
1167
|
+
$custom-shadow-2xl: 0 35px 60px -15px rgba(0, 0, 0, 0.3) !default;
|
|
1168
|
+
$custom-shadow-inner: inset 0 2px 4px 0 rgba(0, 0, 0, 0.06) !default;
|
|
1169
|
+
$custom-shadow-none: none !default;
|
|
1170
|
+
|
|
1171
|
+
// Component-specific shadows
|
|
1172
|
+
$custom-button-shadow: $custom-shadow-sm !default;
|
|
1173
|
+
$custom-button-shadow-hover: $custom-shadow-md !default;
|
|
1174
|
+
$custom-card-shadow: $custom-shadow-base !default;
|
|
1175
|
+
$custom-dropdown-shadow: $custom-shadow-lg !default;
|
|
1176
|
+
$custom-modal-shadow: $custom-shadow-xl !default;
|
|
1177
|
+
$custom-popover-shadow: $custom-shadow-lg !default;
|
|
1178
|
+
$custom-tooltip-shadow: $custom-shadow-md !default;
|
|
1179
|
+
|
|
1180
|
+
// Dark mode shadows
|
|
1181
|
+
$custom-shadow-xs-dark: 0 1px 2px 0 rgba(0, 0, 0, 0.3) !default;
|
|
1182
|
+
$custom-shadow-sm-dark: 0 1px 3px 0 rgba(0, 0, 0, 0.4), 0 1px 2px 0 rgba(0, 0, 0, 0.3) !default;
|
|
1183
|
+
$custom-shadow-base-dark: 0 4px 6px -1px rgba(0, 0, 0, 0.4), 0 2px 4px -1px rgba(0, 0, 0, 0.3) !default;
|
|
1184
|
+
$custom-shadow-lg-dark: 0 20px 25px -5px rgba(0, 0, 0, 0.5), 0 10px 10px -5px rgba(0, 0, 0, 0.4) !default;
|
|
1185
|
+
$custom-shadow-xl-dark: 0 25px 50px -12px rgba(0, 0, 0, 0.6) !default;
|
|
1186
|
+
|
|
1187
|
+
// Export to override defaults
|
|
1188
|
+
$box-shadow: $custom-shadow-base !default;
|
|
1189
|
+
$box-shadow-xs: $custom-shadow-xs !default;
|
|
1190
|
+
$box-shadow-sm: $custom-shadow-sm !default;
|
|
1191
|
+
$box-shadow-lg: $custom-shadow-lg !default;
|
|
1192
|
+
$box-shadow-xl: $custom-shadow-xl !default;
|
|
1193
|
+
$box-shadow-inset: $custom-shadow-inner !default;
|
|
1194
|
+
|
|
1195
|
+
// Dark mode exports
|
|
1196
|
+
$box-shadow-dark: $custom-shadow-base-dark !default;
|
|
1197
|
+
$box-shadow-xs-dark: $custom-shadow-xs-dark !default;
|
|
1198
|
+
$box-shadow-sm-dark: $custom-shadow-sm-dark !default;
|
|
1199
|
+
$box-shadow-lg-dark: $custom-shadow-lg-dark !default;
|
|
1200
|
+
$box-shadow-xl-dark: $custom-shadow-xl-dark !default;
|
|
1201
|
+
`;
|
|
1202
|
+
}
|
|
1203
|
+
|
|
1204
|
+
export function generateRadiusTokens() {
|
|
1205
|
+
return `// Custom Border Radius Tokens
|
|
1206
|
+
// Generated by Atomix CLI
|
|
1207
|
+
// =============================================================================
|
|
1208
|
+
|
|
1209
|
+
// Base radius unit
|
|
1210
|
+
$custom-radius-base: 0.25rem !default; // 4px
|
|
1211
|
+
|
|
1212
|
+
// Radius Scale
|
|
1213
|
+
$custom-radius-none: 0 !default;
|
|
1214
|
+
$custom-radius-sm: calc($custom-radius-base * 0.5) !default; // 2px
|
|
1215
|
+
$custom-radius-base: $custom-radius-base !default; // 4px
|
|
1216
|
+
$custom-radius-md: calc($custom-radius-base * 1.5) !default; // 6px
|
|
1217
|
+
$custom-radius-lg: calc($custom-radius-base * 2) !default; // 8px
|
|
1218
|
+
$custom-radius-xl: calc($custom-radius-base * 3) !default; // 12px
|
|
1219
|
+
$custom-radius-2xl: calc($custom-radius-base * 4) !default; // 16px
|
|
1220
|
+
$custom-radius-3xl: calc($custom-radius-base * 6) !default; // 24px
|
|
1221
|
+
$custom-radius-4xl: calc($custom-radius-base * 8) !default; // 32px
|
|
1222
|
+
$custom-radius-full: 9999px !default; // Fully rounded
|
|
1223
|
+
|
|
1224
|
+
// Component-specific radius
|
|
1225
|
+
$custom-button-radius: $custom-radius-md !default;
|
|
1226
|
+
$custom-button-radius-sm: $custom-radius-sm !default;
|
|
1227
|
+
$custom-button-radius-lg: $custom-radius-lg !default;
|
|
1228
|
+
$custom-card-radius: $custom-radius-lg !default;
|
|
1229
|
+
$custom-input-radius: $custom-radius-md !default;
|
|
1230
|
+
$custom-badge-radius: $custom-radius-full !default;
|
|
1231
|
+
$custom-chip-radius: $custom-radius-full !default;
|
|
1232
|
+
$custom-tooltip-radius: $custom-radius-md !default;
|
|
1233
|
+
$custom-modal-radius: $custom-radius-xl !default;
|
|
1234
|
+
$custom-dropdown-radius: $custom-radius-lg !default;
|
|
1235
|
+
|
|
1236
|
+
// Export to override defaults
|
|
1237
|
+
$border-radius: $custom-radius-md !default;
|
|
1238
|
+
$border-radius-sm: $custom-radius-sm !default;
|
|
1239
|
+
$border-radius-lg: $custom-radius-lg !default;
|
|
1240
|
+
$border-radius-xl: $custom-radius-xl !default;
|
|
1241
|
+
$border-radius-xxl: $custom-radius-2xl !default;
|
|
1242
|
+
$border-radius-3xl: $custom-radius-3xl !default;
|
|
1243
|
+
$border-radius-4xl: $custom-radius-4xl !default;
|
|
1244
|
+
$border-radius-pill: $custom-radius-full !default;
|
|
1245
|
+
|
|
1246
|
+
// Component radius exports
|
|
1247
|
+
$btn-border-radius: $custom-button-radius !default;
|
|
1248
|
+
$btn-border-radius-sm: $custom-button-radius-sm !default;
|
|
1249
|
+
$btn-border-radius-lg: $custom-button-radius-lg !default;
|
|
1250
|
+
$card-border-radius: $custom-card-radius !default;
|
|
1251
|
+
$input-border-radius: $custom-input-radius !default;
|
|
1252
|
+
$badge-border-radius: $custom-badge-radius !default;
|
|
1253
|
+
`;
|
|
1254
|
+
}
|
|
1255
|
+
|
|
1256
|
+
export function generateAnimationTokens() {
|
|
1257
|
+
return `// Custom Animation Tokens
|
|
1258
|
+
// Generated by Atomix CLI
|
|
1259
|
+
// =============================================================================
|
|
1260
|
+
|
|
1261
|
+
// Transition Durations
|
|
1262
|
+
$custom-duration-instant: 0s !default;
|
|
1263
|
+
$custom-duration-fast: 0.15s !default;
|
|
1264
|
+
$custom-duration-base: 0.3s !default;
|
|
1265
|
+
$custom-duration-slow: 0.5s !default;
|
|
1266
|
+
$custom-duration-slower: 0.7s !default;
|
|
1267
|
+
$custom-duration-slowest: 1s !default;
|
|
1268
|
+
|
|
1269
|
+
// Easing Functions
|
|
1270
|
+
$custom-ease-linear: linear !default;
|
|
1271
|
+
$custom-ease-in: cubic-bezier(0.4, 0, 1, 1) !default;
|
|
1272
|
+
$custom-ease-out: cubic-bezier(0, 0, 0.2, 1) !default;
|
|
1273
|
+
$custom-ease-in-out: cubic-bezier(0.4, 0, 0.2, 1) !default;
|
|
1274
|
+
$custom-ease-bounce: cubic-bezier(0.68, -0.55, 0.265, 1.55) !default;
|
|
1275
|
+
$custom-ease-smooth: cubic-bezier(0.23, 1, 0.32, 1) !default;
|
|
1276
|
+
|
|
1277
|
+
// Transition Properties
|
|
1278
|
+
$custom-transition-all: all $custom-duration-base $custom-ease-smooth !default;
|
|
1279
|
+
$custom-transition-colors: background-color $custom-duration-base $custom-ease-smooth,
|
|
1280
|
+
border-color $custom-duration-base $custom-ease-smooth,
|
|
1281
|
+
color $custom-duration-base $custom-ease-smooth,
|
|
1282
|
+
fill $custom-duration-base $custom-ease-smooth,
|
|
1283
|
+
stroke $custom-duration-base $custom-ease-smooth !default;
|
|
1284
|
+
$custom-transition-opacity: opacity $custom-duration-base $custom-ease-smooth !default;
|
|
1285
|
+
$custom-transition-shadow: box-shadow $custom-duration-base $custom-ease-smooth !default;
|
|
1286
|
+
$custom-transition-transform: transform $custom-duration-base $custom-ease-smooth !default;
|
|
1287
|
+
|
|
1288
|
+
// Component-specific transitions
|
|
1289
|
+
$custom-button-transition: $custom-transition-colors, $custom-transition-shadow, $custom-transition-transform !default;
|
|
1290
|
+
$custom-link-transition: $custom-transition-colors, text-decoration-color $custom-duration-base $custom-ease-smooth !default;
|
|
1291
|
+
$custom-input-transition: $custom-transition-colors, $custom-transition-shadow !default;
|
|
1292
|
+
$custom-card-transition: $custom-transition-shadow, $custom-transition-transform !default;
|
|
1293
|
+
$custom-modal-transition: $custom-transition-opacity, $custom-transition-transform !default;
|
|
1294
|
+
$custom-dropdown-transition: $custom-transition-opacity, $custom-transition-transform !default;
|
|
1295
|
+
|
|
1296
|
+
// Animation Keyframes (examples)
|
|
1297
|
+
@keyframes custom-fade-in {
|
|
1298
|
+
from { opacity: 0; }
|
|
1299
|
+
to { opacity: 1; }
|
|
1300
|
+
}
|
|
1301
|
+
|
|
1302
|
+
@keyframes custom-slide-in-up {
|
|
1303
|
+
from {
|
|
1304
|
+
transform: translateY(10px);
|
|
1305
|
+
opacity: 0;
|
|
1306
|
+
}
|
|
1307
|
+
to {
|
|
1308
|
+
transform: translateY(0);
|
|
1309
|
+
opacity: 1;
|
|
1310
|
+
}
|
|
1311
|
+
}
|
|
1312
|
+
|
|
1313
|
+
@keyframes custom-scale-in {
|
|
1314
|
+
from {
|
|
1315
|
+
transform: scale(0.95);
|
|
1316
|
+
opacity: 0;
|
|
1317
|
+
}
|
|
1318
|
+
to {
|
|
1319
|
+
transform: scale(1);
|
|
1320
|
+
opacity: 1;
|
|
1321
|
+
}
|
|
1322
|
+
}
|
|
1323
|
+
|
|
1324
|
+
@keyframes custom-spin {
|
|
1325
|
+
from { transform: rotate(0deg); }
|
|
1326
|
+
to { transform: rotate(360deg); }
|
|
1327
|
+
}
|
|
1328
|
+
|
|
1329
|
+
// Export to override defaults
|
|
1330
|
+
$transition-fast: $custom-transition-all !default;
|
|
1331
|
+
$transition-base: $custom-transition-all !default;
|
|
1332
|
+
$transition-slow: all $custom-duration-slow $custom-ease-smooth !default;
|
|
1333
|
+
|
|
1334
|
+
// Duration exports
|
|
1335
|
+
$transition-duration-fast: $custom-duration-fast !default;
|
|
1336
|
+
$transition-duration-base: $custom-duration-base !default;
|
|
1337
|
+
$transition-duration-slow: $custom-duration-slow !default;
|
|
1338
|
+
|
|
1339
|
+
// Easing exports
|
|
1340
|
+
$easing-base: $custom-ease-smooth !default;
|
|
1341
|
+
$easing-ease-in-out: $custom-ease-in-out !default;
|
|
1342
|
+
$easing-ease-out: $custom-ease-out !default;
|
|
1343
|
+
$easing-ease-in: $custom-ease-in !default;
|
|
1344
|
+
`;
|
|
1345
|
+
}
|
|
1346
|
+
|
|
1347
|
+
/**
|
|
1348
|
+
* Project templates for different project types
|
|
1349
|
+
*/
|
|
1350
|
+
export const projectTemplates = {
|
|
1351
|
+
react: {
|
|
1352
|
+
dependencies: ['react', 'react-dom'],
|
|
1353
|
+
devDependencies: ['@vitejs/plugin-react', 'vite', 'typescript'],
|
|
1354
|
+
files: {
|
|
1355
|
+
'src/App.tsx': `import React from 'react';
|
|
1356
|
+
import './App.css';
|
|
1357
|
+
|
|
1358
|
+
function App() {
|
|
1359
|
+
return (
|
|
1360
|
+
<div className="App">
|
|
1361
|
+
<header className="App-header">
|
|
1362
|
+
<h1>Welcome to Atomix Design System</h1>
|
|
1363
|
+
<p>
|
|
1364
|
+
Your React application is ready with Atomix components!
|
|
1365
|
+
</p>
|
|
1366
|
+
</header>
|
|
1367
|
+
</div>
|
|
1368
|
+
);
|
|
1369
|
+
}
|
|
1370
|
+
|
|
1371
|
+
export default App;`,
|
|
1372
|
+
'src/main.tsx': `import React from 'react';
|
|
1373
|
+
import ReactDOM from 'react-dom/client';
|
|
1374
|
+
import App from './App';
|
|
1375
|
+
|
|
1376
|
+
ReactDOM.createRoot(document.getElementById('root')!).render(
|
|
1377
|
+
<React.StrictMode>
|
|
1378
|
+
<App />
|
|
1379
|
+
</React.StrictMode>,
|
|
1380
|
+
);`,
|
|
1381
|
+
'src/App.css': `/* Import Atomix styles */
|
|
1382
|
+
@use '@shohojdhara/atomix/scss/settings' with (
|
|
1383
|
+
// Your custom theme overrides here
|
|
1384
|
+
);
|
|
1385
|
+
@use '@shohojdhara/atomix/scss/components';
|
|
1386
|
+
|
|
1387
|
+
.App {
|
|
1388
|
+
text-align: center;
|
|
1389
|
+
}
|
|
1390
|
+
|
|
1391
|
+
.App-header {
|
|
1392
|
+
background-color: #282c34;
|
|
1393
|
+
padding: 20px;
|
|
1394
|
+
color: white;
|
|
1395
|
+
min-height: 100vh;
|
|
1396
|
+
display: flex;
|
|
1397
|
+
flex-direction: column;
|
|
1398
|
+
align-items: center;
|
|
1399
|
+
justify-content: center;
|
|
1400
|
+
font-size: calc(10px + 2vmin);
|
|
1401
|
+
}`,
|
|
1402
|
+
'index.html': `<!DOCTYPE html>
|
|
1403
|
+
<html lang="en">
|
|
1404
|
+
<head>
|
|
1405
|
+
<meta charset="UTF-8" />
|
|
1406
|
+
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
|
1407
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
1408
|
+
<title>Atomix React App</title>
|
|
1409
|
+
</head>
|
|
1410
|
+
<body>
|
|
1411
|
+
<div id="root"></div>
|
|
1412
|
+
<script type="module" src="/src/main.tsx"></script>
|
|
1413
|
+
</body>
|
|
1414
|
+
</html>`,
|
|
1415
|
+
'vite.config.ts': `import { defineConfig } from 'vite';
|
|
1416
|
+
import react from '@vitejs/plugin-react';
|
|
1417
|
+
|
|
1418
|
+
export default defineConfig({
|
|
1419
|
+
plugins: [react()],
|
|
1420
|
+
css: {
|
|
1421
|
+
preprocessorOptions: {
|
|
1422
|
+
scss: {
|
|
1423
|
+
additionalData: \`@use "@shohojdhara/atomix/scss/settings" as *;\`
|
|
1424
|
+
}
|
|
1425
|
+
}
|
|
1426
|
+
}
|
|
1427
|
+
});`
|
|
1428
|
+
}
|
|
1429
|
+
},
|
|
1430
|
+
|
|
1431
|
+
nextjs: {
|
|
1432
|
+
dependencies: ['next', 'react', 'react-dom'],
|
|
1433
|
+
devDependencies: ['typescript', '@types/node', '@types/react', '@types/react-dom', 'sass'],
|
|
1434
|
+
files: {
|
|
1435
|
+
'src/pages/_app.tsx': `import '../styles/globals.scss';
|
|
1436
|
+
import type { AppProps } from 'next/app';
|
|
1437
|
+
|
|
1438
|
+
export default function App({ Component, pageProps }: AppProps) {
|
|
1439
|
+
return <Component {...pageProps} />;
|
|
1440
|
+
}`,
|
|
1441
|
+
'src/pages/index.tsx': `import Head from 'next/head';
|
|
1442
|
+
|
|
1443
|
+
export default function Home() {
|
|
1444
|
+
return (
|
|
1445
|
+
<>
|
|
1446
|
+
<Head>
|
|
1447
|
+
<title>Atomix Next.js App</title>
|
|
1448
|
+
<meta name="description" content="Generated by Atomix CLI" />
|
|
1449
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
1450
|
+
</Head>
|
|
1451
|
+
<main>
|
|
1452
|
+
<h1>Welcome to Atomix Design System</h1>
|
|
1453
|
+
<p>Your Next.js application is ready with Atomix components!</p>
|
|
1454
|
+
</main>
|
|
1455
|
+
</>
|
|
1456
|
+
);
|
|
1457
|
+
}`,
|
|
1458
|
+
'src/styles/globals.scss': `/* Import Atomix styles */
|
|
1459
|
+
@use '@shohojdhara/atomix/scss/settings' with (
|
|
1460
|
+
// Your custom theme overrides here
|
|
1461
|
+
);
|
|
1462
|
+
@use '@shohojdhara/atomix/scss/components';
|
|
1463
|
+
|
|
1464
|
+
html,
|
|
1465
|
+
body {
|
|
1466
|
+
padding: 0;
|
|
1467
|
+
margin: 0;
|
|
1468
|
+
font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen,
|
|
1469
|
+
Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
|
|
1470
|
+
}
|
|
1471
|
+
|
|
1472
|
+
main {
|
|
1473
|
+
padding: 2rem;
|
|
1474
|
+
text-align: center;
|
|
1475
|
+
}`,
|
|
1476
|
+
'next.config.js': `/** @type {import('next').NextConfig} */
|
|
1477
|
+
const nextConfig = {
|
|
1478
|
+
reactStrictMode: true,
|
|
1479
|
+
sassOptions: {
|
|
1480
|
+
includePaths: ['./node_modules'],
|
|
1481
|
+
},
|
|
1482
|
+
};
|
|
1483
|
+
|
|
1484
|
+
module.exports = nextConfig;`
|
|
1485
|
+
}
|
|
1486
|
+
},
|
|
1487
|
+
|
|
1488
|
+
vanilla: {
|
|
1489
|
+
dependencies: [],
|
|
1490
|
+
devDependencies: ['vite', 'typescript'],
|
|
1491
|
+
files: {
|
|
1492
|
+
'index.html': `<!DOCTYPE html>
|
|
1493
|
+
<html lang="en">
|
|
1494
|
+
<head>
|
|
1495
|
+
<meta charset="UTF-8" />
|
|
1496
|
+
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
|
1497
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
1498
|
+
<title>Atomix Vanilla App</title>
|
|
1499
|
+
</head>
|
|
1500
|
+
<body>
|
|
1501
|
+
<div id="app">
|
|
1502
|
+
<header>
|
|
1503
|
+
<h1>Welcome to Atomix Design System</h1>
|
|
1504
|
+
<p>Your vanilla JavaScript application is ready with Atomix components!</p>
|
|
1505
|
+
</header>
|
|
1506
|
+
</div>
|
|
1507
|
+
<script type="module" src="/src/main.ts"></script>
|
|
1508
|
+
</body>
|
|
1509
|
+
</html>`,
|
|
1510
|
+
'src/main.ts': `import './styles/main.scss';
|
|
1511
|
+
|
|
1512
|
+
console.log('Atomix Vanilla JavaScript App Initialized');`,
|
|
1513
|
+
'src/styles/main.scss': `/* Import Atomix styles */
|
|
1514
|
+
@use '@shohojdhara/atomix/scss/settings' with (
|
|
1515
|
+
// Your custom theme overrides here
|
|
1516
|
+
);
|
|
1517
|
+
@use '@shohojdhara/atomix/scss/components';
|
|
1518
|
+
|
|
1519
|
+
#app {
|
|
1520
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
1521
|
+
text-align: center;
|
|
1522
|
+
}
|
|
1523
|
+
|
|
1524
|
+
header {
|
|
1525
|
+
background-color: #f8f9fa;
|
|
1526
|
+
padding: 2rem;
|
|
1527
|
+
border-bottom: 1px solid #dee2e6;
|
|
1528
|
+
}`,
|
|
1529
|
+
'vite.config.ts': `import { defineConfig } from 'vite';
|
|
1530
|
+
|
|
1531
|
+
export default defineConfig({
|
|
1532
|
+
css: {
|
|
1533
|
+
preprocessorOptions: {
|
|
1534
|
+
scss: {
|
|
1535
|
+
additionalData: \`@use "@shohojdhara/atomix/scss/settings" as *;\`
|
|
1536
|
+
}
|
|
1537
|
+
}
|
|
1538
|
+
}
|
|
1539
|
+
});`
|
|
1540
|
+
}
|
|
1541
|
+
}
|
|
1542
|
+
};
|
|
1543
|
+
|
|
1544
|
+
/**
|
|
1545
|
+
* Configuration templates for different config formats
|
|
1546
|
+
*/
|
|
1547
|
+
export const configTemplates = {
|
|
1548
|
+
basic: {
|
|
1549
|
+
'.atomixrc.json': {
|
|
1550
|
+
theme: {
|
|
1551
|
+
path: 'themes/custom',
|
|
1552
|
+
tokens: {
|
|
1553
|
+
colors: {
|
|
1554
|
+
primary: '#7AFFD7',
|
|
1555
|
+
secondary: '#FF5733'
|
|
1556
|
+
}
|
|
1557
|
+
}
|
|
1558
|
+
},
|
|
1559
|
+
components: {
|
|
1560
|
+
path: 'src/components',
|
|
1561
|
+
generate: {
|
|
1562
|
+
typescript: true,
|
|
1563
|
+
stories: true,
|
|
1564
|
+
tests: false
|
|
1565
|
+
}
|
|
1566
|
+
},
|
|
1567
|
+
build: {
|
|
1568
|
+
outputPath: 'dist',
|
|
1569
|
+
includeSourceMaps: false
|
|
1570
|
+
}
|
|
1571
|
+
}
|
|
1572
|
+
},
|
|
1573
|
+
|
|
1574
|
+
advanced: {
|
|
1575
|
+
'atomix.config.js': `// Atomix Design System Configuration
|
|
1576
|
+
// Generated by Atomix CLI
|
|
1577
|
+
|
|
1578
|
+
export default {
|
|
1579
|
+
theme: {
|
|
1580
|
+
path: 'themes/custom',
|
|
1581
|
+
tokens: {
|
|
1582
|
+
// Import custom token files
|
|
1583
|
+
extend: ['./tokens/colors.scss', './tokens/spacing.scss']
|
|
1584
|
+
},
|
|
1585
|
+
// Theme configuration
|
|
1586
|
+
darkMode: 'class', // 'class' | 'media' | false
|
|
1587
|
+
cssVarPrefix: 'atomix',
|
|
1588
|
+
scope: ':root'
|
|
1589
|
+
},
|
|
1590
|
+
|
|
1591
|
+
components: {
|
|
1592
|
+
path: 'src/components',
|
|
1593
|
+
// Component generation options
|
|
1594
|
+
generate: {
|
|
1595
|
+
typescript: true,
|
|
1596
|
+
stories: true,
|
|
1597
|
+
tests: true,
|
|
1598
|
+
cssModules: false,
|
|
1599
|
+
// Custom component templates
|
|
1600
|
+
templates: {
|
|
1601
|
+
component: './templates/component.tsx.hbs',
|
|
1602
|
+
story: './templates/story.tsx.hbs',
|
|
1603
|
+
test: './templates/test.tsx.hbs'
|
|
1604
|
+
}
|
|
1605
|
+
},
|
|
1606
|
+
// Component scanning
|
|
1607
|
+
scan: {
|
|
1608
|
+
patterns: ['src/components/**/*.{ts,tsx}'],
|
|
1609
|
+
exclude: ['**/*.test.*', '**/*.stories.*']
|
|
1610
|
+
}
|
|
1611
|
+
},
|
|
1612
|
+
|
|
1613
|
+
build: {
|
|
1614
|
+
outputPath: 'dist',
|
|
1615
|
+
includeSourceMaps: process.env.NODE_ENV === 'development',
|
|
1616
|
+
// Build optimization
|
|
1617
|
+
optimization: {
|
|
1618
|
+
minify: true,
|
|
1619
|
+
treeshake: true,
|
|
1620
|
+
purgeCSS: {
|
|
1621
|
+
enabled: true,
|
|
1622
|
+
content: ['src/**/*.{js,ts,tsx,html}']
|
|
1623
|
+
}
|
|
1624
|
+
}
|
|
1625
|
+
},
|
|
1626
|
+
|
|
1627
|
+
// Development server
|
|
1628
|
+
devServer: {
|
|
1629
|
+
port: 3000,
|
|
1630
|
+
open: true,
|
|
1631
|
+
hmr: true
|
|
1632
|
+
},
|
|
1633
|
+
|
|
1634
|
+
// Plugin configuration
|
|
1635
|
+
plugins: [
|
|
1636
|
+
// '@shohojdhara/atomix-plugin-storybook',
|
|
1637
|
+
// '@shohojdhara/atomix-plugin-tailwind'
|
|
1638
|
+
],
|
|
1639
|
+
|
|
1640
|
+
// CLI commands
|
|
1641
|
+
cli: {
|
|
1642
|
+
generate: {
|
|
1643
|
+
component: {
|
|
1644
|
+
template: 'react',
|
|
1645
|
+
directory: 'src/components'
|
|
1646
|
+
},
|
|
1647
|
+
theme: {
|
|
1648
|
+
template: 'scss',
|
|
1649
|
+
directory: 'themes'
|
|
1650
|
+
}
|
|
1651
|
+
}
|
|
1652
|
+
}
|
|
1653
|
+
};`
|
|
1654
|
+
}
|
|
1655
|
+
};
|