react-phone-input-pro
Version:
Phone number input component for react to format phone numbers according to selected countries in real time.
160 lines (159 loc) • 9.03 kB
JavaScript
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { useEffect, useRef, useState } from 'react';
import { c } from '../data/countries';
import React from 'react';
import { onClickOutside } from '../utils/stylingMethods';
import Arrow from './Arrow';
import { DROPDOWN_PARENT_CLASS, DROPDOWN_BUTTON_CLASS, DROPDOWN_BUTTON_FOCUS_CLASS, DROPDOWN_BUTTON_TEXT_CLASS, DROPDOWN_ARROW_PARENT_CLASS, SELECTED_FLAG_CLASS, FLAG_CLASS, LIST_CLASS, LIST_ITEM_CLASS, LIST_ITEM_BUTTON_CLASS, DROPDOWN_INPUT_PARENT_CLASS, DROPDOWN_INPUT_CLASS, NO_OPTION_CLASS, DROPDOWN_TOP_CLASS, DROPDOWN_BUTTON_OFF_CLASS, FORM_FOCUS_CLASS, SHOW_CLASS, } from '../utils/cssClassNames';
export const CountrySelector = (props) => {
const selector = useRef();
const [imgErr, setImgErr] = useState(true);
const [selectedOption, setSelectedOption] = useState();
const activeOption = useRef();
const shouldShowDrpDwn = useRef(true);
const drpBtn = useRef();
const selectorInput = useRef();
const [search, setSearch] = useState('');
const noOptions = useRef(false);
const [clickedOutside, setClickedOutside] = useState(true);
const [isButtonActive, setIsButtonActive] = useState(false);
useEffect(() => {
const img = new Image();
img.onload = () => {
setSelectedOption(props.flags === undefined || props.flags
? props.defaultCountry.fg
: props.fullIsoCode
? props.defaultCountry.c
: props.defaultCountry.c_sm);
setImgErr(false);
};
img.onerror = () => {
setSelectedOption(props.fullIsoCode ? props.defaultCountry.c : props.defaultCountry.c_sm);
setImgErr(true);
};
img.src = c[0].fg;
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
useEffect(() => {
if (selector.current && props.input && drpBtn.current) {
onClickOutside(selector.current, props.input, drpBtn.current, () => {
setClickedOutside(true);
setIsButtonActive(false);
});
props.drpButton(drpBtn.current);
props.list(selector.current);
}
}, [props]);
const getSelector = () => {
setClickedOutside(false);
setIsButtonActive(true);
if (drpBtn.current) {
const offset = drpBtn.current.getBoundingClientRect();
if (offset.bottom > 500) {
selector.current && shouldShowDrpDwn.current && selector.current.classList.add(DROPDOWN_TOP_CLASS);
}
else {
selector.current && shouldShowDrpDwn.current && selector.current.classList.remove(DROPDOWN_TOP_CLASS);
}
}
selector.current && shouldShowDrpDwn.current && selector.current.classList.toggle(SHOW_CLASS);
props.input.classList.add(FORM_FOCUS_CLASS);
};
const menuStyle = props.onlyCountries
? props.onlyCountries.length < 5
? {
height: 'auto',
}
: {}
: {};
const selectOption = (country, index) => {
setClickedOutside(true);
changeCountry(country['f'], country['d'], country['p']);
setSelectedOption((props.flags === undefined || props.flags) && !imgErr
? country['fg']
: props.fullIsoCode
? country['c']
: country['c_sm']);
activeOption.current = index;
selector.current && shouldShowDrpDwn.current && selector.current.classList.remove(SHOW_CLASS);
};
const countrySelectorStyle = { borderRadius: '4px 0px 0px 4px' };
const changeCountry = (format, code, placeholder) => __awaiter(void 0, void 0, void 0, function* () {
var _a;
props.setFormat({
format,
placeholder,
});
(_a = props.mainInput) === null || _a === void 0 ? void 0 : _a.focus();
props.setCountryCode(code);
});
const countryOptions = (ar) => {
const options = props.onlyCountries
? ar.filter((country) => {
var _a, _b, _c, _d;
const name = country['n'].toLocaleLowerCase();
if (search) {
return ((((_a = props.onlyCountries) === null || _a === void 0 ? void 0 : _a.includes(country['c'])) || ((_b = props.onlyCountries) === null || _b === void 0 ? void 0 : _b.includes(country['c_sm']))) &&
name.startsWith(search));
}
else {
return ((_c = props.onlyCountries) === null || _c === void 0 ? void 0 : _c.includes(country['c'])) || ((_d = props.onlyCountries) === null || _d === void 0 ? void 0 : _d.includes(country['c_sm']));
}
})
: ar.filter((country) => {
const name = country['n'].toLocaleLowerCase();
if (search) {
return name.startsWith(search);
}
else {
return country;
}
});
shouldShowDrpDwn.current = (options.length && options.length > 1) || search ? true : false;
if (!shouldShowDrpDwn.current || props.disabled) {
drpBtn.current && drpBtn.current.classList.add(DROPDOWN_BUTTON_OFF_CLASS);
}
noOptions.current = options.length ? false : true;
return options;
};
return (React.createElement("div", { className: DROPDOWN_PARENT_CLASS },
React.createElement("button", { disabled: props.disabled, className: DROPDOWN_BUTTON_CLASS, ref: (ref) => (drpBtn.current = ref), style: countrySelectorStyle, onMouseOver: () => setClickedOutside(false), onMouseOut: () => !isButtonActive && setClickedOutside(true), onClick: getSelector, type: 'button' },
React.createElement("div", { className: DROPDOWN_BUTTON_TEXT_CLASS },
(props.flags === undefined || props.flags) && !imgErr ? (React.createElement("img", { src: selectedOption, className: SELECTED_FLAG_CLASS, alt: selectedOption })) : (React.createElement("span", null, selectedOption)),
(props.onlyCountries &&
props.onlyCountries.length < 2 &&
(props.onlyCountries[0] === props.defaultCountry.c_sm ||
props.onlyCountries[0] === props.defaultCountry.c)) ||
props.disabled ? ('') : (React.createElement("div", { className: DROPDOWN_ARROW_PARENT_CLASS },
React.createElement(Arrow, { color: clickedOutside ? 'rgb(108, 108, 108)' : 'rgb(0, 145, 255)' }))))),
React.createElement("div", { style: menuStyle, ref: (ref) => (selector.current = ref), className: LIST_CLASS },
(props.searchOption === undefined || props.searchOption) && (React.createElement("div", { className: DROPDOWN_INPUT_PARENT_CLASS },
React.createElement("input", { type: 'search', placeholder: 'Search...', ref: (ref) => (selectorInput.current = ref), className: DROPDOWN_INPUT_CLASS, onClick: () => {
drpBtn.current && drpBtn.current.classList.add(DROPDOWN_BUTTON_FOCUS_CLASS);
}, onChange: (e) => {
setSearch(e.currentTarget.value.toLocaleLowerCase());
} }))),
React.createElement("div", { className: LIST_ITEM_CLASS },
React.createElement("div", null,
countryOptions(c).map((country, index) => {
return (React.createElement("button", { key: index, onClick: () => {
selectOption(country, index);
}, onTouchEnd: () => {
drpBtn.current && drpBtn.current.classList.add(DROPDOWN_BUTTON_FOCUS_CLASS);
}, className: LIST_ITEM_BUTTON_CLASS, type: 'button' },
(props.flags === undefined || props.flags) && !imgErr ? (React.createElement("img", { src: country['fg'], alt: '', className: FLAG_CLASS })) : (''),
' ',
country['n'],
" ",
country['d']));
}),
noOptions.current && React.createElement("p", { className: NO_OPTION_CLASS }, "No options"))))));
};