@web3auth/modal
Version:
Multi chain wallet aggregator for web3Auth
189 lines (186 loc) • 9.02 kB
JavaScript
import { forwardRef, useState, useRef, useEffect } from 'react';
import { useTranslation } from 'react-i18next';
import i18nInstance from '../../localeImport.js';
import { cn } from '../../utils.js';
import PulseLoader from '../PulseLoader/PulseLoader.js';
import { jsxs, jsx } from 'react/jsx-runtime';
const OtpInput = /*#__PURE__*/forwardRef(({
length,
loading,
resendTimer = 60,
onComplete,
onChange,
error = false,
success = false,
disabled = false,
classes,
helperText = "",
onResendTimer,
showCta = true,
showTimer = true,
autoFocus = false,
placeholder = "",
autoComplete = "one-time-code",
type = "text",
resendBtnText = ""
}, ref) => {
const [otpArray, setOtpArray] = useState(Array(length).fill(""));
const [timer, setTimer] = useState(resendTimer !== null && resendTimer !== void 0 ? resendTimer : 0);
const [t] = useTranslation(undefined, {
i18n: i18nInstance
});
const inputRefs = useRef([]);
const isInputValueValid = value => {
return /^\d$/.test(value) && value.trim().length === 1;
};
const handleKeyDown = (e, index) => {
if (e.key === "Backspace" || e.key === "Delete") {
e.preventDefault();
const newOtpArray = [...otpArray];
if (otpArray[index] !== "") {
newOtpArray[index] = "";
} else if (index > 0) {
var _inputRefs$current;
(_inputRefs$current = inputRefs.current[index - 1]) === null || _inputRefs$current === void 0 || _inputRefs$current.focus();
newOtpArray[index - 1] = "";
}
setOtpArray(newOtpArray);
if (onChange) onChange(newOtpArray.join(""));
} else if (e.key === "ArrowLeft") {
var _inputRefs$current2;
e.preventDefault();
(_inputRefs$current2 = inputRefs.current[index - 1]) === null || _inputRefs$current2 === void 0 || _inputRefs$current2.focus();
} else if (e.key === "ArrowRight") {
var _inputRefs$current3;
e.preventDefault();
(_inputRefs$current3 = inputRefs.current[index + 1]) === null || _inputRefs$current3 === void 0 || _inputRefs$current3.focus();
} else if (e.key === " " || e.key === "Spacebar" || e.key === "Space" || !isInputValueValid(e.key) && inputRefs.current[index + 1]) {
e.preventDefault();
inputRefs.current[index + 1].value = "";
}
};
const handleInputChange = (e, index) => {
e.preventDefault();
const {
value
} = e.target;
if (value && value.length > 1 && value.length === length) {
var _inputRefs$current4;
const pastedOtp = value.split("");
const newOtpArray = [...otpArray];
pastedOtp.forEach((key, idx) => {
newOtpArray[idx] = key;
});
setOtpArray(newOtpArray);
(_inputRefs$current4 = inputRefs.current[pastedOtp.length === length ? length - 1 : pastedOtp.length]) === null || _inputRefs$current4 === void 0 || _inputRefs$current4.focus();
if (onComplete && length === newOtpArray.length) onComplete(newOtpArray.join(""));
} else if (isInputValueValid(value)) {
const newOtpArray = [...otpArray].slice(0, length);
newOtpArray[index] = value;
setOtpArray(newOtpArray);
const otp = newOtpArray.join("");
// Move focus to the next input
if (index < length - 1 && inputRefs.current[index + 1]) {
var _inputRefs$current5;
(_inputRefs$current5 = inputRefs.current[index + 1]) === null || _inputRefs$current5 === void 0 || _inputRefs$current5.focus();
}
if (onChange) onChange(value);
if (onComplete && length === otp.length) onComplete(otp);
}
};
const handlePaste = e => {
e.preventDefault();
const pastedData = e.clipboardData.getData("text").slice(0, length);
if (pastedData && /^\d+$/.test(pastedData)) {
var _inputRefs$current6;
const pastedOtp = pastedData.split("");
const newOtpArray = [...otpArray];
pastedOtp.forEach((key, index) => {
newOtpArray[index] = key;
});
setOtpArray(newOtpArray);
(_inputRefs$current6 = inputRefs.current[pastedOtp.length === length ? length - 1 : pastedOtp.length]) === null || _inputRefs$current6 === void 0 || _inputRefs$current6.focus();
if (onComplete && length === newOtpArray.length) onComplete(newOtpArray.join(""));
}
};
const handleResendClick = () => {
setTimer(resendTimer || 0);
if (onResendTimer) onResendTimer();
};
useEffect(() => {
let interval = null;
// Start the resend timer
if (showCta && showTimer) {
interval = window.setInterval(() => {
if (timer > 0) {
setTimer(prev => prev - 1);
} else {
clearInterval(interval);
}
}, 1000);
}
return () => {
clearInterval(interval);
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [timer]);
useEffect(() => {
if (inputRefs && autoFocus) {
var _inputRefs$current7;
(_inputRefs$current7 = inputRefs.current) === null || _inputRefs$current7 === void 0 || _inputRefs$current7[0].focus();
}
}, [autoFocus]);
const helperTextClass = cn("w3a--text-xs w3a--font-normal w3a--text-app-gray-500 dark:w3a--text-app-white w3a--mt-2", {
"w3a--text-app-red-500 dark:w3a--text-app-red-400": error,
"w3a--text-app-green-500 dark:w3a--text-app-green-400": success
}, classes === null || classes === void 0 ? void 0 : classes.helperText);
const inputKey = new Date().getFullYear();
return /*#__PURE__*/jsxs("div", {
className: cn("w3a--flex w3a--flex-col w3a--items-center", classes === null || classes === void 0 ? void 0 : classes.root),
ref: ref,
children: [/*#__PURE__*/jsx("form", {
className: cn("w3a--flex w3a--space-x-2", classes === null || classes === void 0 ? void 0 : classes.inputContainer),
children: otpArray.map((digit, index) => {
var _classes$success, _classes$error, _classes$disabled;
return /*#__PURE__*/jsx("input", {
id: `${inputKey + index}`,
type: type,
value: digit,
autoComplete: autoComplete,
placeholder: Array.isArray(placeholder) ? placeholder[index] : placeholder,
inputMode: "numeric",
onInput: e => handleInputChange(e, index),
onKeyUp: e => handleKeyDown(e, index),
onPaste: handlePaste,
className: cn("w3a--w-12 w3a--h-[42px] w3a--rounded-full w3a--border w3a--text-center w3a--text-xl w3a--focus:outline-none w3a--active:outline-none w3a--focus:border-app-primary-600 dark:w3a--focus:border-app-primary-500 w3a--border-app-gray-300 dark:w3a--border-app-gray-500 w3a--bg-app-gray-50 dark:w3a--bg-app-gray-700 w3a--text-app-gray-900 dark:w3a--text-app-white", success && ((_classes$success = classes === null || classes === void 0 ? void 0 : classes.success) !== null && _classes$success !== void 0 ? _classes$success : "w3a--border-app-green-400 dark:w3a--border-app-green-500 w3a--focus:w3a--border-app-green-400 dark:w3a--focus:w3a--border-app-green-500"), error && ((_classes$error = classes === null || classes === void 0 ? void 0 : classes.error) !== null && _classes$error !== void 0 ? _classes$error : "w3a--border-app-red-600 dark:w3a--border-app-red-500 w3a--focus:w3a--border-app-red-600 dark:w3a--focus:w3a--border-app-red-500"), disabled && ((_classes$disabled = classes === null || classes === void 0 ? void 0 : classes.disabled) !== null && _classes$disabled !== void 0 ? _classes$disabled : "w3a--border-app-gray-200 w3a--bg-app-gray-200 dark:w3a--border-app-gray-700 w3a--focus:w3a--border-app-gray-200 dark:w3a--focus:w3a--border-app-gray-700 w3a--cursor-not-allowed"), classes === null || classes === void 0 ? void 0 : classes.input),
ref: el => {
inputRefs.current[index] = el;
},
disabled: disabled
}, `${inputKey + index}`);
})
}), helperText && /*#__PURE__*/jsx("p", {
className: helperTextClass,
children: helperText
}), loading && /*#__PURE__*/jsx("div", {
className: "w3a--mt-3",
children: /*#__PURE__*/jsx(PulseLoader, {})
}), showCta && !loading && /*#__PURE__*/jsx("div", {
className: cn("w3a--flex w3a--items-center w3a--mt-3", classes === null || classes === void 0 ? void 0 : classes.ctaContainer),
children: timer > 0 && showTimer ? /*#__PURE__*/jsx("span", {
className: cn("w3a--text-xs w3a--text-app-gray-500 dark:w3a--text-app-gray-400", classes === null || classes === void 0 ? void 0 : classes.timerText),
children: t("modal.resendTimer", {
timer: timer
})
}) : /*#__PURE__*/jsx("button", {
type: "button",
className: cn("w3a--text-xs w3a--p-0 w3a--text-app-primary-600 dark:w3a--text-app-primary-500", classes === null || classes === void 0 ? void 0 : classes.resendBtnText),
onClick: handleResendClick,
disabled: timer > 0 && showTimer,
children: resendBtnText || t("modal.resendCode")
})
})]
});
});
OtpInput.displayName = "OtpInput";
export { OtpInput as default };