返回 presentation-ai
input-otp.tsx
根目录 / src / components / ui / input-otp.tsx
1 "use client";
2
3 import { OTPInput, OTPInputContext, type RenderProps } from "input-otp";
4 import { Dot } from "lucide-react";
5 import * as React from "react";
6
7 import { cn } from "@/lib/utils";
8
9 const InputOTP = React.forwardRef<
10 React.ElementRef<typeof OTPInput>,
11 React.ComponentPropsWithoutRef<typeof OTPInput>
12 >(({ className, containerClassName, ...props }, ref) => (
13 <OTPInput
14 ref={ref}
15 containerClassName={cn(
16 "flex items-center gap-2 has-disabled:opacity-50",
17 containerClassName,
18 )}
19 className={cn("disabled:cursor-not-allowed", className)}
20 {...props}
21 />
22 ));
23 InputOTP.displayName = "InputOTP";
24
25 const InputOTPGroup = React.forwardRef<
26 React.ElementRef<"div">,
27 React.ComponentPropsWithoutRef<"div">
28 >(({ className, ...props }, ref) => (
29 <div ref={ref} className={cn("flex items-center", className)} {...props} />
30 ));
31 InputOTPGroup.displayName = "InputOTPGroup";
32
33 const InputOTPSlot = React.forwardRef<
34 React.ElementRef<"div">,
35 React.ComponentPropsWithoutRef<"div"> & { index: number }
36 >(({ index, className, ...props }, ref) => {
37 const inputOTPContext = React.useContext(OTPInputContext) as RenderProps;
38 const { char, hasFakeCaret, isActive } = inputOTPContext.slots[index]!;
39
40 return (
41 <div
42 ref={ref}
43 className={cn(
44 "relative flex h-10 w-10 items-center justify-center border-y border-r border-input text-sm transition-all first:rounded-l-md first:border-l last:rounded-r-md",
45 isActive && "z-10 ring-2 ring-ring ring-offset-background",
46 className,
47 )}
48 {...props}
49 >
50 {char}
51 {hasFakeCaret && (
52 <div className="pointer-events-none absolute inset-0 flex items-center justify-center">
53 <div className="h-4 w-px animate-caret-blink bg-foreground duration-1000" />
54 </div>
55 )}
56 </div>
57 );
58 });
59 InputOTPSlot.displayName = "InputOTPSlot";
60
61 const InputOTPSeparator = React.forwardRef<
62 React.ElementRef<"div">,
63 React.ComponentPropsWithoutRef<"div">
64 >(({ ...props }, ref) => (
65 <div ref={ref} role="separator" {...props}>
66 <Dot />
67 </div>
68 ));
69 InputOTPSeparator.displayName = "InputOTPSeparator";
70
71 export { InputOTP, InputOTPGroup, InputOTPSeparator, InputOTPSlot };
72
72 lines Plain Text