fix: show number keyboard in mobile in otp forms

This commit is contained in:
Koosha Lahouti
2025-10-06 15:46:31 +03:30
parent 18634cbf49
commit 9e42f036e4

View File

@@ -25,6 +25,10 @@ const DigitInput: React.FC<DigitInputProps> = ({
const { i18n } = useTranslation(); const { i18n } = useTranslation();
const inputRefs = useRef<Array<HTMLInputElement | null>>([]); const inputRefs = useRef<Array<HTMLInputElement | null>>([]);
const isMobile =
typeof navigator !== 'undefined' &&
/Mobi|Android|iPhone|iPad|iPod/i.test(navigator.userAgent);
useEffect(() => { useEffect(() => {
inputRefs.current[0]?.focus(); inputRefs.current[0]?.focus();
}, []); }, []);
@@ -44,7 +48,7 @@ const DigitInput: React.FC<DigitInputProps> = ({
setCode(newCode); setCode(newCode);
handleDigitInputValueChange(newCode); handleDigitInputValueChange(newCode);
if (value && index < 4 - 1) { if (value && index < newCode.length - 1) {
inputRefs.current[index + 1]?.focus(); inputRefs.current[index + 1]?.focus();
} }
}; };
@@ -53,37 +57,33 @@ const DigitInput: React.FC<DigitInputProps> = ({
event: KeyboardEvent<HTMLDivElement>, event: KeyboardEvent<HTMLDivElement>,
index: number, index: number,
) => { ) => {
event.preventDefault(); if (event.key === 'Backspace' && code[index]) {
if (index >= 0) { event.preventDefault();
handleChange('', index); handleChange('', index);
inputRefs.current[index - 1]?.focus(); if (index > 0) inputRefs.current[index - 1]?.focus();
} }
}; };
const handlePaste = (event: React.ClipboardEvent) => { const handlePaste = (event: React.ClipboardEvent) => {
event.preventDefault(); event.preventDefault();
const pastedData = event.clipboardData.getData('text').replace(/\D/g, ''); // Remove non-digit characters const pastedData = event.clipboardData.getData('text').replace(/\D/g, '');
const newCode = [...code]; const newCode = [...code];
pastedData.split('').forEach((digit, i) => { pastedData.split('').forEach((digit, i) => {
if (i < code.length) { if (i < newCode.length) newCode[i] = digit;
newCode[i] = digit;
}
}); });
setCode(newCode); setCode(newCode);
handleDigitInputValueChange(newCode); handleDigitInputValueChange(newCode);
// Focus the next empty input after the last pasted character const nextEmpty = newCode.findIndex((d) => d === '');
const lastIndex = Math.min(pastedData.length, code.length) - 1; const focusIndex = nextEmpty === -1 ? newCode.length - 1 : nextEmpty;
if (lastIndex >= 0 && inputRefs.current[lastIndex]) { inputRefs.current[focusIndex]?.focus();
inputRefs.current[lastIndex]?.focus();
}
}; };
return ( return (
<Stack <Stack
direction={i18n.dir() == 'ltr' ? 'row' : 'row-reverse'} direction={i18n.dir() === 'ltr' ? 'row' : 'row-reverse'}
alignItems="center" alignItems="center"
sx={{ gap: 2, width: '100%', my: 4 }} sx={{ gap: 2, width: '100%', my: 4 }}
justifyContent="center" justifyContent="center"
@@ -97,11 +97,18 @@ const DigitInput: React.FC<DigitInputProps> = ({
autoFocus={index === 0} autoFocus={index === 0}
value={digit} value={digit}
onChange={(e) => handleChange(e.target.value, index)} onChange={(e) => handleChange(e.target.value, index)}
onKeyDown={(e) => e.key === 'Backspace' && handleBackspace(e, index)} onKeyDown={(e) => handleBackspace(e, index)}
onPaste={(e) => handlePaste(e)} onPaste={handlePaste}
type={isMobile ? 'tel' : 'text'}
slotProps={{ slotProps={{
htmlInput: { htmlInput: {
maxLength: 1, maxLength: 1,
inputMode: isMobile ? 'numeric' : undefined,
pattern: isMobile ? '[0-9]*' : undefined,
autoComplete: 'one-time-code',
name: 'one-time-code',
enterKeyHint: 'done',
dir: 'ltr',
sx: { sx: {
height: '72px', height: '72px',
color: error color: error