@a2v2ai/uikit 0.0.36 → 0.0.38

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 (185) hide show
  1. package/Alert/Alert.stories.tsx +121 -0
  2. package/Alert/Alert.tsx +71 -0
  3. package/AlertDialog/AlertDialog.stories.tsx +665 -0
  4. package/AlertDialog/AlertDialog.tsx +241 -0
  5. package/Avatar/Avatar.stories.tsx +128 -0
  6. package/Avatar/Avatar.tsx +71 -0
  7. package/Badge/Badge.stories.tsx +76 -0
  8. package/Badge/Badge.tsx +39 -0
  9. package/Breadcrumb/Breadcrumb.stories.tsx +231 -0
  10. package/Breadcrumb/Breadcrumb.tsx +114 -0
  11. package/Button/Button.stories.tsx +684 -0
  12. package/Button/Button.tsx +107 -0
  13. package/Calendar/Calendar.stories.tsx +291 -0
  14. package/Calendar/Calendar.tsx +246 -0
  15. package/Card/Card.stories.tsx +136 -0
  16. package/Card/Card.tsx +96 -0
  17. package/Carousel/Carousel.stories.tsx +256 -0
  18. package/Carousel/Carousel.tsx +301 -0
  19. package/ChatBubble/ChatBubble.stories.tsx +339 -0
  20. package/ChatBubble/ChatBubble.tsx +179 -0
  21. package/Checkbox/Checkbox.stories.tsx +137 -0
  22. package/Checkbox/Checkbox.tsx +53 -0
  23. package/DataTable/DataTable.stories.tsx +400 -0
  24. package/DataTable/DataTable.tsx +207 -0
  25. package/Drawer/Drawer.stories.tsx +721 -0
  26. package/Drawer/Drawer.tsx +201 -0
  27. package/DropdownMenu/DropdownMenu.stories.tsx +251 -0
  28. package/DropdownMenu/DropdownMenu.tsx +199 -0
  29. package/ErrorMessage/ErrorMessage.stories.tsx +159 -0
  30. package/ErrorMessage/ErrorMessage.tsx +55 -0
  31. package/Flex/Flex.stories.tsx +390 -0
  32. package/Flex/Flex.tsx +102 -0
  33. package/IconButton/IconButton.stories.tsx +566 -0
  34. package/IconButton/IconButton.tsx +95 -0
  35. package/Input/Input.stories.tsx +566 -0
  36. package/Input/Input.tsx +168 -0
  37. package/InputOTP/InputOTP.stories.tsx +246 -0
  38. package/InputOTP/InputOTP.tsx +127 -0
  39. package/Label/Label.stories.tsx +110 -0
  40. package/Label/Label.tsx +44 -0
  41. package/Loader/Loader.stories.tsx +170 -0
  42. package/Loader/Loader.tsx +62 -0
  43. package/Menubar/Menubar.stories.tsx +382 -0
  44. package/Menubar/Menubar.tsx +274 -0
  45. package/Menubar/index.ts +18 -0
  46. package/Pagination/Pagination.stories.tsx +196 -0
  47. package/Pagination/Pagination.tsx +122 -0
  48. package/Popover/Popover.stories.tsx +133 -0
  49. package/Popover/Popover.tsx +31 -0
  50. package/Progress/Progress.stories.tsx +146 -0
  51. package/Progress/Progress.tsx +67 -0
  52. package/RadioGroup/RadioGroup.stories.tsx +159 -0
  53. package/RadioGroup/RadioGroup.tsx +68 -0
  54. package/ScrollArea/ScrollArea.stories.tsx +136 -0
  55. package/ScrollArea/ScrollArea.tsx +46 -0
  56. package/Select/Select.stories.tsx +378 -0
  57. package/Select/Select.tsx +230 -0
  58. package/Separator/Separator.stories.tsx +110 -0
  59. package/Separator/Separator.tsx +29 -0
  60. package/Sidebar/Sidebar.stories.tsx +340 -0
  61. package/Sidebar/Sidebar.tsx +414 -0
  62. package/Sidebar/index.ts +28 -0
  63. package/Skeleton/Skeleton.stories.tsx +117 -0
  64. package/Skeleton/Skeleton.tsx +16 -0
  65. package/Slider/Slider.stories.tsx +216 -0
  66. package/Slider/Slider.tsx +29 -0
  67. package/Spinner/Spinner.stories.tsx +210 -0
  68. package/Spinner/Spinner.tsx +78 -0
  69. package/Switch/Switch.stories.tsx +146 -0
  70. package/Switch/Switch.tsx +59 -0
  71. package/Table/Table.stories.tsx +510 -0
  72. package/Table/Table.tsx +114 -0
  73. package/Tabs/Tabs.stories.tsx +197 -0
  74. package/Tabs/Tabs.tsx +74 -0
  75. package/Textarea/Textarea.stories.tsx +187 -0
  76. package/Textarea/Textarea.tsx +73 -0
  77. package/Toast/Toast.stories.tsx +285 -0
  78. package/Toast/Toast.tsx +59 -0
  79. package/Tooltip/Tooltip.stories.tsx +463 -0
  80. package/Tooltip/Tooltip.tsx +96 -0
  81. package/Typography/Typography.stories.tsx +425 -0
  82. package/Typography/Typography.tsx +106 -0
  83. package/helpers.ts +5 -0
  84. package/{icons.js → icons.ts} +1 -1
  85. package/index.ts +217 -0
  86. package/lib/typography-types.ts +223 -0
  87. package/lib/utils.ts +15 -0
  88. package/package.json +36 -33
  89. package/tsconfig.json +22 -0
  90. package/Alert/Alert.d.ts +0 -13
  91. package/Alert/Alert.js +0 -25
  92. package/AlertDialog/AlertDialog.d.ts +0 -43
  93. package/AlertDialog/AlertDialog.js +0 -71
  94. package/Avatar/Avatar.d.ts +0 -14
  95. package/Avatar/Avatar.js +0 -25
  96. package/Badge/Badge.d.ts +0 -11
  97. package/Badge/Badge.js +0 -23
  98. package/Breadcrumb/Breadcrumb.d.ts +0 -19
  99. package/Breadcrumb/Breadcrumb.js +0 -23
  100. package/Button/Button.d.ts +0 -23
  101. package/Button/Button.js +0 -52
  102. package/Calendar/Calendar.d.ts +0 -20
  103. package/Calendar/Calendar.js +0 -78
  104. package/Card/Card.d.ts +0 -16
  105. package/Card/Card.js +0 -28
  106. package/Carousel/Carousel.d.ts +0 -37
  107. package/Carousel/Carousel.js +0 -132
  108. package/ChatBubble/ChatBubble.d.ts +0 -33
  109. package/ChatBubble/ChatBubble.js +0 -107
  110. package/Checkbox/Checkbox.d.ts +0 -12
  111. package/Checkbox/Checkbox.js +0 -20
  112. package/DataTable/DataTable.d.ts +0 -35
  113. package/DataTable/DataTable.js +0 -51
  114. package/Dialog/Dialog.d.ts +0 -35
  115. package/Dialog/Dialog.js +0 -130
  116. package/Drawer/Drawer.d.ts +0 -33
  117. package/Drawer/Drawer.js +0 -55
  118. package/DropdownMenu/DropdownMenu.d.ts +0 -27
  119. package/DropdownMenu/DropdownMenu.js +0 -35
  120. package/ErrorMessage/ErrorMessage.d.ts +0 -27
  121. package/ErrorMessage/ErrorMessage.js +0 -14
  122. package/Flex/Flex.d.ts +0 -31
  123. package/Flex/Flex.js +0 -64
  124. package/IconButton/IconButton.d.ts +0 -23
  125. package/IconButton/IconButton.js +0 -48
  126. package/Input/Input.d.ts +0 -27
  127. package/Input/Input.js +0 -42
  128. package/InputOTP/InputOTP.d.ts +0 -20
  129. package/InputOTP/InputOTP.js +0 -44
  130. package/Label/Label.d.ts +0 -13
  131. package/Label/Label.js +0 -19
  132. package/Loader/Loader.d.ts +0 -21
  133. package/Loader/Loader.js +0 -30
  134. package/Menubar/Menubar.d.ts +0 -26
  135. package/Menubar/Menubar.js +0 -54
  136. package/Menubar/index.d.ts +0 -1
  137. package/Menubar/index.js +0 -1
  138. package/Pagination/Pagination.d.ts +0 -35
  139. package/Pagination/Pagination.js +0 -37
  140. package/Popover/Popover.d.ts +0 -7
  141. package/Popover/Popover.js +0 -10
  142. package/Progress/Progress.d.ts +0 -17
  143. package/Progress/Progress.js +0 -33
  144. package/RadioGroup/RadioGroup.d.ts +0 -13
  145. package/RadioGroup/RadioGroup.js +0 -26
  146. package/ScrollArea/ScrollArea.d.ts +0 -5
  147. package/ScrollArea/ScrollArea.js +0 -11
  148. package/Select/Select.d.ts +0 -29
  149. package/Select/Select.js +0 -50
  150. package/Separator/Separator.d.ts +0 -4
  151. package/Separator/Separator.js +0 -7
  152. package/Sidebar/Sidebar.d.ts +0 -48
  153. package/Sidebar/Sidebar.js +0 -116
  154. package/Sidebar/index.d.ts +0 -2
  155. package/Sidebar/index.js +0 -1
  156. package/Skeleton/Skeleton.d.ts +0 -4
  157. package/Skeleton/Skeleton.js +0 -7
  158. package/Slider/Slider.d.ts +0 -6
  159. package/Slider/Slider.js +0 -7
  160. package/Spinner/Spinner.d.ts +0 -19
  161. package/Spinner/Spinner.js +0 -31
  162. package/Switch/Switch.d.ts +0 -12
  163. package/Switch/Switch.js +0 -30
  164. package/Table/Table.d.ts +0 -10
  165. package/Table/Table.js +0 -20
  166. package/Tabs/Tabs.d.ts +0 -15
  167. package/Tabs/Tabs.js +0 -24
  168. package/Textarea/Textarea.d.ts +0 -19
  169. package/Textarea/Textarea.js +0 -31
  170. package/Toast/Toast.d.ts +0 -12
  171. package/Toast/Toast.js +0 -25
  172. package/Tooltip/Tooltip.d.ts +0 -17
  173. package/Tooltip/Tooltip.js +0 -29
  174. package/Typography/Typography.d.ts +0 -20
  175. package/Typography/Typography.js +0 -43
  176. package/helpers.d.ts +0 -4
  177. package/helpers.js +0 -5
  178. package/icons.d.ts +0 -1
  179. package/index.d.ts +0 -42
  180. package/index.js +0 -45
  181. package/lib/typography-types.d.ts +0 -4
  182. package/lib/typography-types.js +0 -90
  183. package/lib/utils.d.ts +0 -3
  184. package/lib/utils.js +0 -14
  185. package/tmpclaude-2407-cwd +0 -1
@@ -0,0 +1,216 @@
1
+ import type { Meta, StoryObj } from "@storybook/react"
2
+ import { useState } from "react"
3
+
4
+ import { Flex } from "../Flex/Flex"
5
+ import { Typography } from "../Typography/Typography"
6
+ import { Slider } from "./Slider"
7
+
8
+ const meta: Meta<typeof Slider> = {
9
+ title: "Components/Slider",
10
+ component: Slider,
11
+ parameters: {
12
+ layout: "centered",
13
+ },
14
+ argTypes: {
15
+ defaultValue: {
16
+ control: "object",
17
+ description: "The default value of the slider",
18
+ },
19
+ max: {
20
+ control: "number",
21
+ description: "The maximum value",
22
+ },
23
+ min: {
24
+ control: "number",
25
+ description: "The minimum value",
26
+ },
27
+ step: {
28
+ control: "number",
29
+ description: "The step increment",
30
+ },
31
+ disabled: {
32
+ control: "boolean",
33
+ description: "Whether the slider is disabled",
34
+ },
35
+ },
36
+ tags: ["autodocs"],
37
+ }
38
+
39
+ export default meta
40
+ type Story = StoryObj<typeof meta>
41
+
42
+ export const Default: Story = {
43
+ render: () => (
44
+ <div className="w-[300px]">
45
+ <Slider defaultValue={[50]} max={100} step={1} />
46
+ </div>
47
+ ),
48
+ }
49
+
50
+ export const WithValue: Story = {
51
+ render: function Render() {
52
+ const [value, setValue] = useState([50])
53
+
54
+ return (
55
+ <div className="w-[300px]">
56
+ <Flex direction="row" justify="between" className="mb-2">
57
+ <Typography variant="body2">Volume</Typography>
58
+ <Typography variant="body2">{value[0]}%</Typography>
59
+ </Flex>
60
+ <Slider
61
+ value={value}
62
+ onValueChange={setValue}
63
+ max={100}
64
+ step={1}
65
+ />
66
+ </div>
67
+ )
68
+ },
69
+ }
70
+
71
+ export const Temperature: Story = {
72
+ render: function Render() {
73
+ const [value, setValue] = useState([0.5])
74
+
75
+ return (
76
+ <div className="w-[300px] bg-white p-4 rounded-lg">
77
+ <Flex direction="row" justify="between" className="mb-4">
78
+ <Typography variant="body1" color="main-900">Temperature</Typography>
79
+ <Typography variant="body1" color="main-900">{value[0].toFixed(1)}</Typography>
80
+ </Flex>
81
+ <Slider
82
+ value={value}
83
+ onValueChange={setValue}
84
+ max={1}
85
+ min={0}
86
+ step={0.1}
87
+ />
88
+ <Flex direction="row" justify="between" className="mt-2">
89
+ <Typography variant="body2" color="grey-400">Reserved</Typography>
90
+ <Typography variant="body2" color="grey-400">Creative</Typography>
91
+ </Flex>
92
+ </div>
93
+ )
94
+ },
95
+ }
96
+
97
+ export const Range: Story = {
98
+ render: function Render() {
99
+ const [value, setValue] = useState([25, 75])
100
+
101
+ return (
102
+ <div className="w-[300px]">
103
+ <Flex direction="row" justify="between" className="mb-2">
104
+ <Typography variant="body2">Price Range</Typography>
105
+ <Typography variant="body2">${value[0]} - ${value[1]}</Typography>
106
+ </Flex>
107
+ <Slider
108
+ value={value}
109
+ onValueChange={setValue}
110
+ max={100}
111
+ step={1}
112
+ />
113
+ </div>
114
+ )
115
+ },
116
+ }
117
+
118
+ export const Disabled: Story = {
119
+ render: () => (
120
+ <div className="w-[300px]">
121
+ <Slider defaultValue={[50]} max={100} step={1} disabled />
122
+ </div>
123
+ ),
124
+ }
125
+
126
+ export const CustomStep: Story = {
127
+ render: function Render() {
128
+ const [value, setValue] = useState([5])
129
+
130
+ return (
131
+ <div className="w-[300px]">
132
+ <Flex direction="row" justify="between" className="mb-2">
133
+ <Typography variant="body2">Steps of 5</Typography>
134
+ <Typography variant="body2">{value[0]}</Typography>
135
+ </Flex>
136
+ <Slider
137
+ value={value}
138
+ onValueChange={setValue}
139
+ max={100}
140
+ min={0}
141
+ step={5}
142
+ />
143
+ </div>
144
+ )
145
+ },
146
+ }
147
+
148
+ export const AllVariants: Story = {
149
+ render: function Render() {
150
+ const [volume, setVolume] = useState([50])
151
+ const [temperature, setTemperature] = useState([0.5])
152
+ const [priceRange, setPriceRange] = useState([25, 75])
153
+
154
+ return (
155
+ <Flex gap={6} className="w-[350px]">
156
+ <Typography variant="h4" className="text-white">Slider Examples</Typography>
157
+
158
+ <div className="bg-white p-4 rounded-lg space-y-6">
159
+ <Flex gap={2}>
160
+ <Flex direction="row" justify="between">
161
+ <Typography variant="body2" color="main-900">Volume</Typography>
162
+ <Typography variant="body2" color="main-900">{volume[0]}%</Typography>
163
+ </Flex>
164
+ <Slider
165
+ value={volume}
166
+ onValueChange={setVolume}
167
+ max={100}
168
+ step={1}
169
+ />
170
+ </Flex>
171
+
172
+ <Flex gap={2}>
173
+ <Flex direction="row" justify="between">
174
+ <Typography variant="body2" color="main-900">Temperature</Typography>
175
+ <Typography variant="body2" color="main-900">{temperature[0].toFixed(1)}</Typography>
176
+ </Flex>
177
+ <Slider
178
+ value={temperature}
179
+ onValueChange={setTemperature}
180
+ max={1}
181
+ min={0}
182
+ step={0.1}
183
+ />
184
+ <Flex direction="row" justify="between">
185
+ <Typography variant="caption" color="grey-400">Reserved</Typography>
186
+ <Typography variant="caption" color="grey-400">Creative</Typography>
187
+ </Flex>
188
+ </Flex>
189
+
190
+ <Flex gap={2}>
191
+ <Flex direction="row" justify="between">
192
+ <Typography variant="body2" color="main-900">Price Range</Typography>
193
+ <Typography variant="body2" color="main-900">${priceRange[0]} - ${priceRange[1]}</Typography>
194
+ </Flex>
195
+ <Slider
196
+ value={priceRange}
197
+ onValueChange={setPriceRange}
198
+ max={100}
199
+ step={1}
200
+ />
201
+ </Flex>
202
+
203
+ <Flex gap={2}>
204
+ <Typography variant="body2" color="main-900">Disabled</Typography>
205
+ <Slider
206
+ defaultValue={[30]}
207
+ max={100}
208
+ step={1}
209
+ disabled
210
+ />
211
+ </Flex>
212
+ </div>
213
+ </Flex>
214
+ )
215
+ },
216
+ }
@@ -0,0 +1,29 @@
1
+ import * as React from "react"
2
+ import * as SliderPrimitive from "@radix-ui/react-slider"
3
+
4
+ import { cn } from "../lib/utils"
5
+
6
+ export interface SliderProps
7
+ extends React.ComponentPropsWithoutRef<typeof SliderPrimitive.Root> {}
8
+
9
+ const Slider = React.forwardRef<
10
+ React.ElementRef<typeof SliderPrimitive.Root>,
11
+ SliderProps
12
+ >(({ className, ...props }, ref) => (
13
+ <SliderPrimitive.Root
14
+ ref={ref}
15
+ className={cn(
16
+ "relative flex w-full touch-none select-none items-center",
17
+ className
18
+ )}
19
+ {...props}
20
+ >
21
+ <SliderPrimitive.Track className="relative h-1.5 w-full grow overflow-hidden rounded-full bg-grey-300">
22
+ <SliderPrimitive.Range className="absolute h-full bg-main-900" />
23
+ </SliderPrimitive.Track>
24
+ <SliderPrimitive.Thumb className="block size-3 rounded-full border border-main-900 bg-white shadow transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent-600 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50" />
25
+ </SliderPrimitive.Root>
26
+ ))
27
+ Slider.displayName = SliderPrimitive.Root.displayName
28
+
29
+ export { Slider }
@@ -0,0 +1,210 @@
1
+ import type { Meta, StoryObj } from "@storybook/react"
2
+ import { Spinner } from "./Spinner"
3
+ import { Typography } from "../Typography/Typography"
4
+ import { Flex } from "../Flex/Flex"
5
+ import { Button } from "../Button/Button"
6
+
7
+ const meta: Meta<typeof Spinner> = {
8
+ title: "Components/Spinner",
9
+ component: Spinner,
10
+ parameters: {
11
+ layout: "centered",
12
+ },
13
+ tags: ["autodocs"],
14
+ argTypes: {
15
+ size: {
16
+ control: "select",
17
+ options: ["sm", "default", "md", "lg", "xl"],
18
+ description: "The size of the spinner",
19
+ },
20
+ variant: {
21
+ control: "select",
22
+ options: ["default", "primary", "secondary", "muted", "white"],
23
+ description: "The color variant of the spinner",
24
+ },
25
+ label: {
26
+ control: "text",
27
+ description: "Screen reader label for accessibility",
28
+ },
29
+ },
30
+ }
31
+
32
+ export default meta
33
+ type Story = StoryObj<typeof Spinner>
34
+
35
+ export const Default: Story = {
36
+ args: {
37
+ size: "default",
38
+ variant: "default",
39
+ },
40
+ }
41
+
42
+ export const Sizes: Story = {
43
+ render: () => (
44
+ <Flex direction="row" gap={6} align="center">
45
+ <Flex align="center" gap={2}>
46
+ <Spinner size="sm" />
47
+ <Typography variant="caption" color="grey-500">sm</Typography>
48
+ </Flex>
49
+ <Flex align="center" gap={2}>
50
+ <Spinner size="default" />
51
+ <Typography variant="caption" color="grey-500">default</Typography>
52
+ </Flex>
53
+ <Flex align="center" gap={2}>
54
+ <Spinner size="md" />
55
+ <Typography variant="caption" color="grey-500">md</Typography>
56
+ </Flex>
57
+ <Flex align="center" gap={2}>
58
+ <Spinner size="lg" />
59
+ <Typography variant="caption" color="grey-500">lg</Typography>
60
+ </Flex>
61
+ <Flex align="center" gap={2}>
62
+ <Spinner size="xl" />
63
+ <Typography variant="caption" color="grey-500">xl</Typography>
64
+ </Flex>
65
+ </Flex>
66
+ ),
67
+ }
68
+
69
+ export const Variants: Story = {
70
+ render: () => (
71
+ <Flex direction="row" gap={6} align="center">
72
+ <Flex align="center" gap={2}>
73
+ <Spinner variant="primary" />
74
+ <Typography variant="caption" color="grey-500">primary</Typography>
75
+ </Flex>
76
+ <Flex align="center" gap={2}>
77
+ <Spinner variant="secondary" />
78
+ <Typography variant="caption" color="grey-500">secondary</Typography>
79
+ </Flex>
80
+ <Flex align="center" gap={2}>
81
+ <Spinner variant="muted" />
82
+ <Typography variant="caption" color="grey-500">muted</Typography>
83
+ </Flex>
84
+ <Flex align="center" gap={2} className="bg-main-900 p-4 rounded">
85
+ <Spinner variant="white" />
86
+ <Typography variant="caption" className="text-white">white</Typography>
87
+ </Flex>
88
+ </Flex>
89
+ ),
90
+ }
91
+
92
+ export const WithText: Story = {
93
+ render: () => (
94
+ <Flex direction="row" gap={2} align="center">
95
+ <Spinner size="sm" />
96
+ <Typography variant="body2">Loading...</Typography>
97
+ </Flex>
98
+ ),
99
+ }
100
+
101
+ export const InButton: Story = {
102
+ render: () => (
103
+ <Flex direction="row" gap={4}>
104
+ <Button disabled>
105
+ <Spinner size="sm" variant="muted" className="mr-2" />
106
+ Loading
107
+ </Button>
108
+ <Button variant="primary" disabled>
109
+ <Spinner size="sm" variant="white" className="mr-2" />
110
+ Submitting
111
+ </Button>
112
+ </Flex>
113
+ ),
114
+ }
115
+
116
+ export const Centered: Story = {
117
+ render: () => (
118
+ <div className="w-64 h-32 border border-grey-200 rounded-lg flex items-center justify-center">
119
+ <Spinner size="lg" />
120
+ </div>
121
+ ),
122
+ }
123
+
124
+ export const FullPage: Story = {
125
+ render: () => (
126
+ <div className="w-96 h-64 border border-grey-200 rounded-lg relative">
127
+ <div className="absolute inset-0 flex flex-col items-center justify-center bg-white/80">
128
+ <Spinner size="lg" />
129
+ <Typography variant="body2" color="grey-500" className="mt-4">
130
+ Loading content...
131
+ </Typography>
132
+ </div>
133
+ </div>
134
+ ),
135
+ }
136
+
137
+ export const AllVariants: Story = {
138
+ render: () => (
139
+ <Flex gap={8}>
140
+ <div>
141
+ <Typography variant="h4" className="mb-4">Sizes</Typography>
142
+ <Flex direction="row" gap={6} align="end">
143
+ <Flex align="center" gap={2}>
144
+ <Spinner size="sm" />
145
+ <Typography variant="caption" color="grey-500">sm (16px)</Typography>
146
+ </Flex>
147
+ <Flex align="center" gap={2}>
148
+ <Spinner size="default" />
149
+ <Typography variant="caption" color="grey-500">default (24px)</Typography>
150
+ </Flex>
151
+ <Flex align="center" gap={2}>
152
+ <Spinner size="md" />
153
+ <Typography variant="caption" color="grey-500">md (32px)</Typography>
154
+ </Flex>
155
+ <Flex align="center" gap={2}>
156
+ <Spinner size="lg" />
157
+ <Typography variant="caption" color="grey-500">lg (48px)</Typography>
158
+ </Flex>
159
+ <Flex align="center" gap={2}>
160
+ <Spinner size="xl" />
161
+ <Typography variant="caption" color="grey-500">xl (64px)</Typography>
162
+ </Flex>
163
+ </Flex>
164
+ </div>
165
+
166
+ <div>
167
+ <Typography variant="h4" className="mb-4">Color Variants</Typography>
168
+ <Flex direction="row" gap={6} align="center">
169
+ <Flex align="center" gap={2}>
170
+ <Spinner variant="primary" size="md" />
171
+ <Typography variant="caption" color="grey-500">primary</Typography>
172
+ </Flex>
173
+ <Flex align="center" gap={2}>
174
+ <Spinner variant="secondary" size="md" />
175
+ <Typography variant="caption" color="grey-500">secondary</Typography>
176
+ </Flex>
177
+ <Flex align="center" gap={2}>
178
+ <Spinner variant="muted" size="md" />
179
+ <Typography variant="caption" color="grey-500">muted</Typography>
180
+ </Flex>
181
+ <Flex align="center" gap={2} className="bg-main-900 p-4 rounded-lg">
182
+ <Spinner variant="white" size="md" />
183
+ <Typography variant="caption" className="text-white">white</Typography>
184
+ </Flex>
185
+ </Flex>
186
+ </div>
187
+
188
+ <div>
189
+ <Typography variant="h4" className="mb-4">Use Cases</Typography>
190
+ <Flex direction="row" gap={6} align="center" wrap="wrap">
191
+ <Flex direction="row" gap={2} align="center" className="border border-grey-200 rounded-lg p-4">
192
+ <Spinner size="sm" />
193
+ <Typography variant="body2">Loading data...</Typography>
194
+ </Flex>
195
+ <Button disabled className="min-w-32">
196
+ <Spinner size="sm" variant="muted" className="mr-2" />
197
+ Loading
198
+ </Button>
199
+ <Button variant="primary" disabled className="min-w-32">
200
+ <Spinner size="sm" variant="white" className="mr-2" />
201
+ Saving
202
+ </Button>
203
+ </Flex>
204
+ </div>
205
+ </Flex>
206
+ ),
207
+ parameters: {
208
+ layout: "padded",
209
+ },
210
+ }
@@ -0,0 +1,78 @@
1
+ import * as React from "react"
2
+ import { cva } from "class-variance-authority"
3
+ import { cn } from "../lib/utils"
4
+
5
+ type SpinnerSize = "sm" | "default" | "md" | "lg" | "xl"
6
+ type SpinnerVariant = "default" | "primary" | "secondary" | "muted" | "white"
7
+
8
+ const spinnerVariants = cva(
9
+ "animate-spin",
10
+ {
11
+ variants: {
12
+ size: {
13
+ sm: "size-4",
14
+ default: "size-6",
15
+ md: "size-8",
16
+ lg: "size-12",
17
+ xl: "size-16",
18
+ },
19
+ variant: {
20
+ default: "text-accent-500",
21
+ primary: "text-accent-500",
22
+ secondary: "text-grey-500",
23
+ muted: "text-grey-400",
24
+ white: "text-white",
25
+ },
26
+ },
27
+ defaultVariants: {
28
+ size: "default",
29
+ variant: "default",
30
+ },
31
+ }
32
+ )
33
+
34
+ export interface SpinnerProps
35
+ extends React.SVGAttributes<SVGSVGElement> {
36
+ size?: SpinnerSize
37
+ variant?: SpinnerVariant
38
+ /**
39
+ * Screen reader label for accessibility
40
+ * @default "Loading"
41
+ */
42
+ label?: string
43
+ }
44
+
45
+ const Spinner = React.forwardRef<SVGSVGElement, SpinnerProps>(
46
+ ({ className, size, variant, label = "Loading", ...props }, ref) => {
47
+ return (
48
+ <svg
49
+ ref={ref}
50
+ className={cn(spinnerVariants({ size, variant, className }))}
51
+ xmlns="http://www.w3.org/2000/svg"
52
+ fill="none"
53
+ viewBox="0 0 24 24"
54
+ role="status"
55
+ aria-label={label}
56
+ {...props}
57
+ >
58
+ <circle
59
+ className="opacity-25"
60
+ cx="12"
61
+ cy="12"
62
+ r="10"
63
+ stroke="currentColor"
64
+ strokeWidth="4"
65
+ />
66
+ <path
67
+ className="opacity-75"
68
+ fill="currentColor"
69
+ d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
70
+ />
71
+ </svg>
72
+ )
73
+ }
74
+ )
75
+ Spinner.displayName = "Spinner"
76
+
77
+ export { Spinner, spinnerVariants }
78
+ export type { SpinnerSize, SpinnerVariant }
@@ -0,0 +1,146 @@
1
+ import type { Meta, StoryObj } from "@storybook/react"
2
+
3
+ import { Label } from "../Label/Label"
4
+ import { Flex } from "../Flex/Flex"
5
+ import { Typography } from "../Typography/Typography"
6
+ import { Switch } from "./Switch"
7
+
8
+ const meta: Meta<typeof Switch> = {
9
+ title: "Components/Switch",
10
+ component: Switch,
11
+ parameters: {
12
+ layout: "centered",
13
+ },
14
+ argTypes: {
15
+ size: {
16
+ control: "select",
17
+ options: ["small", "regular"],
18
+ description: "The size of the switch",
19
+ },
20
+ checked: {
21
+ control: "boolean",
22
+ description: "The checked state",
23
+ },
24
+ disabled: {
25
+ control: "boolean",
26
+ description: "Whether the switch is disabled",
27
+ },
28
+ },
29
+ tags: ["autodocs"],
30
+ }
31
+
32
+ export default meta
33
+ type Story = StoryObj<typeof meta>
34
+
35
+ export const Default: Story = {
36
+ render: () => <Switch />,
37
+ }
38
+
39
+ export const Checked: Story = {
40
+ render: () => <Switch defaultChecked />,
41
+ }
42
+
43
+ export const WithLabel: Story = {
44
+ render: () => (
45
+ <Flex direction="row" align="center" gap={2}>
46
+ <Switch id="airplane-mode" />
47
+ <Label htmlFor="airplane-mode">Airplane Mode</Label>
48
+ </Flex>
49
+ ),
50
+ }
51
+
52
+ export const Disabled: Story = {
53
+ render: () => (
54
+ <Flex gap={3}>
55
+ <Flex direction="row" align="center" gap={2}>
56
+ <Switch id="disabled" disabled />
57
+ <Label htmlFor="disabled" className="opacity-50">Disabled</Label>
58
+ </Flex>
59
+ <Flex direction="row" align="center" gap={2}>
60
+ <Switch id="disabled-checked" disabled defaultChecked />
61
+ <Label htmlFor="disabled-checked" className="opacity-50">Disabled checked</Label>
62
+ </Flex>
63
+ </Flex>
64
+ ),
65
+ }
66
+
67
+ export const Small: Story = {
68
+ render: () => (
69
+ <Flex direction="row" align="center" gap={2}>
70
+ <Switch id="small" size="small" />
71
+ <Label htmlFor="small" className="text-sm">Small switch</Label>
72
+ </Flex>
73
+ ),
74
+ }
75
+
76
+ export const AllVariants: Story = {
77
+ render: () => (
78
+ <Flex gap={6}>
79
+ <Typography variant="h4" className="text-white">Switch States</Typography>
80
+
81
+ <Flex gap={4}>
82
+ <Flex direction="row" align="center" gap={2}>
83
+ <Switch id="off" />
84
+ <Label htmlFor="off">Off</Label>
85
+ </Flex>
86
+
87
+ <Flex direction="row" align="center" gap={2}>
88
+ <Switch id="on" defaultChecked />
89
+ <Label htmlFor="on">On</Label>
90
+ </Flex>
91
+
92
+ <Flex direction="row" align="center" gap={2}>
93
+ <Switch id="disabled-off" disabled />
94
+ <Label htmlFor="disabled-off" className="opacity-50">Disabled Off</Label>
95
+ </Flex>
96
+
97
+ <Flex direction="row" align="center" gap={2}>
98
+ <Switch id="disabled-on" disabled defaultChecked />
99
+ <Label htmlFor="disabled-on" className="opacity-50">Disabled On</Label>
100
+ </Flex>
101
+ </Flex>
102
+
103
+ <Typography variant="h4" className="text-white mt-4">Sizes</Typography>
104
+
105
+ <Flex gap={4}>
106
+ <Flex direction="row" align="center" gap={2}>
107
+ <Switch id="small-size" size="small" defaultChecked />
108
+ <Label htmlFor="small-size" className="text-sm">Small</Label>
109
+ </Flex>
110
+
111
+ <Flex direction="row" align="center" gap={2}>
112
+ <Switch id="regular-size" size="regular" defaultChecked />
113
+ <Label htmlFor="regular-size">Regular</Label>
114
+ </Flex>
115
+ </Flex>
116
+
117
+ <Typography variant="h4" className="text-white mt-4">Settings Example</Typography>
118
+
119
+ <div className="w-[300px] bg-white rounded-lg p-4 space-y-4">
120
+ <Flex direction="row" justify="between" align="center">
121
+ <Flex gap={1}>
122
+ <Typography variant="body2">Dark Mode</Typography>
123
+ <Typography variant="caption" color="grey-500">Enable dark theme</Typography>
124
+ </Flex>
125
+ <Switch defaultChecked />
126
+ </Flex>
127
+
128
+ <Flex direction="row" justify="between" align="center">
129
+ <Flex gap={1}>
130
+ <Typography variant="body2">Notifications</Typography>
131
+ <Typography variant="caption" color="grey-500">Receive push notifications</Typography>
132
+ </Flex>
133
+ <Switch />
134
+ </Flex>
135
+
136
+ <Flex direction="row" justify="between" align="center">
137
+ <Flex gap={1}>
138
+ <Typography variant="body2">Auto-save</Typography>
139
+ <Typography variant="caption" color="grey-500">Save changes automatically</Typography>
140
+ </Flex>
141
+ <Switch defaultChecked />
142
+ </Flex>
143
+ </div>
144
+ </Flex>
145
+ ),
146
+ }