react-phone-number-input-mui
Version:
Telephone input for React and Material-UI. Fork of catamphetamine awesome work of react-phone-number-input.
401 lines (355 loc) • 15.1 kB
JavaScript
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.getPreSelectedCountry = getPreSelectedCountry;
exports.getCountrySelectOptions = getCountrySelectOptions;
exports.parsePhoneNumber = parsePhoneNumber;
exports.generateNationalNumberDigits = generateNationalNumberDigits;
exports.migrateParsedInputForNewCountry = migrateParsedInputForNewCountry;
exports.e164 = e164;
exports.getCountryForParsedInput = getCountryForParsedInput;
exports.get_country_from_possibly_incomplete_international_phone_number = get_country_from_possibly_incomplete_international_phone_number;
exports.compare_strings = compare_strings;
exports.has_international_option = has_international_option;
exports.strip_country_calling_code = strip_country_calling_code;
exports.get_national_significant_number_part = get_national_significant_number_part;
exports.could_number_belong_to_country = could_number_belong_to_country;
var _custom = require('libphonenumber-js/custom');
/**
* Decides which country should be pre-selected
* when the phone number input component is first mounted.
* @param {object} parsedNumber - A parsed number object: `{ country, phone }`. Can be an empty object.
* @param {string?} country - Pre-defined country (two-letter code).
* @param {string[]?} countries - A list of countries available.
* @param {boolean} includeInternationalOption - Whether "International" country option is available.
* @param {object} metadata - `libphonenumber-js` metadata
* @return {string?}
*/
function getPreSelectedCountry(parsed_number, country, countries, includeInternationalOption, metadata) {
// If can get country from E.164 phone number
// then it overrides the `country` passed (or not passed).
if (parsed_number.country) {
// `country` will be left `undefined` in case of non-detection.
country = parsed_number.country;
}
// Only pre-select a country if it's in the available `countries` list.
if (countries && countries.indexOf(country) < 0) {
country = undefined;
}
// If there will be no "International" option
// then some `country` must be selected.
// It will still be the wrong country though.
// But still country `<select/>` can't be left in a broken state.
if (!country && !has_international_option(countries, includeInternationalOption) && countries && countries.length > 0) {
country = countries[0];
}
return country;
}
/**
* Generates a sorted list of country `<select/>` options.
* @param {string[]} countries - A list of two-letter ("ISO 3166-1 alpha-2") country codes.
* @param {object?} labels - Custom country labels. E.g. `{ RU: 'Россия', US: 'США', ... }`.
* @param {boolean} includeInternationalOption - Whether should include "International" option at the top of the list.
* @return {object[]} A list of objects having shape `{ value : string, label : string }`.
*/
// `default_country_names` argument will be removed in version 2.x
function getCountrySelectOptions(countries, country_names, includeInternationalOption, default_country_names) {
// Generates a `<Select/>` option for each country.
var country_select_options = countries.map(function (country) {
return {
value: country,
// `default_country_names` will be removed from here in version 2.x
label: country_names && country_names[country] || default_country_names[country]
};
});
// Sort the list of countries alphabetically.
country_select_options.sort(function (a, b) {
return compare_strings(a.label, b.label);
});
// Add the "International" option to the country list (if suitable)
if (has_international_option(countries, includeInternationalOption)) {
country_select_options.unshift({
label: country_names && country_names.ZZ || default_country_names.ZZ
});
}
return country_select_options;
}
/**
* Parses a E.164 phone number to an object having shape `{ country : string, phone : string }`.
* @param {string} value = E.164 phone number.
* @param {object} metadata - `libphonenumber-js` metadata
* @example
* parsePhoneNumber('+78005553535')
* // returns `{ country: 'RU', phone: '8005553535' }`
*/
function parsePhoneNumber(value, metadata) {
return (0, _custom.parseNumber)(value || '', metadata);
}
/**
* Generates national number digits for a parsed phone.
* May prepend national prefix.
* @param {object} parsedPhone - Object having shape `{ country : string, phone : string }`.
* @param {object} metadata - `libphonenumber-js` metadata
* @return {string}
* @example
* getNationalNumberDigits({ country: 'RU', phone: '8005553535' })
* // returns '88005553535'
*/
function generateNationalNumberDigits(parsed_phone, metadata) {
return (0, _custom.formatNumber)(parsed_phone, 'National', metadata).replace(/\D/g, '');
}
/**
* Migrates `<input/>` parsed `value` for the newly selected `country`.
* @param {string?} value - The `value` parsed from phone number `<input/>` (it's the `parsed_input` state property, not the `value` property).
* @param {string?} previousCountry - Previously selected country.
* @param {string?} newCountry - Newly selected country. Can't be same as previously selected country.
* @param {object} metadata - `libphonenumber-js` metadata.
* @return {string}
*/
function migrateParsedInputForNewCountry(value, previous_country, new_country, metadata) {
// If `parsed_input` is empty
// then no need to migrate anything.
if (!value) {
return value;
}
// If switching to some country.
// (from "International" or another country)
// If switching from "International" then `value` starts with a `+`.
// Otherwise it may or may not start with a `+`.
if (new_country) {
// If the phone number was entered in international format
// then migrate it to the newly selected country.
// The phone number may be incomplete.
// The phone number entered not necessarily starts with
// the previously selected country phone prefix.
if (value[0] === '+') {
// If the international phone number already contains
// any country calling code then trim the country calling code part.
// (that could also be the newly selected country phone code prefix as well)
// `value` doesn't neccessarily belong to `previous_country`.
// (e.g. if a user enters an international number
// not belonging to any of the reduced `countries` list)
value = strip_country_calling_code(value, previous_country, metadata);
// Prepend country calling code prefix
// for the newly selected country.
return '+' + (0, _custom.getCountryCallingCode)(new_country, metadata) + value;
}
}
// If switching to "International" from a country.
else {
// If the phone number was entered in national format.
if (value[0] !== '+') {
// Format the national phone number as an international one.
// The phone number entered not necessarily even starts with
// the previously selected country phone prefix.
// Even if the phone number belongs to whole another country
// it will still be parsed into some national phone number.
var partial_national_significant_number = get_national_significant_number_part(value, previous_country, metadata);
return (0, _custom.formatNumber)(partial_national_significant_number, previous_country, 'E.164', metadata);
}
}
return value;
}
/**
* Converts phone number digits to a (possibly incomplete) E.164 phone number.
* @param {string?} number - A possibly incomplete phone number digits string. Can be a possibly incomplete E.164 phone number.
* @param {string?} country
* @param {[object} metadata - `libphonenumber-js` metadata.
* @return {string?}
*/
function e164(number, country, metadata) {
if (!number) {
return;
}
// If the phone number is being input in international format.
if (number[0] === '+') {
// If it's just the `+` sign then return nothing.
if (number === '+') {
return;
}
// If there are any digits then the `value` is returned as is.
return number;
}
// For non-international phone numbers
// an accompanying country code is required.
if (!country) {
return;
}
var partial_national_significant_number = get_national_significant_number_part(number, country, metadata);
if (!partial_national_significant_number) {
return;
}
return (0, _custom.formatNumber)(partial_national_significant_number, country, 'E.164', metadata);
}
// If the phone number being input is an international one
// then tries to derive the country from the phone number.
// (regardless of whether there's any country currently selected)
/**
* @param {string} parsedInput - A possibly incomplete E.164 phone number.
* @param {string?} country - Currently selected country.
* @param {string[]?} countries - A list of available countries. If not passed then "all countries" are assumed.
* @param {boolean} includeInternationalOption - Whether "International" country option is available.
* @param {[object} metadata - `libphonenumber-js` metadata.
* @return {string?}
*/
function getCountryForParsedInput(parsed_input, country, countries, includeInternationalOption, metadata) {
if (parsed_input === '+') {
// Don't change the currently selected country yet.
return country;
}
var derived_country = get_country_from_possibly_incomplete_international_phone_number(parsed_input, metadata);
// If a phone number is being input in international form
// and the country can already be derived from it,
// then select that country.
if (derived_country && (!countries || countries.indexOf(derived_country) >= 0)) {
return derived_country;
}
// If "International" country option has not been disabled
// and the international phone number entered doesn't correspond
// to the currently selected country then reset the currently selected country.
else if (country && has_international_option(countries, includeInternationalOption) && !could_number_belong_to_country(parsed_input, country, metadata)) {
return undefined;
}
// Don't change the currently selected country.
return country;
}
/**
* Determines the country for a given (possibly incomplete) E.164 phone number.
* @param {string} number - A possibly incomplete E.164 phone number.
* @param {object} metadata - `libphonenumber-js` metadata.
* @return {string?}
*/
function get_country_from_possibly_incomplete_international_phone_number(number, metadata) {
var formatter = new _custom.AsYouType(null, metadata);
formatter.input(number);
// `001` is a special "non-geograpical entity" code
// in Google's `libphonenumber` library.
if (formatter.country === '001') {
return;
}
return formatter.country;
}
/**
* Compares two strings.
* A helper for `Array.sort()`.
*/
function compare_strings(a, b) {
// Use `String.localeCompare` if it's available.
// https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/String/localeCompare
// Which means everyone except IE <= 10 and Safari <= 10.
// `localeCompare()` is available in latest Node.js versions.
/* istanbul ignore else */
if (String.prototype.localeCompare) {
return a.localeCompare(b);
}
/* istanbul ignore next */
return a < b ? -1 : a > b ? 1 : 0;
}
/**
* Whether should add the "International" option to country `<select/>`.
*/
function has_international_option(countries, includeInternationalOption) {
// `includeInternationalOption` won't be `undefined` in version 2.x
// If this behaviour is explicitly set, then do as it says.
if (includeInternationalOption !== undefined) {
return includeInternationalOption;
}
// If no `countries` were specified
// then it means "the default behaviour"
// which means "include the International option".
if (!countries) {
return true;
}
// Will be removed in version 2.x
//
// If the list of `countries` has been overridden
// then only show "International" option
// if no countries have been left out.
// The reasoning is that if some countries were left out
// and a user selects "International" option
// then he can input a phone number for a non-included country
// and perhaps that's what a developer didn't encourage
// when he was reducing the set of selectable countries.
//
// There are `242` countries total in the default country list in version `1.1.7`.
//
return countries.length >= 242;
}
/**
* Strips `+${countryCallingCode}` prefix from an E.164 phone number.
* @param {string} number - (possibly incomplete) E.164 phone number.
* @param {string?} country - A possible country for this phone number.
* @param {object} metadata - `libphonenumber-js` metadata.
* @return {string}
*/
function strip_country_calling_code(number, country, metadata) {
// Just an optimization, so that it
// doesn't have to iterate through all country calling codes.
if (country) {
var country_calling_prefix = '+' + (0, _custom.getCountryCallingCode)(country, metadata);
// If `country` fits the actual `number`.
if (number.length < country_calling_prefix.length) {
if (country_calling_prefix.indexOf(number) === 0) {
return '';
}
} else {
if (number.indexOf(country_calling_prefix) === 0) {
return number.slice(country_calling_prefix.length);
}
}
}
// If `country` doesn't fit the actual `number`.
// Try all available country calling codes.
for (var _iterator = Object.keys(metadata.country_calling_codes), _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _iterator[Symbol.iterator]();;) {
var _ref;
if (_isArray) {
if (_i >= _iterator.length) break;
_ref = _iterator[_i++];
} else {
_i = _iterator.next();
if (_i.done) break;
_ref = _i.value;
}
var country_calling_code = _ref;
if (number.indexOf(country_calling_code) === '+'.length) {
return number.slice('+'.length + country_calling_code.length);
}
}
return '';
}
/**
* Parses a partially entered national phone number digits
* (or a partially entered E.164 international phone number)
* and returns the national significant number part.
* National significant number returned doesn't come with a national prefix.
* @param {string} number - National number digits. Or possibly incomplete E.164 phone number.
* @param {string?} country
* @param {object} metadata - `libphonenumber-js` metadata.
*/
function get_national_significant_number_part(number, country, metadata) {
// Create "as you type" formatter.
var formatter = new _custom.AsYouType(country, metadata);
// Input partial national phone number.
formatter.input(number);
// Return the parsed partial national phone number.
return formatter.getNationalNumber();
}
/**
* Checks if a partially entered E.164 phone number could belong to a country.
* @param {string} number
* @param {string} country
* @return {boolean}
*/
function could_number_belong_to_country(number, country, metadata) {
var country_calling_code = (0, _custom.getCountryCallingCode)(country, metadata);
var i = 0;
while (i + 1 < number.length && i < country_calling_code.length) {
if (number[i + 1] !== country_calling_code[i]) {
return false;
}
i++;
}
return true;
}
//# sourceMappingURL=input-control.js.map