UNPKG

react-intl-tel-input

Version:

Telephone input component. Rewrite intl-tel-input in React.js.

501 lines (424 loc) 12.2 kB
import React from 'react' import { CountryData } from '../types' export interface IntlTelInputProps { /** * Container CSS class name. * @default 'intl-tel-input' */ containerClassName?: string /** * Text input CSS class name. * @default '' */ inputClassName?: string /** * It's used as `input` field `name` attribute. * @default '' */ fieldName?: string /** * It's used as `input` field `id` attribute. * @default '' */ fieldId?: string /** * The value of the input field. Useful for making input value controlled from outside the component. */ value?: string /** * The value used to initialize input. This will only work on uncontrolled component. * @default '' */ defaultValue?: string /** * Countries data can be configured, it defaults to data defined in `AllCountries`. * @default AllCountries.getCountries() */ countriesData?: CountryData[] | null /** * Whether or not to allow the dropdown. If disabled, there is no dropdown arrow, and the selected flag is not clickable. * Also we display the selected flag on the right instead because it is just a marker of state. * @default true */ allowDropdown?: boolean /** * If there is just a dial code in the input: remove it on blur, and re-add it on focus. * @default true */ autoHideDialCode?: boolean /** * Add or remove input placeholder with an example number for the selected country. * @default true */ autoPlaceholder?: boolean /** * Change the placeholder generated by autoPlaceholder. Must return a string. * @default null */ customPlaceholder?: | ((placeholder: string, selectedCountryData: CountryData) => string) | null /** * Don't display the countries you specify. (Array) * @default [] */ excludeCountries?: string[] /** * Format the input value during initialisation. * @default true */ formatOnInit?: boolean /** * Display the country dial code next to the selected flag so it's not part of the typed number. * Note that this will disable nationalMode because technically we are dealing with international numbers, * but with the dial code separated. * @default false */ separateDialCode?: boolean /** * Default country. * @default '' */ defaultCountry?: string /** * GeoIp lookup function. * @default null */ geoIpLookup?: (countryCode: string) => void /** * Don't insert international dial codes. * @default true */ nationalMode?: boolean /** * Number type to use for placeholders. * @default 'MOBILE' */ numberType?: string /** * The function which can catch the "no this default country" exception. * @default null */ noCountryDataHandler?: (countryCode: string) => void /** * Display only these countries. * @default [] */ onlyCountries?: string[] /** * The countries at the top of the list. defaults to United States and United Kingdom. * @default ['us', 'gb'] */ preferredCountries?: string[] /** * Optional validation callback function. It returns validation status, input box value and selected country data. * @default null */ onPhoneNumberChange?: ( isValid: boolean, value: string, selectedCountryData: CountryData, fullNumber: string, extension: string, ) => void /** * Optional validation callback function. It returns validation status, input box value and selected country data. * @default null */ onPhoneNumberBlur?: ( isValid: boolean, value: string, selectedCountryData: CountryData, fullNumber: string, extension: string, event: React.FocusEvent<HTMLInputElement>, ) => void /** * Optional validation callback function. It returns validation status, input box value and selected country data. * @default null */ onPhoneNumberFocus?: ( isValid: boolean, value: string, selectedCountryData: CountryData, fullNumber: string, extension: string, event: React.FocusEvent<HTMLInputElement>, ) => void /** * Allow main app to do things when a country is selected. * @default null */ onSelectFlag?: ( currentNumber: string, selectedCountryData: CountryData, fullNumber: string, isValid: boolean, ) => void /** * Disable this component. * @default false */ disabled?: boolean /** * Static placeholder for input controller. When defined it takes priority over autoPlaceholder. */ placeholder?: string /** * Enable auto focus * @default false */ autoFocus?: boolean /** * Set the value of the autoComplete attribute on the input. * For example, set it to phone to tell the browser where to auto complete phone numbers. * @default 'off' */ autoComplete?: string /** * Style object for the wrapper div. Useful for setting 100% width on the wrapper, etc. */ style?: React.CSSProperties /** * Render fullscreen flag dropdown when mobile useragent is detected. * The dropdown element is rendered as a direct child of document.body * @default true */ useMobileFullscreenDropdown?: boolean /** * Pass through arbitrary props to the tel input element. * @default {} */ telInputProps?: React.InputHTMLAttributes<HTMLInputElement> /** * Format the number. * @default true */ format?: boolean /** * Allow main app to do things when flag icon is clicked. * @default null */ onFlagClick?: (event: React.MouseEvent<HTMLDivElement, MouseEvent>) => void } export interface IntlTelInputState { showDropdown: boolean highlightedCountry: number value: string disabled: boolean readonly: boolean offsetTop: number outerHeight: number placeholder: string title: string countryCode: string dialCode: string cursorPosition: any } export default class IntlTelInput extends React.Component< IntlTelInputProps, IntlTelInputState > { //#region Properties wrapperClass: { [key: string]: boolean } defaultCountry?: string autoCountry: string tempCountry: string startedLoadingAutoCountry: boolean dropdownContainer?: React.ElementType | '' isOpening: boolean isMobile: boolean preferredCountries: CountryData[] countries: CountryData[] countryCodes: { [key: string]: string[] } windowLoaded: boolean query: string selectedCountryData?: CountryData // prop copies autoHideDialCode: boolean nationalMode: boolean allowDropdown: boolean // refs /** * `<div>` HTML element of the `FlagDropDown` React component. */ flagDropDown: HTMLDivElement | null /** * `<input>` HTML element of the `TelInput` React component. */ tel: HTMLInputElement | null // NOTE: // The underscore.deferred package doesn't have known type definitions. // The closest counterpart is jquery's Deferred object, which it claims to derive itself from. // These two are equivalent if you log it in console: // // underscore.deferred // var deferred = new _.Deferred() // // jquery // var deferred = $.Deferred() deferreds: JQuery.Deferred<any, any, any>[] autoCountryDeferred: JQuery.Deferred<any, any, any> utilsScriptDeferred: JQuery.Deferred<any, any, any> //#endregion //#region Methods /** * Updates flag when value of defaultCountry props change */ updateFlagOnDefaultCountryChange(countryCode?: string): void getTempCountry(countryCode?: string): CountryData['iso2'] | 'auto' /** * set the input value and update the flag */ setNumber(number: string, preventFocus?: boolean): void setFlagDropdownRef(ref: HTMLDivElement | null): void setTelRef(ref: HTMLInputElement | null): void /** * select the given flag, update the placeholder and the active list item * * Note: called from setInitialState, updateFlagFromNumber, selectListItem, setCountry, updateFlagOnDefaultCountryChange */ setFlag(countryCode?: string, isInit?: boolean): void /** * get the extension from the current number */ getExtension(number?: string): string /** * format the number to the given format */ getNumber(number?: string, format?: string): string /** * get the input val, adding the dial code if separateDialCode is enabled */ getFullNumber(number?: string): string /** * try and extract a valid international dial code from a full telephone number */ getDialCode(number: string): string /** * check if the given number contains an unknown area code from */ isUnknownNanp(number?: string, dialCode?: string): boolean /** * add a country code to countryCodes */ addCountryCode( countryCodes: { [key: string]: string[] }, iso2: string, dialCode: string, priority?: number, ): { [key: string]: string[] } processAllCountries(): void /** * process the countryCodes map */ processCountryCodes(): void /** * process preferred countries - iterate through the preferences, * fetching the country data for each one */ processPreferredCountries(): void /** * set the initial state of the input value and the selected flag */ setInitialState(): void initRequests(): void loadCountryFromLocalStorage(): string loadAutoCountry(): void cap(number?: string): string | undefined removeEmptyDialCode(): void /** * highlight the next/prev item in the list (and ensure it is visible) */ handleUpDownKey(key?: number): void /** * select the currently highlighted item */ handleEnterKey(): void /** * find the first list item whose name starts with the query string */ searchForCountry(query: string): void formatNumber(number?: string): string /** * update the input's value to the given val (format first if possible) */ updateValFromNumber( number?: string, doFormat?: boolean, doNotify?: boolean, ): void /** * check if need to select a new flag based on the given number */ updateFlagFromNumber(number?: string, isInit?: boolean): void /** * filter the given countries using the process function */ filterCountries( countryArray: string[], processFunc: (iso2: string) => void, ): void /** * prepare all of the country data, including onlyCountries and preferredCountries options */ processCountryData(): void handleOnBlur(event: React.FocusEvent<HTMLInputElement>): void handleOnFocus(event: React.FocusEvent<HTMLInputElement>): void bindDocumentClick(): void unbindDocumentClick(): void clickSelectedFlag(event: React.MouseEvent<HTMLDivElement, MouseEvent>): void /** * update the input placeholder to an * example number from the currently selected country */ updatePlaceholder(props?: IntlTelInputProps): void toggleDropdown(status?: boolean): void /** * check if an element is visible within it's container, else scroll until it is */ scrollTo(element: Element, middle?: boolean): void /** * replace any existing dial code with the new one * * Note: called from _setFlag */ updateDialCode(newDialCode?: string, hasSelectedListItem?: boolean): string generateMarkup(): void handleSelectedFlagKeydown(event: React.KeyboardEvent<HTMLDivElement>): void /** * validate the input val - assumes the global function isValidNumber (from libphonenumber) */ isValidNumber(number?: string): boolean formatFullNumber(number?: string): string notifyPhoneNumberChange(number?: string): void /** * remove the dial code if separateDialCode is enabled */ beforeSetNumber( number?: string, props?: IntlTelInputProps, ): string | undefined handleWindowScroll(): void handleDocumentKeyDown(event: KeyboardEvent): void handleDocumentClick(event: MouseEvent): void /** * Either notify phoneNumber changed if component is controlled */ handleInputChange(event: React.FocusEvent<HTMLInputElement>): void changeHighlightCountry(showDropdown: boolean, selectedIndex: number): void loadUtils(): void /** * this is called when the geoip call returns */ autoCountryLoaded(): void //#endregion }