@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.
- package/Alert/Alert.stories.tsx +121 -0
- package/Alert/Alert.tsx +71 -0
- package/AlertDialog/AlertDialog.stories.tsx +665 -0
- package/AlertDialog/AlertDialog.tsx +241 -0
- package/Avatar/Avatar.stories.tsx +128 -0
- package/Avatar/Avatar.tsx +71 -0
- package/Badge/Badge.stories.tsx +76 -0
- package/Badge/Badge.tsx +39 -0
- package/Breadcrumb/Breadcrumb.stories.tsx +231 -0
- package/Breadcrumb/Breadcrumb.tsx +114 -0
- package/Button/Button.stories.tsx +684 -0
- package/Button/Button.tsx +90 -0
- package/Calendar/Calendar.stories.tsx +207 -0
- package/Calendar/Calendar.tsx +232 -0
- package/Card/Card.stories.tsx +136 -0
- package/Card/Card.tsx +96 -0
- package/ChatBubble/ChatBubble.stories.tsx +307 -0
- package/ChatBubble/ChatBubble.tsx +167 -0
- package/Checkbox/Checkbox.stories.tsx +137 -0
- package/Checkbox/Checkbox.tsx +53 -0
- package/Drawer/Drawer.stories.tsx +721 -0
- package/Drawer/Drawer.tsx +201 -0
- package/DropdownMenu/DropdownMenu.stories.tsx +251 -0
- package/DropdownMenu/DropdownMenu.tsx +199 -0
- package/ErrorMessage/ErrorMessage.stories.tsx +159 -0
- package/ErrorMessage/ErrorMessage.tsx +55 -0
- package/Flex/Flex.tsx +102 -0
- package/IconButton/IconButton.stories.tsx +566 -0
- package/IconButton/IconButton.tsx +95 -0
- package/Input/Input.stories.tsx +456 -0
- package/Input/Input.tsx +129 -0
- package/InputOTP/InputOTP.stories.tsx +246 -0
- package/InputOTP/InputOTP.tsx +127 -0
- package/Label/Label.stories.tsx +105 -0
- package/Label/Label.tsx +43 -0
- package/Loader/Loader.stories.tsx +170 -0
- package/Loader/Loader.tsx +62 -0
- package/Popover/Popover.stories.tsx +133 -0
- package/Popover/Popover.tsx +31 -0
- package/Progress/Progress.stories.tsx +146 -0
- package/Progress/Progress.tsx +67 -0
- package/README.md +12 -12
- package/RadioGroup/RadioGroup.stories.tsx +159 -0
- package/RadioGroup/RadioGroup.tsx +68 -0
- package/ScrollArea/ScrollArea.stories.tsx +136 -0
- package/ScrollArea/ScrollArea.tsx +46 -0
- package/Select/Select.stories.tsx +242 -0
- package/Select/Select.tsx +180 -0
- package/Separator/Separator.stories.tsx +110 -0
- package/Separator/Separator.tsx +29 -0
- package/Skeleton/Skeleton.stories.tsx +117 -0
- package/Skeleton/Skeleton.tsx +16 -0
- package/Spinner/Spinner.stories.tsx +210 -0
- package/Spinner/Spinner.tsx +78 -0
- package/Switch/Switch.stories.tsx +146 -0
- package/Switch/Switch.tsx +59 -0
- package/Tabs/Tabs.stories.tsx +197 -0
- package/Tabs/Tabs.tsx +74 -0
- package/Textarea/Textarea.stories.tsx +170 -0
- package/Textarea/Textarea.tsx +51 -0
- package/Toast/Toast.stories.tsx +285 -0
- package/Toast/Toast.tsx +59 -0
- package/Tooltip/Tooltip.stories.tsx +463 -0
- package/Tooltip/Tooltip.tsx +96 -0
- package/Typography/Typography.stories.tsx +235 -0
- package/Typography/Typography.tsx +171 -0
- package/helpers.ts +5 -0
- package/icons.ts +2 -0
- package/index.ts +136 -0
- package/lib/utils.ts +15 -0
- package/package.json +4 -1
- package/tsconfig.json +24 -0
- package/Alert/Alert.d.ts +0 -11
- package/Alert/Alert.js +0 -64
- package/AlertDialog/AlertDialog.d.ts +0 -35
- package/AlertDialog/AlertDialog.js +0 -121
- package/Avatar/Avatar.d.ts +0 -12
- package/Avatar/Avatar.js +0 -64
- package/Badge/Badge.d.ts +0 -9
- package/Badge/Badge.js +0 -26
- package/Breadcrumb/Breadcrumb.d.ts +0 -19
- package/Breadcrumb/Breadcrumb.js +0 -65
- package/Button/Button.d.ts +0 -14
- package/Button/Button.js +0 -75
- package/Calendar/Calendar.d.ts +0 -16
- package/Calendar/Calendar.js +0 -113
- package/Card/Card.d.ts +0 -14
- package/Card/Card.js +0 -70
- package/ChatBubble/ChatBubble.d.ts +0 -29
- package/ChatBubble/ChatBubble.js +0 -133
- package/Checkbox/Checkbox.d.ts +0 -10
- package/Checkbox/Checkbox.js +0 -57
- package/Dialog/Dialog.d.ts +0 -35
- package/Dialog/Dialog.js +0 -130
- package/Drawer/Drawer.d.ts +0 -31
- package/Drawer/Drawer.js +0 -69
- package/DropdownMenu/DropdownMenu.d.ts +0 -27
- package/DropdownMenu/DropdownMenu.js +0 -85
- package/ErrorMessage/ErrorMessage.d.ts +0 -27
- package/ErrorMessage/ErrorMessage.js +0 -15
- package/Flex/Flex.d.ts +0 -23
- package/Flex/Flex.js +0 -101
- package/IconButton/IconButton.d.ts +0 -17
- package/IconButton/IconButton.js +0 -85
- package/Input/Input.d.ts +0 -16
- package/Input/Input.js +0 -75
- package/InputOTP/InputOTP.d.ts +0 -18
- package/InputOTP/InputOTP.js +0 -85
- package/Label/Label.d.ts +0 -10
- package/Label/Label.js +0 -57
- package/Loader/Loader.d.ts +0 -18
- package/Loader/Loader.js +0 -67
- package/Popover/Popover.d.ts +0 -7
- package/Popover/Popover.js +0 -49
- package/Progress/Progress.d.ts +0 -13
- package/Progress/Progress.js +0 -71
- package/RadioGroup/RadioGroup.d.ts +0 -11
- package/RadioGroup/RadioGroup.js +0 -64
- package/ScrollArea/ScrollArea.d.ts +0 -5
- package/ScrollArea/ScrollArea.js +0 -48
- package/Select/Select.d.ts +0 -19
- package/Select/Select.js +0 -85
- package/Separator/Separator.d.ts +0 -4
- package/Separator/Separator.js +0 -43
- package/Skeleton/Skeleton.d.ts +0 -4
- package/Skeleton/Skeleton.js +0 -8
- package/Spinner/Spinner.d.ts +0 -15
- package/Spinner/Spinner.js +0 -68
- package/Switch/Switch.d.ts +0 -10
- package/Switch/Switch.js +0 -67
- package/Tabs/Tabs.d.ts +0 -13
- package/Tabs/Tabs.js +0 -64
- package/Textarea/Textarea.d.ts +0 -10
- package/Textarea/Textarea.js +0 -64
- package/Toast/Toast.d.ts +0 -10
- package/Toast/Toast.js +0 -29
- package/Tooltip/Tooltip.d.ts +0 -15
- package/Tooltip/Tooltip.js +0 -68
- package/Typography/Typography.d.ts +0 -15
- package/Typography/Typography.js +0 -125
- package/helpers.d.ts +0 -4
- package/helpers.js +0 -13
- package/icons.d.ts +0 -1
- package/icons.js +0 -18
- package/index.d.ts +0 -35
- package/index.js +0 -183
- package/lib/utils.d.ts +0 -3
- 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
|
+
}
|
package/Label/Label.tsx
ADDED
|
@@ -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
|
+
}
|