add: login page fundamentals
This commit is contained in:
@@ -0,0 +1,77 @@
|
||||
'use client';
|
||||
|
||||
import React, { createRef, useEffect, useRef, useState } from 'react'
|
||||
|
||||
type Props = {
|
||||
htmlFor: string;
|
||||
labelText?: React.ReactNode;
|
||||
value?: string;
|
||||
onChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
|
||||
maxLength?: number;
|
||||
className?: string;
|
||||
} & Omit<React.InputHTMLAttributes<HTMLInputElement>, "id">;
|
||||
|
||||
|
||||
function OTPInputField({ onChange, maxLength = 6, htmlFor, labelText, className, value = '' }: Props) {
|
||||
const values = value?.toString().split('').slice(0, maxLength);
|
||||
const inputRefs = useRef(Array.from({ length: maxLength }, () => createRef<HTMLInputElement>()));
|
||||
const [prevLength, setPrevLength] = useState(0);
|
||||
|
||||
useEffect(() => {
|
||||
const valLength = values.length;
|
||||
const focusIndex = valLength < prevLength
|
||||
? Math.max(0, valLength)
|
||||
: Math.min(valLength, maxLength - 1);
|
||||
|
||||
inputRefs.current[focusIndex]?.current?.focus();
|
||||
setPrevLength(valLength);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [value]);
|
||||
|
||||
const keyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
|
||||
const val = String(value);
|
||||
const target = e.target as HTMLInputElement;
|
||||
const index = +target.id.split('-')[2];
|
||||
|
||||
if (e.key == "Backspace") {
|
||||
let i = Math.max(0, val.length - 1)
|
||||
if (val.length >= maxLength && index < maxLength) {
|
||||
i = maxLength - 1;
|
||||
}
|
||||
inputRefs.current[i]?.current?.focus();
|
||||
setPrevLength(() => i)
|
||||
} else {
|
||||
const i = Math.max(0, val.length)
|
||||
inputRefs.current[i]?.current?.focus();
|
||||
setPrevLength(() => i)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={`${className} h-14 inline-flex relative border-none w-full`}>
|
||||
<label
|
||||
className='absolute right-0 -top-6 px-2 bg-background text-[12px] text-foreground'
|
||||
htmlFor={htmlFor}>
|
||||
{labelText}
|
||||
</label>
|
||||
<div className='inline-flex justify-between items-center gap-2'>
|
||||
{inputRefs?.current?.map((ref, i) => {
|
||||
return (
|
||||
<input
|
||||
key={i}
|
||||
onKeyDown={keyDown}
|
||||
onChange={onChange}
|
||||
id={`${htmlFor}-data-${i}`}
|
||||
readOnly={Math.max(0, values?.length) != i && prevLength != i}
|
||||
ref={ref}
|
||||
value={values?.at(i) ?? ''}
|
||||
maxLength={1}
|
||||
className='outline-none text-center inline-flex items-center justify-center h-full relative border border-[#E5E5E5] w-full rounded-normal group focus-within:border focus-within:border-primary' />
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default OTPInputField
|
||||
Reference in New Issue
Block a user