UNPKG

@web3auth/modal

Version:

Multi chain wallet aggregator for web3Auth

189 lines (186 loc) 9.02 kB
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 };