-
Notifications
You must be signed in to change notification settings - Fork 0
/
OTP.tsx
121 lines (98 loc) · 3.43 KB
/
OTP.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
import React, {useRef} from 'react';
export interface OTPProps {
onComplete: (value: string) => void;
length?: number;
disabled?: boolean;
}
/**
*
* @param root0
* @param root0.disabled
* @param root0.onComplete
*/
export default function OTP({onComplete, disabled, length}: OTPProps) {
const inputRefs = Array.from({length: length ?? 6}, () => useRef<HTMLInputElement>(null));
const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
if (e.key === 'Backspace') {
e.preventDefault();
const currentInputIndex = inputRefs.findIndex(ref => ref.current === document.activeElement);
if (currentInputIndex >= 0) {
const currentInput = inputRefs[currentInputIndex];
if (currentInput.current) {
const currentValue = currentInput.current.value;
if (currentValue !== '') {
currentInput.current.value = '';
}
if (currentInputIndex > 0) {
const previousInput = inputRefs[currentInputIndex - 1];
previousInput.current?.focus();
}
}
}
}
if (e.key === 'Delete') {
e.preventDefault();
const currentInputIndex = inputRefs.findIndex(ref => ref.current === document.activeElement);
if (currentInputIndex >= 0) {
const currentInput = inputRefs[currentInputIndex];
if (currentInput.current) {
const currentValue = currentInput.current.value;
if (currentValue !== '') {
currentInput.current.value = '';
}
if (currentInputIndex < inputRefs.length - 1) {
const nextInput = inputRefs[currentInputIndex + 1];
nextInput.current?.focus();
}
}
}
}
};
const handleOnChange = (index: number, value: string) => {
const newValues = inputRefs.map((ref, i) => (i === index ? value : ref.current?.value ?? ''));
const otpValue = newValues.join('');
if (index < inputRefs.length - 1 && value.length === 1) {
inputRefs[index + 1].current?.focus();
}
if (index > 0 && value === '') {
inputRefs[index - 1].current?.focus();
}
if (newValues.every(val => val !== '')) {
onComplete(otpValue);
inputRefs[index].current?.blur();
}
};
const handlePaste = (e: React.ClipboardEvent<HTMLInputElement>) => {
e.preventDefault();
const pastedValue = e.clipboardData.getData('text').slice(0, inputRefs.length);
const otpValue = pastedValue.slice(0, inputRefs.length);
onComplete(otpValue);
inputRefs.forEach((ref, index) => {
const char = pastedValue[index] || '';
ref.current!.value = char;
handleOnChange(index, char);
});
};
return (
<>
<form className="flex gap-3 w-full items-center justify-center">
{inputRefs.map((ref, index) => {
return (
<div className={'h-16 w-16'}>
<input
disabled={disabled}
ref={ref}
className="w-full h-full flex flex-col items-center justify-center text-center px-5 outline-none rounded-xl border border-neutral-300 text-lg bg-white disabled:bg-neutral-100 transition ease-in-out"
maxLength={1}
type="text"
onKeyDown={handleKeyDown}
onChange={e => handleOnChange(index, e.target.value)}
onPaste={e => handlePaste(e)}
/>
</div>
);
})}
</form>
</>
);
}