@regardio/react 0.5.7 → 0.6.0

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 (180) hide show
  1. package/dist/background-slideshow/index.d.mts +36 -0
  2. package/dist/background-slideshow/index.mjs +110 -0
  3. package/dist/blurry-gradient/index.d.mts +17 -0
  4. package/dist/blurry-gradient/index.mjs +93 -0
  5. package/dist/button/index.d.mts +2 -0
  6. package/dist/button/index.mjs +3 -0
  7. package/dist/button-BiSQpBbc.mjs +129 -0
  8. package/dist/carousel/index.d.mts +40 -0
  9. package/dist/carousel/index.mjs +141 -0
  10. package/dist/checkbox/index.d.mts +37 -0
  11. package/dist/checkbox/index.mjs +70 -0
  12. package/dist/checkbox-group/index.d.mts +17 -0
  13. package/dist/checkbox-group/index.mjs +29 -0
  14. package/dist/chunk-BTpB_u-K.mjs +18 -0
  15. package/dist/countdown/index.d.mts +6 -0
  16. package/dist/countdown/index.mjs +58 -0
  17. package/dist/field/index.d.mts +66 -0
  18. package/dist/field/index.mjs +115 -0
  19. package/dist/fieldset/index.d.mts +33 -0
  20. package/dist/fieldset/index.mjs +61 -0
  21. package/dist/form/index.d.mts +22 -0
  22. package/dist/form/index.mjs +31 -0
  23. package/dist/generic-error/{index.d.ts → index.d.mts} +22 -18
  24. package/dist/generic-error/index.mjs +57 -0
  25. package/dist/grid/index.d.mts +1197 -0
  26. package/dist/grid/index.mjs +221 -0
  27. package/dist/heading/index.d.mts +31 -0
  28. package/dist/heading/index.mjs +29 -0
  29. package/dist/highlight/index.d.mts +18 -0
  30. package/dist/highlight/index.mjs +35 -0
  31. package/dist/hooks/{use-current-route-data.d.ts → use-current-route-data.d.mts} +3 -2
  32. package/dist/hooks/use-current-route-data.mjs +20 -0
  33. package/dist/hooks/{use-focus-search.d.ts → use-focus-search.d.mts} +4 -3
  34. package/dist/hooks/use-focus-search.mjs +21 -0
  35. package/dist/hooks/{use-matches-data.d.ts → use-matches-data.d.mts} +3 -2
  36. package/dist/hooks/use-matches-data.mjs +21 -0
  37. package/dist/hooks/{use-media-query.d.ts → use-media-query.d.mts} +3 -2
  38. package/dist/hooks/use-media-query.mjs +26 -0
  39. package/dist/hooks/use-mobile.d.mts +4 -0
  40. package/dist/hooks/use-mobile.mjs +20 -0
  41. package/dist/hooks/use-nonce.d.mts +8 -0
  42. package/dist/hooks/use-nonce.mjs +13 -0
  43. package/dist/hooks/{use-orientation.d.ts → use-orientation.d.mts} +3 -2
  44. package/dist/hooks/use-orientation.mjs +30 -0
  45. package/dist/hooks/use-user.d.mts +55 -0
  46. package/dist/hooks/use-user.mjs +39 -0
  47. package/dist/icon-button/index.d.mts +29 -0
  48. package/dist/icon-button/index.mjs +36 -0
  49. package/dist/if/index.d.mts +15 -0
  50. package/dist/if/index.mjs +21 -0
  51. package/dist/iframe/index.d.mts +11 -0
  52. package/dist/iframe/index.mjs +15 -0
  53. package/dist/index-Bm-tWhsb.d.mts +30 -0
  54. package/dist/index-YT2CkvL6.d.mts +36 -0
  55. package/dist/input/index.d.mts +2 -0
  56. package/dist/input/index.mjs +3 -0
  57. package/dist/input-CtR6aRVi.mjs +73 -0
  58. package/dist/link/index.d.mts +73 -0
  59. package/dist/link/index.mjs +129 -0
  60. package/dist/list/index.d.mts +71 -0
  61. package/dist/list/index.mjs +54 -0
  62. package/dist/markdown-container/index.d.mts +23 -0
  63. package/dist/markdown-container/index.mjs +71 -0
  64. package/dist/password-input/index.d.mts +24 -0
  65. package/dist/password-input/index.mjs +92 -0
  66. package/dist/picture/{index.d.ts → index.d.mts} +21 -20
  67. package/dist/picture/index.mjs +3 -0
  68. package/dist/picture-DkX3W5zl.mjs +69 -0
  69. package/dist/protected-email/{index.d.ts → index.d.mts} +14 -8
  70. package/dist/protected-email/index.mjs +37 -0
  71. package/dist/radio/index.d.mts +37 -0
  72. package/dist/radio/index.mjs +72 -0
  73. package/dist/radio-group/index.d.mts +17 -0
  74. package/dist/radio-group/index.mjs +29 -0
  75. package/dist/slider/index.d.mts +85 -0
  76. package/dist/slider/index.mjs +133 -0
  77. package/dist/switch/index.d.mts +38 -0
  78. package/dist/switch/index.mjs +87 -0
  79. package/dist/text/index.d.mts +26 -0
  80. package/dist/text/index.mjs +32 -0
  81. package/dist/text-CPlUND-Z.mjs +58 -0
  82. package/dist/toggle/index.d.mts +59 -0
  83. package/dist/toggle/index.mjs +82 -0
  84. package/dist/utils/author/index.d.mts +4 -0
  85. package/dist/utils/author/index.mjs +26 -0
  86. package/dist/utils/text/{index.d.ts → index.d.mts} +4 -3
  87. package/dist/utils/text/index.mjs +3 -0
  88. package/package.json +5 -117
  89. package/src/button/button.stories.tsx +161 -0
  90. package/src/button/button.test.tsx +73 -0
  91. package/src/button/button.tsx +112 -0
  92. package/src/button/index.ts +2 -0
  93. package/src/carousel/carousel-next.tsx +2 -2
  94. package/src/carousel/carousel-previous.tsx +2 -2
  95. package/src/checkbox/checkbox.stories.tsx +118 -0
  96. package/src/checkbox/checkbox.tsx +91 -0
  97. package/src/checkbox/index.ts +2 -0
  98. package/src/checkbox-group/checkbox-group.tsx +40 -0
  99. package/src/checkbox-group/index.ts +2 -0
  100. package/src/field/field.stories.tsx +105 -0
  101. package/src/field/field.test.tsx +61 -0
  102. package/src/field/field.tsx +165 -0
  103. package/src/field/index.ts +12 -0
  104. package/src/fieldset/fieldset.stories.tsx +204 -0
  105. package/src/fieldset/fieldset.test.tsx +63 -0
  106. package/src/fieldset/fieldset.tsx +75 -0
  107. package/src/fieldset/index.ts +7 -0
  108. package/src/form/form.stories.tsx +230 -0
  109. package/src/form/form.test.tsx +68 -0
  110. package/src/form/form.tsx +38 -0
  111. package/src/form/index.ts +2 -0
  112. package/src/icon-button/icon-button.stories.tsx +128 -7
  113. package/src/icon-button/icon-button.test.tsx +152 -0
  114. package/src/icon-button/icon-button.tsx +43 -9
  115. package/src/input/index.ts +2 -0
  116. package/src/input/input.stories.tsx +151 -0
  117. package/src/input/input.test.tsx +65 -0
  118. package/src/input/input.tsx +113 -0
  119. package/src/password-input/index.ts +1 -1
  120. package/src/password-input/password-input.tsx +104 -27
  121. package/src/radio/index.ts +2 -0
  122. package/src/radio/radio.tsx +92 -0
  123. package/src/radio-group/index.ts +2 -0
  124. package/src/radio-group/radio-group.tsx +36 -0
  125. package/src/slider/index.ts +18 -0
  126. package/src/slider/slider.tsx +179 -0
  127. package/src/switch/index.ts +2 -0
  128. package/src/switch/switch.stories.tsx +118 -0
  129. package/src/switch/switch.tsx +101 -0
  130. package/src/toggle/index.ts +2 -0
  131. package/src/toggle/toggle.stories.tsx +232 -0
  132. package/src/toggle/toggle.test.tsx +149 -0
  133. package/src/toggle/toggle.tsx +88 -0
  134. package/dist/background-slideshow/index.d.ts +0 -24
  135. package/dist/background-slideshow/index.js +0 -165
  136. package/dist/blurry-gradient/index.d.ts +0 -16
  137. package/dist/blurry-gradient/index.js +0 -128
  138. package/dist/carousel/index.d.ts +0 -36
  139. package/dist/carousel/index.js +0 -171
  140. package/dist/countdown/index.d.ts +0 -5
  141. package/dist/countdown/index.js +0 -73
  142. package/dist/generic-error/index.js +0 -47
  143. package/dist/grid/index.d.ts +0 -1196
  144. package/dist/grid/index.js +0 -239
  145. package/dist/heading/index.d.ts +0 -24
  146. package/dist/heading/index.js +0 -99
  147. package/dist/highlight/index.d.ts +0 -13
  148. package/dist/highlight/index.js +0 -59
  149. package/dist/hooks/use-current-route-data.js +0 -16
  150. package/dist/hooks/use-focus-search.js +0 -19
  151. package/dist/hooks/use-matches-data.js +0 -15
  152. package/dist/hooks/use-media-query.js +0 -20
  153. package/dist/hooks/use-mobile.d.ts +0 -3
  154. package/dist/hooks/use-mobile.js +0 -19
  155. package/dist/hooks/use-nonce.d.ts +0 -7
  156. package/dist/hooks/use-nonce.js +0 -8
  157. package/dist/hooks/use-orientation.js +0 -29
  158. package/dist/hooks/use-user.d.ts +0 -50
  159. package/dist/hooks/use-user.js +0 -25
  160. package/dist/icon-button/index.d.ts +0 -9
  161. package/dist/icon-button/index.js +0 -17
  162. package/dist/if/index.d.ts +0 -10
  163. package/dist/if/index.js +0 -24
  164. package/dist/iframe/index.d.ts +0 -10
  165. package/dist/iframe/index.js +0 -17
  166. package/dist/link/index.d.ts +0 -55
  167. package/dist/link/index.js +0 -195
  168. package/dist/list/index.d.ts +0 -69
  169. package/dist/list/index.js +0 -65
  170. package/dist/markdown-container/index.d.ts +0 -22
  171. package/dist/markdown-container/index.js +0 -128
  172. package/dist/password-input/index.d.ts +0 -11
  173. package/dist/password-input/index.js +0 -46
  174. package/dist/picture/index.js +0 -68
  175. package/dist/protected-email/index.js +0 -30
  176. package/dist/text/index.d.ts +0 -20
  177. package/dist/text/index.js +0 -38
  178. package/dist/utils/author/index.d.ts +0 -3
  179. package/dist/utils/author/index.js +0 -33
  180. package/dist/utils/text/index.js +0 -73
@@ -0,0 +1,2 @@
1
+ export type { RadioIndicatorProps, RadioRootProps, RadioSize } from './radio';
2
+ export { Radio, RadioIndicator, RadioRoot } from './radio';
@@ -0,0 +1,92 @@
1
+ import { Radio as BaseUIRadio } from '@base-ui/react/radio';
2
+ import { tv } from '@regardio/tailwind/utils';
3
+ import type { ComponentProps } from 'react';
4
+
5
+ const radioRoot = tv({
6
+ base: [
7
+ 'h-4',
8
+ 'w-4',
9
+ 'rounded-full',
10
+ 'border',
11
+ 'border-gray-300',
12
+ 'bg-white',
13
+ 'focus:outline-none',
14
+ 'focus:ring-2',
15
+ 'focus:ring-blue-500',
16
+ 'focus:ring-offset-2',
17
+ 'disabled:cursor-not-allowed',
18
+ 'disabled:opacity-50',
19
+ 'data-[checked]:bg-blue-600',
20
+ 'data-[checked]:border-blue-600',
21
+ 'transition-colors',
22
+ 'duration-200',
23
+ 'cursor-pointer',
24
+ ],
25
+ defaultVariants: {
26
+ size: 'md',
27
+ },
28
+ variants: {
29
+ size: {
30
+ lg: ['h-5', 'w-5'],
31
+ md: ['h-4', 'w-4'],
32
+ sm: ['h-3', 'w-3'],
33
+ },
34
+ },
35
+ });
36
+
37
+ const radioIndicator = tv({
38
+ base: ['flex', 'items-center', 'justify-center', 'text-white', 'data-[unchecked]:invisible'],
39
+ });
40
+
41
+ export type RadioSize = 'sm' | 'md' | 'lg';
42
+
43
+ export interface RadioRootProps extends Omit<ComponentProps<typeof BaseUIRadio.Root>, 'className'> {
44
+ className?: string;
45
+ size?: RadioSize;
46
+ }
47
+
48
+ export interface RadioIndicatorProps
49
+ extends Omit<ComponentProps<typeof BaseUIRadio.Indicator>, 'className'> {
50
+ className?: string;
51
+ }
52
+
53
+ export const RadioRoot = ({ className, size = 'md', ...props }: RadioRootProps) => {
54
+ return (
55
+ <BaseUIRadio.Root
56
+ className={radioRoot({
57
+ className,
58
+ size,
59
+ })}
60
+ {...props}
61
+ />
62
+ );
63
+ };
64
+
65
+ export const RadioIndicator = ({ className, children, ...props }: RadioIndicatorProps) => {
66
+ return (
67
+ <BaseUIRadio.Indicator
68
+ className={radioIndicator({ className })}
69
+ {...props}
70
+ >
71
+ {children || (
72
+ <svg
73
+ fill="currentColor"
74
+ height="8"
75
+ viewBox="0 0 8 8"
76
+ width="8"
77
+ >
78
+ <circle
79
+ cx="4"
80
+ cy="4"
81
+ r="3"
82
+ />
83
+ </svg>
84
+ )}
85
+ </BaseUIRadio.Indicator>
86
+ );
87
+ };
88
+
89
+ export const Radio = {
90
+ Indicator: RadioIndicator,
91
+ Root: RadioRoot,
92
+ };
@@ -0,0 +1,2 @@
1
+ export type { RadioGroupOrientation, RadioGroupProps } from './radio-group';
2
+ export { RadioGroup } from './radio-group';
@@ -0,0 +1,36 @@
1
+ import { RadioGroup as BaseUIRadioGroup } from '@base-ui/react/radio-group';
2
+ import { tv } from '@regardio/tailwind/utils';
3
+ import type { ComponentProps } from 'react';
4
+
5
+ const radioGroup = tv({
6
+ base: ['flex', 'flex-col', 'gap-2'],
7
+ defaultVariants: {
8
+ orientation: 'vertical',
9
+ },
10
+ variants: {
11
+ orientation: {
12
+ horizontal: ['flex-row', 'gap-4'],
13
+ vertical: ['flex-col', 'gap-2'],
14
+ },
15
+ },
16
+ });
17
+
18
+ export type RadioGroupOrientation = 'horizontal' | 'vertical';
19
+
20
+ export interface RadioGroupProps
21
+ extends Omit<ComponentProps<typeof BaseUIRadioGroup>, 'className'> {
22
+ className?: string;
23
+ orientation?: RadioGroupOrientation;
24
+ }
25
+
26
+ export const RadioGroup = ({ className, orientation = 'vertical', ...props }: RadioGroupProps) => {
27
+ return (
28
+ <BaseUIRadioGroup
29
+ className={radioGroup({
30
+ className,
31
+ orientation,
32
+ })}
33
+ {...props}
34
+ />
35
+ );
36
+ };
@@ -0,0 +1,18 @@
1
+ export type {
2
+ SliderControlProps,
3
+ SliderIndicatorProps,
4
+ SliderRootProps,
5
+ SliderSize,
6
+ SliderThumbProps,
7
+ SliderTrackProps,
8
+ SliderValueProps,
9
+ } from './slider';
10
+ export {
11
+ Slider,
12
+ SliderControl,
13
+ SliderIndicator,
14
+ SliderRoot,
15
+ SliderThumb,
16
+ SliderTrack,
17
+ SliderValue,
18
+ } from './slider';
@@ -0,0 +1,179 @@
1
+ import { Slider as BaseUISlider } from '@base-ui/react/slider';
2
+ import { tv } from '@regardio/tailwind/utils';
3
+ import type { ComponentProps } from 'react';
4
+
5
+ const sliderRoot = tv({
6
+ base: ['relative', 'flex', 'items-center', 'w-full'],
7
+ defaultVariants: {
8
+ size: 'md',
9
+ },
10
+ variants: {
11
+ size: {
12
+ lg: ['h-8'],
13
+ md: ['h-6'],
14
+ sm: ['h-4'],
15
+ },
16
+ },
17
+ });
18
+
19
+ const sliderControl = tv({
20
+ base: ['relative', 'flex', 'items-center', 'w-full', 'touch-none'],
21
+ });
22
+
23
+ const sliderTrack = tv({
24
+ base: ['relative', 'w-full', 'rounded-full', 'bg-gray-200', 'overflow-hidden'],
25
+ defaultVariants: {
26
+ size: 'md',
27
+ },
28
+ variants: {
29
+ size: {
30
+ lg: ['h-3'],
31
+ md: ['h-2'],
32
+ sm: ['h-1'],
33
+ },
34
+ },
35
+ });
36
+
37
+ const sliderIndicator = tv({
38
+ base: ['absolute', 'h-full', 'bg-blue-600', 'rounded-full'],
39
+ });
40
+
41
+ const sliderThumb = tv({
42
+ base: [
43
+ 'block',
44
+ 'rounded-full',
45
+ 'bg-white',
46
+ 'border-2',
47
+ 'border-blue-600',
48
+ 'shadow-lg',
49
+ 'focus:outline-none',
50
+ 'focus:ring-2',
51
+ 'focus:ring-blue-500',
52
+ 'focus:ring-offset-2',
53
+ 'disabled:cursor-not-allowed',
54
+ 'disabled:opacity-50',
55
+ 'cursor-grab',
56
+ 'active:cursor-grabbing',
57
+ ],
58
+ defaultVariants: {
59
+ size: 'md',
60
+ },
61
+ variants: {
62
+ size: {
63
+ lg: ['h-6', 'w-6'],
64
+ md: ['h-5', 'w-5'],
65
+ sm: ['h-3', 'w-3'],
66
+ },
67
+ },
68
+ });
69
+
70
+ const sliderValue = tv({
71
+ base: ['text-sm', 'font-medium', 'text-gray-700', 'mb-2'],
72
+ });
73
+
74
+ export type SliderSize = 'sm' | 'md' | 'lg';
75
+
76
+ export interface SliderRootProps
77
+ extends Omit<ComponentProps<typeof BaseUISlider.Root>, 'className'> {
78
+ className?: string;
79
+ size?: SliderSize;
80
+ }
81
+
82
+ export interface SliderControlProps
83
+ extends Omit<ComponentProps<typeof BaseUISlider.Control>, 'className'> {
84
+ className?: string;
85
+ }
86
+
87
+ export interface SliderTrackProps
88
+ extends Omit<ComponentProps<typeof BaseUISlider.Track>, 'className'> {
89
+ className?: string;
90
+ size?: SliderSize;
91
+ }
92
+
93
+ export interface SliderIndicatorProps
94
+ extends Omit<ComponentProps<typeof BaseUISlider.Indicator>, 'className'> {
95
+ className?: string;
96
+ }
97
+
98
+ export interface SliderThumbProps
99
+ extends Omit<ComponentProps<typeof BaseUISlider.Thumb>, 'className'> {
100
+ className?: string;
101
+ size?: SliderSize;
102
+ }
103
+
104
+ export interface SliderValueProps
105
+ extends Omit<ComponentProps<typeof BaseUISlider.Value>, 'className'> {
106
+ className?: string;
107
+ }
108
+
109
+ export const SliderRoot = ({ className, size = 'md', ...props }: SliderRootProps) => {
110
+ return (
111
+ <BaseUISlider.Root
112
+ className={sliderRoot({
113
+ className,
114
+ size,
115
+ })}
116
+ {...props}
117
+ />
118
+ );
119
+ };
120
+
121
+ export const SliderControl = ({ className, ...props }: SliderControlProps) => {
122
+ return (
123
+ <BaseUISlider.Control
124
+ className={sliderControl({ className })}
125
+ {...props}
126
+ />
127
+ );
128
+ };
129
+
130
+ export const SliderTrack = ({ className, size = 'md', ...props }: SliderTrackProps) => {
131
+ return (
132
+ <BaseUISlider.Track
133
+ className={sliderTrack({
134
+ className,
135
+ size,
136
+ })}
137
+ {...props}
138
+ />
139
+ );
140
+ };
141
+
142
+ export const SliderIndicator = ({ className, ...props }: SliderIndicatorProps) => {
143
+ return (
144
+ <BaseUISlider.Indicator
145
+ className={sliderIndicator({ className })}
146
+ {...props}
147
+ />
148
+ );
149
+ };
150
+
151
+ export const SliderThumb = ({ className, size = 'md', ...props }: SliderThumbProps) => {
152
+ return (
153
+ <BaseUISlider.Thumb
154
+ className={sliderThumb({
155
+ className,
156
+ size,
157
+ })}
158
+ {...props}
159
+ />
160
+ );
161
+ };
162
+
163
+ export const SliderValue = ({ className, ...props }: SliderValueProps) => {
164
+ return (
165
+ <BaseUISlider.Value
166
+ className={sliderValue({ className })}
167
+ {...props}
168
+ />
169
+ );
170
+ };
171
+
172
+ export const Slider = {
173
+ Control: SliderControl,
174
+ Indicator: SliderIndicator,
175
+ Root: SliderRoot,
176
+ Thumb: SliderThumb,
177
+ Track: SliderTrack,
178
+ Value: SliderValue,
179
+ };
@@ -0,0 +1,2 @@
1
+ export type { SwitchRootProps, SwitchSize, SwitchThumbProps } from './switch';
2
+ export { Switch, SwitchRoot, SwitchThumb } from './switch';
@@ -0,0 +1,118 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-vite';
2
+ import { useState } from 'react';
3
+ import { Field } from '../field';
4
+ import { Switch } from './switch';
5
+
6
+ const meta: Meta<typeof Switch.Root> = {
7
+ argTypes: {
8
+ disabled: {
9
+ control: 'boolean',
10
+ description: 'Disable the switch',
11
+ },
12
+ size: {
13
+ control: 'select',
14
+ description: 'Switch size',
15
+ options: ['sm', 'md', 'lg'],
16
+ },
17
+ },
18
+ component: Switch.Root,
19
+ parameters: {
20
+ layout: 'centered',
21
+ },
22
+ tags: ['autodocs'],
23
+ title: 'Components/Switch',
24
+ };
25
+
26
+ export default meta;
27
+ type Story = StoryObj<typeof meta>;
28
+
29
+ export const Default: Story = {
30
+ render: () => (
31
+ <Switch.Root>
32
+ <Switch.Thumb />
33
+ </Switch.Root>
34
+ ),
35
+ };
36
+
37
+ export const Checked: Story = {
38
+ render: () => (
39
+ <Switch.Root defaultChecked>
40
+ <Switch.Thumb />
41
+ </Switch.Root>
42
+ ),
43
+ };
44
+
45
+ export const Small: Story = {
46
+ render: () => (
47
+ <Switch.Root size="sm">
48
+ <Switch.Thumb size="sm" />
49
+ </Switch.Root>
50
+ ),
51
+ };
52
+
53
+ export const Large: Story = {
54
+ render: () => (
55
+ <Switch.Root size="lg">
56
+ <Switch.Thumb size="lg" />
57
+ </Switch.Root>
58
+ ),
59
+ };
60
+
61
+ export const Disabled: Story = {
62
+ render: () => (
63
+ <Switch.Root disabled>
64
+ <Switch.Thumb />
65
+ </Switch.Root>
66
+ ),
67
+ };
68
+
69
+ export const WithLabel: Story = {
70
+ render: () => (
71
+ <Field.Root>
72
+ <Field.Label>
73
+ <Switch.Root>
74
+ <Switch.Thumb />
75
+ </Switch.Root>
76
+ Enable notifications
77
+ </Field.Label>
78
+ </Field.Root>
79
+ ),
80
+ };
81
+
82
+ export const Controlled: Story = {
83
+ render: () => {
84
+ const [checked, setChecked] = useState(false);
85
+ return (
86
+ <div className="space-y-4">
87
+ <Field.Root>
88
+ <Field.Label>
89
+ <Switch.Root
90
+ checked={checked}
91
+ onCheckedChange={setChecked}
92
+ >
93
+ <Switch.Thumb />
94
+ </Switch.Root>
95
+ Dark mode
96
+ </Field.Label>
97
+ </Field.Root>
98
+ <p className="text-sm text-gray-600">Mode: {checked ? 'Dark' : 'Light'}</p>
99
+ </div>
100
+ );
101
+ },
102
+ };
103
+
104
+ export const AllSizes: Story = {
105
+ render: () => (
106
+ <div className="flex items-center gap-4">
107
+ <Switch.Root size="sm">
108
+ <Switch.Thumb size="sm" />
109
+ </Switch.Root>
110
+ <Switch.Root size="md">
111
+ <Switch.Thumb size="md" />
112
+ </Switch.Root>
113
+ <Switch.Root size="lg">
114
+ <Switch.Thumb size="lg" />
115
+ </Switch.Root>
116
+ </div>
117
+ ),
118
+ };
@@ -0,0 +1,101 @@
1
+ import { Switch as BaseUISwitch } from '@base-ui/react/switch';
2
+ import { tv } from '@regardio/tailwind/utils';
3
+ import type { ComponentProps } from 'react';
4
+
5
+ const switchRoot = tv({
6
+ base: [
7
+ 'relative',
8
+ 'inline-flex',
9
+ 'items-center',
10
+ 'rounded-full',
11
+ 'transition-colors',
12
+ 'duration-200',
13
+ 'focus:outline-none',
14
+ 'focus:ring-2',
15
+ 'focus:ring-blue-500',
16
+ 'focus:ring-offset-2',
17
+ 'disabled:cursor-not-allowed',
18
+ 'disabled:opacity-50',
19
+ 'cursor-pointer',
20
+ 'bg-gray-300',
21
+ 'data-[checked]:bg-blue-600',
22
+ ],
23
+ defaultVariants: {
24
+ size: 'md',
25
+ },
26
+ variants: {
27
+ size: {
28
+ lg: ['h-8', 'w-14'],
29
+ md: ['h-6', 'w-11'],
30
+ sm: ['h-4', 'w-7'],
31
+ },
32
+ },
33
+ });
34
+
35
+ const switchThumb = tv({
36
+ base: [
37
+ 'pointer-events-none',
38
+ 'inline-block',
39
+ 'rounded-full',
40
+ 'bg-white',
41
+ 'shadow-lg',
42
+ 'ring-0',
43
+ 'transition-transform',
44
+ 'duration-200',
45
+ 'translate-x-0',
46
+ 'data-[checked]:translate-x-full',
47
+ ],
48
+ defaultVariants: {
49
+ size: 'md',
50
+ },
51
+ variants: {
52
+ size: {
53
+ lg: ['h-6', 'w-6', 'data-[checked]:translate-x-6'],
54
+ md: ['h-5', 'w-5', 'data-[checked]:translate-x-5'],
55
+ sm: ['h-3', 'w-3', 'data-[checked]:translate-x-3'],
56
+ },
57
+ },
58
+ });
59
+
60
+ export type SwitchSize = 'sm' | 'md' | 'lg';
61
+
62
+ export interface SwitchRootProps
63
+ extends Omit<ComponentProps<typeof BaseUISwitch.Root>, 'className'> {
64
+ className?: string;
65
+ size?: SwitchSize;
66
+ }
67
+
68
+ export interface SwitchThumbProps
69
+ extends Omit<ComponentProps<typeof BaseUISwitch.Thumb>, 'className'> {
70
+ className?: string;
71
+ size?: SwitchSize;
72
+ }
73
+
74
+ export const SwitchRoot = ({ className, size = 'md', ...props }: SwitchRootProps) => {
75
+ return (
76
+ <BaseUISwitch.Root
77
+ className={switchRoot({
78
+ className,
79
+ size,
80
+ })}
81
+ {...props}
82
+ />
83
+ );
84
+ };
85
+
86
+ export const SwitchThumb = ({ className, size = 'md', ...props }: SwitchThumbProps) => {
87
+ return (
88
+ <BaseUISwitch.Thumb
89
+ className={switchThumb({
90
+ className,
91
+ size,
92
+ })}
93
+ {...props}
94
+ />
95
+ );
96
+ };
97
+
98
+ export const Switch = {
99
+ Root: SwitchRoot,
100
+ Thumb: SwitchThumb,
101
+ };
@@ -0,0 +1,2 @@
1
+ export type { ToggleProps, ToggleSize, ToggleVariant } from './toggle';
2
+ export { Toggle } from './toggle';