diff --git a/packages/docs/docs/02-Usage/01-PhoneInput.md b/packages/docs/docs/02-Usage/01-PhoneInput.md index 1c14a37..3326b31 100644 --- a/packages/docs/docs/02-Usage/01-PhoneInput.md +++ b/packages/docs/docs/02-Usage/01-PhoneInput.md @@ -150,6 +150,14 @@ description={Show prefix and dial code between country selector and phone defaultValue="false" /> +### `disableFocusAfterCountrySelect` + + + ### `disableFormatting` diff --git a/packages/docs/docs/04-Advanced Usage/01-usePhoneInput.md b/packages/docs/docs/04-Advanced Usage/01-usePhoneInput.md index 9c6f9c5..cce4ff3 100644 --- a/packages/docs/docs/04-Advanced Usage/01-usePhoneInput.md +++ b/packages/docs/docs/04-Advanced Usage/01-usePhoneInput.md @@ -182,6 +182,6 @@ description="Current country object." ### `setCountry` diff --git a/src/components/PhoneInput/PhoneInput.test.tsx b/src/components/PhoneInput/PhoneInput.test.tsx index f4bf16f..c6e6884 100644 --- a/src/components/PhoneInput/PhoneInput.test.tsx +++ b/src/components/PhoneInput/PhoneInput.test.tsx @@ -1259,4 +1259,48 @@ describe('PhoneInput', () => { }); }); }); + + describe('disableFocusAfterCountrySelect', () => { + test('should focus on input if disableFocusAfterCountrySelect is not provided', async () => { + render(); + + expect(getInput().value).toBe('+1 '); + + getInput().focus(); + expect(getInput()).toHaveFocus(); + + // remove focus from input + (document.activeElement as HTMLElement).blur(); + + act(() => { + fireEvent.click(getCountrySelector()); + fireEvent.click(getDropdownOption('ua')); + }); + + await Promise.resolve(); + + expect(getInput()).toHaveFocus(); + }); + + test('should not focus on input if disableFocusAfterCountrySelect is true', async () => { + render(); + + expect(getInput().value).toBe('+1 '); + + getInput().focus(); + expect(getInput()).toHaveFocus(); + + // remove focus from input + (document.activeElement as HTMLElement)?.blur(); + + act(() => { + fireEvent.click(getCountrySelector()); + fireEvent.click(getDropdownOption('ua')); + }); + + await Promise.resolve(); + + expect(getInput()).not.toHaveFocus(); + }); + }); }); diff --git a/src/components/PhoneInput/PhoneInput.tsx b/src/components/PhoneInput/PhoneInput.tsx index ffb7545..ca57e9c 100644 --- a/src/components/PhoneInput/PhoneInput.tsx +++ b/src/components/PhoneInput/PhoneInput.tsx @@ -5,7 +5,7 @@ import React, { forwardRef, useImperativeHandle } from 'react'; import { defaultCountries } from '../../data/countryData'; import { usePhoneInput, UsePhoneInputConfig } from '../../hooks/usePhoneInput'; import { buildClassNames } from '../../style/buildClassNames'; -import { CountryIso2, ParsedCountry } from '../../types'; +import { ParsedCountry } from '../../types'; import { CountrySelector, CountrySelectorProps, @@ -46,6 +46,12 @@ export interface PhoneInputProps */ showDisabledDialCodeAndPrefix?: boolean; + /** + * @description Disable auto focus on input field after country select. + * @default false + */ + disableFocusAfterCountrySelect?: boolean; + /** * @description Custom flag URLs array * @default undefined @@ -87,7 +93,7 @@ export interface PhoneInputProps export type PhoneInputRefType = | null | (HTMLInputElement & { - setCountry: (iso2: CountryIso2) => void; + setCountry: ReturnType['setCountry']; state: { phone: string; inputValue: string; @@ -103,6 +109,7 @@ export const PhoneInput = forwardRef( countries = defaultCountries, hideDropdown, showDisabledDialCodeAndPrefix, + disableFocusAfterCountrySelect, flags, style, @@ -177,7 +184,11 @@ export const PhoneInput = forwardRef( style={style} > setCountry(country.iso2)} + onSelect={(country) => + setCountry(country.iso2, { + focusOnInput: !disableFocusAfterCountrySelect, + }) + } flags={flags} selectedCountry={country.iso2} countries={countries} diff --git a/src/hooks/usePhoneInput.ts b/src/hooks/usePhoneInput.ts index d823603..1b18605 100644 --- a/src/hooks/usePhoneInput.ts +++ b/src/hooks/usePhoneInput.ts @@ -312,7 +312,10 @@ export const usePhoneInput = ({ return value; }; - const setNewCountry = (countryIso2: CountryIso2) => { + const setCountry = ( + countryIso2: CountryIso2, + options = { focusOnInput: false }, + ) => { const newCountry = getCountry({ value: countryIso2, field: 'iso2', @@ -335,10 +338,12 @@ export const usePhoneInput = ({ country: newCountry.iso2, }); - // Next tick is used to support UI libraries (had an issue with MUI) - Promise.resolve().then(() => { - inputRef.current?.focus(); - }); + if (options.focusOnInput) { + // Next tick is used to support UI libraries (had an issue with MUI) + Promise.resolve().then(() => { + inputRef.current?.focus(); + }); + } }; const [initialized, setInitialized] = useState(false); @@ -388,7 +393,7 @@ export const usePhoneInput = ({ phone, // Phone in E164 format inputValue, // Formatted phone string. Value that should be rendered inside input element. country: fullCountry, // Current country object. - setCountry: setNewCountry, // Country setter. + setCountry, // Country setter. handlePhoneValueChange, // Change handler for input component inputRef, // Ref object for input component (handles caret position, focus and undo/redo). };