UNPKG

@gravityforms/components

Version:

UI components for use in Gravity Forms development. Both React and vanilla js flavors.

170 lines (153 loc) 5.05 kB
import { React } from '@gravityforms/libraries'; import { getValidLocale, sanitizeLocale } from '@gravityforms/utils'; import { getCountryCallingCode } from 'libphonenumber-js'; const NEEDS_I18N_LABEL = 'Needs i18n'; /** * @function getUnicodeFlag * @description Returns a Unicode flag emoji for a given ISO country code. * * @since 5.6.2 * * @param {string} isoCode The ISO country code. * * @return {string} The Unicode flag emoji. */ export const getUnicodeFlag = ( isoCode ) => { if ( ! isoCode || isoCode.length !== 2 ) { return ''; } // Convert ISO code to regional indicator symbols // e.g., 'U' (char code 85) becomes 0x1F1FA (regional indicator U) // The offset is 0x1F1E6 (base for regional indicators) - 0x41 ('A'). return String.fromCodePoint( ...isoCode.toUpperCase() .split( '' ) .map( ( char ) => char.charCodeAt( 0 ) + ( 0x1F1E6 - 0x41 ) ) ); }; /** * @function getCountriesListItemsFromIsos * @description Returns a list of countries for a given ISO country code. * * @since 5.6.2 * * @param {Array} isoCodes The ISO country codes. * @param {string} language The language to use for the country names. * @param {object} i18n The i18n object. * @param {object} options Options for the country list item. * * @return {Array} The list of countries. */ export const getCountriesListItemsFromIsos = ( isoCodes = [], language = 'en-US', i18n = {}, options = {} ) => { const { showFlag = true, showCallingCode = false, showPlaceholder = false } = options; const listItems = []; const locale = getValidLocale( sanitizeLocale( language ) ); const countryNameProvider = new Intl.DisplayNames( [ locale ], { type: 'region' } ); if ( showPlaceholder ) { listItems.push( { label: i18n?.placeholder || NEEDS_I18N_LABEL, value: '', } ); } for ( const iso of isoCodes ) { try { const name = countryNameProvider.of( iso.toUpperCase() ); if ( name === iso.toUpperCase() ) { // Intl.DisplayNames returns the code itself if it can't find a name. console.warn( `Could not find display name for ISO code: ${ iso }` ); } let fullCallingCode = ''; if ( showCallingCode ) { const callingCode = getCountryCallingCode( iso.toUpperCase() ); fullCallingCode = `+${ callingCode }`; } listItems.push( { searchValue: `${ name } ${ fullCallingCode } ${ iso.toUpperCase() }`, label: name, value: iso.toUpperCase(), beforeLabel: showFlag ? <span className="gform-phone__flag-icon">{ getUnicodeFlag( iso.toUpperCase() ) }</span> : undefined, afterLabel: showCallingCode ? <span className="gform-phone__country-code">{ fullCallingCode }</span> : undefined, } ); } catch ( error ) { // Handle cases where ISO code is invalid for getCountryCallingCode or other errors. console.error( `Error processing ISO code ${ iso }:`, error ); } } return listItems; }; /** * @function sortPreferredCountries * @description Sort the countries list items to set preferred countries first. * If preferredCountries is empty, return the list as is. * If preferredCountries is not empty, split the list into preferred and remaining countries. * * @since 5.5.0 * * @param {Array} listItems List of countries. * @param {Array} preferredCountries List of preferred countries. * @param {object} i18n i18n object. * * @return {Array} The sorted countries list. */ export const sortPreferredCountries = ( listItems, preferredCountries, i18n ) => { if ( preferredCountries.length === 0 ) { return listItems; } let placeholder = null; const filteredListItems = listItems.filter( ( item ) => { if ( ! item.value ) { // Item is placeholder, remove it. placeholder = item; return false; } return true; } ); const countryMap = new Map(); filteredListItems.forEach( ( item ) => { countryMap.set( item.value, item ); } ); // Process the preferred countries in their specified order. const preferred = []; const usedISOs = new Set(); preferredCountries.forEach( ( country ) => { const iso = typeof country === 'string' ? country : country?.value || country?.iso; if ( iso && countryMap.has( iso ) && ! usedISOs.has( iso ) ) { preferred.push( countryMap.get( iso ) ); usedISOs.add( iso ); } } ); // If no preferred countries were found, return the list as is. if ( preferred.length === 0 ) { return listItems; } const remaining = filteredListItems.filter( ( item ) => ! usedISOs.has( item.value ) ); if ( placeholder ) { preferred.unshift( placeholder ); } // If no remaining countries were found, return the preferred list. if ( remaining.length === 0 ) { return preferred; } return [ { type: 'group', items: preferred, label: i18n?.preferredCountries ? { type: 'groupLabel', label: i18n.preferredCountries, } : undefined, }, { type: 'group', items: remaining, label: i18n?.allCountries ? { type: 'groupLabel', label: i18n.allCountries, } : undefined, }, ]; };