{ "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "input-otp", "type": "registry:ui", "title": "Input OTP", "description": "A customizable input OTP component", "dependencies": [ "tailwind-variants", "clsx", "tailwind-merge", "input-otp", "motion" ], "registryDependencies": [ "classes" ], "files": [ { "path": "src/registry/pure-ui/ui/input-otp/index.tsx", "content": "\"use client\";\r\n\r\nimport { createContext, useContext } from \"react\";\r\nimport {\r\n AnimatePresence,\r\n motion,\r\n MotionConfig,\r\n TargetAndTransition,\r\n} from \"motion/react\";\r\nimport { OTPInput, OTPInputContext as OTPInputContextBase } from \"input-otp\";\r\nimport { tv } from \"tailwind-variants\";\r\n\r\nimport { cn } from \"@/lib/classes\";\r\n\r\ntype InputOTPSlotSize = \"sm\" | \"md\" | \"lg\";\r\ntype InputOTPVariant = \"bordered\" | \"underlined\";\r\n\r\ntype InputOTPContextType = {\r\n variant?: InputOTPVariant;\r\n slotSize?: InputOTPSlotSize;\r\n};\r\n\r\nconst InputOTPContext = createContext({\r\n variant: \"bordered\",\r\n slotSize: \"md\",\r\n});\r\n\r\nexport const useInputOTPContext = () => {\r\n const context = useContext(InputOTPContext);\r\n if (!context) {\r\n throw new Error(\r\n \"useInputOTPContext must be used within a InputOTPProvider\"\r\n );\r\n }\r\n return context;\r\n};\r\n\r\nconst InputOTPProvider = ({\r\n children,\r\n variant = \"bordered\",\r\n slotSize = \"md\",\r\n}: InputOTPContextType & { children: React.ReactNode }) => {\r\n return (\r\n \r\n {children}\r\n \r\n );\r\n};\r\n\r\ntype InputOTPProps = React.ComponentProps & {\r\n variant?: InputOTPVariant;\r\n slotSize?: InputOTPSlotSize;\r\n};\r\n\r\nfunction InputOTP({\r\n containerClassName,\r\n className,\r\n variant = \"bordered\",\r\n slotSize = \"md\",\r\n ...props\r\n}: InputOTPProps) {\r\n return (\r\n \r\n \r\n \r\n );\r\n}\r\n\r\ntype InputOTPGroupProps = React.ComponentProps<\"div\">;\r\n\r\nfunction InputOTPGroup({ className, ...props }: InputOTPGroupProps) {\r\n return (\r\n \r\n );\r\n}\r\n\r\ntype InputOTPAnimatedNumberProps = {\r\n value: string | null;\r\n};\r\n\r\nfunction InputOTPAnimatedNumber({ value }: InputOTPAnimatedNumberProps) {\r\n const animationProps: {\r\n [key: string]: TargetAndTransition;\r\n } = {\r\n initial: { opacity: 0, y: 10 },\r\n animate: {\r\n opacity: 1,\r\n y: 0,\r\n transition: {\r\n type: \"tween\",\r\n ease: [0.25, 0.1, 0.25, 1],\r\n duration: 0.2,\r\n },\r\n },\r\n exit: {\r\n opacity: 0,\r\n y: 10,\r\n transition: {\r\n type: \"tween\",\r\n ease: [0.25, 0.1, 0.25, 1],\r\n duration: 0.15,\r\n },\r\n },\r\n };\r\n\r\n return (\r\n
\r\n \r\n {value && (\r\n \r\n {value}\r\n \r\n )}\r\n \r\n
\r\n );\r\n}\r\n\r\nconst inputOtpSlotVariants = tv({\r\n base: \"relative font-semibold flex items-center justify-center\",\r\n variants: {\r\n variant: {\r\n bordered:\r\n \"rounded-[10px] border border-border bg-background dark:bg-input/32\",\r\n underlined:\r\n \"rounded-none border-b border-border bg-background dark:bg-input/32\",\r\n },\r\n slotSize: {\r\n sm: \"h-8 min-h-8 w-8 min-w-8 text-sm\",\r\n md: \"h-10 min-h-10 w-10 min-w-10 text-base\",\r\n lg: \"h-12 min-h-12 w-12 min-w-12 text-lg\",\r\n },\r\n },\r\n defaultVariants: {\r\n variant: \"bordered\",\r\n slotSize: \"md\",\r\n },\r\n});\r\n\r\nconst inputOtpSlotIndicatorVariants = tv({\r\n base: \"absolute inset-0 z-10\",\r\n variants: {\r\n variant: {\r\n bordered: \"rounded-[inherit] ring-2 ring-primary/70 outline-none\",\r\n underlined: \"border-b border-primary\",\r\n },\r\n },\r\n defaultVariants: {\r\n variant: \"bordered\",\r\n },\r\n});\r\n\r\ntype InputOTPSlotProps = React.ComponentProps & {\r\n index: number;\r\n};\r\n\r\nfunction InputOTPSlot({ index, className, ...props }: InputOTPSlotProps) {\r\n const originalContext = useContext(OTPInputContextBase);\r\n const { variant, slotSize } = useInputOTPContext();\r\n\r\n const { char, hasFakeCaret, isActive } = originalContext?.slots[index] ?? {};\r\n\r\n const activeSlots =\r\n originalContext?.slots.filter((slot) => slot.isActive) ?? [];\r\n const isMultiSelect = activeSlots.length > 1;\r\n\r\n return (\r\n \r\n \r\n \r\n\r\n {hasFakeCaret && }\r\n\r\n \r\n {isActive && (\r\n \r\n )}\r\n \r\n \r\n \r\n );\r\n}\r\n\r\ntype InputOTPSeparatorProps = React.ComponentProps<\"div\">;\r\n\r\nfunction InputOTPSeparator({ className, ...props }: InputOTPSeparatorProps) {\r\n return (\r\n \r\n );\r\n}\r\n\r\nfunction FakeCaret() {\r\n return (\r\n \r\n
\r\n
\r\n );\r\n}\r\n\r\nexport { InputOTP, InputOTPGroup, InputOTPSlot, InputOTPSeparator };\r\n", "type": "registry:ui", "target": "components/ui/input-otp.tsx" } ] }