UNPKG

@kunlexze1/react-native-otp-timer

Version:

OTP input component + countdown timer hook for React Native (using react-native-otp-entry)

285 lines (280 loc) 9.43 kB
"use strict"; var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/index.ts var index_exports = {}; __export(index_exports, { OtpInput: () => import_react_native_otp_entry2.OtpInput, OtpWithTimer: () => OtpWithTimer_default, useOtpTimer: () => useOtpTimer, useTimer: () => useTimer_default }); module.exports = __toCommonJS(index_exports); // src/OtpWithTimer.tsx var import_react2 = __toESM(require("react")); var import_react_native2 = require("react-native"); var import_react_native_otp_entry = require("react-native-otp-entry"); // src/useTimer.ts var import_react = require("react"); var import_react_native = require("react-native"); var useTimer = (seconds) => { const [timeLeft, setTimeLeft] = (0, import_react.useState)(seconds); const [hasTimeout, setHasTimeout] = (0, import_react.useState)(false); const [isRunning, setIsRunning] = (0, import_react.useState)(false); const startTimeRef = (0, import_react.useRef)(Date.now()); const timerRef = (0, import_react.useRef)(null); const formatTime = (0, import_react.useCallback)((time) => { const minutes = Math.floor(time / 60); const timeSeconds = time % 60; return `${minutes}mins : ${timeSeconds.toString().padStart(2, "0")}secs`; }, []); const updateTimer = (0, import_react.useCallback)(() => { const elapsedTime = Math.floor((Date.now() - startTimeRef.current) / 1e3); const remainingTime = seconds - elapsedTime; if (remainingTime <= 0) { if (timerRef.current) { clearInterval(timerRef.current); timerRef.current = null; } setHasTimeout(true); setIsRunning(false); setTimeLeft(0); } else { setTimeLeft(remainingTime); } }, [seconds]); const startTimer = (0, import_react.useCallback)(() => { if (timerRef.current) { clearInterval(timerRef.current); timerRef.current = null; } setIsRunning(true); setHasTimeout(false); setTimeLeft(seconds); startTimeRef.current = Date.now(); timerRef.current = setInterval(updateTimer, 1e3); }, [seconds, updateTimer]); const resetOtpTimer = (0, import_react.useCallback)(() => { setHasTimeout(false); setIsRunning(false); setTimeLeft(seconds); startTimeRef.current = Date.now(); if (timerRef.current) { clearInterval(timerRef.current); timerRef.current = null; } }, [seconds]); const endTimer = (0, import_react.useCallback)(() => { if (timerRef.current) { clearInterval(timerRef.current); timerRef.current = null; } setHasTimeout(true); setTimeLeft(0); setIsRunning(false); }, []); (0, import_react.useEffect)(() => { const handleAppStateChange = (nextAppState) => { if (nextAppState === "active") { const elapsedTime = Math.floor((Date.now() - startTimeRef.current) / 1e3); const remainingTime = seconds - elapsedTime; setTimeLeft(remainingTime > 0 ? remainingTime : 0); } }; const subscription = import_react_native.AppState.addEventListener("change", handleAppStateChange); return () => { if (timerRef.current) { clearInterval(timerRef.current); timerRef.current = null; } subscription.remove(); }; }, [seconds]); return { timeLeft: formatTime(timeLeft), hasTimeout, isRunning, startTimer, resetOtpTimer, endTimer }; }; var useTimer_default = useTimer; // src/OtpWithTimer.tsx var import_jsx_runtime = require("react/jsx-runtime"); var OtpWithTimer = import_react2.default.forwardRef( ({ // Timer props timerDuration = 60, timerStyle, timerFormatter, showTimer = true, timerPosition = "top", onTimerExpire, onTimerStart, onTimerReset, onRestartTimer, autoStartTimer = true, showRestartButton = true, restartButtonText = "Resend OTP", restartButtonStyle, containerStyle, // OTP Entry props numberOfDigits, focusColor, autoFocus, hideStick, placeholder, blurOnFilled, disabled, type, secureTextEntry, focusStickBlinkingDuration, onFilled, onTextChange, textInputProps, textProps, theme, ...rest }, ref) => { const { timeLeft, hasTimeout, startTimer, resetOtpTimer } = useTimer_default(timerDuration); const handleRestartTimer = () => { resetOtpTimer(); startTimer(); onRestartTimer == null ? void 0 : onRestartTimer(); onTimerStart == null ? void 0 : onTimerStart(); }; (0, import_react2.useEffect)(() => { if (autoStartTimer) { startTimer(); onTimerStart == null ? void 0 : onTimerStart(); } }, [autoStartTimer, startTimer, onTimerStart]); (0, import_react2.useEffect)(() => { if (hasTimeout) { onTimerExpire == null ? void 0 : onTimerExpire(); } }, [hasTimeout, onTimerExpire]); const handleFilled = (text) => { onFilled == null ? void 0 : onFilled(text); }; const handleTextChange = (text) => { onTextChange == null ? void 0 : onTextChange(text); }; const formatTimerDisplay = (time) => { return timerFormatter ? timerFormatter(time) : time; }; const renderTimer = () => { if (!showTimer) return null; return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: [styles.timerText, timerStyle], children: hasTimeout ? "Timer expired" : formatTimerDisplay(timeLeft) }); }; return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.View, { style: [styles.container, containerStyle], children: [ timerPosition === "top" && renderTimer(), /* @__PURE__ */ (0, import_jsx_runtime.jsx)( import_react_native_otp_entry.OtpInput, { ref, numberOfDigits, focusColor, autoFocus, hideStick, placeholder, blurOnFilled, disabled: disabled || hasTimeout, type, secureTextEntry, focusStickBlinkingDuration, onFilled: handleFilled, onTextChange: handleTextChange, textInputProps, textProps, theme, ...rest } ), timerPosition === "bottom" && renderTimer(), hasTimeout && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.View, { style: styles.expiredContainer, children: [ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: styles.expiredText, children: "Time expired. Please request a new OTP." }), showRestartButton && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.TouchableOpacity, { onPress: handleRestartTimer, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Text, { style: [styles.restartButton, restartButtonStyle], children: restartButtonText }) }) ] }) ] }); } ); var useOtpTimer = (timerDuration = 60) => { const timerHook = useTimer_default(timerDuration); const restartTimer = () => { timerHook.resetOtpTimer(); timerHook.startTimer(); }; return { ...timerHook, resetTimer: timerHook.resetOtpTimer, restartTimer }; }; var styles = import_react_native2.StyleSheet.create({ container: { alignItems: "center" }, timerText: { fontSize: 16, color: "#333", marginVertical: 10, textAlign: "center" }, expiredContainer: { alignItems: "center", marginTop: 10 }, expiredText: { fontSize: 12, color: "#FF0000", textAlign: "center", marginBottom: 8 }, restartButton: { fontSize: 14, color: "#007AFF", fontWeight: "600", textDecorationLine: "underline", paddingVertical: 8, paddingHorizontal: 16 } }); OtpWithTimer.displayName = "OtpWithTimer"; var OtpWithTimer_default = OtpWithTimer; // src/index.ts var import_react_native_otp_entry2 = require("react-native-otp-entry"); // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { OtpInput, OtpWithTimer, useOtpTimer, useTimer }); //# sourceMappingURL=index.js.map