mirror of
https://github.com/documenso/documenso.git
synced 2026-07-10 21:15:15 +10:00
9cb80aa0bc
Adds the pin input to the currently used 2FA components sunsetting the standard input that was previously used.
77 lines
2.1 KiB
TypeScript
77 lines
2.1 KiB
TypeScript
'use client';
|
|
|
|
import * as React from 'react';
|
|
|
|
import { OTPInput, OTPInputContext } from 'input-otp';
|
|
import { Minus } from 'lucide-react';
|
|
|
|
import { cn } from '../lib/utils';
|
|
|
|
const PinInput = 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}
|
|
/>
|
|
));
|
|
|
|
PinInput.displayName = 'PinInput';
|
|
|
|
const PinInputGroup = React.forwardRef<
|
|
React.ElementRef<'div'>,
|
|
React.ComponentPropsWithoutRef<'div'>
|
|
>(({ className, ...props }, ref) => (
|
|
<div ref={ref} className={cn('flex items-center', className)} {...props} />
|
|
));
|
|
|
|
PinInputGroup.displayName = 'PinInputGroup';
|
|
|
|
const PinInputSlot = React.forwardRef<
|
|
React.ElementRef<'div'>,
|
|
React.ComponentPropsWithoutRef<'div'> & { index: number }
|
|
>(({ index, className, ...props }, ref) => {
|
|
const context = React.useContext(OTPInputContext);
|
|
const { char, hasFakeCaret, isActive } = context.slots[index];
|
|
|
|
return (
|
|
<div
|
|
ref={ref}
|
|
className={cn(
|
|
'border-input relative flex h-10 w-10 items-center justify-center border-y border-r font-mono shadow-sm transition-all first:rounded-l-md first:border-l last:rounded-r-md',
|
|
isActive && 'ring-ring z-10 ring-1',
|
|
className,
|
|
)}
|
|
{...props}
|
|
>
|
|
{char}
|
|
{hasFakeCaret && (
|
|
<div className="pointer-events-none absolute inset-0 flex items-center justify-center">
|
|
<div className="animate-caret-blink bg-foreground h-4 w-px duration-1000" />
|
|
</div>
|
|
)}
|
|
</div>
|
|
);
|
|
});
|
|
|
|
PinInputSlot.displayName = 'PinInputSlot';
|
|
|
|
const PinInputSeparator = React.forwardRef<
|
|
React.ElementRef<'div'>,
|
|
React.ComponentPropsWithoutRef<'div'>
|
|
>(({ ...props }, ref) => (
|
|
<div ref={ref} role="separator" {...props}>
|
|
<Minus className="h-5 w-5" />
|
|
</div>
|
|
));
|
|
|
|
PinInputSeparator.displayName = 'PinInputSeparator';
|
|
|
|
export { PinInput, PinInputGroup, PinInputSlot, PinInputSeparator };
|