Skip to content

Commit c19a899

Browse files
samejrericallam
authored andcommitted
InputOTP component supports variant styles
1 parent 6aa5d1b commit c19a899

1 file changed

Lines changed: 48 additions & 8 deletions

File tree

apps/webapp/app/components/primitives/InputOTP.tsx

Lines changed: 48 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,53 +6,93 @@ import { MinusIcon } from "lucide-react";
66

77
import { cn } from "~/utils/cn";
88

9+
const variants = {
10+
default: {
11+
container: "flex items-center gap-2 has-disabled:opacity-50",
12+
group: "flex items-center",
13+
slot: "data-[active=true]:border-ring data-[active=true]:ring-ring/50 data-[active=true]:aria-invalid:ring-destructive/20 dark:data-[active=true]:aria-invalid:ring-destructive/40 aria-invalid:border-destructive data-[active=true]:aria-invalid:border-destructive dark:bg-input/30 border-input relative flex size-9 items-center justify-center border-y border-r text-sm outline-none transition-all first:rounded-l-md first:border-l last:rounded-r-md data-[active=true]:z-10 data-[active=true]:ring-[3px]",
14+
},
15+
large: {
16+
container: "flex items-center gap-3 has-disabled:opacity-50",
17+
group: "flex items-center gap-1",
18+
slot: "data-[active=true]:border-ring data-[active=true]:ring-ring/50 data-[active=true]:aria-invalid:ring-destructive/20 dark:data-[active=true]:aria-invalid:ring-destructive/40 aria-invalid:border-destructive data-[active=true]:aria-invalid:border-destructive bg-charcoal-750 border-charcoal-700 hover:border-charcoal-600 hover:bg-charcoal-650 relative flex h-12 w-12 items-center justify-center border text-base outline-none transition-all rounded-md data-[active=true]:z-10 data-[active=true]:ring-[3px] data-[active=true]:border-indigo-500",
19+
},
20+
minimal: {
21+
container: "flex items-center gap-2 has-disabled:opacity-50",
22+
group: "flex items-center",
23+
slot: "data-[active=true]:border-ring data-[active=true]:ring-ring/50 border-transparent bg-transparent relative flex h-9 w-9 items-center justify-center border-b-2 border-b-charcoal-600 text-sm outline-none transition-all data-[active=true]:border-b-indigo-500 data-[active=true]:z-10",
24+
},
25+
};
26+
927
function InputOTP({
1028
className,
1129
containerClassName,
30+
variant = "default",
31+
fullWidth = false,
1232
...props
1333
}: React.ComponentProps<typeof OTPInput> & {
1434
containerClassName?: string;
35+
variant?: keyof typeof variants;
36+
fullWidth?: boolean;
1537
}) {
38+
const variantStyles = variants[variant];
39+
1640
return (
1741
<OTPInput
1842
data-slot="input-otp"
19-
containerClassName={cn("flex items-center gap-2 has-disabled:opacity-50", containerClassName)}
43+
containerClassName={cn(variantStyles.container, fullWidth && "w-full", containerClassName)}
2044
className={cn("disabled:cursor-not-allowed", className)}
2145
{...props}
2246
/>
2347
);
2448
}
2549

26-
function InputOTPGroup({ className, ...props }: React.ComponentProps<"div">) {
50+
function InputOTPGroup({
51+
className,
52+
variant = "default",
53+
fullWidth = false,
54+
...props
55+
}: React.ComponentProps<"div"> & {
56+
variant?: keyof typeof variants;
57+
fullWidth?: boolean;
58+
}) {
59+
const variantStyles = variants[variant];
60+
2761
return (
28-
<div data-slot="input-otp-group" className={cn("flex items-center", className)} {...props} />
62+
<div
63+
data-slot="input-otp-group"
64+
className={cn(variantStyles.group, fullWidth && "flex-1 gap-1", className)}
65+
{...props}
66+
/>
2967
);
3068
}
3169

3270
function InputOTPSlot({
3371
index,
3472
className,
73+
variant = "default",
74+
fullWidth = false,
3575
...props
3676
}: React.ComponentProps<"div"> & {
3777
index: number;
78+
variant?: keyof typeof variants;
79+
fullWidth?: boolean;
3880
}) {
3981
const inputOTPContext = React.useContext(OTPInputContext);
4082
const { char, hasFakeCaret, isActive } = inputOTPContext?.slots[index] ?? {};
83+
const variantStyles = variants[variant];
4184

4285
return (
4386
<div
4487
data-slot="input-otp-slot"
4588
data-active={isActive}
46-
className={cn(
47-
"data-[active=true]:border-ring data-[active=true]:ring-ring/50 data-[active=true]:aria-invalid:ring-destructive/20 dark:data-[active=true]:aria-invalid:ring-destructive/40 aria-invalid:border-destructive data-[active=true]:aria-invalid:border-destructive dark:bg-input/30 border-input shadow-xs relative flex h-9 w-9 items-center justify-center border-y border-r text-sm outline-none transition-all first:rounded-l-md first:border-l last:rounded-r-md data-[active=true]:z-10 data-[active=true]:ring-[3px]",
48-
className
49-
)}
89+
className={cn(variantStyles.slot, fullWidth && "flex-1", className)}
5090
{...props}
5191
>
5292
{char}
5393
{hasFakeCaret && (
5494
<div className="pointer-events-none absolute inset-0 flex items-center justify-center">
55-
<div className="animate-caret-blink bg-foreground h-4 w-px duration-1000" />
95+
<div className="animate-caret-blink h-4 w-px bg-text-bright duration-1000" />
5696
</div>
5797
)}
5898
</div>

0 commit comments

Comments
 (0)