|
| 1 | +"use client"; |
| 2 | +"use strict"; |
| 3 | +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { |
| 4 | + if (k2 === undefined) k2 = k; |
| 5 | + var desc = Object.getOwnPropertyDescriptor(m, k); |
| 6 | + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { |
| 7 | + desc = { enumerable: true, get: function() { return m[k]; } }; |
| 8 | + } |
| 9 | + Object.defineProperty(o, k2, desc); |
| 10 | +}) : (function(o, m, k, k2) { |
| 11 | + if (k2 === undefined) k2 = k; |
| 12 | + o[k2] = m[k]; |
| 13 | +})); |
| 14 | +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { |
| 15 | + Object.defineProperty(o, "default", { enumerable: true, value: v }); |
| 16 | +}) : function(o, v) { |
| 17 | + o["default"] = v; |
| 18 | +}); |
| 19 | +var __importStar = (this && this.__importStar) || (function () { |
| 20 | + var ownKeys = function(o) { |
| 21 | + ownKeys = Object.getOwnPropertyNames || function (o) { |
| 22 | + var ar = []; |
| 23 | + for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; |
| 24 | + return ar; |
| 25 | + }; |
| 26 | + return ownKeys(o); |
| 27 | + }; |
| 28 | + return function (mod) { |
| 29 | + if (mod && mod.__esModule) return mod; |
| 30 | + var result = {}; |
| 31 | + if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); |
| 32 | + __setModuleDefault(result, mod); |
| 33 | + return result; |
| 34 | + }; |
| 35 | +})(); |
| 36 | +var __importDefault = (this && this.__importDefault) || function (mod) { |
| 37 | + return (mod && mod.__esModule) ? mod : { "default": mod }; |
| 38 | +}; |
| 39 | +Object.defineProperty(exports, "__esModule", { value: true }); |
| 40 | +exports.usePhone = exports.useMask = exports.parsePhoneNumber = exports.getDefaultISO2Code = exports.checkValidity = exports.getFormattedNumber = exports.cleanInput = exports.displayFormat = exports.getRawValue = exports.getCountry = exports.getMetadata = void 0; |
| 41 | +const react_1 = require("react"); |
| 42 | +const phoneLocale = __importStar(require("./locale")); |
| 43 | +const countries_json_1 = __importDefault(require("./metadata/countries.json")); |
| 44 | +const timezones_json_1 = __importDefault(require("./metadata/timezones.json")); |
| 45 | +const validations_json_1 = __importDefault(require("./metadata/validations.json")); |
| 46 | +const slots = new Set("."); |
| 47 | +const getMetadata = (rawValue, countriesList = countries_json_1.default, country = null) => { |
| 48 | + country = country == null && rawValue.startsWith("44") ? "gb" : country; |
| 49 | + if (country != null) |
| 50 | + countriesList = countriesList.filter((c) => c[0] === country); |
| 51 | + return [...countriesList].sort((a, b) => b[2].length - a[2].length).find((c) => rawValue.startsWith(c[2])); |
| 52 | +}; |
| 53 | +exports.getMetadata = getMetadata; |
| 54 | +const getCountry = (countryCode) => { |
| 55 | + return countries_json_1.default.find(([iso]) => iso === countryCode); |
| 56 | +}; |
| 57 | +exports.getCountry = getCountry; |
| 58 | +const getRawValue = (value) => { |
| 59 | + if (typeof value === "string") |
| 60 | + return value.replaceAll(/\D/g, ""); |
| 61 | + return [value === null || value === void 0 ? void 0 : value.countryCode, value === null || value === void 0 ? void 0 : value.areaCode, value === null || value === void 0 ? void 0 : value.phoneNumber].filter(Boolean).join(""); |
| 62 | +}; |
| 63 | +exports.getRawValue = getRawValue; |
| 64 | +const displayFormat = (value) => { |
| 65 | + /** Returns the formatted value that can be displayed as an actual input value */ |
| 66 | + return value.replace(/[.\s\D]+$/, "").replace(/(\(\d+)$/, "$1)"); |
| 67 | +}; |
| 68 | +exports.displayFormat = displayFormat; |
| 69 | +const cleanInput = (input, pattern) => { |
| 70 | + input = input.match(/\d/g) || []; |
| 71 | + return Array.from(pattern, c => input[0] === c || slots.has(c) ? input.shift() || c : c); |
| 72 | +}; |
| 73 | +exports.cleanInput = cleanInput; |
| 74 | +const getFormattedNumber = (rawValue, pattern) => { |
| 75 | + var _a; |
| 76 | + /** Returns the reformatted input value based on the given pattern */ |
| 77 | + if (/^\+\D*?$/.test(rawValue)) |
| 78 | + return "+"; |
| 79 | + pattern = pattern || ((_a = (0, exports.getMetadata)(rawValue)) === null || _a === void 0 ? void 0 : _a[3]) || ""; |
| 80 | + return (0, exports.displayFormat)((0, exports.cleanInput)(rawValue, pattern.replaceAll(/\d/g, ".")).join("")); |
| 81 | +}; |
| 82 | +exports.getFormattedNumber = getFormattedNumber; |
| 83 | +const checkValidity = (metadata, strict = false) => { |
| 84 | + /** Checks if both the area code and phone number match the validation pattern */ |
| 85 | + const pattern = validations_json_1.default[metadata.isoCode][Number(strict)]; |
| 86 | + return new RegExp(pattern).test([metadata.areaCode, metadata.phoneNumber].filter(Boolean).join("")); |
| 87 | +}; |
| 88 | +exports.checkValidity = checkValidity; |
| 89 | +const getDefaultISO2Code = () => { |
| 90 | + /** Returns the default ISO2 code, based on the user's timezone */ |
| 91 | + return (timezones_json_1.default[Intl.DateTimeFormat().resolvedOptions().timeZone] || "") || "us"; |
| 92 | +}; |
| 93 | +exports.getDefaultISO2Code = getDefaultISO2Code; |
| 94 | +const parsePhoneNumber = (formattedNumber, countriesList = countries_json_1.default, country = null) => { |
| 95 | + var _a; |
| 96 | + const value = (0, exports.getRawValue)(formattedNumber); |
| 97 | + const isoCode = ((_a = (0, exports.getMetadata)(value, countriesList, country)) === null || _a === void 0 ? void 0 : _a[0]) || (0, exports.getDefaultISO2Code)(); |
| 98 | + const countryCodePattern = /\+\d+/; |
| 99 | + const areaCodePattern = /^\+\d+\s\(?(\d+)/; |
| 100 | + /** Parses the matching partials of the phone number by predefined regex patterns */ |
| 101 | + const countryCodeMatch = formattedNumber ? (formattedNumber.match(countryCodePattern) || []) : []; |
| 102 | + const areaCodeMatch = formattedNumber ? (formattedNumber.match(areaCodePattern) || []) : []; |
| 103 | + /** Converts the parsed values of the country and area codes to integers if values present */ |
| 104 | + const countryCode = countryCodeMatch.length > 0 ? parseInt(countryCodeMatch[0]) : null; |
| 105 | + const areaCode = areaCodeMatch.length > 1 ? areaCodeMatch[1] : null; |
| 106 | + /** Parses the phone number by removing the country and area codes from the formatted value */ |
| 107 | + const phoneNumberPattern = new RegExp(`^${countryCode}${(areaCode || "")}(\\d+)`); |
| 108 | + const phoneNumberMatch = value ? (value.match(phoneNumberPattern) || []) : []; |
| 109 | + const phoneNumber = phoneNumberMatch.length > 1 ? phoneNumberMatch[1] : null; |
| 110 | + return { countryCode, areaCode, phoneNumber, isoCode }; |
| 111 | +}; |
| 112 | +exports.parsePhoneNumber = parsePhoneNumber; |
| 113 | +const useMask = (pattern) => { |
| 114 | + const backRef = (0, react_1.useRef)(false); |
| 115 | + const clean = (0, react_1.useCallback)((input) => { |
| 116 | + return (0, exports.cleanInput)(input, pattern.replaceAll(/\d/g, ".")); |
| 117 | + }, [pattern]); |
| 118 | + const first = (0, react_1.useMemo)(() => { |
| 119 | + return [...pattern].findIndex(c => slots.has(c)); |
| 120 | + }, [pattern]); |
| 121 | + const prev = (0, react_1.useMemo)((j = 0) => { |
| 122 | + return Array.from(pattern.replaceAll(/\d/g, "."), (c, i) => { |
| 123 | + return slots.has(c) ? j = i + 1 : j; |
| 124 | + }); |
| 125 | + }, [pattern]); |
| 126 | + const onKeyDown = (0, react_1.useCallback)((event) => { |
| 127 | + backRef.current = event.key === "Backspace"; |
| 128 | + }, []); |
| 129 | + const onInput = (0, react_1.useCallback)(({ target }) => { |
| 130 | + const [i, j] = [target.selectionStart, target.selectionEnd].map((i) => { |
| 131 | + i = clean(target.value.slice(0, i)).findIndex(c => slots.has(c)); |
| 132 | + return i < 0 ? prev[prev.length - 1] : backRef.current ? prev[i - 1] || first : i; |
| 133 | + }); |
| 134 | + target.value = (0, exports.getFormattedNumber)(target.value, pattern); |
| 135 | + target.setSelectionRange(i, j); |
| 136 | + backRef.current = false; |
| 137 | + }, [clean, first, pattern, prev]); |
| 138 | + return { |
| 139 | + onInput, |
| 140 | + onKeyDown, |
| 141 | + }; |
| 142 | +}; |
| 143 | +exports.useMask = useMask; |
| 144 | +const usePhone = ({ query = "", locale = "", country = "", distinct = false, countryCode = "", initialValue = "", onlyCountries = [], excludeCountries = [], preferredCountries = [], disableParentheses = false, }) => { |
| 145 | + var _a; |
| 146 | + const defaultValue = (0, exports.getRawValue)(initialValue); |
| 147 | + const defaultMetadata = (0, exports.getMetadata)(defaultValue) || countries_json_1.default.find(([iso]) => iso === country); |
| 148 | + const defaultValueState = defaultValue || ((_a = countries_json_1.default.find(([iso]) => iso === (defaultMetadata === null || defaultMetadata === void 0 ? void 0 : defaultMetadata[0]))) === null || _a === void 0 ? void 0 : _a[2]); |
| 149 | + const [value, setValue] = (0, react_1.useState)(defaultValueState); |
| 150 | + const countriesOnly = (0, react_1.useMemo)(() => { |
| 151 | + const allowList = onlyCountries.length > 0 ? onlyCountries : countries_json_1.default.map(([iso]) => iso); |
| 152 | + return countries_json_1.default.filter(([iso, _1, dial]) => { |
| 153 | + return (allowList.includes(iso) || allowList.includes(dial)) && !excludeCountries.includes(iso) && !excludeCountries.includes(dial); |
| 154 | + }); |
| 155 | + }, [onlyCountries, excludeCountries]); |
| 156 | + const countriesList = (0, react_1.useMemo)(() => { |
| 157 | + const filteredCountries = countriesOnly.filter(([_1, name, dial, mask]) => { |
| 158 | + var _a; |
| 159 | + const q = query.toLowerCase(); |
| 160 | + const countries = locale && ((_a = (phoneLocale[locale])) === null || _a === void 0 ? void 0 : _a.countries); |
| 161 | + const localized = countries && (countries[name] || "").toLowerCase(); |
| 162 | + return [localized, name.toLowerCase(), dial, mask].some(component => component.includes(q)); |
| 163 | + }); |
| 164 | + const seen = new Set(); |
| 165 | + const whitelistCountries = [ |
| 166 | + ...filteredCountries.filter(([iso]) => preferredCountries.includes(iso)), |
| 167 | + ...filteredCountries.filter(([iso]) => !preferredCountries.includes(iso)), |
| 168 | + ]; |
| 169 | + if (!distinct) |
| 170 | + return whitelistCountries; |
| 171 | + return whitelistCountries.filter(([iso]) => !seen.has(iso) && seen.add(iso)); |
| 172 | + }, [countriesOnly, preferredCountries, distinct, locale, query]); |
| 173 | + const metadata = (0, react_1.useMemo)(() => { |
| 174 | + const calculatedMetadata = (0, exports.getMetadata)((0, exports.getRawValue)(value), countriesList, countryCode); |
| 175 | + if (countriesList.find(([iso]) => iso === (calculatedMetadata === null || calculatedMetadata === void 0 ? void 0 : calculatedMetadata[0]) || iso === (defaultMetadata === null || defaultMetadata === void 0 ? void 0 : defaultMetadata[0]))) { |
| 176 | + return calculatedMetadata || defaultMetadata; |
| 177 | + } |
| 178 | + return countriesList[0]; |
| 179 | + }, [countriesList, countryCode, defaultMetadata, value]); |
| 180 | + const pattern = (0, react_1.useMemo)(() => { |
| 181 | + const mask = (metadata === null || metadata === void 0 ? void 0 : metadata[3]) || (defaultMetadata === null || defaultMetadata === void 0 ? void 0 : defaultMetadata[3]) || ""; |
| 182 | + return disableParentheses ? mask.replace(/[()]/g, "") : mask; |
| 183 | + }, [disableParentheses, defaultMetadata, metadata]); |
| 184 | + return { |
| 185 | + value, |
| 186 | + pattern, |
| 187 | + metadata, |
| 188 | + setValue, |
| 189 | + countriesList, |
| 190 | + }; |
| 191 | +}; |
| 192 | +exports.usePhone = usePhone; |
0 commit comments