intl-tel-input 28.1.0 → 29.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/dist/css/intlTelInput-no-assets.css +20 -11
  2. package/dist/css/intlTelInput-no-assets.min.css +1 -1
  3. package/dist/css/intlTelInput.css +20 -11
  4. package/dist/css/intlTelInput.min.css +1 -1
  5. package/dist/js/data.js +1 -1
  6. package/dist/js/data.min.js +1 -1
  7. package/dist/js/intlTelInput.d.ts +38 -23
  8. package/dist/js/intlTelInput.js +362 -300
  9. package/dist/js/intlTelInput.min.js +2 -2
  10. package/dist/js/intlTelInput.mjs +361 -299
  11. package/dist/js/intlTelInputWithUtils.js +734 -726
  12. package/dist/js/intlTelInputWithUtils.min.js +2 -2
  13. package/dist/js/intlTelInputWithUtils.mjs +733 -725
  14. package/dist/js/locale.d.ts +124 -0
  15. package/dist/js/utils.js +83 -83
  16. package/package.json +7 -7
  17. package/dist/js/i18n.d.ts +0 -124
  18. /package/dist/js/{i18n → locale}/ar.js +0 -0
  19. /package/dist/js/{i18n → locale}/bg.js +0 -0
  20. /package/dist/js/{i18n → locale}/bn.js +0 -0
  21. /package/dist/js/{i18n → locale}/bs.js +0 -0
  22. /package/dist/js/{i18n → locale}/ca.js +0 -0
  23. /package/dist/js/{i18n → locale}/cs.js +0 -0
  24. /package/dist/js/{i18n → locale}/da.js +0 -0
  25. /package/dist/js/{i18n → locale}/de.js +0 -0
  26. /package/dist/js/{i18n → locale}/el.js +0 -0
  27. /package/dist/js/{i18n → locale}/en.js +0 -0
  28. /package/dist/js/{i18n → locale}/es.js +0 -0
  29. /package/dist/js/{i18n → locale}/et.js +0 -0
  30. /package/dist/js/{i18n → locale}/fa.js +0 -0
  31. /package/dist/js/{i18n → locale}/fi.js +0 -0
  32. /package/dist/js/{i18n → locale}/fil.js +0 -0
  33. /package/dist/js/{i18n → locale}/fr.js +0 -0
  34. /package/dist/js/{i18n → locale}/he.js +0 -0
  35. /package/dist/js/{i18n → locale}/hi.js +0 -0
  36. /package/dist/js/{i18n → locale}/hr.js +0 -0
  37. /package/dist/js/{i18n → locale}/hu.js +0 -0
  38. /package/dist/js/{i18n → locale}/hy.js +0 -0
  39. /package/dist/js/{i18n → locale}/id.js +0 -0
  40. /package/dist/js/{i18n → locale}/index.js +0 -0
  41. /package/dist/js/{i18n → locale}/is.js +0 -0
  42. /package/dist/js/{i18n → locale}/it.js +0 -0
  43. /package/dist/js/{i18n → locale}/ja.js +0 -0
  44. /package/dist/js/{i18n → locale}/kn.js +0 -0
  45. /package/dist/js/{i18n → locale}/ko.js +0 -0
  46. /package/dist/js/{i18n → locale}/lt.js +0 -0
  47. /package/dist/js/{i18n → locale}/lv.js +0 -0
  48. /package/dist/js/{i18n → locale}/mk.js +0 -0
  49. /package/dist/js/{i18n → locale}/mr.js +0 -0
  50. /package/dist/js/{i18n → locale}/ms.js +0 -0
  51. /package/dist/js/{i18n → locale}/nl.js +0 -0
  52. /package/dist/js/{i18n → locale}/no.js +0 -0
  53. /package/dist/js/{i18n → locale}/pl.js +0 -0
  54. /package/dist/js/{i18n → locale}/pt.js +0 -0
  55. /package/dist/js/{i18n → locale}/ro.js +0 -0
  56. /package/dist/js/{i18n → locale}/ru.js +0 -0
  57. /package/dist/js/{i18n → locale}/sk.js +0 -0
  58. /package/dist/js/{i18n → locale}/sl.js +0 -0
  59. /package/dist/js/{i18n → locale}/sq.js +0 -0
  60. /package/dist/js/{i18n → locale}/sr.js +0 -0
  61. /package/dist/js/{i18n → locale}/sv.js +0 -0
  62. /package/dist/js/{i18n → locale}/sw.js +0 -0
  63. /package/dist/js/{i18n → locale}/ta.js +0 -0
  64. /package/dist/js/{i18n → locale}/te.js +0 -0
  65. /package/dist/js/{i18n → locale}/th.js +0 -0
  66. /package/dist/js/{i18n → locale}/tr.js +0 -0
  67. /package/dist/js/{i18n → locale}/types.js +0 -0
  68. /package/dist/js/{i18n → locale}/uk.js +0 -0
  69. /package/dist/js/{i18n → locale}/ur.js +0 -0
  70. /package/dist/js/{i18n → locale}/uz.js +0 -0
  71. /package/dist/js/{i18n → locale}/vi.js +0 -0
  72. /package/dist/js/{i18n → locale}/zh-hk.js +0 -0
  73. /package/dist/js/{i18n → locale}/zh.js +0 -0
@@ -1,5 +1,5 @@
1
1
  /*
2
- * International Telephone Input v28.1.0
2
+ * International Telephone Input v29.0.1
3
3
  * git+https://github.com/jackocnr/intl-tel-input.git
4
4
  * Licensed under the MIT license
5
5
  */
@@ -26,9 +26,11 @@ var _factory = (() => {
26
26
  // packages/core/src/js/intlTelInput.ts
27
27
  var intlTelInput_exports = {};
28
28
  __export(intlTelInput_exports, {
29
+ COUNTRY_SELECTOR_MODE: () => COUNTRY_SELECTOR_MODE,
29
30
  Iti: () => Iti,
30
31
  NUMBER_FORMAT: () => NUMBER_FORMAT,
31
32
  NUMBER_TYPE: () => NUMBER_TYPE,
33
+ PLACEHOLDER_POLICY: () => PLACEHOLDER_POLICY,
32
34
  VALIDATION_ERROR: () => VALIDATION_ERROR,
33
35
  default: () => intlTelInput_default
34
36
  });
@@ -1787,8 +1789,8 @@ var _factory = (() => {
1787
1789
 
1788
1790
  // packages/core/src/js/constants.ts
1789
1791
  var EVENTS = {
1790
- OPEN_COUNTRY_DROPDOWN: "open:countrydropdown",
1791
- CLOSE_COUNTRY_DROPDOWN: "close:countrydropdown",
1792
+ OPEN_COUNTRY_SELECTOR: "open:countryselector",
1793
+ CLOSE_COUNTRY_SELECTOR: "close:countryselector",
1792
1794
  COUNTRY_CHANGE: "countrychange",
1793
1795
  INPUT: "input",
1794
1796
  // used for synthetic input trigger
@@ -1835,9 +1837,9 @@ var _factory = (() => {
1835
1837
  var LAYOUT = {
1836
1838
  NARROW_VIEWPORT_WIDTH: 500,
1837
1839
  // keep in sync with .iti__country-list CSS media query
1838
- FALLBACK_SELECTED_WITH_DIAL_WIDTH: 78,
1840
+ FALLBACK_SELECTED_COUNTRY_WITH_DIAL_WIDTH: 78,
1839
1841
  // px width fallback when separateDialCode enabled
1840
- FALLBACK_SELECTED_NO_DIAL_WIDTH: 42,
1842
+ FALLBACK_SELECTED_COUNTRY_NO_DIAL_WIDTH: 42,
1841
1843
  // px width fallback when no separate dial code
1842
1844
  INPUT_PADDING_EXTRA_LEFT: 6,
1843
1845
  // px gap between selected country container and input text
@@ -1865,14 +1867,17 @@ var _factory = (() => {
1865
1867
  DIAL_CODE: "1"
1866
1868
  // +1 United States
1867
1869
  };
1868
- var PLACEHOLDER_MODES = {
1869
- AGGRESSIVE: "aggressive",
1870
- POLITE: "polite",
1871
- OFF: "off"
1872
- };
1873
- var INITIAL_COUNTRY = {
1874
- AUTO: "auto"
1870
+ var PLACEHOLDER_POLICY = {
1871
+ AGGRESSIVE: "AGGRESSIVE",
1872
+ POLITE: "POLITE",
1873
+ OFF: "OFF"
1875
1874
  };
1875
+ var COUNTRY_SELECTOR_MODES = [
1876
+ "OFF",
1877
+ "DROPDOWN",
1878
+ "FULLSCREEN",
1879
+ "AUTO"
1880
+ ];
1876
1881
  var NUMBER_FORMATS = [
1877
1882
  "E164",
1878
1883
  "INTERNATIONAL",
@@ -1905,8 +1910,9 @@ var _factory = (() => {
1905
1910
  var NUMBER_FORMAT = toEnumObject(NUMBER_FORMATS);
1906
1911
  var NUMBER_TYPE = toEnumObject(NUMBER_TYPES);
1907
1912
  var VALIDATION_ERROR = toEnumObject(VALIDATION_ERRORS);
1913
+ var COUNTRY_SELECTOR_MODE = toEnumObject(COUNTRY_SELECTOR_MODES);
1908
1914
  var DATA_KEYS = {
1909
- // e.g. <li data-iso2="us"> for country items in dropdown
1915
+ // e.g. <li data-iso2="us"> for country items in the country list
1910
1916
  ISO2: "iso2",
1911
1917
  DIAL_CODE: "dialCode",
1912
1918
  // e.g. <input data-intl-tel-input-id="0"> on the input element
@@ -1924,7 +1930,7 @@ var _factory = (() => {
1924
1930
  MODAL: "aria-modal"
1925
1931
  };
1926
1932
 
1927
- // packages/core/src/js/i18n/en.ts
1933
+ // packages/core/src/js/locale/en.ts
1928
1934
  var interfaceTranslations = {
1929
1935
  selectedCountryAriaLabel: "Change country for phone number, currently selected ${countryName} (${dialCode})",
1930
1936
  noCountrySelected: "Select country for phone number",
@@ -1947,63 +1953,63 @@ var _factory = (() => {
1947
1953
  // packages/core/src/js/core/options.ts
1948
1954
  var mediaQuery = (q) => typeof window !== "undefined" && typeof window.matchMedia === "function" && window.matchMedia(q).matches;
1949
1955
  var isNarrowViewport = () => mediaQuery(`(max-width: ${LAYOUT.NARROW_VIEWPORT_WIDTH}px)`);
1950
- var computeDefaultUseFullscreenPopup = () => {
1956
+ var resolveAutoCountrySelectorMode = () => {
1951
1957
  if (typeof navigator !== "undefined" && typeof window !== "undefined") {
1952
1958
  const isShortViewport = mediaQuery("(max-height: 600px)");
1953
1959
  const isCoarsePointer = mediaQuery("(pointer: coarse)");
1954
- return isNarrowViewport() || isCoarsePointer && isShortViewport;
1960
+ if (isNarrowViewport() || isCoarsePointer && isShortViewport) {
1961
+ return COUNTRY_SELECTOR_MODE.FULLSCREEN;
1962
+ }
1955
1963
  }
1956
- return false;
1964
+ return COUNTRY_SELECTOR_MODE.DROPDOWN;
1957
1965
  };
1958
1966
  var defaults = {
1959
- //* Whether or not to allow the dropdown.
1960
- allowDropdown: true,
1967
+ //* How the country selector is displayed. "DROPDOWN" vs "FULLSCREEN", or "AUTO" to decide itself, or "OFF".
1968
+ countrySelectorMode: COUNTRY_SELECTOR_MODE.AUTO,
1961
1969
  //* The number type to enforce during validation.
1962
1970
  allowedNumberTypes: [NUMBER_TYPE.MOBILE, NUMBER_TYPE.FIXED_LINE],
1963
1971
  //* Whether or not to allow extensions after the main number.
1964
1972
  allowNumberExtensions: false,
1965
1973
  // Allow alphanumeric "phonewords" (e.g. +1 800 FLOWERS) as valid numbers
1966
1974
  allowPhonewords: false,
1967
- //* Add a placeholder in the input with an example number for the selected country.
1968
- autoPlaceholder: PLACEHOLDER_MODES.POLITE,
1969
1975
  //* Add a custom class to the (injected) container element.
1970
1976
  containerClass: "",
1971
1977
  //* Locale for localising country names via Intl.DisplayNames.
1972
1978
  countryNameLocale: "en",
1973
1979
  //* Override individual country names by iso2 code.
1974
1980
  countryNameOverrides: {},
1975
- //* The order of the countries in the dropdown. Defaults to alphabetical.
1981
+ //* The order of the countries in the country list. Defaults to alphabetical.
1976
1982
  countryOrder: null,
1977
- //* Add a country search input at the top of the dropdown.
1983
+ //* Add a country search input at the top of the country selector.
1978
1984
  countrySearch: true,
1979
1985
  //* Modify the auto placeholder.
1980
1986
  customPlaceholder: null,
1981
1987
  //* Always show the dropdown
1982
1988
  dropdownAlwaysOpen: false,
1983
- //* Append menu to specified element.
1984
- dropdownContainer: null,
1989
+ //* Optional DOM element to append the dropdown to (used to escape ancestors with overflow:hidden, or to mount in a custom container). Only consulted in dropdown rendering; ignored when the country selector renders as a fullscreen popup.
1990
+ dropdownParent: null,
1985
1991
  //* Don't display these countries.
1986
1992
  excludeCountries: null,
1987
1993
  //* Fix the dropdown width to the input width (rather than being as wide as the longest country name).
1988
- fixDropdownWidth: true,
1994
+ matchDropdownWidth: true,
1989
1995
  //* Format the number as the user types
1990
1996
  formatAsYouType: true,
1991
- //* Format the input value during initialisation and on setNumber.
1992
- formatOnDisplay: true,
1993
- //* geoIp lookup function.
1994
- geoIpLookup: null,
1995
- //* Inject a hidden input with the name returned from this function, and on submit, populate it with the result of getNumber.
1996
- hiddenInput: null,
1997
- //* Internationalise the core library text e.g. search input placeholder, country names.
1998
- i18n: {},
1997
+ //* Inject hidden inputs with the names returned from this function, and on submit, populate them with the full number and selected country iso2.
1998
+ hiddenInputs: null,
1999
+ //* Translations for the core library UI strings e.g. search input placeholder, country names.
2000
+ uiTranslations: {},
1999
2001
  //* Initial country.
2000
2002
  initialCountry: "",
2003
+ //* Async lookup function used to determine the initial country (e.g. via IP). Ignored if initialCountry is set.
2004
+ initialCountryLookup: null,
2001
2005
  //* A function to load the utils script.
2002
2006
  loadUtils: null,
2003
- //* National vs international formatting for numbers e.g. placeholders and displaying existing numbers.
2004
- nationalMode: false,
2007
+ //* Format used when displaying numbers (placeholder examples and stored values). One of "E164", "INTERNATIONAL", "NATIONAL".
2008
+ numberDisplayFormat: NUMBER_FORMAT.INTERNATIONAL,
2005
2009
  //* Display only these countries.
2006
2010
  onlyCountries: null,
2011
+ //* When to set the placeholder to an example number for the selected country: "POLITE" only when the input has no manually-set placeholder, "AGGRESSIVE" always, "OFF" never.
2012
+ placeholderNumberPolicy: PLACEHOLDER_POLICY.POLITE,
2007
2013
  //* Number type to use for placeholders.
2008
2014
  placeholderNumberType: NUMBER_TYPE.MOBILE,
2009
2015
  //* Add custom classes to the search input element.
@@ -2012,12 +2018,10 @@ var _factory = (() => {
2012
2018
  separateDialCode: true,
2013
2019
  //* When strictMode rejects a key (etc), play a short feedback animation
2014
2020
  strictRejectAnimation: true,
2015
- //* Show flags - for both the selected country, and in the country dropdown
2021
+ //* Show flags - for both the selected country, and in the country list
2016
2022
  showFlags: true,
2017
2023
  //* Only allow certain chars e.g. a plus followed by numeric digits, and cap at max valid length.
2018
- strictMode: true,
2019
- //* Use full screen popup instead of dropdown for country list.
2020
- useFullscreenPopup: computeDefaultUseFullscreenPopup()
2024
+ strictMode: true
2021
2025
  };
2022
2026
  var toString = (val) => JSON.stringify(val);
2023
2027
  var isPlainObject = (val) => Boolean(val) && typeof val === "object" && !Array.isArray(val);
@@ -2029,7 +2033,7 @@ var _factory = (() => {
2029
2033
  const v = val;
2030
2034
  return v.nodeType === 1 && typeof v.tagName === "string" && typeof v.appendChild === "function";
2031
2035
  };
2032
- var placeholderModeSet = new Set(Object.values(PLACEHOLDER_MODES));
2036
+ var placeholderPolicySet = new Set(Object.values(PLACEHOLDER_POLICY));
2033
2037
  var warn = (message) => {
2034
2038
  console.warn(`[intl-tel-input] ${message}`);
2035
2039
  };
@@ -2075,30 +2079,48 @@ var _factory = (() => {
2075
2079
  continue;
2076
2080
  }
2077
2081
  switch (key) {
2078
- case "allowDropdown":
2079
2082
  case "allowNumberExtensions":
2080
2083
  case "allowPhonewords":
2081
2084
  case "countrySearch":
2082
2085
  case "dropdownAlwaysOpen":
2083
- case "fixDropdownWidth":
2086
+ case "matchDropdownWidth":
2084
2087
  case "formatAsYouType":
2085
- case "formatOnDisplay":
2086
- case "nationalMode":
2087
2088
  case "showFlags":
2088
2089
  case "separateDialCode":
2089
2090
  case "strictMode":
2090
2091
  case "strictRejectAnimation":
2091
- case "useFullscreenPopup":
2092
2092
  if (typeof value !== "boolean") {
2093
2093
  warnOption(key, "a boolean", value);
2094
2094
  break;
2095
2095
  }
2096
2096
  validatedOptions[key] = value;
2097
2097
  break;
2098
- case "autoPlaceholder":
2099
- if (typeof value !== "string" || !placeholderModeSet.has(value)) {
2100
- const validModes = Array.from(placeholderModeSet).join(", ");
2101
- warnOption("autoPlaceholder", `one of ${validModes}`, value);
2098
+ case "countrySelectorMode":
2099
+ if (typeof value !== "string" || !COUNTRY_SELECTOR_MODES.includes(value)) {
2100
+ warnOption(
2101
+ "countrySelectorMode",
2102
+ `one of ${COUNTRY_SELECTOR_MODES.map((m) => `"${m}"`).join(", ")}`,
2103
+ value
2104
+ );
2105
+ break;
2106
+ }
2107
+ validatedOptions[key] = value;
2108
+ break;
2109
+ case "numberDisplayFormat":
2110
+ if (typeof value !== "string" || value === NUMBER_FORMAT.RFC3966 || !(value === NUMBER_FORMAT.E164 || value === NUMBER_FORMAT.INTERNATIONAL || value === NUMBER_FORMAT.NATIONAL)) {
2111
+ warnOption(
2112
+ "numberDisplayFormat",
2113
+ 'one of "E164", "INTERNATIONAL", "NATIONAL"',
2114
+ value
2115
+ );
2116
+ break;
2117
+ }
2118
+ validatedOptions[key] = value;
2119
+ break;
2120
+ case "placeholderNumberPolicy":
2121
+ if (typeof value !== "string" || !placeholderPolicySet.has(value)) {
2122
+ const validPolicies = Array.from(placeholderPolicySet).join(", ");
2123
+ warnOption("placeholderNumberPolicy", `one of ${validPolicies}`, value);
2102
2124
  break;
2103
2125
  }
2104
2126
  validatedOptions[key] = value;
@@ -2124,8 +2146,8 @@ var _factory = (() => {
2124
2146
  break;
2125
2147
  }
2126
2148
  case "customPlaceholder":
2127
- case "geoIpLookup":
2128
- case "hiddenInput":
2149
+ case "hiddenInputs":
2150
+ case "initialCountryLookup":
2129
2151
  case "loadUtils":
2130
2152
  if (value !== null && !isFunction(value)) {
2131
2153
  warnOption(key, "a function or null", value);
@@ -2133,9 +2155,9 @@ var _factory = (() => {
2133
2155
  }
2134
2156
  validatedOptions[key] = value;
2135
2157
  break;
2136
- case "dropdownContainer":
2158
+ case "dropdownParent":
2137
2159
  if (value !== null && !isElLike(value)) {
2138
- warnOption("dropdownContainer", "an HTMLElement or null", value);
2160
+ warnOption("dropdownParent", "an HTMLElement or null", value);
2139
2161
  break;
2140
2162
  }
2141
2163
  validatedOptions[key] = value;
@@ -2152,9 +2174,9 @@ var _factory = (() => {
2152
2174
  }
2153
2175
  break;
2154
2176
  }
2155
- case "i18n":
2177
+ case "uiTranslations":
2156
2178
  if (value && !isPlainObject(value)) {
2157
- warnOption("i18n", "an object", value);
2179
+ warnOption("uiTranslations", "an object", value);
2158
2180
  break;
2159
2181
  }
2160
2182
  validatedOptions[key] = value;
@@ -2172,12 +2194,8 @@ var _factory = (() => {
2172
2194
  break;
2173
2195
  }
2174
2196
  const lower = value.toLowerCase();
2175
- if (lower && lower !== INITIAL_COUNTRY.AUTO && !isIso2(lower)) {
2176
- warnOption(
2177
- "initialCountry",
2178
- "a valid iso2 country code or 'auto'",
2179
- value
2180
- );
2197
+ if (lower && !isIso2(lower)) {
2198
+ warnOption("initialCountry", "a valid iso2 country code", value);
2181
2199
  break;
2182
2200
  }
2183
2201
  validatedOptions[key] = value;
@@ -2240,30 +2258,29 @@ var _factory = (() => {
2240
2258
  }
2241
2259
  };
2242
2260
  var applyOptionSideEffects = (o) => {
2261
+ if (o.countrySelectorMode === COUNTRY_SELECTOR_MODE.AUTO) {
2262
+ o.countrySelectorMode = resolveAutoCountrySelectorMode();
2263
+ }
2243
2264
  if (o.dropdownAlwaysOpen) {
2244
- o.useFullscreenPopup = false;
2245
- o.allowDropdown = true;
2265
+ o.countrySelectorMode = COUNTRY_SELECTOR_MODE.DROPDOWN;
2246
2266
  }
2247
- if (o.useFullscreenPopup) {
2248
- o.fixDropdownWidth = false;
2267
+ if (o.countrySelectorMode === COUNTRY_SELECTOR_MODE.FULLSCREEN) {
2268
+ o.matchDropdownWidth = false;
2249
2269
  } else {
2250
2270
  if (isNarrowViewport()) {
2251
- o.fixDropdownWidth = true;
2271
+ o.matchDropdownWidth = true;
2252
2272
  }
2253
2273
  }
2254
2274
  if (o.onlyCountries?.length === 1) {
2255
2275
  o.initialCountry = o.onlyCountries[0];
2256
2276
  }
2257
- if (o.separateDialCode) {
2258
- o.nationalMode = false;
2259
- }
2260
- if (o.allowDropdown && !o.showFlags && !o.separateDialCode) {
2261
- o.nationalMode = false;
2277
+ if (o.separateDialCode && o.numberDisplayFormat === NUMBER_FORMAT.NATIONAL) {
2278
+ o.numberDisplayFormat = NUMBER_FORMAT.INTERNATIONAL;
2262
2279
  }
2263
- if (o.useFullscreenPopup && !o.dropdownContainer) {
2264
- o.dropdownContainer = document.body;
2280
+ if (o.countrySelectorMode !== COUNTRY_SELECTOR_MODE.OFF && !o.showFlags && !o.separateDialCode && o.numberDisplayFormat === NUMBER_FORMAT.NATIONAL) {
2281
+ o.numberDisplayFormat = NUMBER_FORMAT.INTERNATIONAL;
2265
2282
  }
2266
- o.i18n = { ...en_default, ...o.i18n };
2283
+ o.uiTranslations = { ...en_default, ...o.uiTranslations };
2267
2284
  };
2268
2285
 
2269
2286
  // packages/core/src/js/helpers/string.ts
@@ -2474,6 +2491,7 @@ var _factory = (() => {
2474
2491
  };
2475
2492
 
2476
2493
  // packages/core/src/js/core/ui.ts
2494
+ var supportsCssAnchor = typeof CSS !== "undefined" && typeof CSS.supports === "function" && CSS.supports("anchor-name: --x");
2477
2495
  var UI = class _UI {
2478
2496
  // private
2479
2497
  #options;
@@ -2488,8 +2506,8 @@ var _factory = (() => {
2488
2506
  #selectedCountryEl;
2489
2507
  #selectedFlagEl;
2490
2508
  #selectedDialCodeEl;
2491
- #dropdownArrowEl;
2492
- #dropdownContentEl;
2509
+ #arrowEl;
2510
+ #countrySelectorEl;
2493
2511
  #searchIconEl;
2494
2512
  #searchInputEl;
2495
2513
  #searchClearButtonEl;
@@ -2498,11 +2516,11 @@ var _factory = (() => {
2498
2516
  #hiddenInputCountryEl;
2499
2517
  #noResultsMessageEl;
2500
2518
  #searchResultsLiveRegionEl;
2501
- #detachedDropdownEl;
2519
+ #detachedCountrySelectorEl;
2502
2520
  #selectedListItemEl = null;
2503
2521
  #highlightedListItemEl = null;
2504
2522
  #listItemByIso2 = /* @__PURE__ */ new Map();
2505
- #dropdownAbortController = null;
2523
+ #countrySelectorAbortController = null;
2506
2524
  #resizeObserver;
2507
2525
  // public
2508
2526
  telInputEl;
@@ -2527,7 +2545,7 @@ var _factory = (() => {
2527
2545
  );
2528
2546
  }
2529
2547
  }
2530
- //* Generate all of the markup for the core library: the selected country overlay, and the dropdown.
2548
+ //* Generate all of the markup for the core library: the selected country overlay, and the country selector.
2531
2549
  buildMarkup(countries, searchTokens) {
2532
2550
  this.#countries = countries;
2533
2551
  this.#searchTokens = searchTokens;
@@ -2550,13 +2568,13 @@ var _factory = (() => {
2550
2568
  this.ensureDropdownWidthSet();
2551
2569
  }
2552
2570
  #createWrapperAndInsert() {
2553
- const { allowDropdown, showFlags, containerClass, useFullscreenPopup } = this.#options;
2571
+ const { countrySelectorMode, showFlags, containerClass } = this.#options;
2554
2572
  const parentClasses = buildClassNames({
2555
2573
  iti: true,
2556
2574
  "iti--input-container": true,
2557
- "iti--allow-dropdown": allowDropdown,
2575
+ "iti--has-country-selector": countrySelectorMode !== COUNTRY_SELECTOR_MODE.OFF,
2558
2576
  "iti--show-flags": showFlags,
2559
- "iti--inline-dropdown": !useFullscreenPopup,
2577
+ "iti--inline-country-selector": countrySelectorMode !== COUNTRY_SELECTOR_MODE.FULLSCREEN,
2560
2578
  [containerClass]: Boolean(containerClass)
2561
2579
  });
2562
2580
  const wrapper = createEl("div", { class: parentClasses });
@@ -2567,8 +2585,9 @@ var _factory = (() => {
2567
2585
  return wrapper;
2568
2586
  }
2569
2587
  #buildCountryContainer(wrapper) {
2570
- const { allowDropdown, separateDialCode, showFlags } = this.#options;
2571
- if (!allowDropdown && !showFlags && !separateDialCode) {
2588
+ const { countrySelectorMode, separateDialCode, showFlags } = this.#options;
2589
+ const enableCountrySelector = countrySelectorMode !== COUNTRY_SELECTOR_MODE.OFF;
2590
+ if (!enableCountrySelector && !showFlags && !separateDialCode) {
2572
2591
  return;
2573
2592
  }
2574
2593
  this.#countryContainerEl = createEl(
@@ -2577,16 +2596,16 @@ var _factory = (() => {
2577
2596
  { class: `iti__country-container ${CLASSES.V_HIDE}` },
2578
2597
  wrapper
2579
2598
  );
2580
- if (allowDropdown) {
2599
+ if (enableCountrySelector) {
2581
2600
  this.#selectedCountryEl = createEl(
2582
2601
  "button",
2583
2602
  {
2584
2603
  type: "button",
2585
2604
  class: "iti__selected-country",
2586
2605
  [ARIA.EXPANDED]: "false",
2587
- [ARIA.LABEL]: this.#options.i18n.noCountrySelected,
2606
+ [ARIA.LABEL]: this.#options.uiTranslations.noCountrySelected,
2588
2607
  [ARIA.HASPOPUP]: "dialog",
2589
- [ARIA.CONTROLS]: `iti-${this.#id}__dropdown-content`
2608
+ [ARIA.CONTROLS]: `iti-${this.#id}__country-selector`
2590
2609
  },
2591
2610
  this.#countryContainerEl
2592
2611
  );
@@ -2610,8 +2629,8 @@ var _factory = (() => {
2610
2629
  { class: CLASSES.FLAG },
2611
2630
  selectedCountryPrimary
2612
2631
  );
2613
- if (allowDropdown) {
2614
- this.#dropdownArrowEl = createEl(
2632
+ if (enableCountrySelector) {
2633
+ this.#arrowEl = createEl(
2615
2634
  "div",
2616
2635
  { class: "iti__arrow", [ARIA.HIDDEN]: "true" },
2617
2636
  selectedCountryPrimary
@@ -2624,38 +2643,39 @@ var _factory = (() => {
2624
2643
  this.#selectedCountryEl
2625
2644
  );
2626
2645
  }
2627
- if (allowDropdown) {
2628
- this.#buildDropdownContent();
2646
+ if (enableCountrySelector) {
2647
+ this.#buildCountrySelector();
2629
2648
  }
2630
2649
  }
2631
2650
  ensureDropdownWidthSet() {
2632
- const { fixDropdownWidth, allowDropdown } = this.#options;
2633
- if (!allowDropdown || !fixDropdownWidth || this.#dropdownContentEl.style.width) {
2651
+ const { matchDropdownWidth, countrySelectorMode } = this.#options;
2652
+ if (countrySelectorMode === COUNTRY_SELECTOR_MODE.OFF || !matchDropdownWidth || this.#countrySelectorEl.style.width) {
2634
2653
  return;
2635
2654
  }
2636
2655
  const inputWidth = this.telInputEl.offsetWidth;
2637
2656
  if (inputWidth > 0) {
2638
- this.#dropdownContentEl.style.width = `${inputWidth}px`;
2657
+ this.#countrySelectorEl.style.width = `${inputWidth}px`;
2639
2658
  }
2640
2659
  }
2641
- #buildDropdownContent() {
2660
+ #buildCountrySelector() {
2642
2661
  const {
2643
- fixDropdownWidth,
2644
- useFullscreenPopup,
2662
+ matchDropdownWidth,
2663
+ countrySelectorMode,
2645
2664
  countrySearch,
2646
- i18n,
2647
- dropdownContainer,
2665
+ uiTranslations,
2648
2666
  containerClass
2649
2667
  } = this.#options;
2650
- const extraClasses = fixDropdownWidth ? "" : "iti--flexible-dropdown-width";
2651
- this.#dropdownContentEl = createEl("div", {
2652
- id: `iti-${this.#id}__dropdown-content`,
2653
- class: `iti__dropdown-content ${CLASSES.HIDE} ${extraClasses}`,
2668
+ const isFullscreen = countrySelectorMode === COUNTRY_SELECTOR_MODE.FULLSCREEN;
2669
+ const detachedParent = this.#getDetachedParent();
2670
+ const extraClasses = matchDropdownWidth ? "" : "iti--flexible-dropdown-width";
2671
+ this.#countrySelectorEl = createEl("div", {
2672
+ id: `iti-${this.#id}__country-selector`,
2673
+ class: `iti__country-selector ${CLASSES.HIDE} ${extraClasses}`,
2654
2674
  role: "dialog",
2655
2675
  [ARIA.MODAL]: "true"
2656
2676
  });
2657
2677
  if (this.#isRTL) {
2658
- this.#dropdownContentEl.setAttribute("dir", "rtl");
2678
+ this.#countrySelectorEl.setAttribute("dir", "rtl");
2659
2679
  }
2660
2680
  if (countrySearch) {
2661
2681
  this.#buildSearchUI();
@@ -2666,40 +2686,54 @@ var _factory = (() => {
2666
2686
  class: "iti__country-list",
2667
2687
  id: `iti-${this.#id}__country-listbox`,
2668
2688
  role: "listbox",
2669
- [ARIA.LABEL]: i18n.countryListAriaLabel
2689
+ [ARIA.LABEL]: uiTranslations.countryListAriaLabel
2670
2690
  },
2671
- this.#dropdownContentEl
2691
+ this.#countrySelectorEl
2672
2692
  );
2673
2693
  this.#appendListItems();
2674
2694
  if (countrySearch) {
2675
2695
  this.#updateSearchResultsA11yText();
2676
2696
  }
2677
- if (!useFullscreenPopup) {
2697
+ if (!isFullscreen) {
2678
2698
  this.#inlineDropdownHeight = this.#getHiddenInlineDropdownHeight();
2679
2699
  if (countrySearch) {
2680
- this.#dropdownContentEl.style.height = `${this.#inlineDropdownHeight}px`;
2700
+ this.#countrySelectorEl.style.height = `${this.#inlineDropdownHeight}px`;
2681
2701
  }
2682
2702
  }
2683
- if (dropdownContainer) {
2684
- const dropdownClasses = buildClassNames({
2703
+ if (detachedParent) {
2704
+ const wrapperClasses = buildClassNames({
2685
2705
  iti: true,
2686
- "iti--container": true,
2687
- "iti--fullscreen-popup": useFullscreenPopup,
2688
- "iti--inline-dropdown": !useFullscreenPopup,
2706
+ "iti--detached-country-selector": true,
2707
+ "iti--fullscreen-popup": isFullscreen,
2708
+ "iti--inline-country-selector": !isFullscreen,
2689
2709
  [containerClass]: Boolean(containerClass)
2690
2710
  });
2691
- this.#detachedDropdownEl = createEl("div", { class: dropdownClasses });
2692
- this.#detachedDropdownEl.appendChild(this.#dropdownContentEl);
2711
+ this.#detachedCountrySelectorEl = createEl("div", { class: wrapperClasses });
2712
+ this.#detachedCountrySelectorEl.appendChild(this.#countrySelectorEl);
2713
+ if (!isFullscreen) {
2714
+ this.#setupCssAnchorPositioning();
2715
+ }
2693
2716
  } else {
2694
- this.#countryContainerEl.appendChild(this.#dropdownContentEl);
2717
+ this.#countryContainerEl.appendChild(this.#countrySelectorEl);
2718
+ }
2719
+ }
2720
+ //* Resolve the DOM element to attach the country selector to. Fullscreen always uses document.body; dropdown uses the consumer-supplied dropdownParent (if any); otherwise the country selector renders inline within the input wrapper (no detached element).
2721
+ #getDetachedParent() {
2722
+ const { countrySelectorMode, dropdownParent } = this.#options;
2723
+ if (countrySelectorMode === COUNTRY_SELECTOR_MODE.FULLSCREEN) {
2724
+ return document.body;
2695
2725
  }
2726
+ if (countrySelectorMode === COUNTRY_SELECTOR_MODE.DROPDOWN) {
2727
+ return dropdownParent;
2728
+ }
2729
+ return null;
2696
2730
  }
2697
2731
  #buildSearchUI() {
2698
- const { i18n, searchInputClass } = this.#options;
2732
+ const { uiTranslations, searchInputClass } = this.#options;
2699
2733
  const searchWrapper = createEl(
2700
2734
  "div",
2701
2735
  { class: "iti__search-input-wrapper" },
2702
- this.#dropdownContentEl
2736
+ this.#countrySelectorEl
2703
2737
  );
2704
2738
  this.#searchIconEl = createEl(
2705
2739
  "span",
@@ -2717,11 +2751,11 @@ var _factory = (() => {
2717
2751
  // Chrome says inputs need either a name or an id
2718
2752
  type: "search",
2719
2753
  class: `iti__search-input ${searchInputClass}`,
2720
- placeholder: i18n.searchPlaceholder,
2754
+ placeholder: uiTranslations.searchPlaceholder,
2721
2755
  // role=combobox + aria-autocomplete=list + aria-activedescendant allows maintaining focus on the search input while allowing users to navigate search results with up/down keyboard keys
2722
2756
  role: "combobox",
2723
2757
  [ARIA.EXPANDED]: "true",
2724
- [ARIA.LABEL]: i18n.searchPlaceholder,
2758
+ [ARIA.LABEL]: uiTranslations.searchPlaceholder,
2725
2759
  [ARIA.CONTROLS]: `iti-${this.#id}__country-listbox`,
2726
2760
  [ARIA.AUTOCOMPLETE]: "list",
2727
2761
  autocomplete: "off"
@@ -2733,7 +2767,7 @@ var _factory = (() => {
2733
2767
  {
2734
2768
  type: "button",
2735
2769
  class: `iti__search-clear ${CLASSES.HIDE}`,
2736
- [ARIA.LABEL]: i18n.clearSearchAriaLabel,
2770
+ [ARIA.LABEL]: uiTranslations.clearSearchAriaLabel,
2737
2771
  tabindex: "-1"
2738
2772
  },
2739
2773
  searchWrapper
@@ -2742,7 +2776,7 @@ var _factory = (() => {
2742
2776
  this.#searchResultsLiveRegionEl = createEl(
2743
2777
  "span",
2744
2778
  { class: "iti__a11y-text" },
2745
- this.#dropdownContentEl
2779
+ this.#countrySelectorEl
2746
2780
  );
2747
2781
  this.#noResultsMessageEl = createEl(
2748
2782
  "div",
@@ -2751,9 +2785,9 @@ var _factory = (() => {
2751
2785
  [ARIA.HIDDEN]: "true"
2752
2786
  // all a11y messaging happens in this.#searchResultsLiveRegionEl
2753
2787
  },
2754
- this.#dropdownContentEl
2788
+ this.#countrySelectorEl
2755
2789
  );
2756
- this.#noResultsMessageEl.textContent = i18n.searchEmptyState ?? null;
2790
+ this.#noResultsMessageEl.textContent = uiTranslations.searchEmptyState ?? null;
2757
2791
  }
2758
2792
  #updateInputPaddingAndReveal() {
2759
2793
  if (!this.#countryContainerEl) {
@@ -2763,12 +2797,12 @@ var _factory = (() => {
2763
2797
  this.#countryContainerEl.classList.remove(CLASSES.V_HIDE);
2764
2798
  }
2765
2799
  #buildHiddenInputs(wrapper) {
2766
- const { hiddenInput } = this.#options;
2767
- if (!hiddenInput) {
2800
+ const { hiddenInputs } = this.#options;
2801
+ if (!hiddenInputs) {
2768
2802
  return;
2769
2803
  }
2770
2804
  const telInputName = this.telInputEl.getAttribute("name") || "";
2771
- const names = hiddenInput(telInputName);
2805
+ const names = hiddenInputs(telInputName);
2772
2806
  if (names.phone) {
2773
2807
  const existingInput = this.telInputEl.form?.querySelector(
2774
2808
  `input[name="${names.phone}"]`
@@ -2833,7 +2867,7 @@ var _factory = (() => {
2833
2867
  //* Update the input padding to make space for (1) the selected country/globe, (2) the arrow, and (3) the separate dial code, all of which are optional, hence handling this in the JS rather than CSS.
2834
2868
  #updateInputPadding() {
2835
2869
  if (this.#selectedCountryEl) {
2836
- const fallbackWidth = this.#options.separateDialCode ? LAYOUT.FALLBACK_SELECTED_WITH_DIAL_WIDTH : LAYOUT.FALLBACK_SELECTED_NO_DIAL_WIDTH;
2870
+ const fallbackWidth = this.#options.separateDialCode ? LAYOUT.FALLBACK_SELECTED_COUNTRY_WITH_DIAL_WIDTH : LAYOUT.FALLBACK_SELECTED_COUNTRY_NO_DIAL_WIDTH;
2837
2871
  const selectedCountryWidth = this.#selectedCountryEl.offsetWidth || this.#getHiddenSelectedCountryWidth() || fallbackWidth;
2838
2872
  const inputPadding = selectedCountryWidth + LAYOUT.INPUT_PADDING_EXTRA_LEFT;
2839
2873
  this.telInputEl.style.paddingLeft = `${inputPadding}px`;
@@ -2887,24 +2921,24 @@ var _factory = (() => {
2887
2921
  // Get the dropdown height (before it is added to the DOM)
2888
2922
  #getHiddenInlineDropdownHeight() {
2889
2923
  const body = _UI.#getBody();
2890
- this.#dropdownContentEl.classList.remove(CLASSES.HIDE);
2924
+ this.#countrySelectorEl.classList.remove(CLASSES.HIDE);
2891
2925
  const tempContainer = createEl("div", {
2892
- class: "iti iti--inline-dropdown"
2926
+ class: "iti iti--inline-country-selector"
2893
2927
  });
2894
- tempContainer.appendChild(this.#dropdownContentEl);
2928
+ tempContainer.appendChild(this.#countrySelectorEl);
2895
2929
  tempContainer.style.visibility = "hidden";
2896
2930
  body.appendChild(tempContainer);
2897
- const height = this.#dropdownContentEl.offsetHeight;
2931
+ const height = this.#countrySelectorEl.offsetHeight;
2898
2932
  body.removeChild(tempContainer);
2899
2933
  tempContainer.style.visibility = "";
2900
- this.#dropdownContentEl.classList.add(CLASSES.HIDE);
2934
+ this.#countrySelectorEl.classList.add(CLASSES.HIDE);
2901
2935
  return height > 0 ? height : LAYOUT.FALLBACK_DROPDOWN_HEIGHT;
2902
2936
  }
2903
2937
  //* Update search results text (for a11y).
2904
2938
  #updateSearchResultsA11yText() {
2905
- const { i18n } = this.#options;
2939
+ const { uiTranslations } = this.#options;
2906
2940
  const count = this.#countryListEl.childElementCount;
2907
- this.#searchResultsLiveRegionEl.textContent = i18n.searchSummaryAria(count);
2941
+ this.#searchResultsLiveRegionEl.textContent = uiTranslations.searchSummaryAria(count);
2908
2942
  }
2909
2943
  //* Country search: Filter the countries according to the search query.
2910
2944
  #filterCountriesByQuery(query) {
@@ -2922,8 +2956,8 @@ var _factory = (() => {
2922
2956
  this.#showFilteredCountries(matchedCountries);
2923
2957
  }
2924
2958
  //* Pre-fill the search input with "+" and show all countries
2925
- //* (used when user types "+" in the phone input to open the dropdown).
2926
- //* Explicitly focus the search input (openDropdown skips this when
2959
+ //* (used when user types "+" in the phone input to open the country selector).
2960
+ //* Explicitly focus the search input (openCountrySelector skips this when
2927
2961
  //* dropdownAlwaysOpen, but here we need focus to redirect subsequent keystrokes).
2928
2962
  prefillSearchWithPlus() {
2929
2963
  this.#searchInputEl.value = "+";
@@ -3006,15 +3040,15 @@ var _factory = (() => {
3006
3040
  { signal }
3007
3041
  );
3008
3042
  }
3009
- //* Wire up triggers that open/close the dropdown: label click (focus input or swallow repeat click),
3043
+ //* Wire up triggers that open/close the country selector: label click (focus input or swallow repeat click),
3010
3044
  //* selected-country click (open), and keydown on countryContainer (open on arrow/space/enter, close on tab).
3011
- bindAllInitialDropdownListeners(signal, onOpen, onClose) {
3045
+ bindAllInitialCountrySelectorListeners(signal, onOpen, onClose) {
3012
3046
  const label = this.telInputEl.closest("label");
3013
3047
  if (label) {
3014
3048
  label.addEventListener(
3015
3049
  "click",
3016
3050
  (e) => {
3017
- if (!this.isDropdownOpen()) {
3051
+ if (!this.isCountrySelectorOpen()) {
3018
3052
  this.telInputEl.focus();
3019
3053
  } else {
3020
3054
  e.preventDefault();
@@ -3026,7 +3060,7 @@ var _factory = (() => {
3026
3060
  this.#selectedCountryEl.addEventListener(
3027
3061
  "click",
3028
3062
  () => {
3029
- if (!this.isDropdownOpen() && !this.telInputEl.disabled && !this.telInputEl.readOnly) {
3063
+ if (!this.isCountrySelectorOpen() && !this.telInputEl.disabled && !this.telInputEl.readOnly) {
3030
3064
  onOpen();
3031
3065
  }
3032
3066
  },
@@ -3041,7 +3075,7 @@ var _factory = (() => {
3041
3075
  KEYS.SPACE,
3042
3076
  KEYS.ENTER
3043
3077
  ];
3044
- if (!this.isDropdownOpen() && openKeys.includes(e.key)) {
3078
+ if (!this.isCountrySelectorOpen() && openKeys.includes(e.key)) {
3045
3079
  e.preventDefault();
3046
3080
  e.stopPropagation();
3047
3081
  onOpen();
@@ -3053,24 +3087,24 @@ var _factory = (() => {
3053
3087
  { signal }
3054
3088
  );
3055
3089
  }
3056
- //* Open the dropdown: create a fresh AbortController, do the DOM work, and wire up all
3057
- //* dropdown-open listeners (which invoke the caller's onSelect / onClose callbacks).
3058
- openDropdown(onSelect, onClose) {
3059
- const { countrySearch, dropdownAlwaysOpen, dropdownContainer } = this.#options;
3060
- this.#dropdownAbortController = new AbortController();
3090
+ //* Open the country selector: create a fresh AbortController, do the DOM work, and wire up all
3091
+ //* open-state listeners (which invoke the caller's onSelect / onClose callbacks).
3092
+ openCountrySelector(onSelect, onClose) {
3093
+ const { countrySearch, dropdownAlwaysOpen } = this.#options;
3094
+ this.#countrySelectorAbortController = new AbortController();
3061
3095
  this.ensureDropdownWidthSet();
3062
- if (dropdownContainer) {
3063
- this.#injectAndPositionDetachedDropdown();
3096
+ if (this.#detachedCountrySelectorEl) {
3097
+ this.#injectAndPositionDetachedCountrySelector();
3064
3098
  } else {
3065
- const positionBelow = this.#shouldPositionInlineDropdownBelowInput();
3099
+ const positionBelow = this.#shouldPositionDropdownBelowInput();
3066
3100
  const distance = this.telInputEl.offsetHeight + LAYOUT.DROPDOWN_MARGIN;
3067
3101
  if (positionBelow) {
3068
- this.#dropdownContentEl.style.top = `${distance}px`;
3102
+ this.#countrySelectorEl.style.top = `${distance}px`;
3069
3103
  } else {
3070
- this.#dropdownContentEl.style.bottom = `${distance}px`;
3104
+ this.#countrySelectorEl.style.bottom = `${distance}px`;
3071
3105
  }
3072
3106
  }
3073
- this.#dropdownContentEl.classList.remove(CLASSES.HIDE);
3107
+ this.#countrySelectorEl.classList.remove(CLASSES.HIDE);
3074
3108
  this.#selectedCountryEl.setAttribute(ARIA.EXPANDED, "true");
3075
3109
  const itemToHighlight = this.#selectedListItemEl ?? this.#countryListEl.firstElementChild;
3076
3110
  if (itemToHighlight) {
@@ -3079,7 +3113,7 @@ var _factory = (() => {
3079
3113
  if (countrySearch && !dropdownAlwaysOpen) {
3080
3114
  this.#searchInputEl.focus();
3081
3115
  }
3082
- if (this.#options.useFullscreenPopup && this.#detachedDropdownEl && window.visualViewport) {
3116
+ if (this.#options.countrySelectorMode === COUNTRY_SELECTOR_MODE.FULLSCREEN && this.#detachedCountrySelectorEl && window.visualViewport) {
3083
3117
  window.visualViewport.addEventListener(
3084
3118
  "resize",
3085
3119
  () => {
@@ -3088,29 +3122,29 @@ var _factory = (() => {
3088
3122
  this.#scrollCountryListToItem(this.#highlightedListItemEl);
3089
3123
  }
3090
3124
  },
3091
- { signal: this.#dropdownAbortController.signal }
3125
+ { signal: this.#countrySelectorAbortController.signal }
3092
3126
  );
3093
3127
  }
3094
- this.#dropdownArrowEl.classList.add(CLASSES.ARROW_UP);
3095
- this.#bindDropdownOpenListeners(onSelect, onClose);
3128
+ this.#arrowEl.classList.add(CLASSES.ARROW_UP);
3129
+ this.#bindCountrySelectorOpenListeners(onSelect, onClose);
3096
3130
  }
3097
- //* Wire up all listeners needed while the dropdown is open: list-item hover (highlight),
3131
+ //* Wire up all listeners needed while the country selector is open: list-item hover (highlight),
3098
3132
  //* list-item click & enter key (select), click-off & escape (close), search input (filter),
3099
- //* (when countrySearch disabled) typed-char hidden search, and (when dropdown is in an external
3100
- //* container) close on window scroll.
3101
- #bindDropdownOpenListeners(onSelect, onClose) {
3102
- const signal = this.#dropdownAbortController.signal;
3133
+ //* (when countrySearch disabled) typed-char hidden search, and (when the country selector is in an
3134
+ //* external container) update (fixed) position on scroll/resize.
3135
+ #bindCountrySelectorOpenListeners(onSelect, onClose) {
3136
+ const signal = this.#countrySelectorAbortController.signal;
3103
3137
  this.#bindListItemHover(signal);
3104
3138
  this.#bindListItemClick(signal, onSelect);
3105
3139
  if (!this.#options.dropdownAlwaysOpen) {
3106
3140
  this.#bindOutsideClickToClose(signal, onClose);
3107
3141
  }
3108
- this.#bindDropdownKeydownListener(signal, onSelect, onClose);
3142
+ this.#bindCountrySelectorKeydownListener(signal, onSelect, onClose);
3109
3143
  if (this.#options.countrySearch) {
3110
3144
  this.#bindSearchInputListener(signal);
3111
3145
  }
3112
- if (!this.#options.useFullscreenPopup && this.#options.dropdownContainer) {
3113
- window.addEventListener("scroll", onClose, { signal });
3146
+ if (this.#options.countrySelectorMode === COUNTRY_SELECTOR_MODE.DROPDOWN && this.#options.dropdownParent && !supportsCssAnchor) {
3147
+ document.addEventListener("scroll", onClose, { signal, capture: true, passive: true });
3114
3148
  }
3115
3149
  }
3116
3150
  //* When mouse over a list item, just highlight that one (so if they hit "enter" we know which to select).
@@ -3143,13 +3177,13 @@ var _factory = (() => {
3143
3177
  { signal }
3144
3178
  );
3145
3179
  }
3146
- //* Invoke onClickOff when the user clicks anywhere outside the dropdown.
3180
+ //* Invoke onClickOff when the user clicks anywhere outside the country selector.
3147
3181
  #bindOutsideClickToClose(signal, onClickOff) {
3148
3182
  setTimeout(() => {
3149
3183
  document.documentElement.addEventListener(
3150
3184
  "click",
3151
3185
  (e) => {
3152
- if (!this.#dropdownContentEl.contains(e.target)) {
3186
+ if (!this.#countrySelectorEl.contains(e.target)) {
3153
3187
  onClickOff();
3154
3188
  }
3155
3189
  },
@@ -3157,10 +3191,10 @@ var _factory = (() => {
3157
3191
  );
3158
3192
  }, 0);
3159
3193
  }
3160
- //* Keyboard navigation while the dropdown is open: arrow keys navigate, hidden-search keys filter,
3161
- //* and enter/escape invoke the caller's callbacks (which handle country selection / dropdown close).
3194
+ //* Keyboard navigation while the country selector is open: arrow keys navigate, hidden-search keys filter,
3195
+ //* and enter/escape invoke the caller's callbacks (which handle country selection / close).
3162
3196
  //* Uses keydown rather than keypress so non-char keys (arrow, esc) fire and so holding a key repeats.
3163
- #bindDropdownKeydownListener(signal, onEnter, onEscape) {
3197
+ #bindCountrySelectorKeydownListener(signal, onEnter, onEscape) {
3164
3198
  let query = "";
3165
3199
  let queryTimer = null;
3166
3200
  const handleKeydown = (e) => {
@@ -3195,7 +3229,7 @@ var _factory = (() => {
3195
3229
  }
3196
3230
  };
3197
3231
  this.#selectedCountryEl?.addEventListener("keydown", handleKeydown, { signal });
3198
- this.#dropdownContentEl?.addEventListener("keydown", handleKeydown, { signal });
3232
+ this.#countrySelectorEl?.addEventListener("keydown", handleKeydown, { signal });
3199
3233
  }
3200
3234
  //* Wire up country search input listener: typing filters the list, the clear button resets it.
3201
3235
  #bindSearchInputListener(signal) {
@@ -3232,7 +3266,7 @@ var _factory = (() => {
3232
3266
  this.#highlightListItem(next);
3233
3267
  }
3234
3268
  }
3235
- // Update the selected list item in the dropdown
3269
+ // Update the selected list item in the country list
3236
3270
  #updateSelectedListItem(iso2) {
3237
3271
  if (this.#selectedListItemEl && this.#selectedListItemEl.dataset[DATA_KEYS.ISO2] !== iso2) {
3238
3272
  this.#selectedListItemEl.setAttribute(ARIA.SELECTED, "false");
@@ -3283,12 +3317,12 @@ var _factory = (() => {
3283
3317
  this.#countryListEl.scrollTop = 0;
3284
3318
  this.#updateSearchResultsA11yText();
3285
3319
  }
3286
- // UI: Close the dropdown (DOM + abort dropdown-scoped listeners).
3287
- closeDropdown() {
3288
- const { countrySearch, dropdownContainer } = this.#options;
3289
- this.#dropdownAbortController.abort();
3290
- this.#dropdownAbortController = null;
3291
- this.#dropdownContentEl.classList.add(CLASSES.HIDE);
3320
+ // UI: Close the country selector (DOM + abort scoped listeners).
3321
+ closeCountrySelector() {
3322
+ const { countrySearch } = this.#options;
3323
+ this.#countrySelectorAbortController.abort();
3324
+ this.#countrySelectorAbortController = null;
3325
+ this.#countrySelectorEl.classList.add(CLASSES.HIDE);
3292
3326
  this.#selectedCountryEl.setAttribute(ARIA.EXPANDED, "false");
3293
3327
  if (countrySearch) {
3294
3328
  this.#searchInputEl.removeAttribute(ARIA.ACTIVE_DESCENDANT);
@@ -3299,19 +3333,19 @@ var _factory = (() => {
3299
3333
  this.#highlightedListItemEl = null;
3300
3334
  }
3301
3335
  }
3302
- this.#dropdownArrowEl.classList.remove(CLASSES.ARROW_UP);
3303
- if (dropdownContainer) {
3304
- this.#detachedDropdownEl.remove();
3305
- this.#detachedDropdownEl.style.top = "";
3306
- this.#detachedDropdownEl.style.bottom = "";
3307
- this.#detachedDropdownEl.style.paddingLeft = "";
3308
- this.#detachedDropdownEl.style.paddingRight = "";
3336
+ this.#arrowEl.classList.remove(CLASSES.ARROW_UP);
3337
+ if (this.#detachedCountrySelectorEl) {
3338
+ this.#detachedCountrySelectorEl.remove();
3339
+ this.#detachedCountrySelectorEl.style.top = "";
3340
+ this.#detachedCountrySelectorEl.style.bottom = "";
3341
+ this.#detachedCountrySelectorEl.style.paddingLeft = "";
3342
+ this.#detachedCountrySelectorEl.style.paddingRight = "";
3309
3343
  } else {
3310
- this.#dropdownContentEl.style.top = "";
3311
- this.#dropdownContentEl.style.bottom = "";
3344
+ this.#countrySelectorEl.style.top = "";
3345
+ this.#countrySelectorEl.style.bottom = "";
3312
3346
  }
3313
3347
  }
3314
- #shouldPositionInlineDropdownBelowInput() {
3348
+ #shouldPositionDropdownBelowInput() {
3315
3349
  if (this.#options.dropdownAlwaysOpen) {
3316
3350
  return true;
3317
3351
  }
@@ -3320,41 +3354,54 @@ var _factory = (() => {
3320
3354
  const spaceBelow = window.innerHeight - inputPos.bottom;
3321
3355
  return spaceBelow >= this.#inlineDropdownHeight || spaceBelow >= spaceAbove;
3322
3356
  }
3323
- // inject dropdown into container and apply positioning styles
3324
- #injectAndPositionDetachedDropdown() {
3325
- const { dropdownContainer, useFullscreenPopup } = this.#options;
3326
- if (useFullscreenPopup) {
3357
+ // inject the country selector into its detached wrapper and apply positioning styles
3358
+ #injectAndPositionDetachedCountrySelector() {
3359
+ const isFullscreen = this.#options.countrySelectorMode === COUNTRY_SELECTOR_MODE.FULLSCREEN;
3360
+ const detachedParent = this.#getDetachedParent();
3361
+ if (isFullscreen) {
3327
3362
  if (window.innerWidth >= LAYOUT.NARROW_VIEWPORT_WIDTH) {
3328
3363
  const inputPos = this.telInputEl.getBoundingClientRect();
3329
- this.#detachedDropdownEl.style.paddingLeft = `${inputPos.left}px`;
3330
- this.#detachedDropdownEl.style.paddingRight = `${window.innerWidth - inputPos.right}px`;
3364
+ this.#detachedCountrySelectorEl.style.paddingLeft = `${inputPos.left}px`;
3365
+ this.#detachedCountrySelectorEl.style.paddingRight = `${window.innerWidth - inputPos.right}px`;
3331
3366
  }
3332
- } else {
3367
+ } else if (!supportsCssAnchor) {
3333
3368
  const inputPos = this.telInputEl.getBoundingClientRect();
3334
- this.#detachedDropdownEl.style.left = `${inputPos.left}px`;
3335
- const positionBelow = this.#shouldPositionInlineDropdownBelowInput();
3336
- if (positionBelow) {
3337
- this.#detachedDropdownEl.style.top = `${inputPos.bottom + LAYOUT.DROPDOWN_MARGIN}px`;
3369
+ this.#detachedCountrySelectorEl.style.left = `${inputPos.left}px`;
3370
+ if (this.#shouldPositionDropdownBelowInput()) {
3371
+ this.#detachedCountrySelectorEl.style.top = `${inputPos.bottom + LAYOUT.DROPDOWN_MARGIN}px`;
3338
3372
  } else {
3339
- this.#detachedDropdownEl.style.top = "unset";
3340
- this.#detachedDropdownEl.style.bottom = `${window.innerHeight - inputPos.top + LAYOUT.DROPDOWN_MARGIN}px`;
3373
+ this.#detachedCountrySelectorEl.style.top = "unset";
3374
+ this.#detachedCountrySelectorEl.style.bottom = `${window.innerHeight - inputPos.top + LAYOUT.DROPDOWN_MARGIN}px`;
3341
3375
  }
3342
3376
  }
3343
- dropdownContainer.appendChild(this.#detachedDropdownEl);
3377
+ detachedParent.appendChild(this.#detachedCountrySelectorEl);
3378
+ }
3379
+ //* Wire up CSS Anchor Positioning between the input and the detached country selector using a
3380
+ //* unique anchor name per instance. Called once at build time — the matching styles in
3381
+ //* intlTelInput.css only take effect in browsers that support anchor(); elsewhere these
3382
+ //* properties are inert. We append our name to any existing anchor-name (read via
3383
+ //* getComputedStyle so we pick up CSS-defined values), so consumer-set anchors on the input
3384
+ //* are preserved. Caveat: this snapshots the consumer's value once — if they later change
3385
+ //* anchor-name via CSS (e.g. a class swap), our inline write will shadow the change.
3386
+ #setupCssAnchorPositioning() {
3387
+ const anchorName = `--iti-anchor-${this.#id}`;
3388
+ const existing = getComputedStyle(this.telInputEl).anchorName;
3389
+ this.telInputEl.style.anchorName = existing && existing !== "none" ? `${existing}, ${anchorName}` : anchorName;
3390
+ this.#detachedCountrySelectorEl.style.positionAnchor = anchorName;
3344
3391
  }
3345
3392
  // Adjust the fullscreen popup dimensions to match the visual viewport,
3346
3393
  // so it stays above the virtual keyboard on mobile devices.
3347
3394
  #adjustFullscreenPopupToViewport() {
3348
3395
  const vv = window.visualViewport;
3349
- if (!vv || !this.#detachedDropdownEl) {
3396
+ if (!vv || !this.#detachedCountrySelectorEl) {
3350
3397
  return;
3351
3398
  }
3352
3399
  const virtualKeyboardHeight = window.innerHeight - vv.height;
3353
- this.#detachedDropdownEl.style.bottom = `${virtualKeyboardHeight}px`;
3400
+ this.#detachedCountrySelectorEl.style.bottom = `${virtualKeyboardHeight}px`;
3354
3401
  }
3355
- // UI: Whether the dropdown is currently open (visible).
3356
- isDropdownOpen() {
3357
- return !this.#dropdownContentEl.classList.contains(CLASSES.HIDE);
3402
+ // UI: Whether the country selector is currently open (visible).
3403
+ isCountrySelectorOpen() {
3404
+ return !this.#countrySelectorEl.classList.contains(CLASSES.HIDE);
3358
3405
  }
3359
3406
  // Toggle the loading spinner on the selected flag (used during auto-country geoIP lookup).
3360
3407
  setLoading(isLoading) {
@@ -3383,7 +3430,7 @@ var _factory = (() => {
3383
3430
  isLoading() {
3384
3431
  return this.#selectedFlagEl.classList.contains(CLASSES.LOADING);
3385
3432
  }
3386
- // Set the disabled state of the input and dropdown.
3433
+ // Set the disabled state of the input and country selector.
3387
3434
  setDisabled(disabled) {
3388
3435
  this.telInputEl.disabled = disabled;
3389
3436
  if (this.#selectedCountryEl) {
@@ -3394,7 +3441,7 @@ var _factory = (() => {
3394
3441
  }
3395
3442
  }
3396
3443
  }
3397
- // Set the readonly state of the input and dropdown.
3444
+ // Set the readonly state of the input and country selector.
3398
3445
  setReadonly(readonly) {
3399
3446
  this.telInputEl.readOnly = readonly;
3400
3447
  if (this.#selectedCountryEl) {
@@ -3405,12 +3452,12 @@ var _factory = (() => {
3405
3452
  }
3406
3453
  }
3407
3454
  }
3408
- setCountry(selectedCountryData) {
3409
- const { allowDropdown, showFlags, separateDialCode, i18n } = this.#options;
3410
- const name = selectedCountryData?.name;
3411
- const dialCode = selectedCountryData?.dialCode;
3412
- const iso2 = selectedCountryData?.iso2 ?? "";
3413
- if (allowDropdown) {
3455
+ setSelectedCountry(selectedCountry) {
3456
+ const { countrySelectorMode, showFlags, separateDialCode, uiTranslations } = this.#options;
3457
+ const name = selectedCountry?.name;
3458
+ const dialCode = selectedCountry?.dialCode;
3459
+ const iso2 = selectedCountry?.iso2 ?? "";
3460
+ if (countrySelectorMode !== COUNTRY_SELECTOR_MODE.OFF) {
3414
3461
  this.#updateSelectedListItem(iso2);
3415
3462
  }
3416
3463
  if (this.#selectedCountryEl) {
@@ -3419,13 +3466,13 @@ var _factory = (() => {
3419
3466
  let flagContent = null;
3420
3467
  if (iso2) {
3421
3468
  title = name;
3422
- ariaLabel = i18n.selectedCountryAriaLabel.replace("${countryName}", name).replace("${dialCode}", `+${dialCode}`);
3469
+ ariaLabel = uiTranslations.selectedCountryAriaLabel.replace("${countryName}", name).replace("${dialCode}", `+${dialCode}`);
3423
3470
  if (!showFlags) {
3424
3471
  flagContent = buildGlobeIcon();
3425
3472
  }
3426
3473
  } else {
3427
- title = i18n.noCountrySelected;
3428
- ariaLabel = i18n.noCountrySelected;
3474
+ title = uiTranslations.noCountrySelected;
3475
+ ariaLabel = uiTranslations.noCountrySelected;
3429
3476
  flagContent = buildGlobeIcon();
3430
3477
  }
3431
3478
  this.#selectedFlagEl.className = flagClass;
@@ -3574,17 +3621,17 @@ var _factory = (() => {
3574
3621
  };
3575
3622
 
3576
3623
  // packages/core/src/js/format/formatting.ts
3577
- var stripSeparateDialCode = (fullNumber, hasValidDialCode, separateDialCode, selectedCountryData) => {
3624
+ var stripSeparateDialCode = (fullNumber, hasValidDialCode, separateDialCode, selectedCountry) => {
3578
3625
  if (!separateDialCode || !hasValidDialCode) {
3579
3626
  return fullNumber;
3580
3627
  }
3581
- const dialCode = `+${selectedCountryData.dialCode}`;
3628
+ const dialCode = `+${selectedCountry.dialCode}`;
3582
3629
  const start = fullNumber[dialCode.length] === " " || fullNumber[dialCode.length] === "-" ? dialCode.length + 1 : dialCode.length;
3583
3630
  return fullNumber.substring(start);
3584
3631
  };
3585
- var formatNumberAsYouType = (fullNumber, telInputValue, utils, selectedCountryData, separateDialCode) => {
3586
- const result = utils ? utils.formatNumberAsYouType(fullNumber, selectedCountryData?.iso2) : fullNumber;
3587
- const dialCode = selectedCountryData?.dialCode;
3632
+ var formatNumberAsYouType = (fullNumber, telInputValue, utils, selectedCountry, separateDialCode) => {
3633
+ const result = utils ? utils.formatNumberAsYouType(fullNumber, selectedCountry?.iso2) : fullNumber;
3634
+ const dialCode = selectedCountry?.dialCode;
3588
3635
  if (separateDialCode && telInputValue.charAt(0) !== "+" && result.includes(`+${dialCode}`)) {
3589
3636
  const afterDialCode = result.split(`+${dialCode}`)[1] || "";
3590
3637
  return afterDialCode.trim();
@@ -3715,8 +3762,8 @@ var _factory = (() => {
3715
3762
  this.#ui.telInputEl.value = this.#numerals.denormalise(asciiValue);
3716
3763
  }
3717
3764
  #createInitPromise(options) {
3718
- const { initialCountry, geoIpLookup, loadUtils } = options;
3719
- const needsAutoCountryDeferred = initialCountry === INITIAL_COUNTRY.AUTO && Boolean(geoIpLookup);
3765
+ const { initialCountry, initialCountryLookup, loadUtils } = options;
3766
+ const needsAutoCountryDeferred = !initialCountry && Boolean(initialCountryLookup);
3720
3767
  const needsUtilsDeferred = Boolean(loadUtils) && !intlTelInput.utils;
3721
3768
  if (needsAutoCountryDeferred) {
3722
3769
  this.#autoCountryDeferred = createDeferred();
@@ -3738,7 +3785,7 @@ var _factory = (() => {
3738
3785
  this.#initListeners();
3739
3786
  this.#startAsyncLoads();
3740
3787
  if (this.#options.dropdownAlwaysOpen) {
3741
- this.#openDropdown();
3788
+ this.openCountrySelector();
3742
3789
  }
3743
3790
  }
3744
3791
  //********************
@@ -3761,8 +3808,8 @@ var _factory = (() => {
3761
3808
  const value = useAttribute ? attributeValue : inputValue;
3762
3809
  const dialCode = this.#getDialCode(value);
3763
3810
  const isRegionlessNanpNumber = isRegionlessNanp(value);
3764
- const { initialCountry, geoIpLookup } = this.#options;
3765
- const isAutoCountry = initialCountry === INITIAL_COUNTRY.AUTO && geoIpLookup;
3811
+ const { initialCountry, initialCountryLookup } = this.#options;
3812
+ const isAutoCountry = !initialCountry && Boolean(initialCountryLookup);
3766
3813
  const resolvedInitialCountry = isAutoCountry && intlTelInput.autoCountry ? intlTelInput.autoCountry : initialCountry;
3767
3814
  const doingAutoCountryLookup = isAutoCountry && !overrideAutoCountry && !intlTelInput.autoCountry;
3768
3815
  const isValidInitialCountry = isIso2(resolvedInitialCountry);
@@ -3791,11 +3838,11 @@ var _factory = (() => {
3791
3838
  //* Initialise the main event listeners: input keyup, and click selected country.
3792
3839
  #initListeners() {
3793
3840
  this.#bindAllTelInputListeners();
3794
- if (this.#options.allowDropdown) {
3795
- this.#ui.bindAllInitialDropdownListeners(
3841
+ if (this.#options.countrySelectorMode !== COUNTRY_SELECTOR_MODE.OFF) {
3842
+ this.#ui.bindAllInitialCountrySelectorListeners(
3796
3843
  this.#abortController.signal,
3797
- () => this.#openDropdown(),
3798
- () => this.#closeDropdown()
3844
+ () => this.openCountrySelector(),
3845
+ () => this.#closeCountrySelectorInternal()
3799
3846
  );
3800
3847
  }
3801
3848
  this.#ui.bindHiddenInputSubmitListener(
@@ -3804,7 +3851,7 @@ var _factory = (() => {
3804
3851
  () => this.#selectedCountry?.iso2 || ""
3805
3852
  );
3806
3853
  }
3807
- //* Init requests: utils script / geo ip lookup.
3854
+ //* Init requests: utils script / initial country lookup.
3808
3855
  #startAsyncLoads() {
3809
3856
  if (this.#utilsDeferred) {
3810
3857
  const { loadUtils } = this.#options;
@@ -3828,7 +3875,7 @@ var _factory = (() => {
3828
3875
  }
3829
3876
  }
3830
3877
  }
3831
- //* Perform the geo ip lookup.
3878
+ //* Perform the initial country lookup.
3832
3879
  async #loadAutoCountry() {
3833
3880
  if (intlTelInput.autoCountry) {
3834
3881
  this.#handleAutoCountryLoaded();
@@ -3839,14 +3886,14 @@ var _factory = (() => {
3839
3886
  return;
3840
3887
  }
3841
3888
  intlTelInput.startedLoadingAutoCountry = true;
3842
- if (typeof this.#options.geoIpLookup === "function") {
3889
+ if (typeof this.#options.initialCountryLookup === "function") {
3843
3890
  let timeoutId;
3844
3891
  try {
3845
3892
  const iso2 = await Promise.race([
3846
- this.#options.geoIpLookup(),
3893
+ this.#options.initialCountryLookup(),
3847
3894
  new Promise((_, reject) => {
3848
3895
  timeoutId = setTimeout(
3849
- () => reject(new Error("intl-tel-input: geoIpLookup timed out after 10s")),
3896
+ () => reject(new Error("intl-tel-input: initialCountryLookup timed out after 10s")),
3850
3897
  1e4
3851
3898
  );
3852
3899
  })
@@ -3869,8 +3916,8 @@ var _factory = (() => {
3869
3916
  }
3870
3917
  }
3871
3918
  }
3872
- #openDropdownWithPlus() {
3873
- this.#openDropdown();
3919
+ #openCountrySelectorWithPlus() {
3920
+ this.openCountrySelector();
3874
3921
  this.#ui.prefillSearchWithPlus();
3875
3922
  }
3876
3923
  //* Delete the character just typed (the one immediately before the caret). Used by Android workarounds where we can't preventDefault on keydown.
@@ -3890,7 +3937,7 @@ var _factory = (() => {
3890
3937
  //* Android workaround for handling plus when separateDialCode enabled (as impossible to handle with keydown/keyup, for which e.key always returns "Unidentified", see https://stackoverflow.com/q/59584061/217866)
3891
3938
  #handleAndroidPlusKey(inputValue) {
3892
3939
  this.#removeJustTypedChar(inputValue);
3893
- this.#openDropdownWithPlus();
3940
+ this.#openCountrySelectorWithPlus();
3894
3941
  }
3895
3942
  //* Android strictMode workaround: the keydown-based filter can't block these because e.key is "Unidentified" on Android virtual keyboards, so strip them here on input.
3896
3943
  #handleAndroidStrictReject(inputValue, rejectedInput) {
@@ -3960,7 +4007,7 @@ var _factory = (() => {
3960
4007
  strictMode,
3961
4008
  formatAsYouType,
3962
4009
  separateDialCode,
3963
- allowDropdown,
4010
+ countrySelectorMode,
3964
4011
  countrySearch
3965
4012
  } = this.#options;
3966
4013
  const detail = e?.detail;
@@ -3970,7 +4017,7 @@ var _factory = (() => {
3970
4017
  let inputValue = this.#getTelInputValue();
3971
4018
  const isPaste = e?.inputType === INPUT_TYPES.PASTE;
3972
4019
  const isStrictPaste = strictMode && isPaste;
3973
- if (this.#isAndroid && !isPaste && e?.data === "+" && separateDialCode && allowDropdown && countrySearch) {
4020
+ if (this.#isAndroid && !isPaste && e?.data === "+" && separateDialCode && countrySelectorMode !== COUNTRY_SELECTOR_MODE.OFF && countrySearch) {
3974
4021
  this.#handleAndroidPlusKey(inputValue);
3975
4022
  return;
3976
4023
  }
@@ -4017,13 +4064,13 @@ var _factory = (() => {
4017
4064
  //* On keydown event: (1) if strictMode then prevent invalid characters, (2) if separateDialCode then handle plus key
4018
4065
  //* Note that this fires BEFORE the input is updated.
4019
4066
  #handleKeydownEvent = (e) => {
4020
- const { strictMode, separateDialCode, allowDropdown, countrySearch } = this.#options;
4067
+ const { strictMode, separateDialCode, countrySelectorMode, countrySearch } = this.#options;
4021
4068
  if (!e.key || e.key.length !== 1 || e.altKey || e.ctrlKey || e.metaKey) {
4022
4069
  return;
4023
4070
  }
4024
- if (separateDialCode && allowDropdown && countrySearch && e.key === "+") {
4071
+ if (separateDialCode && countrySelectorMode !== COUNTRY_SELECTOR_MODE.OFF && countrySearch && e.key === "+") {
4025
4072
  e.preventDefault();
4026
- this.#openDropdownWithPlus();
4073
+ this.#openCountrySelectorWithPlus();
4027
4074
  return;
4028
4075
  }
4029
4076
  if (!strictMode) {
@@ -4186,27 +4233,36 @@ var _factory = (() => {
4186
4233
  });
4187
4234
  this.#ui.telInputEl.dispatchEvent(e);
4188
4235
  }
4189
- //* Open the dropdown. Bail if already open — otherwise the existing AbortController gets overwritten
4190
- //* and its listeners leak. Reachable via openDropdownWithPlus when dropdownAlwaysOpen is set
4191
- #openDropdown() {
4192
- if (this.#ui.isDropdownOpen()) {
4236
+ //* Open the country selector. Bail if already open — otherwise the existing AbortController gets overwritten
4237
+ //* and its listeners leak. Reachable via openCountrySelectorWithPlus when dropdownAlwaysOpen is set.
4238
+ //* Public so consumers can programmatically open the country selector.
4239
+ openCountrySelector() {
4240
+ if (this.#ui.isCountrySelectorOpen()) {
4193
4241
  return;
4194
4242
  }
4195
- this.#ui.openDropdown(
4243
+ this.#ui.openCountrySelector(
4196
4244
  (li) => this.#selectListItem(li),
4197
- () => this.#closeDropdown()
4245
+ () => this.#closeCountrySelectorInternal()
4198
4246
  );
4199
- this.#dispatchEvent(EVENTS.OPEN_COUNTRY_DROPDOWN);
4247
+ this.#dispatchEvent(EVENTS.OPEN_COUNTRY_SELECTOR);
4200
4248
  }
4201
4249
  //* Update the input's value to the given number (format first if possible)
4202
4250
  //* NOTE: this is called from setInitialState, handleUtilsLoaded and setNumber.
4203
4251
  #updateValueFromNumber(fullNumber) {
4204
- const { formatOnDisplay, nationalMode, separateDialCode } = this.#options;
4252
+ const { numberDisplayFormat, separateDialCode } = this.#options;
4205
4253
  let number = fullNumber;
4206
- if (formatOnDisplay && intlTelInput.utils && this.#selectedCountry) {
4254
+ if (intlTelInput.utils && this.#selectedCountry) {
4207
4255
  const isRegionless = hasRegionlessDialCode(fullNumber);
4208
- const useNational = nationalMode && !isRegionless || !number.startsWith("+") && !separateDialCode;
4209
- const format = useNational ? NUMBER_FORMAT.NATIONAL : NUMBER_FORMAT.INTERNATIONAL;
4256
+ const preserveUserNational = !number.startsWith("+") && !separateDialCode;
4257
+ const useNational = numberDisplayFormat === NUMBER_FORMAT.NATIONAL && !isRegionless || preserveUserNational;
4258
+ let format;
4259
+ if (useNational) {
4260
+ format = NUMBER_FORMAT.NATIONAL;
4261
+ } else if (numberDisplayFormat === NUMBER_FORMAT.E164 && !isRegionless) {
4262
+ format = NUMBER_FORMAT.E164;
4263
+ } else {
4264
+ format = NUMBER_FORMAT.INTERNATIONAL;
4265
+ }
4210
4266
  number = intlTelInput.utils.formatNumber(
4211
4267
  number,
4212
4268
  this.#selectedCountry?.iso2,
@@ -4303,14 +4359,14 @@ var _factory = (() => {
4303
4359
  return null;
4304
4360
  }
4305
4361
  //* Update the selected country, dial code (if separateDialCode), placeholder, title, and selected list item.
4306
- //* Note: called from setInitialState, updateCountryFromNumber, selectListItem, setCountry.
4362
+ //* Note: called from setInitialState, updateCountryFromNumber, selectListItem, setSelectedCountry.
4307
4363
  #updateSelectedCountry(iso2) {
4308
4364
  const prevIso2 = this.#selectedCountry?.iso2 || "";
4309
4365
  this.#selectedCountry = iso2 ? this.#countryByIso2.get(iso2) : null;
4310
4366
  if (this.#selectedCountry) {
4311
4367
  this.#fallbackCountryIso2 = this.#selectedCountry.iso2;
4312
4368
  }
4313
- this.#ui.setCountry(this.#selectedCountry);
4369
+ this.#ui.setSelectedCountry(this.#selectedCountry);
4314
4370
  this.#updatePlaceholder();
4315
4371
  this.#updateMaxCoreNumberLength();
4316
4372
  return prevIso2 !== iso2;
@@ -4328,12 +4384,11 @@ var _factory = (() => {
4328
4384
  }
4329
4385
  let exampleNumber = intlTelInput.utils.getExampleNumber(
4330
4386
  iso2,
4331
- false,
4332
4387
  placeholderNumberType,
4333
- true
4388
+ NUMBER_FORMAT.E164
4334
4389
  );
4335
4390
  let validNumber = exampleNumber;
4336
- while (intlTelInput.utils.isPossibleNumber(
4391
+ while (intlTelInput.utils.isValidNumber(
4337
4392
  exampleNumber,
4338
4393
  iso2,
4339
4394
  allowedNumberTypes
@@ -4350,19 +4405,19 @@ var _factory = (() => {
4350
4405
  //* Update the input placeholder to an example number from the currently selected country.
4351
4406
  #updatePlaceholder() {
4352
4407
  const {
4353
- autoPlaceholder,
4408
+ placeholderNumberPolicy,
4354
4409
  placeholderNumberType,
4355
- nationalMode,
4410
+ numberDisplayFormat,
4356
4411
  customPlaceholder
4357
4412
  } = this.#options;
4358
- const shouldSetPlaceholder = autoPlaceholder === PLACEHOLDER_MODES.AGGRESSIVE || !this.#ui.hadInitialPlaceholder && autoPlaceholder === PLACEHOLDER_MODES.POLITE;
4413
+ const shouldSetPlaceholder = placeholderNumberPolicy === PLACEHOLDER_POLICY.AGGRESSIVE || !this.#ui.hadInitialPlaceholder && placeholderNumberPolicy === PLACEHOLDER_POLICY.POLITE;
4359
4414
  if (!intlTelInput.utils || !shouldSetPlaceholder) {
4360
4415
  return;
4361
4416
  }
4362
4417
  let placeholder = this.#selectedCountry ? intlTelInput.utils.getExampleNumber(
4363
4418
  this.#selectedCountry.iso2,
4364
- nationalMode,
4365
- placeholderNumberType
4419
+ placeholderNumberType,
4420
+ numberDisplayFormat
4366
4421
  ) : "";
4367
4422
  placeholder = this.#prepareNumberForInput(placeholder);
4368
4423
  if (typeof customPlaceholder === "function") {
@@ -4370,36 +4425,40 @@ var _factory = (() => {
4370
4425
  }
4371
4426
  this.#ui.telInputEl.setAttribute("placeholder", placeholder);
4372
4427
  }
4373
- //* Called when the user selects a list item from the dropdown (no-op if listItem is null).
4428
+ //* Called when the user selects a list item from the country list (no-op if listItem is null).
4374
4429
  #selectListItem(listItem) {
4375
4430
  if (!listItem) {
4376
4431
  return;
4377
4432
  }
4378
4433
  const iso2 = listItem.dataset[DATA_KEYS.ISO2];
4379
4434
  const countryChanged = this.#updateSelectedCountry(iso2);
4380
- this.#closeDropdown();
4435
+ this.#closeCountrySelectorInternal();
4381
4436
  const dialCode = listItem.dataset[DATA_KEYS.DIAL_CODE];
4382
4437
  this.#updateDialCode(dialCode);
4383
- if (this.#options.formatOnDisplay) {
4384
- const inputValue = this.#getTelInputValue();
4385
- this.#updateValueFromNumber(inputValue);
4386
- }
4438
+ const inputValue = this.#getTelInputValue();
4439
+ this.#updateValueFromNumber(inputValue);
4387
4440
  this.#ui.telInputEl.focus();
4388
4441
  if (countryChanged) {
4389
4442
  this.#dispatchCountryChangeEvent();
4390
4443
  this.#dispatchEvent(EVENTS.INPUT, { isCountryChange: true });
4391
4444
  }
4392
4445
  }
4393
- //* Close the dropdown and unbind any listeners.
4394
- #closeDropdown(isDestroy) {
4395
- if (!this.#ui.isDropdownOpen() || this.#options.dropdownAlwaysOpen && !isDestroy) {
4446
+ //* Public: close the country selector (consumer-callable; delegates to the internal helper
4447
+ //* without the destroy-specific path).
4448
+ closeCountrySelector() {
4449
+ this.#closeCountrySelectorInternal();
4450
+ }
4451
+ //* Close the country selector and unbind any listeners. The isDestroy flag forces close even
4452
+ //* when dropdownAlwaysOpen is set, so destroy() can fully tear down.
4453
+ #closeCountrySelectorInternal(isDestroy) {
4454
+ if (!this.#ui.isCountrySelectorOpen() || this.#options.dropdownAlwaysOpen && !isDestroy) {
4396
4455
  return;
4397
4456
  }
4398
- this.#ui.closeDropdown();
4399
- this.#dispatchEvent(EVENTS.CLOSE_COUNTRY_DROPDOWN);
4457
+ this.#ui.closeCountrySelector();
4458
+ this.#dispatchEvent(EVENTS.CLOSE_COUNTRY_SELECTOR);
4400
4459
  }
4401
4460
  //* Replace any existing dial code with the new one
4402
- //* Note: called from selectListItem and setCountry
4461
+ //* Note: called from selectListItem and setSelectedCountry
4403
4462
  #updateDialCode(newDialCodeDigits) {
4404
4463
  const inputValue = this.#getTelInputValue();
4405
4464
  if (!inputValue.startsWith("+")) {
@@ -4479,7 +4538,7 @@ var _factory = (() => {
4479
4538
  //**************************
4480
4539
  //* INTERNAL METHODS
4481
4540
  //**************************
4482
- //* Called when the geoip call returns.
4541
+ //* Called when the initial country lookup returns.
4483
4542
  #handleAutoCountryLoaded() {
4484
4543
  if (!this.#autoCountryDeferred || !intlTelInput.autoCountry) {
4485
4544
  return;
@@ -4488,15 +4547,17 @@ var _factory = (() => {
4488
4547
  this.#autoCountryDeferred.resolve();
4489
4548
  return;
4490
4549
  }
4491
- if (this.#ui.isLoading()) {
4492
- this.setCountry(intlTelInput.autoCountry);
4550
+ const isFocused = document.activeElement === this.#ui.telInputEl;
4551
+ const hasTypedValue = Boolean(this.#getTelInputValue());
4552
+ if (this.#ui.isLoading() && !(isFocused && hasTypedValue)) {
4553
+ this.setSelectedCountry(intlTelInput.autoCountry);
4493
4554
  } else {
4494
4555
  this.#fallbackCountryIso2 = intlTelInput.autoCountry;
4495
4556
  }
4496
4557
  this.#ui.setLoading(false);
4497
4558
  this.#autoCountryDeferred.resolve();
4498
4559
  }
4499
- //* Called when the geoip call fails or times out.
4560
+ //* Called when the initial country lookup fails or times out.
4500
4561
  #handleAutoCountryFailure() {
4501
4562
  if (!this.#isActive) {
4502
4563
  this.#autoCountryDeferred?.reject();
@@ -4517,7 +4578,8 @@ var _factory = (() => {
4517
4578
  return;
4518
4579
  }
4519
4580
  const inputValue = this.#getTelInputValue();
4520
- if (inputValue) {
4581
+ const isFocused = document.activeElement === this.#ui.telInputEl;
4582
+ if (inputValue && !isFocused) {
4521
4583
  this.#updateValueFromNumber(inputValue);
4522
4584
  }
4523
4585
  if (this.#selectedCountry) {
@@ -4543,8 +4605,8 @@ var _factory = (() => {
4543
4605
  return;
4544
4606
  }
4545
4607
  this.#isActive = false;
4546
- if (this.#options.allowDropdown) {
4547
- this.#closeDropdown(true);
4608
+ if (this.#options.countrySelectorMode !== COUNTRY_SELECTOR_MODE.OFF) {
4609
+ this.#closeCountrySelectorInternal(true);
4548
4610
  }
4549
4611
  this.#abortController.abort();
4550
4612
  this.#ui.destroy();
@@ -4592,7 +4654,7 @@ var _factory = (() => {
4592
4654
  );
4593
4655
  }
4594
4656
  //* Get the country data for the currently selected country.
4595
- getSelectedCountryData() {
4657
+ getSelectedCountry() {
4596
4658
  return this.#selectedCountry ?? null;
4597
4659
  }
4598
4660
  //* Get the validation error e.g. "TOO_SHORT" / "TOO_LONG", or null if it can't be determined / instance is destroyed.
@@ -4647,7 +4709,7 @@ var _factory = (() => {
4647
4709
  if (!this.#selectedCountry && !hasRegionlessDialCode(value)) {
4648
4710
  return false;
4649
4711
  }
4650
- const check = mode === "precise" ? intlTelInput.utils.isValidNumber : intlTelInput.utils.isPossibleNumber;
4712
+ const check = mode === "precise" ? intlTelInput.utils.isValidNumberPrecise : intlTelInput.utils.isValidNumber;
4651
4713
  if (!check(value, iso2, allowedNumberTypes)) {
4652
4714
  return false;
4653
4715
  }
@@ -4660,7 +4722,7 @@ var _factory = (() => {
4660
4722
  return true;
4661
4723
  }
4662
4724
  //* Update the selected country, and update the input value accordingly.
4663
- setCountry(iso2) {
4725
+ setSelectedCountry(iso2) {
4664
4726
  if (!this.#isActive) {
4665
4727
  return;
4666
4728
  }
@@ -4675,10 +4737,8 @@ var _factory = (() => {
4675
4737
  }
4676
4738
  this.#updateSelectedCountry(iso2Lower);
4677
4739
  this.#updateDialCode(this.#selectedCountry?.dialCode || "");
4678
- if (this.#options.formatOnDisplay) {
4679
- const inputValue = this.#getTelInputValue();
4680
- this.#updateValueFromNumber(inputValue);
4681
- }
4740
+ const inputValue = this.#getTelInputValue();
4741
+ this.#updateValueFromNumber(inputValue);
4682
4742
  this.#dispatchCountryChangeEvent();
4683
4743
  this.#dispatchEvent(EVENTS.INPUT, { isCountryChange: true });
4684
4744
  }
@@ -4703,14 +4763,14 @@ var _factory = (() => {
4703
4763
  this.#options.placeholderNumberType = type;
4704
4764
  this.#updatePlaceholder();
4705
4765
  }
4706
- // Set the disabled state of the input and dropdown.
4766
+ // Set the disabled state of the input and country selector.
4707
4767
  setDisabled(disabled) {
4708
4768
  if (!this.#isActive) {
4709
4769
  return;
4710
4770
  }
4711
4771
  this.#ui.setDisabled(disabled);
4712
4772
  }
4713
- // Set the readonly state of the input and dropdown.
4773
+ // Set the readonly state of the input and country selector.
4714
4774
  setReadonly(readonly) {
4715
4775
  if (!this.#isActive) {
4716
4776
  return;
@@ -4720,7 +4780,7 @@ var _factory = (() => {
4720
4780
  //********************
4721
4781
  //* STATIC METHODS
4722
4782
  //********************
4723
- // Internal instance notification used by utils/geoip loaders.
4783
+ // Internal instance notification used by utils/initial-country loaders.
4724
4784
  // Kept public so module-level helpers (e.g. attachUtils) can call it, while still allowing
4725
4785
  // access to private instance methods.
4726
4786
  static forEachInstance(method, ...args) {
@@ -4784,8 +4844,8 @@ var _factory = (() => {
4784
4844
  defaults,
4785
4845
  //* Using a static var like this allows us to mock it in the tests.
4786
4846
  documentReady: () => document.readyState === "complete",
4787
- //* Get the country data object.
4788
- getCountryData: () => data_default,
4847
+ //* Get the full list of all countries the library knows about.
4848
+ getAllCountries: () => data_default,
4789
4849
  //* A getter for the core library instance.
4790
4850
  getInstance: (input) => {
4791
4851
  const id = input.dataset[DATA_KEYS.INSTANCE_ID];
@@ -4796,10 +4856,12 @@ var _factory = (() => {
4796
4856
  attachUtils,
4797
4857
  startedLoadingUtils: false,
4798
4858
  startedLoadingAutoCountry: false,
4799
- version: "28.1.0",
4859
+ version: "29.0.1",
4800
4860
  NUMBER_FORMAT,
4801
4861
  NUMBER_TYPE,
4802
- VALIDATION_ERROR
4862
+ VALIDATION_ERROR,
4863
+ PLACEHOLDER_POLICY,
4864
+ COUNTRY_SELECTOR_MODE
4803
4865
  }
4804
4866
  );
4805
4867
  var intlTelInput_default = intlTelInput;