@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.
Files changed (249) hide show
  1. package/CHANGELOG.md +39 -0
  2. package/README.md +2 -0
  3. package/build-tools/EXAMPLES.md +372 -0
  4. package/build-tools/README.md +242 -0
  5. package/build-tools/__tests__/error-handler.test.js +230 -0
  6. package/build-tools/__tests__/index.test.js +141 -0
  7. package/build-tools/__tests__/rollup-plugin.test.js +194 -0
  8. package/build-tools/__tests__/utils.test.js +161 -0
  9. package/build-tools/__tests__/vite-plugin.test.js +129 -0
  10. package/build-tools/__tests__/webpack-loader.test.js +190 -0
  11. package/build-tools/error-handler.js +308 -0
  12. package/build-tools/index.d.ts +43 -0
  13. package/build-tools/index.js +88 -0
  14. package/build-tools/package.json +67 -0
  15. package/build-tools/rollup-plugin.js +236 -0
  16. package/build-tools/types.d.ts +163 -0
  17. package/build-tools/utils.js +203 -0
  18. package/build-tools/vite-plugin.js +161 -0
  19. package/build-tools/webpack-loader.js +123 -0
  20. package/dist/atomix.css +298 -167
  21. package/dist/atomix.css.map +1 -1
  22. package/dist/atomix.min.css +3 -3
  23. package/dist/atomix.min.css.map +1 -1
  24. package/dist/build-tools/EXAMPLES.md +372 -0
  25. package/dist/build-tools/README.md +242 -0
  26. package/dist/build-tools/__tests__/error-handler.test.js +230 -0
  27. package/dist/build-tools/__tests__/index.test.js +141 -0
  28. package/dist/build-tools/__tests__/rollup-plugin.test.js +194 -0
  29. package/dist/build-tools/__tests__/utils.test.js +161 -0
  30. package/dist/build-tools/__tests__/vite-plugin.test.js +129 -0
  31. package/dist/build-tools/__tests__/webpack-loader.test.js +190 -0
  32. package/dist/build-tools/error-handler.js +308 -0
  33. package/dist/build-tools/index.d.ts +43 -0
  34. package/dist/build-tools/index.js +88 -0
  35. package/dist/build-tools/package.json +67 -0
  36. package/dist/build-tools/rollup-plugin.js +236 -0
  37. package/dist/build-tools/types.d.ts +163 -0
  38. package/dist/build-tools/utils.js +203 -0
  39. package/dist/build-tools/vite-plugin.js +161 -0
  40. package/dist/build-tools/webpack-loader.js +123 -0
  41. package/dist/charts.d.ts +2 -2
  42. package/dist/charts.js +87 -58
  43. package/dist/charts.js.map +1 -1
  44. package/dist/core.d.ts +42 -12
  45. package/dist/core.js +175 -135
  46. package/dist/core.js.map +1 -1
  47. package/dist/forms.d.ts +30 -16
  48. package/dist/forms.js +146 -131
  49. package/dist/forms.js.map +1 -1
  50. package/dist/heavy.d.ts +2 -2
  51. package/dist/heavy.js +151 -118
  52. package/dist/heavy.js.map +1 -1
  53. package/dist/index.d.ts +130 -106
  54. package/dist/index.esm.js +1083 -465
  55. package/dist/index.esm.js.map +1 -1
  56. package/dist/index.js +1102 -483
  57. package/dist/index.js.map +1 -1
  58. package/dist/index.min.js +1 -1
  59. package/dist/index.min.js.map +1 -1
  60. package/dist/theme.d.ts +27 -2
  61. package/dist/theme.js +721 -108
  62. package/dist/theme.js.map +1 -1
  63. package/package.json +23 -8
  64. package/scripts/atomix-cli.js +749 -1153
  65. package/scripts/cli/__tests__/README.md +81 -0
  66. package/scripts/cli/__tests__/basic.test.js +115 -0
  67. package/scripts/cli/__tests__/component-generator.test.js +332 -0
  68. package/scripts/cli/__tests__/integration.test.js +327 -0
  69. package/scripts/cli/__tests__/test-setup.js +133 -0
  70. package/scripts/cli/__tests__/token-manager.test.js +251 -0
  71. package/scripts/cli/__tests__/utils.test.js +78 -118
  72. package/scripts/cli/component-generator.js +564 -0
  73. package/scripts/cli/dependency-checker.js +355 -0
  74. package/scripts/cli/documentation-sync.js +542 -0
  75. package/scripts/cli/interactive-init.js +129 -292
  76. package/scripts/cli/mappings.js +211 -0
  77. package/scripts/cli/migration-tools.js +95 -288
  78. package/scripts/cli/template-manager.js +105 -0
  79. package/scripts/cli/templates/README.md +123 -0
  80. package/scripts/cli/templates/common-templates.js +636 -0
  81. package/scripts/cli/templates/composable-templates.js +171 -0
  82. package/scripts/cli/templates/config-templates.js +126 -0
  83. package/scripts/cli/templates/index.js +102 -0
  84. package/scripts/cli/templates/project-templates.js +342 -0
  85. package/scripts/cli/templates/react-templates.js +331 -0
  86. package/scripts/cli/templates/scss-templates.js +155 -0
  87. package/scripts/cli/templates/storybook-templates.js +236 -0
  88. package/scripts/cli/templates/testing-templates.js +224 -0
  89. package/scripts/cli/templates/testing-utils.js +278 -0
  90. package/scripts/cli/templates/token-templates.js +447 -0
  91. package/scripts/cli/templates/types-templates.js +147 -0
  92. package/scripts/cli/templates.js +35 -0
  93. package/scripts/cli/theme-bridge.js +28 -16
  94. package/scripts/cli/token-manager.js +432 -247
  95. package/scripts/cli/utils.js +37 -26
  96. package/src/components/Accordion/Accordion.stories.tsx +369 -870
  97. package/src/components/Accordion/Accordion.test.tsx +57 -0
  98. package/src/components/Accordion/Accordion.tsx +4 -0
  99. package/src/components/AtomixGlass/AtomixGlass.tsx +80 -39
  100. package/src/components/AtomixGlass/AtomixGlassContainer.tsx +103 -81
  101. package/src/components/AtomixGlass/__snapshots__/AtomixGlass.test.tsx.snap +8 -7
  102. package/src/components/AtomixGlass/glass-utils.ts +2 -2
  103. package/src/components/AtomixGlass/shader-utils.ts +5 -0
  104. package/src/components/AtomixGlass/stories/Customization.stories.tsx +131 -0
  105. package/src/components/AtomixGlass/stories/Examples.stories.tsx +2965 -2861
  106. package/src/components/AtomixGlass/stories/Modes.stories.tsx +1 -1
  107. package/src/components/AtomixGlass/stories/Overview.stories.tsx +348 -0
  108. package/src/components/AtomixGlass/stories/Performance.stories.tsx +103 -0
  109. package/src/components/AtomixGlass/stories/Playground.stories.tsx +73 -59
  110. package/src/components/AtomixGlass/stories/{ShaderVariants.stories.tsx → Shaders.stories.tsx} +1 -1
  111. package/src/components/AtomixGlass/stories/shared-components.tsx +90 -190
  112. package/src/components/Avatar/Avatar.stories.tsx +239 -27
  113. package/src/components/Badge/Badge.stories.tsx +132 -373
  114. package/src/components/Badge/Badge.test.tsx +51 -0
  115. package/src/components/Badge/Badge.tsx +20 -1
  116. package/src/components/Block/Block.stories.tsx +26 -17
  117. package/src/components/Breadcrumb/Breadcrumb.stories.tsx +141 -23
  118. package/src/components/Breadcrumb/Breadcrumb.tsx +2 -2
  119. package/src/components/Button/Button.stories.tsx +463 -1126
  120. package/src/components/Button/Button.test.tsx +107 -0
  121. package/src/components/Button/Button.tsx +50 -54
  122. package/src/components/Button/ButtonGroup.stories.tsx +373 -217
  123. package/src/components/Button/README.md +5 -0
  124. package/src/components/Callout/Callout.stories.tsx +299 -644
  125. package/src/components/Callout/Callout.test.tsx +10 -10
  126. package/src/components/Callout/Callout.tsx +7 -7
  127. package/src/components/Callout/README.md +9 -8
  128. package/src/components/Card/Card.stories.tsx +248 -68
  129. package/src/components/Card/Card.tsx +2 -2
  130. package/src/components/Chart/Chart.stories.tsx +156 -14
  131. package/src/components/Chart/Chart.tsx +1 -1
  132. package/src/components/ColorModeToggle/ColorModeToggle.stories.tsx +151 -69
  133. package/src/components/Countdown/Countdown.stories.tsx +115 -8
  134. package/src/components/DataTable/DataTable.stories.tsx +346 -146
  135. package/src/components/DataTable/DataTable.tsx +14 -12
  136. package/src/components/DatePicker/DatePicker.stories.tsx +325 -1066
  137. package/src/components/Dropdown/Dropdown.stories.tsx +157 -37
  138. package/src/components/EdgePanel/EdgePanel.stories.tsx +230 -21
  139. package/src/components/Footer/Footer.stories.tsx +392 -328
  140. package/src/components/Form/Checkbox.stories.tsx +143 -9
  141. package/src/components/Form/Checkbox.test.tsx +63 -0
  142. package/src/components/Form/Checkbox.tsx +90 -52
  143. package/src/components/Form/Form.stories.tsx +121 -22
  144. package/src/components/Form/FormGroup.stories.tsx +128 -5
  145. package/src/components/Form/Input.stories.tsx +28 -16
  146. package/src/components/Form/Input.test.tsx +59 -0
  147. package/src/components/Form/Input.tsx +97 -95
  148. package/src/components/Form/Radio.stories.tsx +232 -97
  149. package/src/components/Form/Radio.tsx +2 -2
  150. package/src/components/Form/Select.stories.tsx +144 -12
  151. package/src/components/Form/Select.tsx +2 -2
  152. package/src/components/Form/Textarea.stories.tsx +171 -13
  153. package/src/components/Form/Textarea.test.tsx +45 -0
  154. package/src/components/Form/Textarea.tsx +88 -86
  155. package/src/components/Hero/Hero.stories.tsx +333 -32
  156. package/src/components/List/List.stories.tsx +143 -5
  157. package/src/components/Modal/Modal.stories.tsx +185 -46
  158. package/src/components/Navigation/Navbar/Navbar.stories.tsx +5 -5
  159. package/src/components/Navigation/Navbar/Navbar.tsx +1 -1
  160. package/src/components/Navigation/README.md +1 -1
  161. package/src/components/Pagination/Pagination.stories.tsx +5 -2
  162. package/src/components/Pagination/Pagination.tsx +1 -1
  163. package/src/components/PhotoViewer/PhotoViewer.stories.tsx +10 -10
  164. package/src/components/Popover/Popover.stories.tsx +449 -99
  165. package/src/components/ProductReview/ProductReview.tsx +1 -1
  166. package/src/components/Progress/Progress.stories.tsx +167 -5
  167. package/src/components/Progress/Progress.tsx +46 -46
  168. package/src/components/Rating/Rating.stories.tsx +4 -4
  169. package/src/components/Rating/Rating.tsx +8 -8
  170. package/src/components/River/River.stories.tsx +1 -1
  171. package/src/components/SectionIntro/SectionIntro.stories.tsx +240 -48
  172. package/src/components/Slider/Slider.stories.tsx +63 -63
  173. package/src/components/Spinner/Spinner.stories.tsx +104 -10
  174. package/src/components/Spinner/Spinner.test.tsx +35 -0
  175. package/src/components/Spinner/Spinner.tsx +9 -2
  176. package/src/components/Steps/Steps.stories.tsx +172 -43
  177. package/src/components/Tabs/Tabs.stories.tsx +136 -10
  178. package/src/components/Testimonial/Testimonial.stories.tsx +121 -4
  179. package/src/components/Todo/Todo.stories.tsx +198 -9
  180. package/src/components/Toggle/Toggle.stories.tsx +153 -43
  181. package/src/components/Toggle/Toggle.test.tsx +91 -0
  182. package/src/components/Toggle/Toggle.tsx +44 -27
  183. package/src/components/Tooltip/Tooltip.stories.tsx +194 -104
  184. package/src/components/Tooltip/Tooltip.tsx +1 -1
  185. package/src/components/Upload/Upload.stories.tsx +113 -24
  186. package/src/layouts/Grid/Grid.stories.tsx +49 -49
  187. package/src/layouts/MasonryGrid/MasonryGrid.stories.tsx +2 -2
  188. package/src/lib/README.md +2 -2
  189. package/src/lib/__tests__/theme-tools.test.ts +193 -0
  190. package/src/lib/composables/index.ts +2 -2
  191. package/src/lib/composables/useAccordion.ts +12 -3
  192. package/src/lib/composables/useAtomixGlass.ts +28 -56
  193. package/src/lib/composables/useBreadcrumb.ts +2 -2
  194. package/src/lib/composables/useCallout.ts +7 -7
  195. package/src/lib/composables/useChartExport.ts +2 -7
  196. package/src/lib/composables/useDataTable.ts +46 -29
  197. package/src/lib/composables/useNavbar.ts +1 -1
  198. package/src/lib/constants/components.ts +10 -33
  199. package/src/lib/storybook/InteractiveDemo.tsx +113 -0
  200. package/src/lib/storybook/PreviewContainer.tsx +36 -0
  201. package/src/lib/storybook/VariantsGrid.tsx +21 -0
  202. package/src/lib/storybook/index.ts +3 -0
  203. package/src/lib/theme/core/createThemeObject.ts +9 -5
  204. package/src/lib/theme/devtools/CLI.ts +155 -0
  205. package/src/lib/theme/devtools/DesignTokensCustomizer.stories.tsx +213 -0
  206. package/src/lib/theme/devtools/DesignTokensCustomizer.tsx +566 -0
  207. package/src/lib/theme/devtools/LiveEditor.tsx +2 -1
  208. package/src/lib/theme/devtools/index.ts +3 -0
  209. package/src/lib/theme/errors/errors.ts +8 -0
  210. package/src/lib/theme/runtime/ThemeProvider.tsx +117 -57
  211. package/src/lib/theme/runtime/__tests__/ThemeProvider.integration.test.tsx +305 -0
  212. package/src/lib/theme/runtime/__tests__/ThemeProvider.test.tsx +588 -0
  213. package/src/lib/theme/utils/__tests__/themeValidation.test.ts +264 -0
  214. package/src/lib/theme/utils/index.ts +1 -0
  215. package/src/lib/theme/utils/themeValidation.ts +501 -0
  216. package/src/lib/theme-tools.ts +32 -3
  217. package/src/lib/types/components.ts +82 -27
  218. package/src/lib/utils/__tests__/csv.test.ts +45 -0
  219. package/src/lib/utils/csv.ts +17 -0
  220. package/src/lib/utils/dataTableExport.ts +1 -10
  221. package/src/lib/utils/themeNaming.ts +1 -1
  222. package/src/styles/01-settings/_index.scss +2 -1
  223. package/src/styles/01-settings/_settings.accordion.scss +28 -7
  224. package/src/styles/01-settings/_settings.colors.scss +11 -11
  225. package/src/styles/01-settings/_settings.typography.scss +5 -5
  226. package/src/styles/02-tools/_tools.utility-api.scss +14 -0
  227. package/src/styles/06-components/_components.accordion.scss +56 -14
  228. package/src/styles/06-components/_components.callout.scss +29 -33
  229. package/src/styles/06-components/_components.checkbox.scss +23 -17
  230. package/src/styles/06-components/_index.scss +1 -1
  231. package/src/styles/99-utilities/_index.scss +2 -0
  232. package/src/styles/99-utilities/_utilities.display.scss +14 -3
  233. package/src/styles/99-utilities/_utilities.flex.scss +10 -10
  234. package/src/styles/99-utilities/_utilities.scss +3 -1
  235. package/src/styles/99-utilities/_utilities.text-gradient.scss +45 -0
  236. package/src/styles/99-utilities/_utilities.text.scss +28 -8
  237. package/themes/dark-complementary/README.md +98 -0
  238. package/themes/dark-complementary/index.scss +158 -0
  239. package/themes/default-light/README.md +81 -0
  240. package/themes/default-light/index.scss +154 -0
  241. package/themes/high-contrast/README.md +105 -0
  242. package/themes/high-contrast/index.scss +172 -0
  243. package/themes/test-theme/README.md +38 -0
  244. package/themes/test-theme/index.scss +47 -0
  245. package/scripts/cli/__tests__/cli-commands.test.js +0 -204
  246. package/scripts/cli/__tests__/vitest.config.js +0 -26
  247. package/src/components/AtomixGlass/stories/AtomixGlass.stories.tsx +0 -1438
  248. package/src/lib/composables/useButton.ts +0 -93
  249. 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
- 'The Toggle component 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.',
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
- initialOn: {
73
+ defaultChecked: {
20
74
  control: { type: 'boolean' },
21
- description: 'Whether the toggle is initially on',
22
- defaultValue: false,
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
- defaultValue: false,
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 Default: Story = {
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
- initialOn: false,
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
- initialOn: true,
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 Disabled: Story = {
64
- render: args => (
65
- <div style={{ display: 'flex', justifyContent: 'center', padding: '30px' }}>
66
- <Toggle {...args} />
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
- args: {
70
- initialOn: false,
71
- disabled: true,
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 DisabledOn: Story = {
194
+ export const WithGlassEffect: Story = {
76
195
  render: args => (
77
- <div style={{ display: 'flex', justifyContent: 'center', padding: '30px' }}>
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
- initialOn: true,
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
- render: (args: any) => (
94
- <div
95
- style={{
96
- background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
97
- padding: '3rem',
98
- borderRadius: '12px',
99
- minHeight: '200px',
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
- initialOn: true,
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
- initialOn: false,
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 initially on
8
+ * Whether the toggle is checked (controlled)
9
9
  */
10
- initialOn?: boolean;
10
+ checked?: boolean;
11
11
 
12
12
  /**
13
- * Callback when the toggle is turned on
13
+ * Whether the toggle is initially checked (uncontrolled)
14
+ * @default false
14
15
  */
15
- onToggleOn?: () => void;
16
+ defaultChecked?: boolean;
16
17
 
17
18
  /**
18
- * Callback when the toggle is turned off
19
+ * Callback when the toggle state changes
19
20
  */
20
- onToggleOff?: () => void;
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
- * Additional CSS class for the toggle
29
+ * Accessibility label
29
30
  */
30
- className?: string;
31
+ 'aria-label'?: string;
31
32
 
32
33
  /**
33
- * Inline style for the component
34
+ * Accessibility description
34
35
  */
35
- style?: React.CSSProperties;
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
- initialOn = false,
49
- onToggleOn,
50
- onToggleOff,
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 [isOn, setIsOn] = useState(initialOn);
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 newState = !isOn;
63
- setIsOn(newState);
71
+ const nextChecked = !isChecked;
64
72
 
65
- if (newState) {
66
- if (onToggleOn) onToggleOn();
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={`c-toggle ${isOn ? TOGGLE.CLASSES.IS_ON : ''} ${disabled ? 'is-disabled' : ''} ${className}`}
99
+ className={toggleClass}
85
100
  style={style}
86
101
  onClick={handleClick}
87
102
  onKeyDown={handleKeyDown}
88
103
  role="switch"
89
- aria-checked={isOn}
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>