@regardio/react 0.5.5 → 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.
- package/dist/background-slideshow/index.d.mts +36 -0
- package/dist/background-slideshow/index.mjs +110 -0
- package/dist/blurry-gradient/index.d.mts +17 -0
- package/dist/blurry-gradient/index.mjs +93 -0
- package/dist/button/index.d.mts +2 -0
- package/dist/button/index.mjs +3 -0
- package/dist/button-BiSQpBbc.mjs +129 -0
- package/dist/carousel/index.d.mts +40 -0
- package/dist/carousel/index.mjs +141 -0
- package/dist/checkbox/index.d.mts +37 -0
- package/dist/checkbox/index.mjs +70 -0
- package/dist/checkbox-group/index.d.mts +17 -0
- package/dist/checkbox-group/index.mjs +29 -0
- package/dist/chunk-BTpB_u-K.mjs +18 -0
- package/dist/countdown/index.d.mts +6 -0
- package/dist/countdown/index.mjs +58 -0
- package/dist/field/index.d.mts +66 -0
- package/dist/field/index.mjs +115 -0
- package/dist/fieldset/index.d.mts +33 -0
- package/dist/fieldset/index.mjs +61 -0
- package/dist/form/index.d.mts +22 -0
- package/dist/form/index.mjs +31 -0
- package/dist/generic-error/{index.d.ts → index.d.mts} +22 -18
- package/dist/generic-error/index.mjs +57 -0
- package/dist/grid/index.d.mts +1197 -0
- package/dist/grid/index.mjs +221 -0
- package/dist/heading/index.d.mts +31 -0
- package/dist/heading/index.mjs +29 -0
- package/dist/highlight/index.d.mts +18 -0
- package/dist/highlight/index.mjs +35 -0
- package/dist/hooks/{use-current-route-data.d.ts → use-current-route-data.d.mts} +3 -2
- package/dist/hooks/use-current-route-data.mjs +20 -0
- package/dist/hooks/{use-focus-search.d.ts → use-focus-search.d.mts} +4 -3
- package/dist/hooks/use-focus-search.mjs +21 -0
- package/dist/hooks/{use-matches-data.d.ts → use-matches-data.d.mts} +3 -2
- package/dist/hooks/use-matches-data.mjs +21 -0
- package/dist/hooks/{use-media-query.d.ts → use-media-query.d.mts} +3 -2
- package/dist/hooks/use-media-query.mjs +26 -0
- package/dist/hooks/use-mobile.d.mts +4 -0
- package/dist/hooks/use-mobile.mjs +20 -0
- package/dist/hooks/use-nonce.d.mts +8 -0
- package/dist/hooks/use-nonce.mjs +13 -0
- package/dist/hooks/{use-orientation.d.ts → use-orientation.d.mts} +3 -2
- package/dist/hooks/use-orientation.mjs +30 -0
- package/dist/hooks/use-user.d.mts +55 -0
- package/dist/hooks/use-user.mjs +39 -0
- package/dist/icon-button/index.d.mts +29 -0
- package/dist/icon-button/index.mjs +36 -0
- package/dist/if/index.d.mts +15 -0
- package/dist/if/index.mjs +21 -0
- package/dist/iframe/index.d.mts +11 -0
- package/dist/iframe/index.mjs +15 -0
- package/dist/index-Bm-tWhsb.d.mts +30 -0
- package/dist/index-YT2CkvL6.d.mts +36 -0
- package/dist/input/index.d.mts +2 -0
- package/dist/input/index.mjs +3 -0
- package/dist/input-CtR6aRVi.mjs +73 -0
- package/dist/link/index.d.mts +73 -0
- package/dist/link/index.mjs +129 -0
- package/dist/list/index.d.mts +71 -0
- package/dist/list/index.mjs +54 -0
- package/dist/markdown-container/index.d.mts +23 -0
- package/dist/markdown-container/index.mjs +71 -0
- package/dist/password-input/index.d.mts +24 -0
- package/dist/password-input/index.mjs +92 -0
- package/dist/picture/{index.d.ts → index.d.mts} +21 -20
- package/dist/picture/index.mjs +3 -0
- package/dist/picture-DkX3W5zl.mjs +69 -0
- package/dist/protected-email/{index.d.ts → index.d.mts} +14 -8
- package/dist/protected-email/index.mjs +37 -0
- package/dist/radio/index.d.mts +37 -0
- package/dist/radio/index.mjs +72 -0
- package/dist/radio-group/index.d.mts +17 -0
- package/dist/radio-group/index.mjs +29 -0
- package/dist/slider/index.d.mts +85 -0
- package/dist/slider/index.mjs +133 -0
- package/dist/switch/index.d.mts +38 -0
- package/dist/switch/index.mjs +87 -0
- package/dist/text/index.d.mts +26 -0
- package/dist/text/index.mjs +32 -0
- package/dist/text-CPlUND-Z.mjs +58 -0
- package/dist/toggle/index.d.mts +59 -0
- package/dist/toggle/index.mjs +82 -0
- package/dist/utils/author/index.d.mts +4 -0
- package/dist/utils/author/index.mjs +26 -0
- package/dist/utils/text/{index.d.ts → index.d.mts} +4 -3
- package/dist/utils/text/index.mjs +3 -0
- package/package.json +17 -129
- package/src/button/button.stories.tsx +161 -0
- package/src/button/button.test.tsx +73 -0
- package/src/button/button.tsx +112 -0
- package/src/button/index.ts +2 -0
- package/src/carousel/carousel-next.tsx +2 -2
- package/src/carousel/carousel-previous.tsx +2 -2
- package/src/checkbox/checkbox.stories.tsx +118 -0
- package/src/checkbox/checkbox.tsx +91 -0
- package/src/checkbox/index.ts +2 -0
- package/src/checkbox-group/checkbox-group.tsx +40 -0
- package/src/checkbox-group/index.ts +2 -0
- package/src/field/field.stories.tsx +105 -0
- package/src/field/field.test.tsx +61 -0
- package/src/field/field.tsx +165 -0
- package/src/field/index.ts +12 -0
- package/src/fieldset/fieldset.stories.tsx +204 -0
- package/src/fieldset/fieldset.test.tsx +63 -0
- package/src/fieldset/fieldset.tsx +75 -0
- package/src/fieldset/index.ts +7 -0
- package/src/form/form.stories.tsx +230 -0
- package/src/form/form.test.tsx +68 -0
- package/src/form/form.tsx +38 -0
- package/src/form/index.ts +2 -0
- package/src/icon-button/icon-button.stories.tsx +128 -7
- package/src/icon-button/icon-button.test.tsx +152 -0
- package/src/icon-button/icon-button.tsx +43 -9
- package/src/input/index.ts +2 -0
- package/src/input/input.stories.tsx +151 -0
- package/src/input/input.test.tsx +65 -0
- package/src/input/input.tsx +113 -0
- package/src/link/link.test.tsx +169 -0
- package/src/password-input/index.ts +1 -1
- package/src/password-input/password-input.tsx +104 -27
- package/src/radio/index.ts +2 -0
- package/src/radio/radio.tsx +92 -0
- package/src/radio-group/index.ts +2 -0
- package/src/radio-group/radio-group.tsx +36 -0
- package/src/slider/index.ts +18 -0
- package/src/slider/slider.tsx +179 -0
- package/src/switch/index.ts +2 -0
- package/src/switch/switch.stories.tsx +118 -0
- package/src/switch/switch.tsx +101 -0
- package/src/toggle/index.ts +2 -0
- package/src/toggle/toggle.stories.tsx +232 -0
- package/src/toggle/toggle.test.tsx +149 -0
- package/src/toggle/toggle.tsx +88 -0
- package/src/utils/text/text.test.tsx +110 -0
- package/dist/background-slideshow/index.d.ts +0 -24
- package/dist/background-slideshow/index.js +0 -165
- package/dist/blurry-gradient/index.d.ts +0 -16
- package/dist/blurry-gradient/index.js +0 -128
- package/dist/carousel/index.d.ts +0 -36
- package/dist/carousel/index.js +0 -171
- package/dist/countdown/index.d.ts +0 -5
- package/dist/countdown/index.js +0 -73
- package/dist/generic-error/index.js +0 -47
- package/dist/grid/index.d.ts +0 -1196
- package/dist/grid/index.js +0 -239
- package/dist/heading/index.d.ts +0 -24
- package/dist/heading/index.js +0 -99
- package/dist/highlight/index.d.ts +0 -13
- package/dist/highlight/index.js +0 -59
- package/dist/hooks/use-current-route-data.js +0 -16
- package/dist/hooks/use-focus-search.js +0 -19
- package/dist/hooks/use-matches-data.js +0 -15
- package/dist/hooks/use-media-query.js +0 -20
- package/dist/hooks/use-mobile.d.ts +0 -3
- package/dist/hooks/use-mobile.js +0 -19
- package/dist/hooks/use-nonce.d.ts +0 -7
- package/dist/hooks/use-nonce.js +0 -8
- package/dist/hooks/use-orientation.js +0 -29
- package/dist/hooks/use-user.d.ts +0 -50
- package/dist/hooks/use-user.js +0 -25
- package/dist/icon-button/index.d.ts +0 -9
- package/dist/icon-button/index.js +0 -17
- package/dist/if/index.d.ts +0 -10
- package/dist/if/index.js +0 -24
- package/dist/iframe/index.d.ts +0 -10
- package/dist/iframe/index.js +0 -17
- package/dist/link/index.d.ts +0 -55
- package/dist/link/index.js +0 -195
- package/dist/list/index.d.ts +0 -69
- package/dist/list/index.js +0 -65
- package/dist/markdown-container/index.d.ts +0 -22
- package/dist/markdown-container/index.js +0 -128
- package/dist/password-input/index.d.ts +0 -11
- package/dist/password-input/index.js +0 -46
- package/dist/picture/index.js +0 -68
- package/dist/protected-email/index.js +0 -30
- package/dist/text/index.d.ts +0 -20
- package/dist/text/index.js +0 -38
- package/dist/utils/author/index.d.ts +0 -3
- package/dist/utils/author/index.js +0 -33
- package/dist/utils/text/index.js +0 -73
|
@@ -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,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,232 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react-vite';
|
|
2
|
+
import type React from 'react';
|
|
3
|
+
import { useState } from 'react';
|
|
4
|
+
import { Button } from '../button';
|
|
5
|
+
import { Toggle } from './toggle';
|
|
6
|
+
|
|
7
|
+
const meta: Meta<typeof Toggle> = {
|
|
8
|
+
argTypes: {
|
|
9
|
+
defaultPressed: {
|
|
10
|
+
control: 'boolean',
|
|
11
|
+
description: 'Initial pressed state (uncontrolled)',
|
|
12
|
+
},
|
|
13
|
+
disabled: {
|
|
14
|
+
control: 'boolean',
|
|
15
|
+
description: 'Disable the toggle',
|
|
16
|
+
},
|
|
17
|
+
pressed: {
|
|
18
|
+
control: 'boolean',
|
|
19
|
+
description: 'Pressed state (controlled)',
|
|
20
|
+
},
|
|
21
|
+
size: {
|
|
22
|
+
control: 'select',
|
|
23
|
+
description: 'Toggle size',
|
|
24
|
+
options: ['sm', 'md', 'lg'],
|
|
25
|
+
},
|
|
26
|
+
variant: {
|
|
27
|
+
control: 'select',
|
|
28
|
+
description: 'Toggle variant',
|
|
29
|
+
options: ['default', 'outline', 'ghost'],
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
component: Toggle,
|
|
33
|
+
parameters: {
|
|
34
|
+
layout: 'centered',
|
|
35
|
+
},
|
|
36
|
+
tags: ['autodocs'],
|
|
37
|
+
title: 'Components/Toggle',
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export default meta;
|
|
41
|
+
type Story = StoryObj<typeof meta>;
|
|
42
|
+
|
|
43
|
+
const HeartIcon = ({ filled = false }) => (
|
|
44
|
+
<svg
|
|
45
|
+
fill={filled ? 'currentColor' : 'none'}
|
|
46
|
+
height="16"
|
|
47
|
+
stroke="currentColor"
|
|
48
|
+
strokeWidth="2"
|
|
49
|
+
viewBox="0 0 16 16"
|
|
50
|
+
width="16"
|
|
51
|
+
>
|
|
52
|
+
<path d="M7.99961 13.8667C7.88761 13.8667 7.77561 13.8315 7.68121 13.7611C7.43321 13.5766 1.59961 9.1963 1.59961 5.8667C1.59961 3.80856 3.27481 2.13336 5.33294 2.13336C6.59054 2.13336 7.49934 2.81176 7.99961 3.3131C8.49988 2.81176 9.40868 2.13336 10.6663 2.13336C12.7244 2.13336 14.3996 3.80803 14.3996 5.8667C14.3996 9.1963 8.56601 13.5766 8.31801 13.7616C8.22361 13.8315 8.11161 13.8667 7.99961 13.8667Z" />
|
|
53
|
+
</svg>
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
const StarIcon = ({ filled = false }) => (
|
|
57
|
+
<svg
|
|
58
|
+
fill={filled ? 'currentColor' : 'none'}
|
|
59
|
+
height="16"
|
|
60
|
+
stroke="currentColor"
|
|
61
|
+
strokeWidth="2"
|
|
62
|
+
viewBox="0 0 16 16"
|
|
63
|
+
width="16"
|
|
64
|
+
>
|
|
65
|
+
<path d="m8 1.62 1.94 3.93 4.34.63-3.14 3.06.74 4.32L8 12.22l-3.88 2.34.74-4.32-3.14-3.06 4.34-.63L8 1.62Z" />
|
|
66
|
+
</svg>
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
const SettingsIcon = () => (
|
|
70
|
+
<svg
|
|
71
|
+
fill="none"
|
|
72
|
+
height="16"
|
|
73
|
+
stroke="currentColor"
|
|
74
|
+
strokeWidth="2"
|
|
75
|
+
viewBox="0 0 16 16"
|
|
76
|
+
width="16"
|
|
77
|
+
>
|
|
78
|
+
<circle
|
|
79
|
+
cx="8"
|
|
80
|
+
cy="8"
|
|
81
|
+
r="2"
|
|
82
|
+
/>
|
|
83
|
+
<path d="m8 1v3m0 6v3m2.83-9.83 2.12 2.12M1.17 5.17l2.12 2.12m9.42 0 2.12 2.12M1.17 10.83l2.12-2.12" />
|
|
84
|
+
</svg>
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
export const Default: Story = {
|
|
88
|
+
args: {
|
|
89
|
+
children: <HeartIcon />,
|
|
90
|
+
title: 'Favorite',
|
|
91
|
+
},
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
export const Pressed: Story = {
|
|
95
|
+
args: {
|
|
96
|
+
children: <HeartIcon filled />,
|
|
97
|
+
defaultPressed: true,
|
|
98
|
+
title: 'Favorite',
|
|
99
|
+
},
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
export const Controlled: Story = {
|
|
103
|
+
render: () => {
|
|
104
|
+
const [pressed, setPressed] = useState(false);
|
|
105
|
+
return (
|
|
106
|
+
<Toggle
|
|
107
|
+
onPressedChange={setPressed}
|
|
108
|
+
pressed={pressed}
|
|
109
|
+
title="Favorite"
|
|
110
|
+
>
|
|
111
|
+
<HeartIcon filled={pressed} />
|
|
112
|
+
</Toggle>
|
|
113
|
+
);
|
|
114
|
+
},
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
export const Ghost: Story = {
|
|
118
|
+
args: {
|
|
119
|
+
children: <StarIcon />,
|
|
120
|
+
title: 'Star',
|
|
121
|
+
variant: 'ghost',
|
|
122
|
+
},
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
export const Small: Story = {
|
|
126
|
+
args: {
|
|
127
|
+
children: <SettingsIcon />,
|
|
128
|
+
size: 'sm',
|
|
129
|
+
title: 'Settings',
|
|
130
|
+
},
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
export const Large: Story = {
|
|
134
|
+
args: {
|
|
135
|
+
children: <SettingsIcon />,
|
|
136
|
+
size: 'lg',
|
|
137
|
+
title: 'Settings',
|
|
138
|
+
},
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
export const Disabled: Story = {
|
|
142
|
+
args: {
|
|
143
|
+
children: <HeartIcon />,
|
|
144
|
+
disabled: true,
|
|
145
|
+
title: 'Favorite',
|
|
146
|
+
},
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
export const AllVariants: Story = {
|
|
150
|
+
render: () => (
|
|
151
|
+
<div className="flex gap-4">
|
|
152
|
+
<Toggle title="Default">
|
|
153
|
+
<HeartIcon />
|
|
154
|
+
</Toggle>
|
|
155
|
+
<Toggle
|
|
156
|
+
title="Outline"
|
|
157
|
+
variant="outline"
|
|
158
|
+
>
|
|
159
|
+
<StarIcon />
|
|
160
|
+
</Toggle>
|
|
161
|
+
<Toggle
|
|
162
|
+
title="Ghost"
|
|
163
|
+
variant="ghost"
|
|
164
|
+
>
|
|
165
|
+
<SettingsIcon />
|
|
166
|
+
</Toggle>
|
|
167
|
+
</div>
|
|
168
|
+
),
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
export const AllSizes: Story = {
|
|
172
|
+
render: () => (
|
|
173
|
+
<div className="flex items-center gap-4">
|
|
174
|
+
<Toggle
|
|
175
|
+
size="sm"
|
|
176
|
+
title="Small"
|
|
177
|
+
>
|
|
178
|
+
<HeartIcon />
|
|
179
|
+
</Toggle>
|
|
180
|
+
<Toggle
|
|
181
|
+
size="md"
|
|
182
|
+
title="Medium"
|
|
183
|
+
>
|
|
184
|
+
<HeartIcon />
|
|
185
|
+
</Toggle>
|
|
186
|
+
<Toggle
|
|
187
|
+
size="lg"
|
|
188
|
+
title="Large"
|
|
189
|
+
>
|
|
190
|
+
<HeartIcon />
|
|
191
|
+
</Toggle>
|
|
192
|
+
</div>
|
|
193
|
+
),
|
|
194
|
+
};
|
|
195
|
+
|
|
196
|
+
export const Interactive: Story = {
|
|
197
|
+
render: () => {
|
|
198
|
+
const [pressed, setPressed] = useState(false);
|
|
199
|
+
return (
|
|
200
|
+
<div className="space-y-4">
|
|
201
|
+
<Toggle
|
|
202
|
+
onPressedChange={setPressed}
|
|
203
|
+
pressed={pressed}
|
|
204
|
+
title="Toggle favorite"
|
|
205
|
+
>
|
|
206
|
+
<HeartIcon filled={pressed} />
|
|
207
|
+
</Toggle>
|
|
208
|
+
<p className="text-sm text-gray-600">State: {pressed ? 'pressed' : 'not pressed'}</p>
|
|
209
|
+
</div>
|
|
210
|
+
);
|
|
211
|
+
},
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
export const CustomRender: Story = {
|
|
215
|
+
args: {
|
|
216
|
+
render: (props: React.ComponentProps<'button'>) => (
|
|
217
|
+
<Button
|
|
218
|
+
{...props}
|
|
219
|
+
className="inline-flex items-center justify-center w-10 h-10 rounded-full bg-blue-500 text-white hover:bg-blue-600 focus:ring-2 focus:ring-blue-500 focus:ring-offset-2"
|
|
220
|
+
>
|
|
221
|
+
<svg
|
|
222
|
+
fill="currentColor"
|
|
223
|
+
height="16"
|
|
224
|
+
viewBox="0 0 16 16"
|
|
225
|
+
width="16"
|
|
226
|
+
>
|
|
227
|
+
<path d="m6.5 3.5 3 3-3 3" />
|
|
228
|
+
</svg>
|
|
229
|
+
</Button>
|
|
230
|
+
),
|
|
231
|
+
},
|
|
232
|
+
};
|