@a2v2ai/uikit 0.0.1 → 0.0.3

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 (148) 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 +90 -0
  13. package/Calendar/Calendar.stories.tsx +207 -0
  14. package/Calendar/Calendar.tsx +232 -0
  15. package/Card/Card.stories.tsx +136 -0
  16. package/Card/Card.tsx +96 -0
  17. package/ChatBubble/ChatBubble.stories.tsx +307 -0
  18. package/ChatBubble/ChatBubble.tsx +167 -0
  19. package/Checkbox/Checkbox.stories.tsx +137 -0
  20. package/Checkbox/Checkbox.tsx +53 -0
  21. package/Drawer/Drawer.stories.tsx +721 -0
  22. package/Drawer/Drawer.tsx +201 -0
  23. package/DropdownMenu/DropdownMenu.stories.tsx +251 -0
  24. package/DropdownMenu/DropdownMenu.tsx +199 -0
  25. package/ErrorMessage/ErrorMessage.stories.tsx +159 -0
  26. package/ErrorMessage/ErrorMessage.tsx +55 -0
  27. package/Flex/Flex.tsx +102 -0
  28. package/IconButton/IconButton.stories.tsx +566 -0
  29. package/IconButton/IconButton.tsx +95 -0
  30. package/Input/Input.stories.tsx +456 -0
  31. package/Input/Input.tsx +129 -0
  32. package/InputOTP/InputOTP.stories.tsx +246 -0
  33. package/InputOTP/InputOTP.tsx +127 -0
  34. package/Label/Label.stories.tsx +105 -0
  35. package/Label/Label.tsx +43 -0
  36. package/Loader/Loader.stories.tsx +170 -0
  37. package/Loader/Loader.tsx +62 -0
  38. package/Popover/Popover.stories.tsx +133 -0
  39. package/Popover/Popover.tsx +31 -0
  40. package/Progress/Progress.stories.tsx +146 -0
  41. package/Progress/Progress.tsx +67 -0
  42. package/README.md +12 -12
  43. package/RadioGroup/RadioGroup.stories.tsx +159 -0
  44. package/RadioGroup/RadioGroup.tsx +68 -0
  45. package/ScrollArea/ScrollArea.stories.tsx +136 -0
  46. package/ScrollArea/ScrollArea.tsx +46 -0
  47. package/Select/Select.stories.tsx +242 -0
  48. package/Select/Select.tsx +180 -0
  49. package/Separator/Separator.stories.tsx +110 -0
  50. package/Separator/Separator.tsx +29 -0
  51. package/Skeleton/Skeleton.stories.tsx +117 -0
  52. package/Skeleton/Skeleton.tsx +16 -0
  53. package/Spinner/Spinner.stories.tsx +210 -0
  54. package/Spinner/Spinner.tsx +78 -0
  55. package/Switch/Switch.stories.tsx +146 -0
  56. package/Switch/Switch.tsx +59 -0
  57. package/Tabs/Tabs.stories.tsx +197 -0
  58. package/Tabs/Tabs.tsx +74 -0
  59. package/Textarea/Textarea.stories.tsx +170 -0
  60. package/Textarea/Textarea.tsx +51 -0
  61. package/Toast/Toast.stories.tsx +285 -0
  62. package/Toast/Toast.tsx +59 -0
  63. package/Tooltip/Tooltip.stories.tsx +463 -0
  64. package/Tooltip/Tooltip.tsx +96 -0
  65. package/Typography/Typography.stories.tsx +235 -0
  66. package/Typography/Typography.tsx +171 -0
  67. package/helpers.ts +5 -0
  68. package/icons.ts +2 -0
  69. package/index.ts +136 -0
  70. package/lib/utils.ts +15 -0
  71. package/package.json +4 -1
  72. package/tsconfig.json +24 -0
  73. package/Alert/Alert.d.ts +0 -11
  74. package/Alert/Alert.js +0 -64
  75. package/AlertDialog/AlertDialog.d.ts +0 -35
  76. package/AlertDialog/AlertDialog.js +0 -121
  77. package/Avatar/Avatar.d.ts +0 -12
  78. package/Avatar/Avatar.js +0 -64
  79. package/Badge/Badge.d.ts +0 -9
  80. package/Badge/Badge.js +0 -26
  81. package/Breadcrumb/Breadcrumb.d.ts +0 -19
  82. package/Breadcrumb/Breadcrumb.js +0 -65
  83. package/Button/Button.d.ts +0 -14
  84. package/Button/Button.js +0 -75
  85. package/Calendar/Calendar.d.ts +0 -16
  86. package/Calendar/Calendar.js +0 -113
  87. package/Card/Card.d.ts +0 -14
  88. package/Card/Card.js +0 -70
  89. package/ChatBubble/ChatBubble.d.ts +0 -29
  90. package/ChatBubble/ChatBubble.js +0 -133
  91. package/Checkbox/Checkbox.d.ts +0 -10
  92. package/Checkbox/Checkbox.js +0 -57
  93. package/Dialog/Dialog.d.ts +0 -35
  94. package/Dialog/Dialog.js +0 -130
  95. package/Drawer/Drawer.d.ts +0 -31
  96. package/Drawer/Drawer.js +0 -69
  97. package/DropdownMenu/DropdownMenu.d.ts +0 -27
  98. package/DropdownMenu/DropdownMenu.js +0 -85
  99. package/ErrorMessage/ErrorMessage.d.ts +0 -27
  100. package/ErrorMessage/ErrorMessage.js +0 -15
  101. package/Flex/Flex.d.ts +0 -23
  102. package/Flex/Flex.js +0 -101
  103. package/IconButton/IconButton.d.ts +0 -17
  104. package/IconButton/IconButton.js +0 -85
  105. package/Input/Input.d.ts +0 -16
  106. package/Input/Input.js +0 -75
  107. package/InputOTP/InputOTP.d.ts +0 -18
  108. package/InputOTP/InputOTP.js +0 -85
  109. package/Label/Label.d.ts +0 -10
  110. package/Label/Label.js +0 -57
  111. package/Loader/Loader.d.ts +0 -18
  112. package/Loader/Loader.js +0 -67
  113. package/Popover/Popover.d.ts +0 -7
  114. package/Popover/Popover.js +0 -49
  115. package/Progress/Progress.d.ts +0 -13
  116. package/Progress/Progress.js +0 -71
  117. package/RadioGroup/RadioGroup.d.ts +0 -11
  118. package/RadioGroup/RadioGroup.js +0 -64
  119. package/ScrollArea/ScrollArea.d.ts +0 -5
  120. package/ScrollArea/ScrollArea.js +0 -48
  121. package/Select/Select.d.ts +0 -19
  122. package/Select/Select.js +0 -85
  123. package/Separator/Separator.d.ts +0 -4
  124. package/Separator/Separator.js +0 -43
  125. package/Skeleton/Skeleton.d.ts +0 -4
  126. package/Skeleton/Skeleton.js +0 -8
  127. package/Spinner/Spinner.d.ts +0 -15
  128. package/Spinner/Spinner.js +0 -68
  129. package/Switch/Switch.d.ts +0 -10
  130. package/Switch/Switch.js +0 -67
  131. package/Tabs/Tabs.d.ts +0 -13
  132. package/Tabs/Tabs.js +0 -64
  133. package/Textarea/Textarea.d.ts +0 -10
  134. package/Textarea/Textarea.js +0 -64
  135. package/Toast/Toast.d.ts +0 -10
  136. package/Toast/Toast.js +0 -29
  137. package/Tooltip/Tooltip.d.ts +0 -15
  138. package/Tooltip/Tooltip.js +0 -68
  139. package/Typography/Typography.d.ts +0 -15
  140. package/Typography/Typography.js +0 -125
  141. package/helpers.d.ts +0 -4
  142. package/helpers.js +0 -13
  143. package/icons.d.ts +0 -1
  144. package/icons.js +0 -18
  145. package/index.d.ts +0 -35
  146. package/index.js +0 -183
  147. package/lib/utils.d.ts +0 -3
  148. package/lib/utils.js +0 -18
@@ -0,0 +1,246 @@
1
+ import type { Meta, StoryObj } from "@storybook/react"
2
+ import * as React from "react"
3
+ import {
4
+ InputOTP,
5
+ InputOTPGroup,
6
+ InputOTPSlot,
7
+ InputOTPSeparator,
8
+ } from "./InputOTP"
9
+ import { Typography } from "../Typography/Typography"
10
+ import { Flex } from "../Flex/Flex"
11
+
12
+ const meta: Meta<typeof InputOTP> = {
13
+ title: "Components/InputOTP",
14
+ component: InputOTP,
15
+ parameters: {
16
+ layout: "centered",
17
+ },
18
+ tags: ["autodocs"],
19
+ }
20
+
21
+ export default meta
22
+ type Story = StoryObj<typeof InputOTP>
23
+
24
+ export const Default: Story = {
25
+ render: () => (
26
+ <InputOTP maxLength={6}>
27
+ <InputOTPGroup>
28
+ <InputOTPSlot index={0} />
29
+ <InputOTPSlot index={1} />
30
+ <InputOTPSlot index={2} />
31
+ <InputOTPSlot index={3} />
32
+ <InputOTPSlot index={4} />
33
+ <InputOTPSlot index={5} />
34
+ </InputOTPGroup>
35
+ </InputOTP>
36
+ ),
37
+ }
38
+
39
+ export const WithSeparator: Story = {
40
+ render: () => (
41
+ <InputOTP maxLength={6}>
42
+ <InputOTPGroup>
43
+ <InputOTPSlot index={0} />
44
+ <InputOTPSlot index={1} />
45
+ <InputOTPSlot index={2} />
46
+ </InputOTPGroup>
47
+ <InputOTPSeparator />
48
+ <InputOTPGroup>
49
+ <InputOTPSlot index={3} />
50
+ <InputOTPSlot index={4} />
51
+ <InputOTPSlot index={5} />
52
+ </InputOTPGroup>
53
+ </InputOTP>
54
+ ),
55
+ }
56
+
57
+ export const FourDigits: Story = {
58
+ render: () => (
59
+ <InputOTP maxLength={4}>
60
+ <InputOTPGroup>
61
+ <InputOTPSlot index={0} />
62
+ <InputOTPSlot index={1} />
63
+ <InputOTPSlot index={2} />
64
+ <InputOTPSlot index={3} />
65
+ </InputOTPGroup>
66
+ </InputOTP>
67
+ ),
68
+ }
69
+
70
+ export const Disabled: Story = {
71
+ render: () => (
72
+ <InputOTP maxLength={6} disabled>
73
+ <InputOTPGroup>
74
+ <InputOTPSlot index={0} />
75
+ <InputOTPSlot index={1} />
76
+ <InputOTPSlot index={2} />
77
+ <InputOTPSlot index={3} />
78
+ <InputOTPSlot index={4} />
79
+ <InputOTPSlot index={5} />
80
+ </InputOTPGroup>
81
+ </InputOTP>
82
+ ),
83
+ }
84
+
85
+ export const Controlled: Story = {
86
+ render: () => {
87
+ const [value, setValue] = React.useState("")
88
+
89
+ return (
90
+ <Flex direction="column" gap={4} align="center">
91
+ <InputOTP
92
+ maxLength={6}
93
+ value={value}
94
+ onChange={(value: string) => setValue(value)}
95
+ >
96
+ <InputOTPGroup>
97
+ <InputOTPSlot index={0} />
98
+ <InputOTPSlot index={1} />
99
+ <InputOTPSlot index={2} />
100
+ <InputOTPSlot index={3} />
101
+ <InputOTPSlot index={4} />
102
+ <InputOTPSlot index={5} />
103
+ </InputOTPGroup>
104
+ </InputOTP>
105
+ <Typography variant="body2" color="grey-500">
106
+ Value: {value || "(empty)"}
107
+ </Typography>
108
+ </Flex>
109
+ )
110
+ },
111
+ }
112
+
113
+ export const WithPattern: Story = {
114
+ render: () => (
115
+ <Flex direction="column" gap={4} align="center">
116
+ <Typography variant="body2" color="grey-500">
117
+ Only digits allowed
118
+ </Typography>
119
+ <InputOTP maxLength={6} pattern="^[0-9]+$">
120
+ <InputOTPGroup>
121
+ <InputOTPSlot index={0} />
122
+ <InputOTPSlot index={1} />
123
+ <InputOTPSlot index={2} />
124
+ <InputOTPSlot index={3} />
125
+ <InputOTPSlot index={4} />
126
+ <InputOTPSlot index={5} />
127
+ </InputOTPGroup>
128
+ </InputOTP>
129
+ </Flex>
130
+ ),
131
+ }
132
+
133
+ export const Sizes: Story = {
134
+ render: () => (
135
+ <Flex direction="column" gap={6} align="center">
136
+ <div>
137
+ <Typography variant="body2" color="grey-500" className="mb-2 text-center">
138
+ Small
139
+ </Typography>
140
+ <InputOTP maxLength={4}>
141
+ <InputOTPGroup>
142
+ <InputOTPSlot index={0} slotSize="sm" />
143
+ <InputOTPSlot index={1} slotSize="sm" />
144
+ <InputOTPSlot index={2} slotSize="sm" />
145
+ <InputOTPSlot index={3} slotSize="sm" />
146
+ </InputOTPGroup>
147
+ </InputOTP>
148
+ </div>
149
+ <div>
150
+ <Typography variant="body2" color="grey-500" className="mb-2 text-center">
151
+ Default
152
+ </Typography>
153
+ <InputOTP maxLength={4}>
154
+ <InputOTPGroup>
155
+ <InputOTPSlot index={0} />
156
+ <InputOTPSlot index={1} />
157
+ <InputOTPSlot index={2} />
158
+ <InputOTPSlot index={3} />
159
+ </InputOTPGroup>
160
+ </InputOTP>
161
+ </div>
162
+ <div>
163
+ <Typography variant="body2" color="grey-500" className="mb-2 text-center">
164
+ Large
165
+ </Typography>
166
+ <InputOTP maxLength={4}>
167
+ <InputOTPGroup>
168
+ <InputOTPSlot index={0} slotSize="lg" />
169
+ <InputOTPSlot index={1} slotSize="lg" />
170
+ <InputOTPSlot index={2} slotSize="lg" />
171
+ <InputOTPSlot index={3} slotSize="lg" />
172
+ </InputOTPGroup>
173
+ </InputOTP>
174
+ </div>
175
+ </Flex>
176
+ ),
177
+ parameters: {
178
+ layout: "padded",
179
+ },
180
+ }
181
+
182
+ export const AllVariants: Story = {
183
+ render: () => (
184
+ <Flex direction="column" gap={8}>
185
+ <div>
186
+ <Typography variant="h4" className="mb-4">6-Digit Code</Typography>
187
+ <InputOTP maxLength={6}>
188
+ <InputOTPGroup>
189
+ <InputOTPSlot index={0} />
190
+ <InputOTPSlot index={1} />
191
+ <InputOTPSlot index={2} />
192
+ <InputOTPSlot index={3} />
193
+ <InputOTPSlot index={4} />
194
+ <InputOTPSlot index={5} />
195
+ </InputOTPGroup>
196
+ </InputOTP>
197
+ </div>
198
+
199
+ <div>
200
+ <Typography variant="h4" className="mb-4">With Separator (3-3)</Typography>
201
+ <InputOTP maxLength={6}>
202
+ <InputOTPGroup>
203
+ <InputOTPSlot index={0} />
204
+ <InputOTPSlot index={1} />
205
+ <InputOTPSlot index={2} />
206
+ </InputOTPGroup>
207
+ <InputOTPSeparator />
208
+ <InputOTPGroup>
209
+ <InputOTPSlot index={3} />
210
+ <InputOTPSlot index={4} />
211
+ <InputOTPSlot index={5} />
212
+ </InputOTPGroup>
213
+ </InputOTP>
214
+ </div>
215
+
216
+ <div>
217
+ <Typography variant="h4" className="mb-4">4-Digit PIN</Typography>
218
+ <InputOTP maxLength={4}>
219
+ <InputOTPGroup>
220
+ <InputOTPSlot index={0} />
221
+ <InputOTPSlot index={1} />
222
+ <InputOTPSlot index={2} />
223
+ <InputOTPSlot index={3} />
224
+ </InputOTPGroup>
225
+ </InputOTP>
226
+ </div>
227
+
228
+ <div>
229
+ <Typography variant="h4" className="mb-4">Disabled State</Typography>
230
+ <InputOTP maxLength={6} disabled>
231
+ <InputOTPGroup>
232
+ <InputOTPSlot index={0} />
233
+ <InputOTPSlot index={1} />
234
+ <InputOTPSlot index={2} />
235
+ <InputOTPSlot index={3} />
236
+ <InputOTPSlot index={4} />
237
+ <InputOTPSlot index={5} />
238
+ </InputOTPGroup>
239
+ </InputOTP>
240
+ </div>
241
+ </Flex>
242
+ ),
243
+ parameters: {
244
+ layout: "padded",
245
+ },
246
+ }
@@ -0,0 +1,127 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import { OTPInput, OTPInputContext } from "input-otp"
5
+ import { Minus } from "lucide-react"
6
+ import { cva } from "class-variance-authority"
7
+ import { cn } from "../lib/utils"
8
+
9
+ type InputOTPSlotSize = "sm" | "default" | "lg"
10
+
11
+ const inputOTPVariants = cva(
12
+ "flex items-center gap-2 has-[:disabled]:opacity-50",
13
+ {
14
+ variants: {},
15
+ defaultVariants: {},
16
+ }
17
+ )
18
+
19
+ export interface InputOTPProps
20
+ extends Omit<React.ComponentPropsWithoutRef<typeof OTPInput>, "render"> {
21
+ children?: React.ReactNode
22
+ }
23
+
24
+ const InputOTP = React.forwardRef<HTMLInputElement, InputOTPProps>(
25
+ ({ className, containerClassName, children, ...props }, ref) => (
26
+ <OTPInput
27
+ ref={ref}
28
+ containerClassName={cn(
29
+ "flex items-center gap-2 has-[:disabled]:opacity-50",
30
+ containerClassName
31
+ )}
32
+ className={cn("disabled:cursor-not-allowed", className)}
33
+ {...props}
34
+ render={({ slots, isFocused, isHovering }) => (
35
+ <OTPInputContext.Provider value={{ slots, isFocused, isHovering }}>
36
+ {children}
37
+ </OTPInputContext.Provider>
38
+ )}
39
+ />
40
+ )
41
+ )
42
+ InputOTP.displayName = "InputOTP"
43
+
44
+ const InputOTPGroup = React.forwardRef<
45
+ HTMLDivElement,
46
+ React.ComponentPropsWithoutRef<"div">
47
+ >(({ className, ...props }, ref) => (
48
+ <div ref={ref} className={cn("flex items-center", className)} {...props} />
49
+ ))
50
+ InputOTPGroup.displayName = "InputOTPGroup"
51
+
52
+ const inputOTPSlotVariants = cva(
53
+ // Match Input component styles: border-grey-300, rounded-lg, focus ring
54
+ "relative flex items-center justify-center bg-white border border-grey-300 text-main-950 font-sans transition-all first:rounded-l-lg last:rounded-r-lg first:border-l border-l-0",
55
+ {
56
+ variants: {
57
+ slotSize: {
58
+ sm: "h-8 w-8 text-sm rounded-md first:rounded-l-md last:rounded-r-md",
59
+ default: "h-9 w-9 text-sm",
60
+ lg: "h-10 w-10 text-base",
61
+ },
62
+ },
63
+ defaultVariants: {
64
+ slotSize: "default",
65
+ },
66
+ }
67
+ )
68
+
69
+ export interface InputOTPSlotProps
70
+ extends React.ComponentPropsWithoutRef<"div"> {
71
+ index: number
72
+ slotSize?: InputOTPSlotSize
73
+ }
74
+
75
+ const InputOTPSlot = React.forwardRef<HTMLDivElement, InputOTPSlotProps>(
76
+ ({ index, className, slotSize, ...props }, ref) => {
77
+ const inputOTPContext = React.useContext(OTPInputContext)
78
+ const slot = inputOTPContext.slots[index]
79
+
80
+ if (!slot) {
81
+ return null
82
+ }
83
+
84
+ const { char, hasFakeCaret, isActive } = slot
85
+
86
+ return (
87
+ <div
88
+ ref={ref}
89
+ className={cn(
90
+ inputOTPSlotVariants({ slotSize }),
91
+ // Match Input focus style: ring-[3px] ring-grey-300/50
92
+ isActive && "z-10 border-grey-300 ring-[3px] ring-grey-300/50",
93
+ className
94
+ )}
95
+ {...props}
96
+ >
97
+ {char}
98
+ {hasFakeCaret && (
99
+ <div className="pointer-events-none absolute inset-0 flex items-center justify-center">
100
+ <div className="h-4 w-px animate-caret-blink bg-main-950 duration-1000" />
101
+ </div>
102
+ )}
103
+ </div>
104
+ )
105
+ }
106
+ )
107
+ InputOTPSlot.displayName = "InputOTPSlot"
108
+
109
+ const InputOTPSeparator = React.forwardRef<
110
+ HTMLDivElement,
111
+ React.ComponentPropsWithoutRef<"div">
112
+ >(({ ...props }, ref) => (
113
+ <div ref={ref} role="separator" {...props}>
114
+ <Minus className="text-grey-400" />
115
+ </div>
116
+ ))
117
+ InputOTPSeparator.displayName = "InputOTPSeparator"
118
+
119
+ export {
120
+ InputOTP,
121
+ InputOTPGroup,
122
+ InputOTPSlot,
123
+ InputOTPSeparator,
124
+ inputOTPVariants,
125
+ inputOTPSlotVariants,
126
+ }
127
+ export type { InputOTPSlotSize }
@@ -0,0 +1,105 @@
1
+ import type { Meta, StoryObj } from "@storybook/react"
2
+
3
+ import { Input } from "../Input/Input"
4
+ import { Checkbox } from "../Checkbox/Checkbox"
5
+ import { Flex } from "../Flex/Flex"
6
+ import { Typography } from "../Typography/Typography"
7
+ import { Label } from "./Label"
8
+
9
+ const meta: Meta<typeof Label> = {
10
+ title: "Components/Label",
11
+ component: Label,
12
+ parameters: {
13
+ layout: "centered",
14
+ },
15
+ argTypes: {
16
+ variant: {
17
+ control: "select",
18
+ options: ["default", "muted", "error"],
19
+ description: "The visual variant of the label",
20
+ },
21
+ },
22
+ tags: ["autodocs"],
23
+ }
24
+
25
+ export default meta
26
+ type Story = StoryObj<typeof meta>
27
+
28
+ export const Default: Story = {
29
+ render: () => <Label>Email address</Label>,
30
+ }
31
+
32
+ export const WithInput: Story = {
33
+ render: () => (
34
+ <Flex direction="column" gap={2} className="w-[300px]">
35
+ <Label htmlFor="email">Email</Label>
36
+ <Input type="email" id="email" placeholder="Enter your email" />
37
+ </Flex>
38
+ ),
39
+ }
40
+
41
+ export const WithCheckbox: Story = {
42
+ render: () => (
43
+ <Flex align="center" gap={2}>
44
+ <Checkbox id="terms" />
45
+ <Label htmlFor="terms">Accept terms and conditions</Label>
46
+ </Flex>
47
+ ),
48
+ }
49
+
50
+ export const Muted: Story = {
51
+ render: () => <Label variant="muted">Optional field</Label>,
52
+ }
53
+
54
+ export const Error: Story = {
55
+ render: () => (
56
+ <Flex direction="column" gap={2} className="w-[300px]">
57
+ <Label htmlFor="email-error" variant="error">Email</Label>
58
+ <Input type="email" id="email-error" variant="error" placeholder="Enter your email" />
59
+ <Typography variant="caption" color="error-500">Please enter a valid email address</Typography>
60
+ </Flex>
61
+ ),
62
+ }
63
+
64
+ export const AllVariants: Story = {
65
+ render: () => (
66
+ <Flex direction="column" gap={6}>
67
+ <Typography variant="h4" className="text-white">Label Variants</Typography>
68
+
69
+ <Flex direction="column" gap={4}>
70
+ <Flex direction="column" gap={2} className="w-[300px]">
71
+ <Label htmlFor="default">Default Label</Label>
72
+ <Input id="default" placeholder="Default input" />
73
+ </Flex>
74
+
75
+ <Flex direction="column" gap={2} className="w-[300px]">
76
+ <Flex gap={2} align="center">
77
+ <Label htmlFor="with-optional">Name</Label>
78
+ <Label variant="muted">(optional)</Label>
79
+ </Flex>
80
+ <Input id="with-optional" placeholder="Enter your name" />
81
+ </Flex>
82
+
83
+ <Flex direction="column" gap={2} className="w-[300px]">
84
+ <Label htmlFor="error-field" variant="error">Password</Label>
85
+ <Input id="error-field" type="password" variant="error" placeholder="Enter password" />
86
+ <Typography variant="caption" color="error-500">Password must be at least 8 characters</Typography>
87
+ </Flex>
88
+ </Flex>
89
+
90
+ <Typography variant="h4" className="text-white mt-4">With Form Controls</Typography>
91
+
92
+ <Flex direction="column" gap={3}>
93
+ <Flex align="center" gap={2}>
94
+ <Checkbox id="newsletter" />
95
+ <Label htmlFor="newsletter">Subscribe to newsletter</Label>
96
+ </Flex>
97
+
98
+ <Flex align="center" gap={2}>
99
+ <Checkbox id="updates" defaultChecked />
100
+ <Label htmlFor="updates">Receive product updates</Label>
101
+ </Flex>
102
+ </Flex>
103
+ </Flex>
104
+ ),
105
+ }
@@ -0,0 +1,43 @@
1
+ import * as React from "react"
2
+ import * as LabelPrimitive from "@radix-ui/react-label"
3
+ import { cva } from "class-variance-authority"
4
+
5
+ import { cn } from "../lib/utils"
6
+
7
+ type LabelVariant = "default" | "muted" | "error"
8
+
9
+ const labelVariants = cva(
10
+ "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70",
11
+ {
12
+ variants: {
13
+ variant: {
14
+ default: "text-main-950",
15
+ muted: "text-grey-500",
16
+ error: "text-error-600",
17
+ },
18
+ },
19
+ defaultVariants: {
20
+ variant: "default",
21
+ },
22
+ }
23
+ )
24
+
25
+ export interface LabelProps
26
+ extends React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root> {
27
+ variant?: LabelVariant
28
+ }
29
+
30
+ const Label = React.forwardRef<
31
+ React.ElementRef<typeof LabelPrimitive.Root>,
32
+ LabelProps
33
+ >(({ className, variant, ...props }, ref) => (
34
+ <LabelPrimitive.Root
35
+ ref={ref}
36
+ className={cn(labelVariants({ variant }), className)}
37
+ {...props}
38
+ />
39
+ ))
40
+ Label.displayName = LabelPrimitive.Root.displayName
41
+
42
+ export { Label, labelVariants }
43
+ export type { LabelVariant }
@@ -0,0 +1,170 @@
1
+ import type { Meta, StoryObj } from "@storybook/react"
2
+ import { Button } from "../Button/Button"
3
+ import { Flex } from "../Flex/Flex"
4
+ import { Typography } from "../Typography/Typography"
5
+ import { Loader } from "./Loader"
6
+
7
+ const meta: Meta<typeof Loader> = {
8
+ title: "Components/Loader",
9
+ component: Loader,
10
+ parameters: {
11
+ layout: "centered",
12
+ },
13
+ tags: ["autodocs"],
14
+ argTypes: {
15
+ size: {
16
+ control: "select",
17
+ options: ["mini", "small", "regular", "large"],
18
+ description: "The size of the loader",
19
+ },
20
+ color: {
21
+ control: "select",
22
+ options: ["main", "grey", "white", "current"],
23
+ description: "The color of the loader",
24
+ },
25
+ label: {
26
+ control: "text",
27
+ description: "Accessibility label for the loader",
28
+ },
29
+ },
30
+ }
31
+
32
+ export default meta
33
+ type Story = StoryObj<typeof Loader>
34
+
35
+ export const Default: Story = {
36
+ args: {
37
+ size: "regular",
38
+ color: "main",
39
+ },
40
+ }
41
+
42
+ export const Mini: Story = {
43
+ args: {
44
+ size: "mini",
45
+ color: "main",
46
+ },
47
+ }
48
+
49
+ export const Small: Story = {
50
+ args: {
51
+ size: "small",
52
+ color: "main",
53
+ },
54
+ }
55
+
56
+ export const Regular: Story = {
57
+ args: {
58
+ size: "regular",
59
+ color: "main",
60
+ },
61
+ }
62
+
63
+ export const Large: Story = {
64
+ args: {
65
+ size: "large",
66
+ color: "main",
67
+ },
68
+ }
69
+
70
+ export const Grey: Story = {
71
+ args: {
72
+ size: "regular",
73
+ color: "grey",
74
+ },
75
+ }
76
+
77
+ export const White: Story = {
78
+ args: {
79
+ size: "regular",
80
+ color: "white",
81
+ },
82
+ parameters: {
83
+ backgrounds: { default: "dark" },
84
+ },
85
+ decorators: [
86
+ (Story) => (
87
+ <Flex className="bg-main-600 p-4 rounded-lg">
88
+ <Story />
89
+ </Flex>
90
+ ),
91
+ ],
92
+ }
93
+
94
+ export const InButton: Story = {
95
+ render: () => (
96
+ <Button disabled>
97
+ <Loader size="small" color="current" className="mr-2" />
98
+ Loading...
99
+ </Button>
100
+ ),
101
+ }
102
+
103
+ export const AllVariants: Story = {
104
+ render: () => (
105
+ <Flex direction="column" gap={8}>
106
+ {/* Sizes */}
107
+ <Flex direction="column" gap={4}>
108
+ <Typography variant="subtitle1" color="main-700">Sizes</Typography>
109
+ <Flex align="center" gap={6}>
110
+ <Flex direction="column" align="center" gap={2}>
111
+ <Loader size="mini" />
112
+ <Typography variant="body3" color="main-500">Mini</Typography>
113
+ </Flex>
114
+ <Flex direction="column" align="center" gap={2}>
115
+ <Loader size="small" />
116
+ <Typography variant="body3" color="main-500">Small</Typography>
117
+ </Flex>
118
+ <Flex direction="column" align="center" gap={2}>
119
+ <Loader size="regular" />
120
+ <Typography variant="body3" color="main-500">Regular</Typography>
121
+ </Flex>
122
+ <Flex direction="column" align="center" gap={2}>
123
+ <Loader size="large" />
124
+ <Typography variant="body3" color="main-500">Large</Typography>
125
+ </Flex>
126
+ </Flex>
127
+ </Flex>
128
+
129
+ {/* Colors */}
130
+ <Flex direction="column" gap={4}>
131
+ <Typography variant="subtitle1" color="main-700">Colors</Typography>
132
+ <Flex align="center" gap={6}>
133
+ <Flex direction="column" align="center" gap={2}>
134
+ <Loader color="main" />
135
+ <Typography variant="body3" color="main-500">Main</Typography>
136
+ </Flex>
137
+ <Flex direction="column" align="center" gap={2}>
138
+ <Loader color="grey" />
139
+ <Typography variant="body3" color="main-500">Grey</Typography>
140
+ </Flex>
141
+ <Flex direction="column" align="center" gap={2} className="bg-main-600 p-3 rounded-lg">
142
+ <Loader color="white" />
143
+ <Typography variant="body3" className="text-white">White</Typography>
144
+ </Flex>
145
+ </Flex>
146
+ </Flex>
147
+
148
+ {/* Usage Examples */}
149
+ <Flex direction="column" gap={4}>
150
+ <Typography variant="subtitle1" color="main-700">Usage Examples</Typography>
151
+ <Flex direction="column" gap={4}>
152
+ <Flex align="center" gap={4}>
153
+ <Button disabled>
154
+ <Loader size="small" color="current" className="mr-2" />
155
+ Loading...
156
+ </Button>
157
+ <Typography variant="body3" color="main-500">In Button</Typography>
158
+ </Flex>
159
+ <Flex align="center" gap={4}>
160
+ <Flex align="center" gap={2} className="text-main-600">
161
+ <Loader size="small" color="current" />
162
+ <Typography variant="body2">Processing...</Typography>
163
+ </Flex>
164
+ <Typography variant="body3" color="main-500">Inline with text</Typography>
165
+ </Flex>
166
+ </Flex>
167
+ </Flex>
168
+ </Flex>
169
+ ),
170
+ }