'use client'; import * as React from 'react'; import { OTPInput, OTPInputContext } from 'input-otp'; import { MinusIcon } from 'lucide-react'; import { cn } from '../../shared/utils'; /** * Segmented input for one-time passwords and verification codes. * * @description * Splits the input into individual slots to facilitate digit-by-digit entry * of verification codes. Built on the `input-otp` library. * * @ai-rules * 1. `maxLength` on the root must match the total number of `` components. * 2. Use `` to cluster slots and `` for visual dividers (e.g., "123-456"). * 3. Connect to React Hook Form via `` — treat `value`/`onChange` same as a regular input. */ function InputOTP({ className, containerClassName, ...props }: React.ComponentProps & { containerClassName?: string; }) { return ( ); } function InputOTPGroup({ className, ...props }: React.ComponentProps<'div'>) { return (
); } function InputOTPSlot({ index, className, size = 'md', ...props }: React.ComponentProps<'div'> & { index: number; /** * Size variant — matches the form component sizing scale. * - `sm`: 32×32px slot, text-sm * - `md`: 40×40px slot, text-base — **default** * - `lg`: 48×48px slot, text-lg */ size?: 'sm' | 'md' | 'lg'; }) { const inputOTPContext = React.useContext(OTPInputContext); const { char, hasFakeCaret, isActive } = inputOTPContext?.slots[index] ?? {}; const sizeClasses = { sm: 'h-8 w-8 text-sm', md: 'h-10 w-10 text-base', lg: 'h-12 w-12 text-lg', }; return (
{char} {hasFakeCaret && (
)}
); } function InputOTPSeparator({ ...props }: React.ComponentProps<'div'>) { return (
); } export { InputOTP, InputOTPGroup, InputOTPSlot, InputOTPSeparator };