UNPKG

rn-phone-input-field

Version:

A React Native phone number input component built from scratch, featuring a text input for number entry, a custom dropdown for selecting country codes, and validation logic using regex or country-specific rules. It supports formatting, localization, and s

159 lines (156 loc) 9.24 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __rest = (this && this.__rest) || function (s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]]; } return t; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); var react_1 = __importStar(require("react")); var react_native_1 = require("react-native"); var assets_1 = __importDefault(require("../assets/assets")); var CountryPickerModal_1 = __importDefault(require("../country-picker/CountryPickerModal")); var styles_1 = __importDefault(require("../../styles")); var phoneUtils_1 = require("./phoneUtils"); var PhoneInput = (0, react_1.forwardRef)(function (_a, ref) { var onChangeText = _a.onChangeText, onSelectCountryCode = _a.onSelectCountryCode, _b = _a.defaultCountry, defaultCountry = _b === void 0 ? 'US' : _b, _c = _a.defaultValue, defaultValue = _c === void 0 ? '' : _c, containerStyle = _a.containerStyle, placeholder = _a.placeholder, inputProps = _a.inputProps, textInputStyle = _a.textInputStyle, downArrowIcon = _a.downArrowIcon, _d = _a.placeholderColor, placeholderColor = _d === void 0 ? '#999' : _d, iconContainerStyle = _a.iconContainerStyle, codeTextStyle = _a.codeTextStyle, _e = _a.darkMode, darkMode = _e === void 0 ? false : _e, searchInputProps = _a.searchInputProps; var countryPickerRef = (0, react_1.useRef)(null); var onSelectCountryCodeRef = (0, react_1.useRef)(onSelectCountryCode); var _f = (0, react_1.useState)(function () { return (0, phoneUtils_1.getCountryByCode)(defaultCountry); }), selectedCountry = _f[0], setSelectedCountry = _f[1]; var _g = (0, react_1.useState)(''), value = _g[0], setValue = _g[1]; var _h = inputProps || {}, _j = _h.keyboardType, keyboardType = _j === void 0 ? 'phone-pad' : _j, inputPropsMaxLength = _h.maxLength, inputPropsOnChangeText = _h.onChangeText, inputPropsStyle = _h.style, restInputProps = __rest(_h, ["keyboardType", "maxLength", "onChangeText", "style"]); var themedStyles = (0, react_1.useMemo)(function () { return (0, styles_1.default)(darkMode); }, [darkMode]); var maxNationalNumberLength = (0, react_1.useMemo)(function () { return (0, phoneUtils_1.getMaxNationalNumberLength)(selectedCountry); }, [selectedCountry]); var inputMaxLength = (0, react_1.useMemo)(function () { if (typeof inputPropsMaxLength !== 'number') { return maxNationalNumberLength; } return Math.min(inputPropsMaxLength, maxNationalNumberLength); }, [inputPropsMaxLength, maxNationalNumberLength]); (0, react_1.useEffect)(function () { onSelectCountryCodeRef.current = onSelectCountryCode; }, [onSelectCountryCode]); var emitSelectedCountry = (0, react_1.useCallback)(function (country) { var _a; (_a = onSelectCountryCodeRef.current) === null || _a === void 0 ? void 0 : _a.call(onSelectCountryCodeRef, (0, phoneUtils_1.toSelectedCountryPayload)(country)); }, []); var applyValue = (0, react_1.useCallback)(function (nextValue) { var parsedValue = (0, phoneUtils_1.parsePhoneValue)(nextValue, defaultCountry); var nextCountry = parsedValue.country || (0, phoneUtils_1.getCountryByCode)(defaultCountry); var sanitizedValue = (0, phoneUtils_1.sanitizePhoneInputValue)(parsedValue.nationalNumber, nextCountry); setSelectedCountry(nextCountry); setValue(sanitizedValue); emitSelectedCountry(nextCountry); }, [defaultCountry, emitSelectedCountry]); (0, react_1.useEffect)(function () { applyValue(defaultValue); }, [applyValue, defaultValue]); var handleTextChange = (0, react_1.useCallback)(function (nextValue) { var sanitizedValue = (0, phoneUtils_1.sanitizePhoneInputValue)(nextValue, selectedCountry); setValue(sanitizedValue); onChangeText === null || onChangeText === void 0 ? void 0 : onChangeText(sanitizedValue); inputPropsOnChangeText === null || inputPropsOnChangeText === void 0 ? void 0 : inputPropsOnChangeText(sanitizedValue); }, [inputPropsOnChangeText, onChangeText, selectedCountry]); var handleCountrySelect = (0, react_1.useCallback)(function (country) { var sanitizedValue = (0, phoneUtils_1.sanitizePhoneInputValue)(value, country); setSelectedCountry(country); setValue(sanitizedValue); emitSelectedCountry(country); if (sanitizedValue !== value) { onChangeText === null || onChangeText === void 0 ? void 0 : onChangeText(sanitizedValue); inputPropsOnChangeText === null || inputPropsOnChangeText === void 0 ? void 0 : inputPropsOnChangeText(sanitizedValue); } }, [emitSelectedCountry, inputPropsOnChangeText, onChangeText, value]); var openCountryPicker = (0, react_1.useCallback)(function () { var _a; (_a = countryPickerRef.current) === null || _a === void 0 ? void 0 : _a.openModal(); }, []); var defaultDownArrowIcon = (0, react_1.useMemo)(function () { return (<react_native_1.Image source={{ uri: darkMode ? assets_1.default.downArrowDarkIcon : assets_1.default.downArrowDefaultIcon, }} resizeMode="contain" style={{ height: 12, width: 12 }}/>); }, [darkMode]); (0, react_1.useImperativeHandle)(ref, function () { return ({ isValidNumber: function (phoneNumber) { return (0, phoneUtils_1.isValidForCountry)(selectedCountry, phoneNumber); }, onChangeText: function (nextValue) { handleTextChange(nextValue); }, defaultCountry: function (code) { var nextCountry = (0, phoneUtils_1.getCountryByCode)(code); var sanitizedValue = (0, phoneUtils_1.sanitizePhoneInputValue)(value, nextCountry); setSelectedCountry(nextCountry); setValue(sanitizedValue); emitSelectedCountry(nextCountry); if (sanitizedValue !== value) { onChangeText === null || onChangeText === void 0 ? void 0 : onChangeText(sanitizedValue); inputPropsOnChangeText === null || inputPropsOnChangeText === void 0 ? void 0 : inputPropsOnChangeText(sanitizedValue); } }, defaultValue: function (text) { applyValue(text); }, }); }, [ applyValue, emitSelectedCountry, handleTextChange, inputPropsOnChangeText, onChangeText, selectedCountry, value, ]); return (<> <react_native_1.View style={[themedStyles.container, containerStyle]}> <react_native_1.TouchableOpacity activeOpacity={0.7} onPress={openCountryPicker} style={[themedStyles.flexRow, iconContainerStyle]} accessibilityLabel="Select country code" accessibilityRole="button"> <react_native_1.Text style={themedStyles.ft28}>{selectedCountry.icon}</react_native_1.Text> <react_native_1.Text style={[themedStyles.ft16, codeTextStyle]}> +{selectedCountry.callingCode} </react_native_1.Text> {downArrowIcon || defaultDownArrowIcon} </react_native_1.TouchableOpacity> <react_native_1.TextInput {...restInputProps} value={value} onChangeText={handleTextChange} placeholder={placeholder} placeholderTextColor={placeholderColor} keyboardType={keyboardType} maxLength={inputMaxLength} style={[ themedStyles.ft16, themedStyles.width75, textInputStyle, inputPropsStyle, ]}/> </react_native_1.View> <CountryPickerModal_1.default ref={countryPickerRef} darkMode={darkMode} onSelect={handleCountrySelect} searchInputProps={searchInputProps}/> </>); }); PhoneInput.displayName = 'PhoneInput'; exports.default = PhoneInput;