@shohojdhara/atomix 0.3.13 → 0.3.15
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 +39 -0
- package/README.md +2 -0
- package/build-tools/EXAMPLES.md +372 -0
- package/build-tools/README.md +242 -0
- package/build-tools/__tests__/error-handler.test.js +230 -0
- package/build-tools/__tests__/index.test.js +141 -0
- package/build-tools/__tests__/rollup-plugin.test.js +194 -0
- package/build-tools/__tests__/utils.test.js +161 -0
- package/build-tools/__tests__/vite-plugin.test.js +129 -0
- package/build-tools/__tests__/webpack-loader.test.js +190 -0
- package/build-tools/error-handler.js +308 -0
- package/build-tools/index.d.ts +43 -0
- package/build-tools/index.js +88 -0
- package/build-tools/package.json +67 -0
- package/build-tools/rollup-plugin.js +236 -0
- package/build-tools/types.d.ts +163 -0
- package/build-tools/utils.js +203 -0
- package/build-tools/vite-plugin.js +161 -0
- package/build-tools/webpack-loader.js +123 -0
- package/dist/atomix.css +298 -167
- package/dist/atomix.css.map +1 -1
- package/dist/atomix.min.css +3 -3
- package/dist/atomix.min.css.map +1 -1
- package/dist/build-tools/EXAMPLES.md +372 -0
- package/dist/build-tools/README.md +242 -0
- package/dist/build-tools/__tests__/error-handler.test.js +230 -0
- package/dist/build-tools/__tests__/index.test.js +141 -0
- package/dist/build-tools/__tests__/rollup-plugin.test.js +194 -0
- package/dist/build-tools/__tests__/utils.test.js +161 -0
- package/dist/build-tools/__tests__/vite-plugin.test.js +129 -0
- package/dist/build-tools/__tests__/webpack-loader.test.js +190 -0
- package/dist/build-tools/error-handler.js +308 -0
- package/dist/build-tools/index.d.ts +43 -0
- package/dist/build-tools/index.js +88 -0
- package/dist/build-tools/package.json +67 -0
- package/dist/build-tools/rollup-plugin.js +236 -0
- package/dist/build-tools/types.d.ts +163 -0
- package/dist/build-tools/utils.js +203 -0
- package/dist/build-tools/vite-plugin.js +161 -0
- package/dist/build-tools/webpack-loader.js +123 -0
- package/dist/charts.d.ts +2 -2
- package/dist/charts.js +87 -58
- package/dist/charts.js.map +1 -1
- package/dist/core.d.ts +42 -12
- package/dist/core.js +175 -135
- package/dist/core.js.map +1 -1
- package/dist/forms.d.ts +30 -16
- package/dist/forms.js +146 -131
- package/dist/forms.js.map +1 -1
- package/dist/heavy.d.ts +2 -2
- package/dist/heavy.js +151 -118
- package/dist/heavy.js.map +1 -1
- package/dist/index.d.ts +130 -106
- package/dist/index.esm.js +1083 -465
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +1102 -483
- 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 +23 -8
- package/scripts/atomix-cli.js +749 -1153
- package/scripts/cli/__tests__/README.md +81 -0
- package/scripts/cli/__tests__/basic.test.js +115 -0
- package/scripts/cli/__tests__/component-generator.test.js +332 -0
- package/scripts/cli/__tests__/integration.test.js +327 -0
- package/scripts/cli/__tests__/test-setup.js +133 -0
- package/scripts/cli/__tests__/token-manager.test.js +251 -0
- package/scripts/cli/__tests__/utils.test.js +78 -118
- package/scripts/cli/component-generator.js +564 -0
- package/scripts/cli/dependency-checker.js +355 -0
- package/scripts/cli/documentation-sync.js +542 -0
- package/scripts/cli/interactive-init.js +129 -292
- package/scripts/cli/mappings.js +211 -0
- package/scripts/cli/migration-tools.js +95 -288
- package/scripts/cli/template-manager.js +105 -0
- package/scripts/cli/templates/README.md +123 -0
- package/scripts/cli/templates/common-templates.js +636 -0
- package/scripts/cli/templates/composable-templates.js +171 -0
- package/scripts/cli/templates/config-templates.js +126 -0
- package/scripts/cli/templates/index.js +102 -0
- package/scripts/cli/templates/project-templates.js +342 -0
- package/scripts/cli/templates/react-templates.js +331 -0
- package/scripts/cli/templates/scss-templates.js +155 -0
- package/scripts/cli/templates/storybook-templates.js +236 -0
- package/scripts/cli/templates/testing-templates.js +224 -0
- package/scripts/cli/templates/testing-utils.js +278 -0
- package/scripts/cli/templates/token-templates.js +447 -0
- package/scripts/cli/templates/types-templates.js +147 -0
- package/scripts/cli/templates.js +35 -0
- package/scripts/cli/theme-bridge.js +28 -16
- package/scripts/cli/token-manager.js +432 -247
- package/scripts/cli/utils.js +37 -26
- package/src/components/Accordion/Accordion.stories.tsx +369 -870
- package/src/components/Accordion/Accordion.test.tsx +57 -0
- package/src/components/Accordion/Accordion.tsx +4 -0
- package/src/components/AtomixGlass/AtomixGlass.tsx +80 -39
- package/src/components/AtomixGlass/AtomixGlassContainer.tsx +103 -81
- package/src/components/AtomixGlass/__snapshots__/AtomixGlass.test.tsx.snap +8 -7
- package/src/components/AtomixGlass/glass-utils.ts +2 -2
- package/src/components/AtomixGlass/shader-utils.ts +5 -0
- package/src/components/AtomixGlass/stories/Customization.stories.tsx +131 -0
- package/src/components/AtomixGlass/stories/Examples.stories.tsx +2965 -2861
- package/src/components/AtomixGlass/stories/Modes.stories.tsx +1 -1
- package/src/components/AtomixGlass/stories/Overview.stories.tsx +348 -0
- package/src/components/AtomixGlass/stories/Performance.stories.tsx +103 -0
- package/src/components/AtomixGlass/stories/Playground.stories.tsx +73 -59
- package/src/components/AtomixGlass/stories/{ShaderVariants.stories.tsx → Shaders.stories.tsx} +1 -1
- package/src/components/AtomixGlass/stories/shared-components.tsx +90 -190
- package/src/components/Avatar/Avatar.stories.tsx +239 -27
- package/src/components/Badge/Badge.stories.tsx +132 -373
- package/src/components/Badge/Badge.test.tsx +51 -0
- package/src/components/Badge/Badge.tsx +20 -1
- package/src/components/Block/Block.stories.tsx +26 -17
- package/src/components/Breadcrumb/Breadcrumb.stories.tsx +141 -23
- package/src/components/Breadcrumb/Breadcrumb.tsx +2 -2
- package/src/components/Button/Button.stories.tsx +463 -1126
- package/src/components/Button/Button.test.tsx +107 -0
- package/src/components/Button/Button.tsx +50 -54
- package/src/components/Button/ButtonGroup.stories.tsx +373 -217
- package/src/components/Button/README.md +5 -0
- package/src/components/Callout/Callout.stories.tsx +299 -644
- 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.stories.tsx +248 -68
- package/src/components/Card/Card.tsx +2 -2
- package/src/components/Chart/Chart.stories.tsx +156 -14
- package/src/components/Chart/Chart.tsx +1 -1
- package/src/components/ColorModeToggle/ColorModeToggle.stories.tsx +151 -69
- package/src/components/Countdown/Countdown.stories.tsx +115 -8
- package/src/components/DataTable/DataTable.stories.tsx +346 -146
- package/src/components/DataTable/DataTable.tsx +14 -12
- package/src/components/DatePicker/DatePicker.stories.tsx +325 -1066
- package/src/components/Dropdown/Dropdown.stories.tsx +157 -37
- package/src/components/EdgePanel/EdgePanel.stories.tsx +230 -21
- package/src/components/Footer/Footer.stories.tsx +392 -328
- package/src/components/Form/Checkbox.stories.tsx +143 -9
- package/src/components/Form/Checkbox.test.tsx +63 -0
- package/src/components/Form/Checkbox.tsx +90 -52
- package/src/components/Form/Form.stories.tsx +121 -22
- package/src/components/Form/FormGroup.stories.tsx +128 -5
- 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 +232 -97
- package/src/components/Form/Radio.tsx +2 -2
- package/src/components/Form/Select.stories.tsx +144 -12
- package/src/components/Form/Select.tsx +2 -2
- package/src/components/Form/Textarea.stories.tsx +171 -13
- package/src/components/Form/Textarea.test.tsx +45 -0
- package/src/components/Form/Textarea.tsx +88 -86
- package/src/components/Hero/Hero.stories.tsx +333 -32
- package/src/components/List/List.stories.tsx +143 -5
- package/src/components/Modal/Modal.stories.tsx +185 -46
- 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 +449 -99
- package/src/components/ProductReview/ProductReview.tsx +1 -1
- package/src/components/Progress/Progress.stories.tsx +167 -5
- 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/River/River.stories.tsx +1 -1
- package/src/components/SectionIntro/SectionIntro.stories.tsx +240 -48
- package/src/components/Slider/Slider.stories.tsx +63 -63
- package/src/components/Spinner/Spinner.stories.tsx +104 -10
- package/src/components/Spinner/Spinner.test.tsx +35 -0
- package/src/components/Spinner/Spinner.tsx +9 -2
- package/src/components/Steps/Steps.stories.tsx +172 -43
- package/src/components/Tabs/Tabs.stories.tsx +136 -10
- package/src/components/Testimonial/Testimonial.stories.tsx +121 -4
- package/src/components/Todo/Todo.stories.tsx +198 -9
- package/src/components/Toggle/Toggle.stories.tsx +153 -43
- package/src/components/Toggle/Toggle.test.tsx +91 -0
- package/src/components/Toggle/Toggle.tsx +44 -27
- package/src/components/Tooltip/Tooltip.stories.tsx +194 -104
- package/src/components/Tooltip/Tooltip.tsx +1 -1
- package/src/components/Upload/Upload.stories.tsx +113 -24
- package/src/layouts/Grid/Grid.stories.tsx +49 -49
- package/src/layouts/MasonryGrid/MasonryGrid.stories.tsx +2 -2
- package/src/lib/README.md +2 -2
- package/src/lib/__tests__/theme-tools.test.ts +193 -0
- package/src/lib/composables/index.ts +2 -2
- package/src/lib/composables/useAccordion.ts +12 -3
- package/src/lib/composables/useAtomixGlass.ts +28 -56
- package/src/lib/composables/useBreadcrumb.ts +2 -2
- package/src/lib/composables/useCallout.ts +7 -7
- package/src/lib/composables/useChartExport.ts +2 -7
- package/src/lib/composables/useDataTable.ts +46 -29
- package/src/lib/composables/useNavbar.ts +1 -1
- package/src/lib/constants/components.ts +10 -33
- 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 +82 -27
- package/src/lib/utils/__tests__/csv.test.ts +45 -0
- package/src/lib/utils/csv.ts +17 -0
- package/src/lib/utils/dataTableExport.ts +1 -10
- package/src/lib/utils/themeNaming.ts +1 -1
- package/src/styles/01-settings/_index.scss +2 -1
- package/src/styles/01-settings/_settings.accordion.scss +28 -7
- package/src/styles/01-settings/_settings.colors.scss +11 -11
- package/src/styles/01-settings/_settings.typography.scss +5 -5
- package/src/styles/02-tools/_tools.utility-api.scss +14 -0
- package/src/styles/06-components/_components.accordion.scss +56 -14
- package/src/styles/06-components/_components.callout.scss +29 -33
- package/src/styles/06-components/_components.checkbox.scss +23 -17
- package/src/styles/06-components/_index.scss +1 -1
- package/src/styles/99-utilities/_index.scss +2 -0
- 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.scss +3 -1
- package/src/styles/99-utilities/_utilities.text-gradient.scss +45 -0
- package/src/styles/99-utilities/_utilities.text.scss +28 -8
- package/themes/dark-complementary/README.md +98 -0
- package/themes/dark-complementary/index.scss +158 -0
- package/themes/default-light/README.md +81 -0
- package/themes/default-light/index.scss +154 -0
- package/themes/high-contrast/README.md +105 -0
- package/themes/high-contrast/index.scss +172 -0
- package/themes/test-theme/README.md +38 -0
- package/themes/test-theme/index.scss +47 -0
- package/scripts/cli/__tests__/cli-commands.test.js +0 -204
- package/scripts/cli/__tests__/vitest.config.js +0 -26
- package/src/components/AtomixGlass/stories/AtomixGlass.stories.tsx +0 -1438
- package/src/lib/composables/useButton.ts +0 -93
- package/src/lib/composables/useCheckbox.ts +0 -70
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import type { Meta, StoryObj } from '@storybook/react';
|
|
3
|
+
import { fn } from '@storybook/test';
|
|
3
4
|
import { Toggle } from './Toggle';
|
|
4
5
|
|
|
5
6
|
const meta = {
|
|
@@ -9,26 +10,101 @@ const meta = {
|
|
|
9
10
|
layout: 'centered',
|
|
10
11
|
docs: {
|
|
11
12
|
description: {
|
|
12
|
-
component:
|
|
13
|
-
|
|
13
|
+
component: `
|
|
14
|
+
# Toggle
|
|
15
|
+
|
|
16
|
+
## Overview
|
|
17
|
+
|
|
18
|
+
Toggle provides an on/off switch control for binary choices. It offers a more visually distinct alternative to checkboxes for settings, preferences, or feature toggles. Toggles support disabled states and can include glass morphism effects.
|
|
19
|
+
|
|
20
|
+
## Features
|
|
21
|
+
|
|
22
|
+
- On/off state control
|
|
23
|
+
- Uncontrolled and controlled usage
|
|
24
|
+
- Disabled state
|
|
25
|
+
- Glass morphism effect
|
|
26
|
+
- Accessible design
|
|
27
|
+
- Responsive behavior
|
|
28
|
+
|
|
29
|
+
## Accessibility
|
|
30
|
+
|
|
31
|
+
- Keyboard support: Toggle with Space or Enter key
|
|
32
|
+
- Screen reader: State changes announced appropriately
|
|
33
|
+
- ARIA support: Proper roles and properties for toggle components
|
|
34
|
+
- Focus management: Visible focus indicators maintained
|
|
35
|
+
|
|
36
|
+
## Usage Examples
|
|
37
|
+
|
|
38
|
+
### Basic Usage
|
|
39
|
+
|
|
40
|
+
\`\`\`tsx
|
|
41
|
+
<Toggle
|
|
42
|
+
defaultChecked={false}
|
|
43
|
+
onChange={(checked) => console.log(checked)}
|
|
44
|
+
/>
|
|
45
|
+
\`\`\`
|
|
46
|
+
|
|
47
|
+
### Controlled Usage
|
|
48
|
+
|
|
49
|
+
\`\`\`tsx
|
|
50
|
+
<Toggle
|
|
51
|
+
checked={isEnabled}
|
|
52
|
+
onChange={setEnabled}
|
|
53
|
+
/>
|
|
54
|
+
\`\`\`
|
|
55
|
+
|
|
56
|
+
## API Reference
|
|
57
|
+
|
|
58
|
+
### Props
|
|
59
|
+
|
|
60
|
+
| Prop | Type | Default | Description |
|
|
61
|
+
| ---- | ---- | ------- | ----------- |
|
|
62
|
+
| defaultChecked | boolean | false | Whether the toggle is initially on (uncontrolled) |
|
|
63
|
+
| checked | boolean | - | Whether the toggle is on (controlled) |
|
|
64
|
+
| onChange | (checked: boolean) => void | - | Callback when the toggle state changes |
|
|
65
|
+
| disabled | boolean | false | Whether the toggle is disabled |
|
|
66
|
+
| glass | boolean | false | Enable glass morphism effect |
|
|
67
|
+
`,
|
|
14
68
|
},
|
|
15
69
|
},
|
|
16
70
|
},
|
|
17
71
|
tags: ['autodocs'],
|
|
18
72
|
argTypes: {
|
|
19
|
-
|
|
73
|
+
defaultChecked: {
|
|
20
74
|
control: { type: 'boolean' },
|
|
21
|
-
description: 'Whether the toggle is initially on',
|
|
22
|
-
|
|
75
|
+
description: 'Whether the toggle is initially on (uncontrolled)',
|
|
76
|
+
table: {
|
|
77
|
+
type: { summary: 'boolean' },
|
|
78
|
+
defaultValue: { summary: false },
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
checked: {
|
|
82
|
+
control: { type: 'boolean' },
|
|
83
|
+
description: 'Whether the toggle is on (controlled)',
|
|
84
|
+
table: {
|
|
85
|
+
type: { summary: 'boolean' },
|
|
86
|
+
defaultValue: { summary: '-' },
|
|
87
|
+
},
|
|
88
|
+
},
|
|
89
|
+
onChange: {
|
|
90
|
+
action: 'changed',
|
|
91
|
+
description: 'Callback when the toggle state changes',
|
|
23
92
|
},
|
|
24
93
|
disabled: {
|
|
25
94
|
control: { type: 'boolean' },
|
|
26
95
|
description: 'Whether the toggle is disabled',
|
|
27
|
-
|
|
96
|
+
table: {
|
|
97
|
+
type: { summary: 'boolean' },
|
|
98
|
+
defaultValue: { summary: false },
|
|
99
|
+
},
|
|
28
100
|
},
|
|
29
101
|
glass: {
|
|
30
102
|
control: 'boolean',
|
|
31
103
|
description: 'Enable glass morphism effect',
|
|
104
|
+
table: {
|
|
105
|
+
type: { summary: 'boolean' },
|
|
106
|
+
defaultValue: { summary: false },
|
|
107
|
+
},
|
|
32
108
|
},
|
|
33
109
|
},
|
|
34
110
|
} satisfies Meta<typeof Toggle>;
|
|
@@ -36,16 +112,42 @@ const meta = {
|
|
|
36
112
|
export default meta;
|
|
37
113
|
type Story = StoryObj<typeof meta>;
|
|
38
114
|
|
|
39
|
-
export const
|
|
115
|
+
export const BasicUsage: Story = {
|
|
40
116
|
render: args => (
|
|
41
117
|
<div style={{ display: 'flex', justifyContent: 'center', padding: '30px' }}>
|
|
42
118
|
<Toggle {...args} />
|
|
43
119
|
</div>
|
|
44
120
|
),
|
|
45
121
|
args: {
|
|
46
|
-
|
|
122
|
+
defaultChecked: false,
|
|
47
123
|
disabled: false,
|
|
48
124
|
},
|
|
125
|
+
parameters: {
|
|
126
|
+
docs: {
|
|
127
|
+
description: {
|
|
128
|
+
story: 'Basic toggle with default settings.',
|
|
129
|
+
},
|
|
130
|
+
},
|
|
131
|
+
},
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
export const Controlled: Story = {
|
|
135
|
+
render: () => {
|
|
136
|
+
const [isChecked, setIsChecked] = React.useState(false);
|
|
137
|
+
return (
|
|
138
|
+
<div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: '1rem' }}>
|
|
139
|
+
<p>Checked: {isChecked ? 'Yes' : 'No'}</p>
|
|
140
|
+
<Toggle checked={isChecked} onChange={setIsChecked} />
|
|
141
|
+
</div>
|
|
142
|
+
);
|
|
143
|
+
},
|
|
144
|
+
parameters: {
|
|
145
|
+
docs: {
|
|
146
|
+
description: {
|
|
147
|
+
story: 'Controlled toggle using checked and onChange.',
|
|
148
|
+
},
|
|
149
|
+
},
|
|
150
|
+
},
|
|
49
151
|
};
|
|
50
152
|
|
|
51
153
|
export const InitiallyOn: Story = {
|
|
@@ -55,61 +157,69 @@ export const InitiallyOn: Story = {
|
|
|
55
157
|
</div>
|
|
56
158
|
),
|
|
57
159
|
args: {
|
|
58
|
-
|
|
160
|
+
defaultChecked: true,
|
|
59
161
|
disabled: false,
|
|
60
162
|
},
|
|
163
|
+
parameters: {
|
|
164
|
+
docs: {
|
|
165
|
+
description: {
|
|
166
|
+
story: 'Toggle that starts in the "on" position.',
|
|
167
|
+
},
|
|
168
|
+
},
|
|
169
|
+
},
|
|
61
170
|
};
|
|
62
171
|
|
|
63
|
-
export const
|
|
64
|
-
render:
|
|
65
|
-
<div style={{ display: 'flex',
|
|
66
|
-
<
|
|
172
|
+
export const DisabledStates: Story = {
|
|
173
|
+
render: () => (
|
|
174
|
+
<div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: '2rem', padding: '30px' }}>
|
|
175
|
+
<div style={{ display: 'flex', alignItems: 'center', gap: '1rem' }}>
|
|
176
|
+
<Toggle disabled={true} checked={false} />
|
|
177
|
+
<span>Disabled Off</span>
|
|
178
|
+
</div>
|
|
179
|
+
<div style={{ display: 'flex', alignItems: 'center', gap: '1rem' }}>
|
|
180
|
+
<Toggle disabled={true} checked={true} />
|
|
181
|
+
<span>Disabled On</span>
|
|
182
|
+
</div>
|
|
67
183
|
</div>
|
|
68
184
|
),
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
185
|
+
parameters: {
|
|
186
|
+
docs: {
|
|
187
|
+
description: {
|
|
188
|
+
story: 'Toggle in both disabled states (off and on).',
|
|
189
|
+
},
|
|
190
|
+
},
|
|
72
191
|
},
|
|
73
192
|
};
|
|
74
193
|
|
|
75
|
-
export const
|
|
194
|
+
export const WithGlassEffect: Story = {
|
|
76
195
|
render: args => (
|
|
77
|
-
<div style={{
|
|
196
|
+
<div style={{
|
|
197
|
+
display: 'flex',
|
|
198
|
+
justifyContent: 'center',
|
|
199
|
+
padding: '30px',
|
|
200
|
+
background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
|
|
201
|
+
minHeight: '200px'
|
|
202
|
+
}}>
|
|
78
203
|
<Toggle {...args} />
|
|
79
204
|
</div>
|
|
80
205
|
),
|
|
81
206
|
args: {
|
|
82
|
-
|
|
83
|
-
disabled: true,
|
|
84
|
-
},
|
|
85
|
-
};
|
|
86
|
-
|
|
87
|
-
export const Glass: Story = {
|
|
88
|
-
args: {
|
|
89
|
-
initialOn: false,
|
|
207
|
+
defaultChecked: false,
|
|
90
208
|
disabled: false,
|
|
91
209
|
glass: true,
|
|
92
210
|
},
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
display: 'flex',
|
|
101
|
-
alignItems: 'center',
|
|
102
|
-
justifyContent: 'center',
|
|
103
|
-
}}
|
|
104
|
-
>
|
|
105
|
-
<Toggle {...args} />
|
|
106
|
-
</div>
|
|
107
|
-
),
|
|
211
|
+
parameters: {
|
|
212
|
+
docs: {
|
|
213
|
+
description: {
|
|
214
|
+
story: 'Toggle with glass morphism effect applied.',
|
|
215
|
+
},
|
|
216
|
+
},
|
|
217
|
+
},
|
|
108
218
|
};
|
|
109
219
|
|
|
110
220
|
export const GlassOn: Story = {
|
|
111
221
|
args: {
|
|
112
|
-
|
|
222
|
+
defaultChecked: true,
|
|
113
223
|
disabled: false,
|
|
114
224
|
glass: true,
|
|
115
225
|
},
|
|
@@ -135,7 +245,7 @@ export const GlassOn: Story = {
|
|
|
135
245
|
|
|
136
246
|
export const GlassCustom: Story = {
|
|
137
247
|
args: {
|
|
138
|
-
|
|
248
|
+
defaultChecked: false,
|
|
139
249
|
disabled: false,
|
|
140
250
|
glass: {
|
|
141
251
|
displacementScale: 80,
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { render, screen, fireEvent } from '@testing-library/react';
|
|
2
|
+
import { describe, it, expect, vi } from 'vitest';
|
|
3
|
+
import { Toggle } from './Toggle';
|
|
4
|
+
import React from 'react';
|
|
5
|
+
|
|
6
|
+
describe('Toggle Component', () => {
|
|
7
|
+
it('renders correctly', () => {
|
|
8
|
+
render(<Toggle />);
|
|
9
|
+
const toggle = screen.getByRole('switch');
|
|
10
|
+
expect(toggle).toBeInTheDocument();
|
|
11
|
+
expect(toggle).toHaveAttribute('aria-checked', 'false');
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it('handles defaultChecked (uncontrolled)', () => {
|
|
15
|
+
render(<Toggle defaultChecked={true} />);
|
|
16
|
+
const toggle = screen.getByRole('switch');
|
|
17
|
+
expect(toggle).toHaveAttribute('aria-checked', 'true');
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it('toggles state when clicked (uncontrolled)', () => {
|
|
21
|
+
const handleChange = vi.fn();
|
|
22
|
+
render(<Toggle onChange={handleChange} />);
|
|
23
|
+
const toggle = screen.getByRole('switch');
|
|
24
|
+
|
|
25
|
+
fireEvent.click(toggle);
|
|
26
|
+
expect(toggle).toHaveAttribute('aria-checked', 'true');
|
|
27
|
+
expect(handleChange).toHaveBeenCalledWith(true);
|
|
28
|
+
|
|
29
|
+
fireEvent.click(toggle);
|
|
30
|
+
expect(toggle).toHaveAttribute('aria-checked', 'false');
|
|
31
|
+
expect(handleChange).toHaveBeenCalledWith(false);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('handles checked (controlled)', () => {
|
|
35
|
+
const { rerender } = render(<Toggle checked={true} />);
|
|
36
|
+
const toggle = screen.getByRole('switch');
|
|
37
|
+
expect(toggle).toHaveAttribute('aria-checked', 'true');
|
|
38
|
+
|
|
39
|
+
rerender(<Toggle checked={false} />);
|
|
40
|
+
expect(toggle).toHaveAttribute('aria-checked', 'false');
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('calls onChange but does not toggle internally when controlled', () => {
|
|
44
|
+
const handleChange = vi.fn();
|
|
45
|
+
render(<Toggle checked={false} onChange={handleChange} />);
|
|
46
|
+
const toggle = screen.getByRole('switch');
|
|
47
|
+
|
|
48
|
+
fireEvent.click(toggle);
|
|
49
|
+
expect(handleChange).toHaveBeenCalledWith(true);
|
|
50
|
+
// Should still be false because it's controlled and we haven't rerendered with checked={true}
|
|
51
|
+
expect(toggle).toHaveAttribute('aria-checked', 'false');
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it('does not toggle when disabled', () => {
|
|
55
|
+
const handleChange = vi.fn();
|
|
56
|
+
render(<Toggle disabled onChange={handleChange} />);
|
|
57
|
+
const toggle = screen.getByRole('switch');
|
|
58
|
+
|
|
59
|
+
fireEvent.click(toggle);
|
|
60
|
+
expect(handleChange).not.toHaveBeenCalled();
|
|
61
|
+
expect(toggle).toHaveAttribute('aria-checked', 'false');
|
|
62
|
+
expect(toggle).toHaveAttribute('aria-disabled', 'true');
|
|
63
|
+
expect(toggle).toHaveAttribute('tabindex', '-1');
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it('handles keyboard interaction', () => {
|
|
67
|
+
const handleChange = vi.fn();
|
|
68
|
+
render(<Toggle onChange={handleChange} />);
|
|
69
|
+
const toggle = screen.getByRole('switch');
|
|
70
|
+
|
|
71
|
+
fireEvent.keyDown(toggle, { key: 'Enter' });
|
|
72
|
+
expect(toggle).toHaveAttribute('aria-checked', 'true');
|
|
73
|
+
expect(handleChange).toHaveBeenCalledWith(true);
|
|
74
|
+
|
|
75
|
+
fireEvent.keyDown(toggle, { key: ' ' });
|
|
76
|
+
expect(toggle).toHaveAttribute('aria-checked', 'false');
|
|
77
|
+
expect(handleChange).toHaveBeenCalledWith(false);
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it('applies accessibility attributes', () => {
|
|
81
|
+
render(
|
|
82
|
+
<Toggle
|
|
83
|
+
aria-label="Accessible Toggle"
|
|
84
|
+
aria-describedby="description-id"
|
|
85
|
+
/>
|
|
86
|
+
);
|
|
87
|
+
const toggle = screen.getByRole('switch');
|
|
88
|
+
expect(toggle).toHaveAttribute('aria-label', 'Accessible Toggle');
|
|
89
|
+
expect(toggle).toHaveAttribute('aria-describedby', 'description-id');
|
|
90
|
+
});
|
|
91
|
+
});
|
|
@@ -1,23 +1,24 @@
|
|
|
1
|
-
import React, { useState } from 'react';
|
|
1
|
+
import React, { useState, useCallback, useEffect } from 'react';
|
|
2
2
|
import { TOGGLE } from '../../lib/constants/components';
|
|
3
3
|
import { AtomixGlass } from '../AtomixGlass/AtomixGlass';
|
|
4
|
-
import { AtomixGlassProps } from '../../lib/types/components';
|
|
4
|
+
import { AtomixGlassProps, BaseComponentProps } from '../../lib/types/components';
|
|
5
5
|
|
|
6
|
-
export interface ToggleProps {
|
|
6
|
+
export interface ToggleProps extends BaseComponentProps {
|
|
7
7
|
/**
|
|
8
|
-
* Whether the toggle is
|
|
8
|
+
* Whether the toggle is checked (controlled)
|
|
9
9
|
*/
|
|
10
|
-
|
|
10
|
+
checked?: boolean;
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
|
-
*
|
|
13
|
+
* Whether the toggle is initially checked (uncontrolled)
|
|
14
|
+
* @default false
|
|
14
15
|
*/
|
|
15
|
-
|
|
16
|
+
defaultChecked?: boolean;
|
|
16
17
|
|
|
17
18
|
/**
|
|
18
|
-
* Callback when the toggle
|
|
19
|
+
* Callback when the toggle state changes
|
|
19
20
|
*/
|
|
20
|
-
|
|
21
|
+
onChange?: (checked: boolean) => void;
|
|
21
22
|
|
|
22
23
|
/**
|
|
23
24
|
* Whether the toggle is disabled
|
|
@@ -25,14 +26,14 @@ export interface ToggleProps {
|
|
|
25
26
|
disabled?: boolean;
|
|
26
27
|
|
|
27
28
|
/**
|
|
28
|
-
*
|
|
29
|
+
* Accessibility label
|
|
29
30
|
*/
|
|
30
|
-
|
|
31
|
+
'aria-label'?: string;
|
|
31
32
|
|
|
32
33
|
/**
|
|
33
|
-
*
|
|
34
|
+
* Accessibility description
|
|
34
35
|
*/
|
|
35
|
-
|
|
36
|
+
'aria-describedby'?: string;
|
|
36
37
|
|
|
37
38
|
/**
|
|
38
39
|
* Glass morphism effect for the toggle
|
|
@@ -45,29 +46,36 @@ export interface ToggleProps {
|
|
|
45
46
|
* Toggle component for switching between two states
|
|
46
47
|
*/
|
|
47
48
|
export const Toggle: React.FC<ToggleProps> = ({
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
49
|
+
checked: controlledChecked,
|
|
50
|
+
defaultChecked = false,
|
|
51
|
+
onChange,
|
|
51
52
|
disabled = false,
|
|
52
53
|
className = '',
|
|
53
54
|
style,
|
|
54
55
|
glass,
|
|
56
|
+
'aria-label': ariaLabel,
|
|
57
|
+
'aria-describedby': ariaDescribedBy,
|
|
55
58
|
}) => {
|
|
56
|
-
const
|
|
59
|
+
const isControlled = controlledChecked !== undefined;
|
|
60
|
+
const [internalChecked, setInternalChecked] = useState(defaultChecked);
|
|
61
|
+
const isChecked = isControlled ? controlledChecked : internalChecked;
|
|
62
|
+
|
|
63
|
+
// Sync internal state with defaultChecked if it changes (standard uncontrolled behavior)
|
|
64
|
+
// Actually, standard behavior is only using defaultChecked on mount, but sometimes syncing is needed.
|
|
65
|
+
// For now, let's keep it simple.
|
|
57
66
|
|
|
58
67
|
// Handle toggle click
|
|
59
|
-
const handleClick = () => {
|
|
68
|
+
const handleClick = useCallback(() => {
|
|
60
69
|
if (disabled) return;
|
|
61
70
|
|
|
62
|
-
const
|
|
63
|
-
setIsOn(newState);
|
|
71
|
+
const nextChecked = !isChecked;
|
|
64
72
|
|
|
65
|
-
if (
|
|
66
|
-
|
|
67
|
-
} else {
|
|
68
|
-
if (onToggleOff) onToggleOff();
|
|
73
|
+
if (!isControlled) {
|
|
74
|
+
setInternalChecked(nextChecked);
|
|
69
75
|
}
|
|
70
|
-
|
|
76
|
+
|
|
77
|
+
onChange?.(nextChecked);
|
|
78
|
+
}, [disabled, isChecked, isControlled, onChange]);
|
|
71
79
|
|
|
72
80
|
// Handle key down events
|
|
73
81
|
const handleKeyDown = (e: React.KeyboardEvent) => {
|
|
@@ -79,16 +87,25 @@ export const Toggle: React.FC<ToggleProps> = ({
|
|
|
79
87
|
}
|
|
80
88
|
};
|
|
81
89
|
|
|
90
|
+
const toggleClass = [
|
|
91
|
+
'c-toggle',
|
|
92
|
+
isChecked && TOGGLE.CLASSES.IS_ON,
|
|
93
|
+
disabled && 'is-disabled',
|
|
94
|
+
className,
|
|
95
|
+
].filter(Boolean).join(' ');
|
|
96
|
+
|
|
82
97
|
const toggleContent = (
|
|
83
98
|
<div
|
|
84
|
-
className={
|
|
99
|
+
className={toggleClass}
|
|
85
100
|
style={style}
|
|
86
101
|
onClick={handleClick}
|
|
87
102
|
onKeyDown={handleKeyDown}
|
|
88
103
|
role="switch"
|
|
89
|
-
aria-checked={
|
|
104
|
+
aria-checked={isChecked}
|
|
90
105
|
tabIndex={disabled ? -1 : 0}
|
|
91
106
|
aria-disabled={disabled}
|
|
107
|
+
aria-label={ariaLabel}
|
|
108
|
+
aria-describedby={ariaDescribedBy}
|
|
92
109
|
>
|
|
93
110
|
<div className="c-toggle__switch"></div>
|
|
94
111
|
</div>
|