summaryrefslogtreecommitdiff
path: root/components/ui/input-otp.tsx
diff options
context:
space:
mode:
authorYuren Hao <97327730+YurenHao0426@users.noreply.github.com>2025-02-02 23:59:29 -0600
committerGitHub <noreply@github.com>2025-02-02 23:59:29 -0600
commit1774317d667aed94b2a2f0acae885ce9420de8e2 (patch)
tree71ca71920e68a43536bc58085ebc96e193db776a /components/ui/input-otp.tsx
Add files via uploadHEADmain
initialization
Diffstat (limited to 'components/ui/input-otp.tsx')
-rw-r--r--components/ui/input-otp.tsx71
1 files changed, 71 insertions, 0 deletions
diff --git a/components/ui/input-otp.tsx b/components/ui/input-otp.tsx
new file mode 100644
index 0000000..f66fcfa
--- /dev/null
+++ b/components/ui/input-otp.tsx
@@ -0,0 +1,71 @@
+"use client"
+
+import * as React from "react"
+import { OTPInput, OTPInputContext } from "input-otp"
+import { Dot } from "lucide-react"
+
+import { cn } from "@/lib/utils"
+
+const InputOTP = React.forwardRef<
+ React.ElementRef<typeof OTPInput>,
+ React.ComponentPropsWithoutRef<typeof OTPInput>
+>(({ className, containerClassName, ...props }, ref) => (
+ <OTPInput
+ ref={ref}
+ containerClassName={cn(
+ "flex items-center gap-2 has-[:disabled]:opacity-50",
+ containerClassName
+ )}
+ className={cn("disabled:cursor-not-allowed", className)}
+ {...props}
+ />
+))
+InputOTP.displayName = "InputOTP"
+
+const InputOTPGroup = React.forwardRef<
+ React.ElementRef<"div">,
+ React.ComponentPropsWithoutRef<"div">
+>(({ className, ...props }, ref) => (
+ <div ref={ref} className={cn("flex items-center", className)} {...props} />
+))
+InputOTPGroup.displayName = "InputOTPGroup"
+
+const InputOTPSlot = React.forwardRef<
+ React.ElementRef<"div">,
+ React.ComponentPropsWithoutRef<"div"> & { index: number }
+>(({ index, className, ...props }, ref) => {
+ const inputOTPContext = React.useContext(OTPInputContext)
+ const { char, hasFakeCaret, isActive } = inputOTPContext.slots[index]
+
+ return (
+ <div
+ ref={ref}
+ className={cn(
+ "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",
+ isActive && "z-10 ring-2 ring-ring ring-offset-background",
+ className
+ )}
+ {...props}
+ >
+ {char}
+ {hasFakeCaret && (
+ <div className="pointer-events-none absolute inset-0 flex items-center justify-center">
+ <div className="h-4 w-px animate-caret-blink bg-foreground duration-1000" />
+ </div>
+ )}
+ </div>
+ )
+})
+InputOTPSlot.displayName = "InputOTPSlot"
+
+const InputOTPSeparator = React.forwardRef<
+ React.ElementRef<"div">,
+ React.ComponentPropsWithoutRef<"div">
+>(({ ...props }, ref) => (
+ <div ref={ref} role="separator" {...props}>
+ <Dot />
+ </div>
+))
+InputOTPSeparator.displayName = "InputOTPSeparator"
+
+export { InputOTP, InputOTPGroup, InputOTPSlot, InputOTPSeparator }