UNPKG

react-native-animated-otp-input

Version:

@anhquan291/react-native-animated-otp-input is a tiny library which provides an elegant UI with smooth Animation for the end user to input one time passcode (OTP). It also handles the input suggestion on iOS when the OTP SMS is received.

220 lines (219 loc) 7.2 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = exports.OtpInput = void 0; var _react = _interopRequireWildcard(require("react")); var _reactNative = require("react-native"); var _reactNativeReanimated = _interopRequireWildcard(require("react-native-reanimated")); function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); } function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; } function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); } /* eslint-disable react-hooks/exhaustive-deps */ const { width } = _reactNative.Dimensions.get('window'); const OtpContext = /*#__PURE__*/(0, _react.createContext)({}); const OtpItem = ({ i }) => { const { inputRef, onPress, otpValue, onFocusNext, onFocusPrevious, setFocus, setOtpValue, focus, focusColor, autoFocus, containerStyle, inputStyle, textStyle, otpCount, editable, enteringAnimated, exitingAnimated, rest } = (0, _react.useContext)(OtpContext); const border = (0, _reactNativeReanimated.useSharedValue)(focus === i ? 1.5 : 0); const borderStyle = (0, _reactNativeReanimated.useAnimatedStyle)(() => { return { borderWidth: border.value }; }, []); (0, _react.useEffect)(() => { border.value = (0, _reactNativeReanimated.withDelay)(50, (0, _reactNativeReanimated.withTiming)(focus === i ? 1.5 : 0, { duration: 100 })); }, [focus]); (0, _react.useEffect)(() => { if (otpValue) { if ((otpValue[i]?.length ?? 0) > 1) { const format = otpValue[i]?.substring(0, otpCount); const numbers = format?.split('') ?? []; setOtpValue(numbers); setFocus(-1); _reactNative.Keyboard.dismiss(); } } }, [otpValue]); return /*#__PURE__*/_react.default.createElement(_reactNative.View, { key: i, style: [containerStyle] }, /*#__PURE__*/_react.default.createElement(_reactNative.TextInput, _extends({ style: [styles.inputSize, inputStyle], caretHidden: true, keyboardType: "number-pad", ref: inputRef.current[i], value: otpValue[i], onChangeText: v => onFocusNext(v, i), onKeyPress: e => onFocusPrevious(e.nativeEvent.key, i), textContentType: "oneTimeCode", autoFocus: autoFocus && i === 0 }, rest)), /*#__PURE__*/_react.default.createElement(_reactNative.Pressable, { disabled: !editable, onPress: onPress, style: styles.overlay }, /*#__PURE__*/_react.default.createElement(_reactNativeReanimated.default.View, { style: [{ borderColor: focusColor }, styles.inputSize, styles.input, borderStyle, inputStyle] }, otpValue[i] !== '' && /*#__PURE__*/_react.default.createElement(_reactNativeReanimated.default.Text, { entering: enteringAnimated, exiting: exitingAnimated, style: [styles.text, textStyle] }, otpValue[i])))); }; const OtpInput = ({ otpCount = 6, containerStyle = {}, inputStyle = {}, textStyle = {}, focusColor = '#4497ce', autoFocus = false, editable = true, enteringAnimated = _reactNativeReanimated.FadeInDown, exitingAnimated = _reactNativeReanimated.FadeOut, onCodeFilled, onCodeChanged, ...rest }) => { const inputRef = (0, _react.useRef)([]); const data = new Array(otpCount).fill(''); inputRef.current = data.map((_, index) => inputRef.current[index] = /*#__PURE__*/_react.default.createRef()); const [focus, setFocus] = (0, _react.useState)(0); const [otpValue, setOtpValue] = (0, _react.useState)(data); const onPress = () => { if (focus === -1) { setFocus(otpCount - 1); otpValue[data.length - 1] = ''; setOtpValue([...otpValue]); inputRef.current[data.length - 1].current.focus(); } else { inputRef.current[focus].current.focus(); } }; const onFocusNext = (value, index) => { if (index < data.length - 1 && value) { inputRef.current[index + 1].current.focus(); setFocus(index + 1); } if (index === data.length - 1) { setFocus(-1); inputRef.current[index].current.blur(); } otpValue[index] = value; setOtpValue([...otpValue]); }; const onFocusPrevious = (key, index) => { if (key === 'Backspace' && index !== 0) { inputRef.current[index - 1].current.focus(); setFocus(index - 1); otpValue[index - 1] = ''; setOtpValue([...otpValue]); } else if (key === 'Backspace' && index === 0) { otpValue[0] = ''; } }; if (otpCount < 4 && otpCount > 6) { throw 'OTP Count min is 4 and max is 6'; } const inputProps = { inputRef, otpValue, onPress, onFocusNext, onFocusPrevious, setFocus, setOtpValue, focus, autoFocus, containerStyle, inputStyle, textStyle, focusColor, otpCount, editable, enteringAnimated, exitingAnimated, rest }; (0, _react.useEffect)(() => { onCodeChanged && onCodeChanged(Number(otpValue.join(''))); if (otpValue && Number(otpValue.join('').length === otpCount) && onCodeFilled) { onCodeFilled(Number(otpValue.join(''))); } }, [otpValue]); return /*#__PURE__*/_react.default.createElement(OtpContext.Provider, { value: inputProps }, /*#__PURE__*/_react.default.createElement(_reactNative.View, { style: [styles.rowCenter, styles.container] }, data.map((_, i) => { return /*#__PURE__*/_react.default.createElement(OtpItem, { key: i, i: i }); }))); }; exports.OtpInput = OtpInput; const styles = _reactNative.StyleSheet.create({ container: { width: width, height: 100 }, rowCenter: { flexDirection: 'row', alignItems: 'center', justifyContent: 'center' }, inputSize: { height: 60, width: 45, marginHorizontal: 8 }, input: { alignItems: 'center', justifyContent: 'center', backgroundColor: '#FFFFFF', borderRadius: 8, shadowOpacity: 0.09, shadowColor: '#000', shadowOffset: { width: 0, height: 2 }, shadowRadius: 10, elevation: 3 }, text: { fontWeight: '600', fontSize: 26, color: '#2b4156' }, overlay: { position: 'absolute' } }); var _default = exports.default = OtpInput; //# sourceMappingURL=index.js.map