@pakenfit/react-native-pin-input
Version:
Phone Pin Input for React Native
161 lines (160 loc) • 6.91 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.PinInput = void 0;
var _react = _interopRequireWildcard(require("react"));
var _reactNative = require("react-native");
var _Input = require("./Input");
var Clipboard = _interopRequireWildcard(require("expo-clipboard"));
var _constants = require("../constants");
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
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); }
const PinInput = exports.PinInput = /*#__PURE__*/(0, _react.forwardRef)((_ref, ref) => {
let {
length = 4,
inputProps,
inputStyle,
containerProps,
containerStyle,
onFillEnded,
autoFocus = true
} = _ref;
const pins = Array.from({
length
}).map((_, i) => i);
const inputRefs = (0, _react.useRef)([]);
const pinsValues = (0, _react.useRef)([]);
const iosOTP = (0, _react.useRef)({
key: '',
index: null
});
const [keyPressed, setKeyPressed] = (0, _react.useState)(false);
const handleOTP = (0, _react.useCallback)(otp => {
const regexp = new RegExp(`[0-9]{${length}}`);
const otps = otp.match(regexp);
if (otps !== null && otps !== void 0 && otps.length) {
const otpSplits = otp.split('');
otpSplits.forEach((otpSplit, i) => {
var _inputRefs$current$i;
return inputRefs === null || inputRefs === void 0 || (_inputRefs$current$i = inputRefs.current[i]) === null || _inputRefs$current$i === void 0 ? void 0 : _inputRefs$current$i.setNativeProps({
text: otpSplit
});
});
onFillEnded === null || onFillEnded === void 0 || onFillEnded(otp);
iosOTP.current = {
key: '',
index: null
};
_reactNative.Keyboard.dismiss();
return true;
}
return false;
}, [length, onFillEnded]);
const handleChangeText = (0, _react.useCallback)(async (text, index) => {
const copiedText = await Clipboard.getStringAsync();
if (copiedText.includes(text) && !keyPressed) {
const otpHandled = handleOTP(copiedText);
if (otpHandled) {
return;
}
}
pinsValues.current[index] = text;
if (index + 1 <= pins.length - 1) {
var _inputRefs$current;
inputRefs === null || inputRefs === void 0 || (_inputRefs$current = inputRefs.current[index + 1]) === null || _inputRefs$current === void 0 || _inputRefs$current.focus();
} else {
onFillEnded === null || onFillEnded === void 0 || onFillEnded(pinsValues.current.join(''));
setKeyPressed(false);
_reactNative.Keyboard.dismiss();
}
}, [handleOTP, keyPressed, onFillEnded, pins.length]);
const onKeyPress = (0, _react.useCallback)((event, index) => {
event.persist();
setKeyPressed(true);
if (_constants.IS_IOS && Number.isInteger(Number(event.nativeEvent.key))) {
if (iosOTP.current.index === null) {
iosOTP.current = {
key: event.nativeEvent.key,
index
};
} else {
if (iosOTP.current.index === index) {
iosOTP.current = {
key: `${iosOTP.current.key}${event.nativeEvent.key}`,
index
};
} else {
iosOTP.current = {
key: '',
index: null
};
}
}
if (iosOTP.current.key.length === length) {
handleOTP(iosOTP.current.key);
return;
}
}
if (event.nativeEvent.key === 'Backspace') {
// Clear only the current digit if it has value
if (pinsValues.current[index]) {
pinsValues.current[index] = '';
// Don't move focus - stay on current field
// We only reset partial state, not the entire PIN
} else {
// Only move to previous field when current field is empty
if (index - 1 >= 0) {
var _inputRefs$current2;
inputRefs === null || inputRefs === void 0 || (_inputRefs$current2 = inputRefs.current[index - 1]) === null || _inputRefs$current2 === void 0 || _inputRefs$current2.focus();
}
}
setKeyPressed(false);
iosOTP.current = {
key: '',
index: null
};
}
}, [handleOTP, length]);
const clear = (0, _react.useCallback)(() => {
var _inputRefs$current$;
pinsValues.current = [];
inputRefs.current.forEach(input => {
input === null || input === void 0 || input.setNativeProps({
text: '',
placeholder: '0'
});
});
(_inputRefs$current$ = inputRefs.current[0]) === null || _inputRefs$current$ === void 0 || _inputRefs$current$.focus();
}, []);
(0, _react.useImperativeHandle)(ref, () => ({
clear
}), [clear]);
return /*#__PURE__*/_react.default.createElement(_reactNative.View, _extends({
style: [styles.container, containerStyle]
}, containerProps), pins.map(pin => {
return /*#__PURE__*/_react.default.createElement(_Input.Input, _extends({}, inputProps, {
autoFocus: autoFocus && pin === 0,
ref: input => inputRefs === null || inputRefs === void 0 ? void 0 : inputRefs.current.push(input),
key: pin,
style: inputStyle,
onChangeText: text => handleChangeText(text, pin),
onKeyPress: event => onKeyPress(event, pin),
autoComplete: "sms-otp",
textContentType: "oneTimeCode",
keyboardType: "numeric"
}));
}));
});
PinInput.displayName = 'PinInput';
const styles = _reactNative.StyleSheet.create({
container: {
display: 'flex',
flexDirection: 'row',
gap: 5,
alignItems: 'center',
justifyContent: 'center'
}
});
//# sourceMappingURL=PinInput.js.map