Extract admin dashboard from ghabilee-frontend2 into a dedicated Next.js app for backoffice.ghabilee.ir (no SEO indexing / Clarity).
76 lines
2.3 KiB
TypeScript
76 lines
2.3 KiB
TypeScript
'use client'
|
|
|
|
import type { ComponentProps, ReactNode } from 'react'
|
|
|
|
import { Description, FieldError, InputOTP } from '@heroui/react'
|
|
|
|
import { cn } from '@/lib/cn'
|
|
|
|
type InputOtpProps = Omit<
|
|
ComponentProps<typeof InputOTP>,
|
|
'children' | 'className' | 'fullWidth' | 'maxLength' | 'radius' | 'size' | 'variant'
|
|
> & {
|
|
className?: string
|
|
classNames?: { segmentWrapper?: string; segment?: string }
|
|
description?: ReactNode
|
|
descriptionClassName?: string
|
|
errorMessage?: ReactNode
|
|
fullWidth?: boolean
|
|
isReadOnly?: boolean
|
|
isRequired?: boolean
|
|
length: number
|
|
radius?: string
|
|
size?: string
|
|
validationBehavior?: 'native' | 'aria'
|
|
variant?: 'flat' | 'bordered' | 'faded' | 'underlined'
|
|
}
|
|
|
|
export function InputOtp({
|
|
className,
|
|
classNames,
|
|
description,
|
|
descriptionClassName,
|
|
errorMessage,
|
|
fullWidth: _fullWidth,
|
|
isInvalid,
|
|
isReadOnly,
|
|
isRequired,
|
|
length,
|
|
radius: _radius,
|
|
size: _size,
|
|
validationBehavior: _validationBehavior,
|
|
variant,
|
|
...props
|
|
}: InputOtpProps) {
|
|
return (
|
|
<div className={cn('flex w-full min-w-0 flex-col gap-1 overflow-x-clip px-5', className)}>
|
|
<InputOTP
|
|
{...props}
|
|
autoComplete={props.autoComplete ?? 'one-time-code'}
|
|
isInvalid={isInvalid}
|
|
maxLength={length}
|
|
readOnly={isReadOnly}
|
|
required={isRequired}
|
|
variant={variant === 'bordered' || variant === 'underlined' ? 'secondary' : 'primary'}
|
|
>
|
|
<InputOTP.Group className={cn('flex w-full min-w-0 justify-center gap-2', classNames?.segmentWrapper)}>
|
|
{Array.from({ length }, (_, index) => (
|
|
<InputOTP.Slot
|
|
key={index}
|
|
className={cn(
|
|
'shrink !outline-none !ring-0 !shadow-none',
|
|
'data-[active=true]:!border-primary data-[active=true]:!outline-none data-[active=true]:!ring-0',
|
|
'data-[invalid=true]:!border data-[invalid=true]:!border-fourth data-[invalid=true]:!outline-none data-[invalid=true]:!ring-0',
|
|
classNames?.segment
|
|
)}
|
|
index={index}
|
|
/>
|
|
))}
|
|
</InputOTP.Group>
|
|
</InputOTP>
|
|
{description ? <Description className={descriptionClassName}>{description}</Description> : null}
|
|
{isInvalid && errorMessage ? <FieldError className="text-center text-sm">{errorMessage}</FieldError> : null}
|
|
</div>
|
|
)
|
|
}
|