intl-tel-input 25.10.11 → 25.11.0

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.
@@ -1,5 +1,5 @@
1
1
  /*
2
- * International Telephone Input v25.10.11
2
+ * International Telephone Input v25.11.0
3
3
  * https://github.com/jackocnr/intl-tel-input.git
4
4
  * Licensed under the MIT license
5
5
  */
@@ -2091,6 +2091,7 @@ var factoryOutput = (() => {
2091
2091
  var normaliseString = (s = "") => s.normalize("NFD").replace(/[\u0300-\u036f]/g, "").toLowerCase();
2092
2092
 
2093
2093
  // src/js/modules/utils/dom.ts
2094
+ var buildClassNames = (flags) => Object.keys(flags).filter((k) => Boolean(flags[k])).join(" ");
2094
2095
  var createEl = (tagName, attrs, container) => {
2095
2096
  const el = document.createElement(tagName);
2096
2097
  if (attrs) {
@@ -2102,258 +2103,23 @@ var factoryOutput = (() => {
2102
2103
  return el;
2103
2104
  };
2104
2105
 
2105
- // src/js/modules/data/country-data.ts
2106
- function processAllCountries(options) {
2107
- const { onlyCountries, excludeCountries } = options;
2108
- if (onlyCountries.length) {
2109
- const lowerCaseOnlyCountries = onlyCountries.map((country) => country.toLowerCase());
2110
- return data_default.filter((country) => lowerCaseOnlyCountries.includes(country.iso2));
2111
- } else if (excludeCountries.length) {
2112
- const lowerCaseExcludeCountries = excludeCountries.map((country) => country.toLowerCase());
2113
- return data_default.filter((country) => !lowerCaseExcludeCountries.includes(country.iso2));
2114
- }
2115
- return data_default;
2116
- }
2117
- function translateCountryNames(countries, options) {
2118
- for (const c of countries) {
2119
- const iso2 = c.iso2.toLowerCase();
2120
- if (options.i18n[iso2]) {
2121
- c.name = options.i18n[iso2];
2122
- }
2123
- }
2124
- }
2125
- function processDialCodes(countries, options) {
2126
- const dialCodes = /* @__PURE__ */ new Set();
2127
- let dialCodeMaxLen = 0;
2128
- const dialCodeToIso2Map = {};
2129
- const _addToDialCodeMap = (iso2, dialCode, priority) => {
2130
- if (!iso2 || !dialCode) {
2131
- return;
2132
- }
2133
- if (dialCode.length > dialCodeMaxLen) {
2134
- dialCodeMaxLen = dialCode.length;
2135
- }
2136
- if (!dialCodeToIso2Map.hasOwnProperty(dialCode)) {
2137
- dialCodeToIso2Map[dialCode] = [];
2138
- }
2139
- const iso2List = dialCodeToIso2Map[dialCode];
2140
- if (iso2List.includes(iso2)) {
2141
- return;
2142
- }
2143
- const index = priority !== void 0 ? priority : iso2List.length;
2144
- iso2List[index] = iso2;
2145
- };
2146
- for (const c of countries) {
2147
- if (!dialCodes.has(c.dialCode)) {
2148
- dialCodes.add(c.dialCode);
2149
- }
2150
- for (let k = 1; k < c.dialCode.length; k++) {
2151
- const partialDialCode = c.dialCode.substring(0, k);
2152
- _addToDialCodeMap(c.iso2, partialDialCode);
2153
- }
2154
- _addToDialCodeMap(c.iso2, c.dialCode, c.priority);
2155
- }
2156
- if (options.onlyCountries.length || options.excludeCountries.length) {
2157
- dialCodes.forEach((dialCode) => {
2158
- dialCodeToIso2Map[dialCode] = dialCodeToIso2Map[dialCode].filter(Boolean);
2159
- });
2160
- }
2161
- for (const c of countries) {
2162
- if (c.areaCodes) {
2163
- const rootIso2Code = dialCodeToIso2Map[c.dialCode][0];
2164
- for (const areaCode of c.areaCodes) {
2165
- for (let k = 1; k < areaCode.length; k++) {
2166
- const partialAreaCode = areaCode.substring(0, k);
2167
- const partialDialCode = c.dialCode + partialAreaCode;
2168
- _addToDialCodeMap(rootIso2Code, partialDialCode);
2169
- _addToDialCodeMap(c.iso2, partialDialCode);
2170
- }
2171
- _addToDialCodeMap(c.iso2, c.dialCode + areaCode);
2172
- }
2173
- }
2174
- }
2175
- return { dialCodes, dialCodeMaxLen, dialCodeToIso2Map };
2176
- }
2177
- function sortCountries(countries, options) {
2178
- if (options.countryOrder) {
2179
- options.countryOrder = options.countryOrder.map((iso2) => iso2.toLowerCase());
2180
- }
2181
- countries.sort((a, b) => {
2182
- const { countryOrder } = options;
2183
- if (countryOrder) {
2184
- const aIndex = countryOrder.indexOf(a.iso2);
2185
- const bIndex = countryOrder.indexOf(b.iso2);
2186
- const aIndexExists = aIndex > -1;
2187
- const bIndexExists = bIndex > -1;
2188
- if (aIndexExists || bIndexExists) {
2189
- if (aIndexExists && bIndexExists) {
2190
- return aIndex - bIndex;
2191
- }
2192
- return aIndexExists ? -1 : 1;
2193
- }
2194
- }
2195
- return a.name.localeCompare(b.name);
2196
- });
2197
- }
2198
- function cacheSearchTokens(countries) {
2199
- for (const c of countries) {
2200
- c.normalisedName = normaliseString(c.name);
2201
- c.initials = c.name.split(/[^a-zA-ZÀ-ÿа-яА-Я]/).map((word) => word[0]).join("").toLowerCase();
2202
- c.dialCodePlus = `+${c.dialCode}`;
2203
- }
2204
- }
2205
-
2206
- // src/js/modules/format/formatting.ts
2207
- function beforeSetNumber(fullNumber, dialCode, separateDialCode, selectedCountryData) {
2208
- let number = fullNumber;
2209
- if (separateDialCode) {
2210
- if (dialCode) {
2211
- dialCode = `+${selectedCountryData.dialCode}`;
2212
- const start = number[dialCode.length] === " " || number[dialCode.length] === "-" ? dialCode.length + 1 : dialCode.length;
2213
- number = number.substring(start);
2214
- }
2215
- }
2216
- return number;
2217
- }
2218
- function formatNumberAsYouType(fullNumber, telInputValue, utils, selectedCountryData, separateDialCode) {
2219
- const result = utils ? utils.formatNumberAsYouType(fullNumber, selectedCountryData.iso2) : fullNumber;
2220
- const { dialCode } = selectedCountryData;
2221
- if (separateDialCode && telInputValue.charAt(0) !== "+" && result.includes(`+${dialCode}`)) {
2222
- const afterDialCode = result.split(`+${dialCode}`)[1] || "";
2223
- return afterDialCode.trim();
2224
- }
2225
- return result;
2226
- }
2227
-
2228
- // src/js/modules/format/caret.ts
2229
- function translateCursorPosition(relevantChars, formattedValue, prevCaretPos, isDeleteForwards) {
2230
- if (prevCaretPos === 0 && !isDeleteForwards) {
2231
- return 0;
2232
- }
2233
- let relevantCharCount = 0;
2234
- for (let i = 0; i < formattedValue.length; i++) {
2235
- if (/[+0-9]/.test(formattedValue[i])) {
2236
- relevantCharCount++;
2237
- }
2238
- if (relevantCharCount === relevantChars && !isDeleteForwards) {
2239
- return i + 1;
2240
- }
2241
- if (isDeleteForwards && relevantCharCount === relevantChars + 1) {
2242
- return i;
2243
- }
2244
- }
2245
- return formattedValue.length;
2246
- }
2247
-
2248
- // src/js/modules/data/nanp-regionless.ts
2249
- var regionlessNanpNumbers = [
2250
- "800",
2251
- "822",
2252
- "833",
2253
- "844",
2254
- "855",
2255
- "866",
2256
- "877",
2257
- "880",
2258
- "881",
2259
- "882",
2260
- "883",
2261
- "884",
2262
- "885",
2263
- "886",
2264
- "887",
2265
- "888",
2266
- "889"
2267
- ];
2268
- var isRegionlessNanp = (number) => {
2269
- const numeric = getNumeric(number);
2270
- if (numeric.charAt(0) === "1") {
2271
- const areaCode = numeric.substring(1, 4);
2272
- return regionlessNanpNumbers.includes(areaCode);
2273
- }
2274
- return false;
2275
- };
2276
-
2277
- // src/js/intl-tel-input.ts
2278
- for (const c of data_default) {
2279
- c.name = en_default[c.iso2];
2280
- }
2281
- var id = 0;
2282
- var iso2Set = new Set(data_default.map((c) => c.iso2));
2283
- var isIso2 = (val) => iso2Set.has(val);
2284
- var forEachInstance = (method, ...args) => {
2285
- const { instances } = intlTelInput;
2286
- Object.values(instances).forEach((instance) => instance[method](...args));
2287
- };
2288
- var Iti = class _Iti {
2289
- /**
2290
- * Build a space-delimited class string from an object map of className -> truthy/falsey.
2291
- * Only keys with truthy values are included.
2292
- */
2293
- static _buildClassNames(flags) {
2294
- return Object.keys(flags).filter((k) => Boolean(flags[k])).join(" ");
2295
- }
2296
- constructor(input, customOptions = {}) {
2297
- this.id = id++;
2298
- this.telInput = input;
2106
+ // src/js/modules/core/ui.ts
2107
+ var UI = class {
2108
+ constructor(input, options, id2) {
2299
2109
  this.highlightedItem = null;
2300
- this.options = Object.assign({}, defaults, customOptions);
2110
+ input.dataset.intlTelInputId = id2.toString();
2111
+ this.telInput = input;
2112
+ this.options = options;
2113
+ this.id = id2;
2301
2114
  this.hadInitialPlaceholder = Boolean(input.getAttribute("placeholder"));
2302
- }
2303
- _detectEnvironmentAndLayout() {
2304
- this.isAndroid = typeof navigator !== "undefined" ? /Android/i.test(navigator.userAgent) : false;
2305
2115
  this.isRTL = !!this.telInput.closest("[dir=rtl]");
2306
- this.telInput.dir = "ltr";
2307
- const showOnDefaultSide = this.options.allowDropdown || this.options.separateDialCode;
2308
- this.showSelectedCountryOnLeft = this.isRTL ? !showOnDefaultSide : showOnDefaultSide;
2309
2116
  if (this.options.separateDialCode) {
2310
- if (this.isRTL) {
2311
- this.originalPaddingRight = this.telInput.style.paddingRight;
2312
- } else {
2313
- this.originalPaddingLeft = this.telInput.style.paddingLeft;
2314
- }
2117
+ this.originalPaddingLeft = this.telInput.style.paddingLeft;
2315
2118
  }
2316
2119
  }
2317
- _createInitPromises() {
2318
- const autoCountryPromise = new Promise((resolve, reject) => {
2319
- this.resolveAutoCountryPromise = resolve;
2320
- this.rejectAutoCountryPromise = reject;
2321
- });
2322
- const utilsScriptPromise = new Promise((resolve, reject) => {
2323
- this.resolveUtilsScriptPromise = resolve;
2324
- this.rejectUtilsScriptPromise = reject;
2325
- });
2326
- this.promise = Promise.all([autoCountryPromise, utilsScriptPromise]);
2327
- }
2328
- //* Can't be private as it's called from intlTelInput convenience wrapper.
2329
- _init() {
2330
- applyOptionSideEffects(this.options);
2331
- this._detectEnvironmentAndLayout();
2332
- this._createInitPromises();
2333
- this.selectedCountryData = {};
2334
- this._processCountryData();
2335
- this._generateMarkup();
2336
- this._setInitialState();
2337
- this._initListeners();
2338
- this._initRequests();
2339
- }
2340
- //********************
2341
- //* PRIVATE METHODS
2342
- //********************
2343
- //* Prepare all of the country data, including onlyCountries, excludeCountries, countryOrder options.
2344
- _processCountryData() {
2345
- this.countries = processAllCountries(this.options);
2346
- const dialRes = processDialCodes(this.countries, this.options);
2347
- this.dialCodes = dialRes.dialCodes;
2348
- this.dialCodeMaxLen = dialRes.dialCodeMaxLen;
2349
- this.dialCodeToIso2Map = dialRes.dialCodeToIso2Map;
2350
- translateCountryNames(this.countries, this.options);
2351
- sortCountries(this.countries, this.options);
2352
- this.countryByIso2 = new Map(this.countries.map((c) => [c.iso2, c]));
2353
- cacheSearchTokens(this.countries);
2354
- }
2355
2120
  //* Generate all of the markup for the plugin: the selected country overlay, and the dropdown.
2356
- _generateMarkup() {
2121
+ generateMarkup(countries) {
2122
+ this.countries = countries;
2357
2123
  this._prepareTelInput();
2358
2124
  const wrapper = this._createWrapperAndInsert();
2359
2125
  this._maybeBuildCountryContainer(wrapper);
@@ -2363,7 +2129,7 @@ var factoryOutput = (() => {
2363
2129
  }
2364
2130
  _prepareTelInput() {
2365
2131
  this.telInput.classList.add("iti__tel-input");
2366
- if (!this.telInput.hasAttribute("autocomplete") && !(this.telInput.form && this.telInput.form.hasAttribute("autocomplete"))) {
2132
+ if (!this.telInput.hasAttribute("autocomplete") && !this.telInput.form?.hasAttribute("autocomplete")) {
2367
2133
  this.telInput.setAttribute("autocomplete", "off");
2368
2134
  }
2369
2135
  }
@@ -2374,23 +2140,22 @@ var factoryOutput = (() => {
2374
2140
  containerClass,
2375
2141
  useFullscreenPopup
2376
2142
  } = this.options;
2377
- const parentClasses = _Iti._buildClassNames({
2378
- "iti": true,
2143
+ const parentClasses = buildClassNames({
2144
+ iti: true,
2379
2145
  "iti--allow-dropdown": allowDropdown,
2380
2146
  "iti--show-flags": showFlags,
2381
2147
  "iti--inline-dropdown": !useFullscreenPopup,
2382
2148
  [containerClass]: Boolean(containerClass)
2383
2149
  });
2384
2150
  const wrapper = createEl("div", { class: parentClasses });
2385
- this.telInput.parentNode?.insertBefore(wrapper, this.telInput);
2151
+ if (this.isRTL) {
2152
+ wrapper.setAttribute("dir", "ltr");
2153
+ }
2154
+ this.telInput.before(wrapper);
2386
2155
  return wrapper;
2387
2156
  }
2388
2157
  _maybeBuildCountryContainer(wrapper) {
2389
- const {
2390
- allowDropdown,
2391
- separateDialCode,
2392
- showFlags
2393
- } = this.options;
2158
+ const { allowDropdown, separateDialCode, showFlags } = this.options;
2394
2159
  if (allowDropdown || showFlags || separateDialCode) {
2395
2160
  this.countryContainer = createEl(
2396
2161
  "div",
@@ -2398,11 +2163,6 @@ var factoryOutput = (() => {
2398
2163
  { class: "iti__country-container iti__v-hide" },
2399
2164
  wrapper
2400
2165
  );
2401
- if (this.showSelectedCountryOnLeft) {
2402
- this.countryContainer.style.left = "0px";
2403
- } else {
2404
- this.countryContainer.style.right = "0px";
2405
- }
2406
2166
  if (allowDropdown) {
2407
2167
  this.selectedCountry = createEl(
2408
2168
  "button",
@@ -2446,7 +2206,7 @@ var factoryOutput = (() => {
2446
2206
  if (separateDialCode) {
2447
2207
  this.selectedDialCode = createEl(
2448
2208
  "div",
2449
- { class: "iti__selected-dial-code", dir: "ltr" },
2209
+ { class: "iti__selected-dial-code" },
2450
2210
  this.selectedCountry
2451
2211
  );
2452
2212
  }
@@ -2471,6 +2231,9 @@ var factoryOutput = (() => {
2471
2231
  role: "dialog",
2472
2232
  "aria-modal": "true"
2473
2233
  });
2234
+ if (this.isRTL) {
2235
+ this.dropdownContent.setAttribute("dir", "rtl");
2236
+ }
2474
2237
  if (countrySearch) {
2475
2238
  this._buildSearchUI();
2476
2239
  }
@@ -2485,12 +2248,12 @@ var factoryOutput = (() => {
2485
2248
  this.dropdownContent
2486
2249
  );
2487
2250
  this._appendListItems();
2488
- if (countrySearch) {
2489
- this._updateSearchResultsA11yText();
2251
+ if (this.options.countrySearch) {
2252
+ this.updateSearchResultsA11yText();
2490
2253
  }
2491
2254
  if (dropdownContainer) {
2492
- const dropdownClasses = _Iti._buildClassNames({
2493
- "iti": true,
2255
+ const dropdownClasses = buildClassNames({
2256
+ iti: true,
2494
2257
  "iti--container": true,
2495
2258
  "iti--fullscreen-popup": useFullscreenPopup,
2496
2259
  "iti--inline-dropdown": !useFullscreenPopup,
@@ -2536,7 +2299,7 @@ var factoryOutput = (() => {
2536
2299
  "aria-label": i18n.searchPlaceholder,
2537
2300
  "aria-controls": `iti-${this.id}__country-listbox`,
2538
2301
  "aria-autocomplete": "list",
2539
- "autocomplete": "off"
2302
+ autocomplete: "off"
2540
2303
  },
2541
2304
  searchWrapper
2542
2305
  );
@@ -2573,80 +2336,478 @@ var factoryOutput = (() => {
2573
2336
  },
2574
2337
  this.dropdownContent
2575
2338
  );
2576
- this.searchNoResults.textContent = i18n.zeroSearchResults;
2339
+ this.searchNoResults.textContent = i18n.zeroSearchResults;
2340
+ }
2341
+ _maybeUpdateInputPaddingAndReveal() {
2342
+ if (this.countryContainer) {
2343
+ this.updateInputPadding();
2344
+ this.countryContainer.classList.remove("iti__v-hide");
2345
+ }
2346
+ }
2347
+ _maybeBuildHiddenInputs(wrapper) {
2348
+ const { hiddenInput } = this.options;
2349
+ if (hiddenInput) {
2350
+ const telInputName = this.telInput.getAttribute("name") || "";
2351
+ const names = hiddenInput(telInputName);
2352
+ if (names.phone) {
2353
+ const existingInput = this.telInput.form?.querySelector(
2354
+ `input[name="${names.phone}"]`
2355
+ );
2356
+ if (existingInput) {
2357
+ this.hiddenInput = existingInput;
2358
+ } else {
2359
+ this.hiddenInput = createEl("input", {
2360
+ type: "hidden",
2361
+ name: names.phone
2362
+ });
2363
+ wrapper.appendChild(this.hiddenInput);
2364
+ }
2365
+ }
2366
+ if (names.country) {
2367
+ const existingInput = this.telInput.form?.querySelector(
2368
+ `input[name="${names.country}"]`
2369
+ );
2370
+ if (existingInput) {
2371
+ this.hiddenInputCountry = existingInput;
2372
+ } else {
2373
+ this.hiddenInputCountry = createEl("input", {
2374
+ type: "hidden",
2375
+ name: names.country
2376
+ });
2377
+ wrapper.appendChild(this.hiddenInputCountry);
2378
+ }
2379
+ }
2380
+ }
2381
+ }
2382
+ //* For each country: add a country list item <li> to the countryList <ul> container.
2383
+ _appendListItems() {
2384
+ const frag = document.createDocumentFragment();
2385
+ for (let i = 0; i < this.countries.length; i++) {
2386
+ const c = this.countries[i];
2387
+ const liClass = buildClassNames({
2388
+ iti__country: true,
2389
+ iti__highlight: i === 0
2390
+ });
2391
+ const listItem = createEl("li", {
2392
+ id: `iti-${this.id}__item-${c.iso2}`,
2393
+ class: liClass,
2394
+ tabindex: "-1",
2395
+ role: "option",
2396
+ "aria-selected": "false"
2397
+ });
2398
+ listItem.dataset.dialCode = c.dialCode;
2399
+ listItem.dataset.countryCode = c.iso2;
2400
+ c.nodeById[this.id] = listItem;
2401
+ if (this.options.showFlags) {
2402
+ createEl("div", { class: `iti__flag iti__${c.iso2}` }, listItem);
2403
+ }
2404
+ const nameEl = createEl("span", { class: "iti__country-name" }, listItem);
2405
+ nameEl.textContent = c.name;
2406
+ const dialEl = createEl("span", { class: "iti__dial-code" }, listItem);
2407
+ if (this.isRTL) {
2408
+ dialEl.setAttribute("dir", "ltr");
2409
+ }
2410
+ dialEl.textContent = `+${c.dialCode}`;
2411
+ frag.appendChild(listItem);
2412
+ }
2413
+ this.countryList.appendChild(frag);
2414
+ }
2415
+ //* Update the input padding to make space for the selected country/dial code.
2416
+ updateInputPadding() {
2417
+ if (this.selectedCountry) {
2418
+ const saneDefaultWidth = this.options.separateDialCode ? 78 : 42;
2419
+ const selectedCountryWidth = this.selectedCountry.offsetWidth || this._getHiddenSelectedCountryWidth() || saneDefaultWidth;
2420
+ const inputPadding = selectedCountryWidth + 6;
2421
+ this.telInput.style.paddingLeft = `${inputPadding}px`;
2422
+ }
2423
+ }
2424
+ //* When input is in a hidden container during init, we cannot calculate the selected country width.
2425
+ //* Fix: clone the markup, make it invisible, add it to the end of the DOM, and then measure it's width.
2426
+ //* To get the right styling to apply, all we need is a shallow clone of the container,
2427
+ //* and then to inject a deep clone of the selectedCountry element.
2428
+ _getHiddenSelectedCountryWidth() {
2429
+ if (this.telInput.parentNode) {
2430
+ let body;
2431
+ try {
2432
+ body = window.top.document.body;
2433
+ } catch (e) {
2434
+ body = document.body;
2435
+ }
2436
+ const containerClone = this.telInput.parentNode.cloneNode(
2437
+ false
2438
+ );
2439
+ containerClone.style.visibility = "hidden";
2440
+ body.appendChild(containerClone);
2441
+ const countryContainerClone = this.countryContainer.cloneNode();
2442
+ containerClone.appendChild(countryContainerClone);
2443
+ const selectedCountryClone = this.selectedCountry.cloneNode(
2444
+ true
2445
+ );
2446
+ countryContainerClone.appendChild(selectedCountryClone);
2447
+ const width = selectedCountryClone.offsetWidth;
2448
+ body.removeChild(containerClone);
2449
+ return width;
2450
+ }
2451
+ return 0;
2452
+ }
2453
+ //* Update search results text (for a11y).
2454
+ updateSearchResultsA11yText() {
2455
+ const { i18n } = this.options;
2456
+ const count = this.countryList.childElementCount;
2457
+ let searchText;
2458
+ if (count === 0) {
2459
+ searchText = i18n.zeroSearchResults;
2460
+ } else {
2461
+ if (i18n.searchResultsText) {
2462
+ searchText = i18n.searchResultsText(count);
2463
+ } else if (count === 1) {
2464
+ searchText = i18n.oneSearchResult;
2465
+ } else {
2466
+ searchText = i18n.multipleSearchResults.replace(
2467
+ "${count}",
2468
+ count.toString()
2469
+ );
2470
+ }
2471
+ }
2472
+ this.searchResultsA11yText.textContent = searchText;
2473
+ }
2474
+ //* Check if an element is visible within it's container, else scroll until it is.
2475
+ scrollTo(element) {
2476
+ const container = this.countryList;
2477
+ const scrollTop = document.documentElement.scrollTop;
2478
+ const containerHeight = container.offsetHeight;
2479
+ const containerTop = container.getBoundingClientRect().top + scrollTop;
2480
+ const containerBottom = containerTop + containerHeight;
2481
+ const elementHeight = element.offsetHeight;
2482
+ const elementTop = element.getBoundingClientRect().top + scrollTop;
2483
+ const elementBottom = elementTop + elementHeight;
2484
+ const newScrollTop = elementTop - containerTop + container.scrollTop;
2485
+ if (elementTop < containerTop) {
2486
+ container.scrollTop = newScrollTop;
2487
+ } else if (elementBottom > containerBottom) {
2488
+ const heightDifference = containerHeight - elementHeight;
2489
+ container.scrollTop = newScrollTop - heightDifference;
2490
+ }
2491
+ }
2492
+ //* Remove highlighting from other list items and highlight the given item.
2493
+ highlightListItem(listItem, shouldFocus) {
2494
+ const prevItem = this.highlightedItem;
2495
+ if (prevItem) {
2496
+ prevItem.classList.remove("iti__highlight");
2497
+ prevItem.setAttribute("aria-selected", "false");
2498
+ }
2499
+ this.highlightedItem = listItem;
2500
+ if (this.highlightedItem) {
2501
+ this.highlightedItem.classList.add("iti__highlight");
2502
+ this.highlightedItem.setAttribute("aria-selected", "true");
2503
+ if (this.options.countrySearch) {
2504
+ const activeDescendant = this.highlightedItem.getAttribute("id") || "";
2505
+ this.searchInput.setAttribute(
2506
+ "aria-activedescendant",
2507
+ activeDescendant
2508
+ );
2509
+ }
2510
+ }
2511
+ if (shouldFocus) {
2512
+ this.highlightedItem.focus();
2513
+ }
2514
+ }
2515
+ //* Country search: Filter the country list to the given array of countries.
2516
+ filterCountries(matchedCountries) {
2517
+ this.countryList.innerHTML = "";
2518
+ let noCountriesAddedYet = true;
2519
+ for (const c of matchedCountries) {
2520
+ const listItem = c.nodeById[this.id];
2521
+ if (listItem) {
2522
+ this.countryList.appendChild(listItem);
2523
+ if (noCountriesAddedYet) {
2524
+ this.highlightListItem(listItem, false);
2525
+ noCountriesAddedYet = false;
2526
+ }
2527
+ }
2528
+ }
2529
+ if (noCountriesAddedYet) {
2530
+ this.highlightListItem(null, false);
2531
+ if (this.searchNoResults) {
2532
+ this.searchNoResults.classList.remove("iti__hide");
2533
+ }
2534
+ } else if (this.searchNoResults) {
2535
+ this.searchNoResults.classList.add("iti__hide");
2536
+ }
2537
+ this.countryList.scrollTop = 0;
2538
+ this.updateSearchResultsA11yText();
2539
+ }
2540
+ destroy() {
2541
+ this.telInput.iti = void 0;
2542
+ delete this.telInput.dataset.intlTelInputId;
2543
+ if (this.options.separateDialCode) {
2544
+ this.telInput.style.paddingLeft = this.originalPaddingLeft;
2545
+ }
2546
+ const wrapper = this.telInput.parentNode;
2547
+ wrapper.before(this.telInput);
2548
+ wrapper.remove();
2549
+ this.telInput = null;
2550
+ this.countryContainer = null;
2551
+ this.selectedCountry = null;
2552
+ this.selectedCountryInner = null;
2553
+ this.selectedDialCode = null;
2554
+ this.dropdownArrow = null;
2555
+ this.dropdownContent = null;
2556
+ this.searchInput = null;
2557
+ this.searchIcon = null;
2558
+ this.searchClearButton = null;
2559
+ this.searchNoResults = null;
2560
+ this.searchResultsA11yText = null;
2561
+ this.countryList = null;
2562
+ this.dropdown = null;
2563
+ this.hiddenInput = null;
2564
+ this.hiddenInputCountry = null;
2565
+ this.highlightedItem = null;
2566
+ for (const c of this.countries) {
2567
+ delete c.nodeById[this.id];
2568
+ }
2569
+ this.countries = null;
2570
+ }
2571
+ };
2572
+
2573
+ // src/js/modules/data/country-data.ts
2574
+ function processAllCountries(options) {
2575
+ const { onlyCountries, excludeCountries } = options;
2576
+ if (onlyCountries.length) {
2577
+ const lowerCaseOnlyCountries = onlyCountries.map((country) => country.toLowerCase());
2578
+ return data_default.filter((country) => lowerCaseOnlyCountries.includes(country.iso2));
2579
+ } else if (excludeCountries.length) {
2580
+ const lowerCaseExcludeCountries = excludeCountries.map((country) => country.toLowerCase());
2581
+ return data_default.filter((country) => !lowerCaseExcludeCountries.includes(country.iso2));
2582
+ }
2583
+ return data_default;
2584
+ }
2585
+ function translateCountryNames(countries, options) {
2586
+ for (const c of countries) {
2587
+ const iso2 = c.iso2.toLowerCase();
2588
+ if (options.i18n[iso2]) {
2589
+ c.name = options.i18n[iso2];
2590
+ }
2591
+ }
2592
+ }
2593
+ function processDialCodes(countries, options) {
2594
+ const dialCodes = /* @__PURE__ */ new Set();
2595
+ let dialCodeMaxLen = 0;
2596
+ const dialCodeToIso2Map = {};
2597
+ const _addToDialCodeMap = (iso2, dialCode, priority) => {
2598
+ if (!iso2 || !dialCode) {
2599
+ return;
2600
+ }
2601
+ if (dialCode.length > dialCodeMaxLen) {
2602
+ dialCodeMaxLen = dialCode.length;
2603
+ }
2604
+ if (!dialCodeToIso2Map.hasOwnProperty(dialCode)) {
2605
+ dialCodeToIso2Map[dialCode] = [];
2606
+ }
2607
+ const iso2List = dialCodeToIso2Map[dialCode];
2608
+ if (iso2List.includes(iso2)) {
2609
+ return;
2610
+ }
2611
+ const index = priority !== void 0 ? priority : iso2List.length;
2612
+ iso2List[index] = iso2;
2613
+ };
2614
+ for (const c of countries) {
2615
+ if (!dialCodes.has(c.dialCode)) {
2616
+ dialCodes.add(c.dialCode);
2617
+ }
2618
+ for (let k = 1; k < c.dialCode.length; k++) {
2619
+ const partialDialCode = c.dialCode.substring(0, k);
2620
+ _addToDialCodeMap(c.iso2, partialDialCode);
2621
+ }
2622
+ _addToDialCodeMap(c.iso2, c.dialCode, c.priority);
2623
+ }
2624
+ if (options.onlyCountries.length || options.excludeCountries.length) {
2625
+ dialCodes.forEach((dialCode) => {
2626
+ dialCodeToIso2Map[dialCode] = dialCodeToIso2Map[dialCode].filter(Boolean);
2627
+ });
2628
+ }
2629
+ for (const c of countries) {
2630
+ if (c.areaCodes) {
2631
+ const rootIso2Code = dialCodeToIso2Map[c.dialCode][0];
2632
+ for (const areaCode of c.areaCodes) {
2633
+ for (let k = 1; k < areaCode.length; k++) {
2634
+ const partialAreaCode = areaCode.substring(0, k);
2635
+ const partialDialCode = c.dialCode + partialAreaCode;
2636
+ _addToDialCodeMap(rootIso2Code, partialDialCode);
2637
+ _addToDialCodeMap(c.iso2, partialDialCode);
2638
+ }
2639
+ _addToDialCodeMap(c.iso2, c.dialCode + areaCode);
2640
+ }
2641
+ }
2642
+ }
2643
+ return { dialCodes, dialCodeMaxLen, dialCodeToIso2Map };
2644
+ }
2645
+ function sortCountries(countries, options) {
2646
+ if (options.countryOrder) {
2647
+ options.countryOrder = options.countryOrder.map((iso2) => iso2.toLowerCase());
2648
+ }
2649
+ countries.sort((a, b) => {
2650
+ const { countryOrder } = options;
2651
+ if (countryOrder) {
2652
+ const aIndex = countryOrder.indexOf(a.iso2);
2653
+ const bIndex = countryOrder.indexOf(b.iso2);
2654
+ const aIndexExists = aIndex > -1;
2655
+ const bIndexExists = bIndex > -1;
2656
+ if (aIndexExists || bIndexExists) {
2657
+ if (aIndexExists && bIndexExists) {
2658
+ return aIndex - bIndex;
2659
+ }
2660
+ return aIndexExists ? -1 : 1;
2661
+ }
2662
+ }
2663
+ return a.name.localeCompare(b.name);
2664
+ });
2665
+ }
2666
+ function cacheSearchTokens(countries) {
2667
+ for (const c of countries) {
2668
+ c.normalisedName = normaliseString(c.name);
2669
+ c.initials = c.name.split(/[^a-zA-ZÀ-ÿа-яА-Я]/).map((word) => word[0]).join("").toLowerCase();
2670
+ c.dialCodePlus = `+${c.dialCode}`;
2671
+ }
2672
+ }
2673
+
2674
+ // src/js/modules/format/formatting.ts
2675
+ function beforeSetNumber(fullNumber, dialCode, separateDialCode, selectedCountryData) {
2676
+ let number = fullNumber;
2677
+ if (separateDialCode) {
2678
+ if (dialCode) {
2679
+ dialCode = `+${selectedCountryData.dialCode}`;
2680
+ const start = number[dialCode.length] === " " || number[dialCode.length] === "-" ? dialCode.length + 1 : dialCode.length;
2681
+ number = number.substring(start);
2682
+ }
2683
+ }
2684
+ return number;
2685
+ }
2686
+ function formatNumberAsYouType(fullNumber, telInputValue, utils, selectedCountryData, separateDialCode) {
2687
+ const result = utils ? utils.formatNumberAsYouType(fullNumber, selectedCountryData.iso2) : fullNumber;
2688
+ const { dialCode } = selectedCountryData;
2689
+ if (separateDialCode && telInputValue.charAt(0) !== "+" && result.includes(`+${dialCode}`)) {
2690
+ const afterDialCode = result.split(`+${dialCode}`)[1] || "";
2691
+ return afterDialCode.trim();
2692
+ }
2693
+ return result;
2694
+ }
2695
+
2696
+ // src/js/modules/format/caret.ts
2697
+ function translateCursorPosition(relevantChars, formattedValue, prevCaretPos, isDeleteForwards) {
2698
+ if (prevCaretPos === 0 && !isDeleteForwards) {
2699
+ return 0;
2700
+ }
2701
+ let relevantCharCount = 0;
2702
+ for (let i = 0; i < formattedValue.length; i++) {
2703
+ if (/[+0-9]/.test(formattedValue[i])) {
2704
+ relevantCharCount++;
2705
+ }
2706
+ if (relevantCharCount === relevantChars && !isDeleteForwards) {
2707
+ return i + 1;
2708
+ }
2709
+ if (isDeleteForwards && relevantCharCount === relevantChars + 1) {
2710
+ return i;
2711
+ }
2712
+ }
2713
+ return formattedValue.length;
2714
+ }
2715
+
2716
+ // src/js/modules/data/nanp-regionless.ts
2717
+ var regionlessNanpNumbers = [
2718
+ "800",
2719
+ "822",
2720
+ "833",
2721
+ "844",
2722
+ "855",
2723
+ "866",
2724
+ "877",
2725
+ "880",
2726
+ "881",
2727
+ "882",
2728
+ "883",
2729
+ "884",
2730
+ "885",
2731
+ "886",
2732
+ "887",
2733
+ "888",
2734
+ "889"
2735
+ ];
2736
+ var isRegionlessNanp = (number) => {
2737
+ const numeric = getNumeric(number);
2738
+ if (numeric.charAt(0) === "1") {
2739
+ const areaCode = numeric.substring(1, 4);
2740
+ return regionlessNanpNumbers.includes(areaCode);
2741
+ }
2742
+ return false;
2743
+ };
2744
+
2745
+ // src/js/intl-tel-input.ts
2746
+ for (const c of data_default) {
2747
+ c.name = countries_default[c.iso2];
2748
+ }
2749
+ var id = 0;
2750
+ var iso2Set = new Set(data_default.map((c) => c.iso2));
2751
+ var isIso2 = (val) => iso2Set.has(val);
2752
+ var Iti = class _Iti {
2753
+ constructor(input, customOptions = {}) {
2754
+ this.id = id++;
2755
+ this.options = { ...defaults, ...customOptions };
2756
+ applyOptionSideEffects(this.options);
2757
+ this.ui = new UI(input, this.options, this.id);
2758
+ this.isAndroid = _Iti._getIsAndroid();
2759
+ this.promise = this._createInitPromises();
2760
+ this.countries = processAllCountries(this.options);
2761
+ const { dialCodes, dialCodeMaxLen, dialCodeToIso2Map } = processDialCodes(
2762
+ this.countries,
2763
+ this.options
2764
+ );
2765
+ this.dialCodes = dialCodes;
2766
+ this.dialCodeMaxLen = dialCodeMaxLen;
2767
+ this.dialCodeToIso2Map = dialCodeToIso2Map;
2768
+ this.countryByIso2 = new Map(this.countries.map((c) => [c.iso2, c]));
2769
+ this._init();
2577
2770
  }
2578
- _maybeUpdateInputPaddingAndReveal() {
2579
- if (this.countryContainer) {
2580
- this._updateInputPadding();
2581
- this.countryContainer.classList.remove("iti__v-hide");
2582
- }
2771
+ static _getIsAndroid() {
2772
+ return typeof navigator !== "undefined" ? /Android/i.test(navigator.userAgent) : false;
2583
2773
  }
2584
- _maybeBuildHiddenInputs(wrapper) {
2585
- const { hiddenInput } = this.options;
2586
- if (hiddenInput) {
2587
- const telInputName = this.telInput.getAttribute("name") || "";
2588
- const names = hiddenInput(telInputName);
2589
- if (names.phone) {
2590
- const existingInput = this.telInput.form?.querySelector(`input[name="${names.phone}"]`);
2591
- if (existingInput) {
2592
- this.hiddenInput = existingInput;
2593
- } else {
2594
- this.hiddenInput = createEl("input", {
2595
- type: "hidden",
2596
- name: names.phone
2597
- });
2598
- wrapper.appendChild(this.hiddenInput);
2599
- }
2600
- }
2601
- if (names.country) {
2602
- const existingInput = this.telInput.form?.querySelector(`input[name="${names.country}"]`);
2603
- if (existingInput) {
2604
- this.hiddenInputCountry = existingInput;
2605
- } else {
2606
- this.hiddenInputCountry = createEl("input", {
2607
- type: "hidden",
2608
- name: names.country
2609
- });
2610
- wrapper.appendChild(this.hiddenInputCountry);
2611
- }
2612
- }
2613
- }
2774
+ _createInitPromises() {
2775
+ const autoCountryPromise = new Promise((resolve, reject) => {
2776
+ this.resolveAutoCountryPromise = resolve;
2777
+ this.rejectAutoCountryPromise = reject;
2778
+ });
2779
+ const utilsScriptPromise = new Promise((resolve, reject) => {
2780
+ this.resolveUtilsScriptPromise = resolve;
2781
+ this.rejectUtilsScriptPromise = reject;
2782
+ });
2783
+ return Promise.all([autoCountryPromise, utilsScriptPromise]);
2614
2784
  }
2615
- //* For each country: add a country list item <li> to the countryList <ul> container.
2616
- _appendListItems() {
2617
- for (let i = 0; i < this.countries.length; i++) {
2618
- const c = this.countries[i];
2619
- const extraClass = i === 0 ? "iti__highlight" : "";
2620
- const listItem = createEl(
2621
- "li",
2622
- {
2623
- id: `iti-${this.id}__item-${c.iso2}`,
2624
- class: `iti__country ${extraClass}`,
2625
- tabindex: "-1",
2626
- role: "option",
2627
- "data-dial-code": c.dialCode,
2628
- "data-country-code": c.iso2,
2629
- "aria-selected": "false"
2630
- },
2631
- this.countryList
2632
- );
2633
- c.nodeById[this.id] = listItem;
2634
- let content = "";
2635
- if (this.options.showFlags) {
2636
- content += `<div class='iti__flag iti__${c.iso2}'></div>`;
2637
- }
2638
- content += `<span class='iti__country-name'>${c.name}</span>`;
2639
- content += `<span class='iti__dial-code' dir='ltr'>+${c.dialCode}</span>`;
2640
- listItem.insertAdjacentHTML("beforeend", content);
2641
- }
2785
+ //* Can't be private as it's called from intlTelInput convenience wrapper.
2786
+ _init() {
2787
+ this.selectedCountryData = {};
2788
+ this.abortController = new AbortController();
2789
+ this._processCountryData();
2790
+ this.ui.generateMarkup(this.countries);
2791
+ this._setInitialState();
2792
+ this._initListeners();
2793
+ this._initRequests();
2794
+ }
2795
+ //********************
2796
+ //* PRIVATE METHODS
2797
+ //********************
2798
+ //* Prepare all of the country data, including onlyCountries, excludeCountries, countryOrder options.
2799
+ _processCountryData() {
2800
+ translateCountryNames(this.countries, this.options);
2801
+ sortCountries(this.countries, this.options);
2802
+ cacheSearchTokens(this.countries);
2642
2803
  }
2643
2804
  //* Set the initial state of the input value and the selected country by:
2644
2805
  //* 1. Extracting a dial code from the given number
2645
2806
  //* 2. Using explicit initialCountry
2646
2807
  _setInitialState(overrideAutoCountry = false) {
2647
- const attributeValue = this.telInput.getAttribute("value");
2648
- const inputValue = this.telInput.value;
2649
- const useAttribute = attributeValue && attributeValue.charAt(0) === "+" && (!inputValue || inputValue.charAt(0) !== "+");
2808
+ const attributeValue = this.ui.telInput.getAttribute("value");
2809
+ const inputValue = this.ui.telInput.value;
2810
+ const useAttribute = attributeValue && attributeValue.startsWith("+") && (!inputValue || !inputValue.startsWith("+"));
2650
2811
  const val = useAttribute ? attributeValue : inputValue;
2651
2812
  const dialCode = this._getDialCode(val);
2652
2813
  const isRegionlessNanpNumber = isRegionlessNanp(val);
@@ -2676,47 +2837,49 @@ var factoryOutput = (() => {
2676
2837
  if (this.options.allowDropdown) {
2677
2838
  this._initDropdownListeners();
2678
2839
  }
2679
- if ((this.hiddenInput || this.hiddenInputCountry) && this.telInput.form) {
2840
+ if ((this.ui.hiddenInput || this.ui.hiddenInputCountry) && this.ui.telInput.form) {
2680
2841
  this._initHiddenInputListener();
2681
2842
  }
2682
2843
  }
2683
2844
  //* Update hidden input on form submit.
2684
2845
  _initHiddenInputListener() {
2685
- this._handleHiddenInputSubmit = () => {
2686
- if (this.hiddenInput) {
2687
- this.hiddenInput.value = this.getNumber();
2846
+ const handleHiddenInputSubmit = () => {
2847
+ if (this.ui.hiddenInput) {
2848
+ this.ui.hiddenInput.value = this.getNumber();
2688
2849
  }
2689
- if (this.hiddenInputCountry) {
2690
- this.hiddenInputCountry.value = this.getSelectedCountryData().iso2 || "";
2850
+ if (this.ui.hiddenInputCountry) {
2851
+ this.ui.hiddenInputCountry.value = this.selectedCountryData.iso2 || "";
2691
2852
  }
2692
2853
  };
2693
- this.telInput.form?.addEventListener(
2694
- "submit",
2695
- this._handleHiddenInputSubmit
2696
- );
2854
+ this.ui.telInput.form?.addEventListener("submit", handleHiddenInputSubmit, {
2855
+ signal: this.abortController.signal
2856
+ });
2697
2857
  }
2698
2858
  //* initialise the dropdown listeners.
2699
2859
  _initDropdownListeners() {
2700
- this._handleLabelClick = (e) => {
2701
- if (this.dropdownContent.classList.contains("iti__hide")) {
2702
- this.telInput.focus();
2860
+ const signal = this.abortController.signal;
2861
+ const handleLabelClick = (e) => {
2862
+ if (this.ui.dropdownContent.classList.contains("iti__hide")) {
2863
+ this.ui.telInput.focus();
2703
2864
  } else {
2704
2865
  e.preventDefault();
2705
2866
  }
2706
2867
  };
2707
- const label = this.telInput.closest("label");
2868
+ const label = this.ui.telInput.closest("label");
2708
2869
  if (label) {
2709
- label.addEventListener("click", this._handleLabelClick);
2870
+ label.addEventListener("click", handleLabelClick, { signal });
2710
2871
  }
2711
- this._handleClickSelectedCountry = () => {
2712
- const dropdownClosed = this.dropdownContent.classList.contains("iti__hide");
2713
- if (dropdownClosed && !this.telInput.disabled && !this.telInput.readOnly) {
2872
+ const handleClickSelectedCountry = () => {
2873
+ const dropdownClosed = this.ui.dropdownContent.classList.contains("iti__hide");
2874
+ if (dropdownClosed && !this.ui.telInput.disabled && !this.ui.telInput.readOnly) {
2714
2875
  this._openDropdown();
2715
2876
  }
2716
2877
  };
2717
- this.selectedCountry.addEventListener("click", this._handleClickSelectedCountry);
2718
- this._handleCountryContainerKeydown = (e) => {
2719
- const isDropdownHidden = this.dropdownContent.classList.contains("iti__hide");
2878
+ this.ui.selectedCountry.addEventListener("click", handleClickSelectedCountry, {
2879
+ signal
2880
+ });
2881
+ const handleCountryContainerKeydown = (e) => {
2882
+ const isDropdownHidden = this.ui.dropdownContent.classList.contains("iti__hide");
2720
2883
  if (isDropdownHidden && ["ArrowUp", "ArrowDown", " ", "Enter"].includes(e.key)) {
2721
2884
  e.preventDefault();
2722
2885
  e.stopPropagation();
@@ -2726,26 +2889,29 @@ var factoryOutput = (() => {
2726
2889
  this._closeDropdown();
2727
2890
  }
2728
2891
  };
2729
- this.countryContainer.addEventListener(
2892
+ this.ui.countryContainer.addEventListener(
2730
2893
  "keydown",
2731
- this._handleCountryContainerKeydown
2894
+ handleCountryContainerKeydown,
2895
+ { signal }
2732
2896
  );
2733
2897
  }
2734
2898
  //* Init many requests: utils script / geo ip lookup.
2735
2899
  _initRequests() {
2736
- let { loadUtils, initialCountry, geoIpLookup } = this.options;
2900
+ const { loadUtils, initialCountry, geoIpLookup } = this.options;
2737
2901
  if (loadUtils && !intlTelInput.utils) {
2738
- this._doAttachUtils = () => {
2902
+ const doAttachUtils = () => {
2739
2903
  intlTelInput.attachUtils(loadUtils)?.catch(() => {
2740
2904
  });
2741
2905
  };
2742
2906
  if (intlTelInput.documentReady()) {
2743
- this._doAttachUtils();
2907
+ doAttachUtils();
2744
2908
  } else {
2745
- this._handlePageLoad = () => {
2746
- this._doAttachUtils();
2909
+ const handlePageLoad = () => {
2910
+ doAttachUtils();
2747
2911
  };
2748
- window.addEventListener("load", this._handlePageLoad);
2912
+ window.addEventListener("load", handlePageLoad, {
2913
+ signal: this.abortController.signal
2914
+ });
2749
2915
  }
2750
2916
  } else {
2751
2917
  this.resolveUtilsScriptPromise();
@@ -2785,8 +2951,8 @@ var factoryOutput = (() => {
2785
2951
  }
2786
2952
  _openDropdownWithPlus() {
2787
2953
  this._openDropdown();
2788
- this.searchInput.value = "+";
2789
- this._filterCountries("");
2954
+ this.ui.searchInput.value = "+";
2955
+ this._filterCountriesByQuery("");
2790
2956
  }
2791
2957
  //* Initialize the tel input listeners.
2792
2958
  _initTelInputListeners() {
@@ -2795,55 +2961,77 @@ var factoryOutput = (() => {
2795
2961
  this._maybeBindPasteListener();
2796
2962
  }
2797
2963
  _bindInputListener() {
2798
- const { strictMode, formatAsYouType, separateDialCode, allowDropdown, countrySearch } = this.options;
2964
+ const {
2965
+ strictMode,
2966
+ formatAsYouType,
2967
+ separateDialCode,
2968
+ allowDropdown,
2969
+ countrySearch
2970
+ } = this.options;
2799
2971
  let userOverrideFormatting = false;
2800
- if (/\p{L}/u.test(this.telInput.value)) {
2972
+ if (/\p{L}/u.test(this.ui.telInput.value)) {
2801
2973
  userOverrideFormatting = true;
2802
2974
  }
2803
- this._handleInputEvent = (e) => {
2975
+ const handleInputEvent = (e) => {
2804
2976
  if (this.isAndroid && e?.data === "+" && separateDialCode && allowDropdown && countrySearch) {
2805
- const currentCaretPos = this.telInput.selectionStart || 0;
2806
- const valueBeforeCaret = this.telInput.value.substring(0, currentCaretPos - 1);
2807
- const valueAfterCaret = this.telInput.value.substring(currentCaretPos);
2808
- this.telInput.value = valueBeforeCaret + valueAfterCaret;
2977
+ const currentCaretPos = this.ui.telInput.selectionStart || 0;
2978
+ const valueBeforeCaret = this.ui.telInput.value.substring(
2979
+ 0,
2980
+ currentCaretPos - 1
2981
+ );
2982
+ const valueAfterCaret = this.ui.telInput.value.substring(currentCaretPos);
2983
+ this.ui.telInput.value = valueBeforeCaret + valueAfterCaret;
2809
2984
  this._openDropdownWithPlus();
2810
2985
  return;
2811
2986
  }
2812
- if (this._updateCountryFromNumber(this.telInput.value)) {
2987
+ if (this._updateCountryFromNumber(this.ui.telInput.value)) {
2813
2988
  this._triggerCountryChange();
2814
2989
  }
2815
2990
  const isFormattingChar = e?.data && /[^+0-9]/.test(e.data);
2816
- const isPaste = e?.inputType === "insertFromPaste" && this.telInput.value;
2991
+ const isPaste = e?.inputType === "insertFromPaste" && this.ui.telInput.value;
2817
2992
  if (isFormattingChar || isPaste && !strictMode) {
2818
2993
  userOverrideFormatting = true;
2819
- } else if (!/[^+0-9]/.test(this.telInput.value)) {
2994
+ } else if (!/[^+0-9]/.test(this.ui.telInput.value)) {
2820
2995
  userOverrideFormatting = false;
2821
2996
  }
2822
2997
  const isSetNumber = e?.detail && e.detail["isSetNumber"];
2823
2998
  if (formatAsYouType && !userOverrideFormatting && !isSetNumber) {
2824
- const currentCaretPos = this.telInput.selectionStart || 0;
2825
- const valueBeforeCaret = this.telInput.value.substring(0, currentCaretPos);
2826
- const relevantCharsBeforeCaret = valueBeforeCaret.replace(/[^+0-9]/g, "").length;
2999
+ const currentCaretPos = this.ui.telInput.selectionStart || 0;
3000
+ const valueBeforeCaret = this.ui.telInput.value.substring(
3001
+ 0,
3002
+ currentCaretPos
3003
+ );
3004
+ const relevantCharsBeforeCaret = valueBeforeCaret.replace(
3005
+ /[^+0-9]/g,
3006
+ ""
3007
+ ).length;
2827
3008
  const isDeleteForwards = e?.inputType === "deleteContentForward";
2828
3009
  const fullNumber = this._getFullNumber();
2829
3010
  const formattedValue = formatNumberAsYouType(
2830
3011
  fullNumber,
2831
- this.telInput.value,
3012
+ this.ui.telInput.value,
2832
3013
  intlTelInput.utils,
2833
3014
  this.selectedCountryData,
2834
3015
  this.options.separateDialCode
2835
3016
  );
2836
- const newCaretPos = translateCursorPosition(relevantCharsBeforeCaret, formattedValue, currentCaretPos, isDeleteForwards);
2837
- this.telInput.value = formattedValue;
2838
- this.telInput.setSelectionRange(newCaretPos, newCaretPos);
3017
+ const newCaretPos = translateCursorPosition(
3018
+ relevantCharsBeforeCaret,
3019
+ formattedValue,
3020
+ currentCaretPos,
3021
+ isDeleteForwards
3022
+ );
3023
+ this.ui.telInput.value = formattedValue;
3024
+ this.ui.telInput.setSelectionRange(newCaretPos, newCaretPos);
2839
3025
  }
2840
3026
  };
2841
- this.telInput.addEventListener("input", this._handleInputEvent);
3027
+ this.ui.telInput.addEventListener("input", handleInputEvent, {
3028
+ signal: this.abortController.signal
3029
+ });
2842
3030
  }
2843
3031
  _maybeBindKeydownListener() {
2844
3032
  const { strictMode, separateDialCode, allowDropdown, countrySearch } = this.options;
2845
3033
  if (strictMode || separateDialCode) {
2846
- this._handleKeydownEvent = (e) => {
3034
+ const handleKeydownEvent = (e) => {
2847
3035
  if (e.key && e.key.length === 1 && !e.altKey && !e.ctrlKey && !e.metaKey) {
2848
3036
  if (separateDialCode && allowDropdown && countrySearch && e.key === "+") {
2849
3037
  e.preventDefault();
@@ -2851,14 +3039,17 @@ var factoryOutput = (() => {
2851
3039
  return;
2852
3040
  }
2853
3041
  if (strictMode) {
2854
- const value = this.telInput.value;
2855
- const alreadyHasPlus = value.charAt(0) === "+";
2856
- const isInitialPlus = !alreadyHasPlus && this.telInput.selectionStart === 0 && e.key === "+";
3042
+ const value = this.ui.telInput.value;
3043
+ const alreadyHasPlus = value.startsWith("+");
3044
+ const isInitialPlus = !alreadyHasPlus && this.ui.telInput.selectionStart === 0 && e.key === "+";
2857
3045
  const isNumeric = /^[0-9]$/.test(e.key);
2858
3046
  const isAllowedChar = separateDialCode ? isNumeric : isInitialPlus || isNumeric;
2859
- const newValue = value.slice(0, this.telInput.selectionStart) + e.key + value.slice(this.telInput.selectionEnd);
3047
+ const newValue = value.slice(0, this.ui.telInput.selectionStart) + e.key + value.slice(this.ui.telInput.selectionEnd);
2860
3048
  const newFullNumber = this._getFullNumber(newValue);
2861
- const coreNumber = intlTelInput.utils.getCoreNumber(newFullNumber, this.selectedCountryData.iso2);
3049
+ const coreNumber = intlTelInput.utils.getCoreNumber(
3050
+ newFullNumber,
3051
+ this.selectedCountryData.iso2
3052
+ );
2862
3053
  const hasExceededMaxLength = this.maxCoreNumberLength && coreNumber.length > this.maxCoreNumberLength;
2863
3054
  const newCountry = this._getNewCountryFromNumber(newFullNumber);
2864
3055
  const isChangingDialCode = newCountry !== null;
@@ -2868,14 +3059,16 @@ var factoryOutput = (() => {
2868
3059
  }
2869
3060
  }
2870
3061
  };
2871
- this.telInput.addEventListener("keydown", this._handleKeydownEvent);
3062
+ this.ui.telInput.addEventListener("keydown", handleKeydownEvent, {
3063
+ signal: this.abortController.signal
3064
+ });
2872
3065
  }
2873
3066
  }
2874
3067
  _maybeBindPasteListener() {
2875
3068
  if (this.options.strictMode) {
2876
- this._handlePasteEvent = (e) => {
3069
+ const handlePasteEvent = (e) => {
2877
3070
  e.preventDefault();
2878
- const input = this.telInput;
3071
+ const input = this.ui.telInput;
2879
3072
  const selStart = input.selectionStart;
2880
3073
  const selEnd = input.selectionEnd;
2881
3074
  const before = input.value.slice(0, selStart);
@@ -2910,82 +3103,95 @@ var factoryOutput = (() => {
2910
3103
  input.setSelectionRange(caretPos, caretPos);
2911
3104
  input.dispatchEvent(new InputEvent("input", { bubbles: true }));
2912
3105
  };
2913
- this.telInput.addEventListener("paste", this._handlePasteEvent);
3106
+ this.ui.telInput.addEventListener("paste", handlePasteEvent, {
3107
+ signal: this.abortController.signal
3108
+ });
2914
3109
  }
2915
3110
  }
2916
3111
  //* Adhere to the input's maxlength attr.
2917
3112
  _cap(number) {
2918
- const max = parseInt(this.telInput.getAttribute("maxlength") || "", 10);
3113
+ const max = Number(this.ui.telInput.getAttribute("maxlength"));
2919
3114
  return max && number.length > max ? number.substring(0, max) : number;
2920
3115
  }
2921
- //* Trigger a custom event on the input.
3116
+ //* Trigger a custom event on the input (typed via ItiEventMap).
2922
3117
  _trigger(name, detailProps = {}) {
2923
3118
  const e = new CustomEvent(name, {
2924
3119
  bubbles: true,
2925
3120
  cancelable: true,
2926
3121
  detail: detailProps
2927
3122
  });
2928
- this.telInput.dispatchEvent(e);
3123
+ this.ui.telInput.dispatchEvent(e);
2929
3124
  }
2930
3125
  //* Open the dropdown.
2931
3126
  _openDropdown() {
2932
3127
  const { fixDropdownWidth, countrySearch } = this.options;
3128
+ this.dropdownAbortController = new AbortController();
2933
3129
  if (fixDropdownWidth) {
2934
- this.dropdownContent.style.width = `${this.telInput.offsetWidth}px`;
3130
+ this.ui.dropdownContent.style.width = `${this.ui.telInput.offsetWidth}px`;
2935
3131
  }
2936
- this.dropdownContent.classList.remove("iti__hide");
2937
- this.selectedCountry.setAttribute("aria-expanded", "true");
3132
+ this.ui.dropdownContent.classList.remove("iti__hide");
3133
+ this.ui.selectedCountry.setAttribute("aria-expanded", "true");
2938
3134
  this._setDropdownPosition();
2939
3135
  if (countrySearch) {
2940
- const firstCountryItem = this.countryList.firstElementChild;
3136
+ const firstCountryItem = this.ui.countryList.firstElementChild;
2941
3137
  if (firstCountryItem) {
2942
- this._highlightListItem(firstCountryItem, false);
2943
- this.countryList.scrollTop = 0;
3138
+ this.ui.highlightListItem(firstCountryItem, false);
3139
+ this.ui.countryList.scrollTop = 0;
2944
3140
  }
2945
- this.searchInput.focus();
3141
+ this.ui.searchInput.focus();
2946
3142
  }
2947
3143
  this._bindDropdownListeners();
2948
- this.dropdownArrow.classList.add("iti__arrow--up");
3144
+ this.ui.dropdownArrow.classList.add("iti__arrow--up");
2949
3145
  this._trigger("open:countrydropdown");
2950
3146
  }
2951
3147
  //* Set the dropdown position
2952
3148
  _setDropdownPosition() {
2953
3149
  if (this.options.dropdownContainer) {
2954
- this.options.dropdownContainer.appendChild(this.dropdown);
3150
+ this.options.dropdownContainer.appendChild(this.ui.dropdown);
2955
3151
  }
2956
3152
  if (!this.options.useFullscreenPopup) {
2957
- const inputPosRelativeToVP = this.telInput.getBoundingClientRect();
2958
- const inputHeight = this.telInput.offsetHeight;
3153
+ const inputPosRelativeToVP = this.ui.telInput.getBoundingClientRect();
3154
+ const inputHeight = this.ui.telInput.offsetHeight;
2959
3155
  if (this.options.dropdownContainer) {
2960
- this.dropdown.style.top = `${inputPosRelativeToVP.top + inputHeight}px`;
2961
- this.dropdown.style.left = `${inputPosRelativeToVP.left}px`;
2962
- this._handleWindowScroll = () => this._closeDropdown();
2963
- window.addEventListener("scroll", this._handleWindowScroll);
3156
+ this.ui.dropdown.style.top = `${inputPosRelativeToVP.top + inputHeight}px`;
3157
+ this.ui.dropdown.style.left = `${inputPosRelativeToVP.left}px`;
3158
+ const handleWindowScroll = () => this._closeDropdown();
3159
+ window.addEventListener("scroll", handleWindowScroll, {
3160
+ signal: this.dropdownAbortController.signal
3161
+ });
2964
3162
  }
2965
3163
  }
2966
3164
  }
2967
3165
  //* We only bind dropdown listeners when the dropdown is open.
2968
3166
  _bindDropdownListeners() {
2969
- this._handleMouseoverCountryList = (e) => {
2970
- const listItem = e.target?.closest(".iti__country");
3167
+ const signal = this.dropdownAbortController.signal;
3168
+ const handleMouseoverCountryList = (e) => {
3169
+ const listItem = e.target?.closest(
3170
+ ".iti__country"
3171
+ );
2971
3172
  if (listItem) {
2972
- this._highlightListItem(listItem, false);
3173
+ this.ui.highlightListItem(listItem, false);
2973
3174
  }
2974
3175
  };
2975
- this.countryList.addEventListener(
2976
- "mouseover",
2977
- this._handleMouseoverCountryList
2978
- );
2979
- this._handleClickCountryList = (e) => {
2980
- const listItem = e.target?.closest(".iti__country");
3176
+ this.ui.countryList.addEventListener("mouseover", handleMouseoverCountryList, {
3177
+ signal
3178
+ });
3179
+ const handleClickCountryList = (e) => {
3180
+ const listItem = e.target?.closest(
3181
+ ".iti__country"
3182
+ );
2981
3183
  if (listItem) {
2982
3184
  this._selectListItem(listItem);
2983
3185
  }
2984
3186
  };
2985
- this.countryList.addEventListener("click", this._handleClickCountryList);
2986
- this._handleClickOffToClose = (e) => {
3187
+ this.ui.countryList.addEventListener("click", handleClickCountryList, {
3188
+ signal
3189
+ });
3190
+ const handleClickOffToClose = (e) => {
2987
3191
  const target = e.target;
2988
- const clickedInsideDropdown = !!target.closest(`#iti-${this.id}__dropdown-content`);
3192
+ const clickedInsideDropdown = !!target.closest(
3193
+ `#iti-${this.id}__dropdown-content`
3194
+ );
2989
3195
  if (!clickedInsideDropdown) {
2990
3196
  this._closeDropdown();
2991
3197
  }
@@ -2993,12 +3199,13 @@ var factoryOutput = (() => {
2993
3199
  setTimeout(() => {
2994
3200
  document.documentElement.addEventListener(
2995
3201
  "click",
2996
- this._handleClickOffToClose
3202
+ handleClickOffToClose,
3203
+ { signal }
2997
3204
  );
2998
3205
  }, 0);
2999
3206
  let query = "";
3000
3207
  let queryTimer = null;
3001
- this._handleKeydownOnDropdown = (e) => {
3208
+ const handleKeydownOnDropdown = (e) => {
3002
3209
  if (["ArrowUp", "ArrowDown", "Enter", "Escape"].includes(e.key)) {
3003
3210
  e.preventDefault();
3004
3211
  e.stopPropagation();
@@ -3022,19 +3229,19 @@ var factoryOutput = (() => {
3022
3229
  }, 1e3);
3023
3230
  }
3024
3231
  };
3025
- document.addEventListener("keydown", this._handleKeydownOnDropdown);
3232
+ document.addEventListener("keydown", handleKeydownOnDropdown, { signal });
3026
3233
  if (this.options.countrySearch) {
3027
3234
  const doFilter = () => {
3028
- const inputQuery = this.searchInput.value.trim();
3029
- this._filterCountries(inputQuery);
3030
- if (this.searchInput.value) {
3031
- this.searchClearButton.classList.remove("iti__hide");
3235
+ const inputQuery = this.ui.searchInput.value.trim();
3236
+ this._filterCountriesByQuery(inputQuery);
3237
+ if (this.ui.searchInput.value) {
3238
+ this.ui.searchClearButton.classList.remove("iti__hide");
3032
3239
  } else {
3033
- this.searchClearButton.classList.add("iti__hide");
3240
+ this.ui.searchClearButton.classList.add("iti__hide");
3034
3241
  }
3035
3242
  };
3036
3243
  let keyupTimer = null;
3037
- this._handleSearchChange = () => {
3244
+ const handleSearchChange = () => {
3038
3245
  if (keyupTimer) {
3039
3246
  clearTimeout(keyupTimer);
3040
3247
  }
@@ -3043,13 +3250,17 @@ var factoryOutput = (() => {
3043
3250
  keyupTimer = null;
3044
3251
  }, 100);
3045
3252
  };
3046
- this.searchInput.addEventListener("input", this._handleSearchChange);
3047
- this._handleSearchClear = () => {
3048
- this.searchInput.value = "";
3049
- this.searchInput.focus();
3253
+ this.ui.searchInput.addEventListener("input", handleSearchChange, {
3254
+ signal
3255
+ });
3256
+ const handleSearchClear = () => {
3257
+ this.ui.searchInput.value = "";
3258
+ this.ui.searchInput.focus();
3050
3259
  doFilter();
3051
3260
  };
3052
- this.searchClearButton.addEventListener("click", this._handleSearchClear);
3261
+ this.ui.searchClearButton.addEventListener("click", handleSearchClear, {
3262
+ signal
3263
+ });
3053
3264
  }
3054
3265
  }
3055
3266
  //* Hidden search (countrySearch disabled): Find the first list item whose name starts with the query string.
@@ -3058,42 +3269,21 @@ var factoryOutput = (() => {
3058
3269
  const startsWith = c.name.substring(0, query.length).toLowerCase() === query;
3059
3270
  if (startsWith) {
3060
3271
  const listItem = c.nodeById[this.id];
3061
- this._highlightListItem(listItem, false);
3062
- this._scrollTo(listItem);
3272
+ this.ui.highlightListItem(listItem, false);
3273
+ this.ui.scrollTo(listItem);
3063
3274
  break;
3064
3275
  }
3065
3276
  }
3066
3277
  }
3067
- //* Country search enabled: Filter the countries according to the search query.
3068
- _filterCountries(query) {
3069
- this.countryList.innerHTML = "";
3278
+ //* Country search: Filter the countries according to the search query.
3279
+ _filterCountriesByQuery(query) {
3070
3280
  let matchedCountries;
3071
3281
  if (query === "") {
3072
3282
  matchedCountries = this.countries;
3073
3283
  } else {
3074
3284
  matchedCountries = this._getMatchedCountries(query);
3075
3285
  }
3076
- let noCountriesAddedYet = true;
3077
- for (const c of matchedCountries) {
3078
- const listItem = c.nodeById[this.id];
3079
- if (listItem) {
3080
- this.countryList.appendChild(listItem);
3081
- if (noCountriesAddedYet) {
3082
- this._highlightListItem(listItem, false);
3083
- noCountriesAddedYet = false;
3084
- }
3085
- }
3086
- }
3087
- if (noCountriesAddedYet) {
3088
- this._highlightListItem(null, false);
3089
- if (this.searchNoResults) {
3090
- this.searchNoResults.classList.remove("iti__hide");
3091
- }
3092
- } else if (this.searchNoResults) {
3093
- this.searchNoResults.classList.add("iti__hide");
3094
- }
3095
- this.countryList.scrollTop = 0;
3096
- this._updateSearchResultsA11yText();
3286
+ this.ui.filterCountries(matchedCountries);
3097
3287
  }
3098
3288
  _getMatchedCountries(query) {
3099
3289
  const normalisedQuery = normaliseString(query);
@@ -3127,39 +3317,21 @@ var factoryOutput = (() => {
3127
3317
  ...initialsMatches.sort((a, b) => a.priority - b.priority)
3128
3318
  ];
3129
3319
  }
3130
- //* Update search results text (for a11y).
3131
- _updateSearchResultsA11yText() {
3132
- const { i18n } = this.options;
3133
- const count = this.countryList.childElementCount;
3134
- let searchText;
3135
- if (count === 0) {
3136
- searchText = i18n.zeroSearchResults;
3137
- } else {
3138
- if (i18n.searchResultsText) {
3139
- searchText = i18n.searchResultsText(count);
3140
- } else if (count === 1) {
3141
- searchText = i18n.oneSearchResult;
3142
- } else {
3143
- searchText = i18n.multipleSearchResults.replace("${count}", count.toString());
3144
- }
3145
- }
3146
- this.searchResultsA11yText.textContent = searchText;
3147
- }
3148
3320
  //* Highlight the next/prev item in the list (and ensure it is visible).
3149
3321
  _handleUpDownKey(key) {
3150
- let next = key === "ArrowUp" ? this.highlightedItem?.previousElementSibling : this.highlightedItem?.nextElementSibling;
3151
- if (!next && this.countryList.childElementCount > 1) {
3152
- next = key === "ArrowUp" ? this.countryList.lastElementChild : this.countryList.firstElementChild;
3322
+ let next = key === "ArrowUp" ? this.ui.highlightedItem?.previousElementSibling : this.ui.highlightedItem?.nextElementSibling;
3323
+ if (!next && this.ui.countryList.childElementCount > 1) {
3324
+ next = key === "ArrowUp" ? this.ui.countryList.lastElementChild : this.ui.countryList.firstElementChild;
3153
3325
  }
3154
3326
  if (next) {
3155
- this._scrollTo(next);
3156
- this._highlightListItem(next, false);
3327
+ this.ui.scrollTo(next);
3328
+ this.ui.highlightListItem(next, false);
3157
3329
  }
3158
3330
  }
3159
3331
  //* Select the currently highlighted item.
3160
3332
  _handleEnterKey() {
3161
- if (this.highlightedItem) {
3162
- this._selectListItem(this.highlightedItem);
3333
+ if (this.ui.highlightedItem) {
3334
+ this._selectListItem(this.ui.highlightedItem);
3163
3335
  }
3164
3336
  }
3165
3337
  //* Update the input's value to the given val (format first if possible)
@@ -3167,7 +3339,7 @@ var factoryOutput = (() => {
3167
3339
  _updateValFromNumber(fullNumber) {
3168
3340
  let number = fullNumber;
3169
3341
  if (this.options.formatOnDisplay && intlTelInput.utils && this.selectedCountryData) {
3170
- const useNational = this.options.nationalMode || number.charAt(0) !== "+" && !this.options.separateDialCode;
3342
+ const useNational = this.options.nationalMode || !number.startsWith("+") && !this.options.separateDialCode;
3171
3343
  const { NATIONAL, INTERNATIONAL } = intlTelInput.utils.numberFormat;
3172
3344
  const format = useNational ? NATIONAL : INTERNATIONAL;
3173
3345
  number = intlTelInput.utils.formatNumber(
@@ -3177,7 +3349,7 @@ var factoryOutput = (() => {
3177
3349
  );
3178
3350
  }
3179
3351
  number = this._beforeSetNumber(number);
3180
- this.telInput.value = number;
3352
+ this.ui.telInput.value = number;
3181
3353
  }
3182
3354
  //* Check if need to select a new country based on the given number
3183
3355
  //* Note: called from _setInitialState, keyup handler, setNumber.
@@ -3191,11 +3363,11 @@ var factoryOutput = (() => {
3191
3363
  // if there is a selected country, and the number doesn't start with a dial code, then add it
3192
3364
  _ensureHasDialCode(number) {
3193
3365
  const { dialCode, nationalPrefix } = this.selectedCountryData;
3194
- const alreadyHasPlus = number.charAt(0) === "+";
3366
+ const alreadyHasPlus = number.startsWith("+");
3195
3367
  if (alreadyHasPlus || !dialCode) {
3196
3368
  return number;
3197
3369
  }
3198
- const hasPrefix = nationalPrefix && number.charAt(0) === nationalPrefix && !this.options.separateDialCode;
3370
+ const hasPrefix = nationalPrefix && number.startsWith(nationalPrefix) && !this.options.separateDialCode;
3199
3371
  const cleanNumber = hasPrefix ? number.substring(1) : number;
3200
3372
  return `+${dialCode}${cleanNumber}`;
3201
3373
  }
@@ -3228,7 +3400,9 @@ var factoryOutput = (() => {
3228
3400
  }
3229
3401
  const { areaCodes, priority } = this.selectedCountryData;
3230
3402
  if (areaCodes) {
3231
- const dialCodeAreaCodes = areaCodes.map((areaCode) => `${selectedDialCode}${areaCode}`);
3403
+ const dialCodeAreaCodes = areaCodes.map(
3404
+ (areaCode) => `${selectedDialCode}${areaCode}`
3405
+ );
3232
3406
  for (const dialCodeAreaCode of dialCodeAreaCodes) {
3233
3407
  if (numeric.startsWith(dialCodeAreaCode)) {
3234
3408
  return null;
@@ -3242,33 +3416,13 @@ var factoryOutput = (() => {
3242
3416
  if (!isValidSelection && !alreadySelected) {
3243
3417
  return iso2Codes[0];
3244
3418
  }
3245
- } else if (number.charAt(0) === "+" && numeric.length) {
3419
+ } else if (number.startsWith("+") && numeric.length) {
3246
3420
  return "";
3247
3421
  } else if ((!number || number === "+") && !selectedIso2) {
3248
3422
  return this.defaultCountry;
3249
3423
  }
3250
3424
  return null;
3251
3425
  }
3252
- //* Remove highlighting from other list items and highlight the given item.
3253
- _highlightListItem(listItem, shouldFocus) {
3254
- const prevItem = this.highlightedItem;
3255
- if (prevItem) {
3256
- prevItem.classList.remove("iti__highlight");
3257
- prevItem.setAttribute("aria-selected", "false");
3258
- }
3259
- this.highlightedItem = listItem;
3260
- if (this.highlightedItem) {
3261
- this.highlightedItem.classList.add("iti__highlight");
3262
- this.highlightedItem.setAttribute("aria-selected", "true");
3263
- if (this.options.countrySearch) {
3264
- const activeDescendant = this.highlightedItem.getAttribute("id") || "";
3265
- this.searchInput.setAttribute("aria-activedescendant", activeDescendant);
3266
- }
3267
- }
3268
- if (shouldFocus) {
3269
- this.highlightedItem.focus();
3270
- }
3271
- }
3272
3426
  //* Update the selected country, dial code (if separateDialCode), placeholder, title, and active list item.
3273
3427
  //* Note: called from _setInitialState, _updateCountryFromNumber, _selectListItem, setCountry.
3274
3428
  _setCountry(iso2) {
@@ -3278,7 +3432,7 @@ var factoryOutput = (() => {
3278
3432
  if (this.selectedCountryData.iso2) {
3279
3433
  this.defaultCountry = this.selectedCountryData.iso2;
3280
3434
  }
3281
- if (this.selectedCountry) {
3435
+ if (this.ui.selectedCountry) {
3282
3436
  const flagClass = iso2 && showFlags ? `iti__flag iti__${iso2}` : "iti__flag iti__globe";
3283
3437
  let ariaLabel, title;
3284
3438
  if (iso2) {
@@ -3289,32 +3443,19 @@ var factoryOutput = (() => {
3289
3443
  title = i18n.noCountrySelected;
3290
3444
  ariaLabel = i18n.noCountrySelected;
3291
3445
  }
3292
- this.selectedCountryInner.className = flagClass;
3293
- this.selectedCountry.setAttribute("title", title);
3294
- this.selectedCountry.setAttribute("aria-label", ariaLabel);
3446
+ this.ui.selectedCountryInner.className = flagClass;
3447
+ this.ui.selectedCountry.setAttribute("title", title);
3448
+ this.ui.selectedCountry.setAttribute("aria-label", ariaLabel);
3295
3449
  }
3296
3450
  if (separateDialCode) {
3297
3451
  const dialCode = this.selectedCountryData.dialCode ? `+${this.selectedCountryData.dialCode}` : "";
3298
- this.selectedDialCode.innerHTML = dialCode;
3299
- this._updateInputPadding();
3452
+ this.ui.selectedDialCode.textContent = dialCode;
3453
+ this.ui.updateInputPadding();
3300
3454
  }
3301
3455
  this._updatePlaceholder();
3302
3456
  this._updateMaxLength();
3303
3457
  return prevIso2 !== iso2;
3304
3458
  }
3305
- //* Update the input padding to make space for the selected country/dial code.
3306
- _updateInputPadding() {
3307
- if (this.selectedCountry) {
3308
- const saneDefaultWidth = this.options.separateDialCode ? 78 : 42;
3309
- const selectedCountryWidth = this.selectedCountry.offsetWidth || this._getHiddenSelectedCountryWidth() || saneDefaultWidth;
3310
- const inputPadding = selectedCountryWidth + 6;
3311
- if (this.showSelectedCountryOnLeft) {
3312
- this.telInput.style.paddingLeft = `${inputPadding}px`;
3313
- } else {
3314
- this.telInput.style.paddingRight = `${inputPadding}px`;
3315
- }
3316
- }
3317
- }
3318
3459
  //* Update the maximum valid number length for the currently selected country.
3319
3460
  _updateMaxLength() {
3320
3461
  const { strictMode, placeholderNumberType, validationNumberTypes } = this.options;
@@ -3329,7 +3470,11 @@ var factoryOutput = (() => {
3329
3470
  true
3330
3471
  );
3331
3472
  let validNumber = exampleNumber;
3332
- while (intlTelInput.utils.isPossibleNumber(exampleNumber, iso2, validationNumberTypes)) {
3473
+ while (intlTelInput.utils.isPossibleNumber(
3474
+ exampleNumber,
3475
+ iso2,
3476
+ validationNumberTypes
3477
+ )) {
3333
3478
  validNumber = exampleNumber;
3334
3479
  exampleNumber += "0";
3335
3480
  }
@@ -3343,31 +3488,6 @@ var factoryOutput = (() => {
3343
3488
  }
3344
3489
  }
3345
3490
  }
3346
- //* When input is in a hidden container during init, we cannot calculate the selected country width.
3347
- //* Fix: clone the markup, make it invisible, add it to the end of the DOM, and then measure it's width.
3348
- //* To get the right styling to apply, all we need is a shallow clone of the container,
3349
- //* and then to inject a deep clone of the selectedCountry element.
3350
- _getHiddenSelectedCountryWidth() {
3351
- if (this.telInput.parentNode) {
3352
- let body;
3353
- try {
3354
- body = window.top.document.body;
3355
- } catch (e) {
3356
- body = document.body;
3357
- }
3358
- const containerClone = this.telInput.parentNode.cloneNode(false);
3359
- containerClone.style.visibility = "hidden";
3360
- body.appendChild(containerClone);
3361
- const countryContainerClone = this.countryContainer.cloneNode();
3362
- containerClone.appendChild(countryContainerClone);
3363
- const selectedCountryClone = this.selectedCountry.cloneNode(true);
3364
- countryContainerClone.appendChild(selectedCountryClone);
3365
- const width = selectedCountryClone.offsetWidth;
3366
- body.removeChild(containerClone);
3367
- return width;
3368
- }
3369
- return 0;
3370
- }
3371
3491
  //* Update the input placeholder to an example number from the currently selected country.
3372
3492
  _updatePlaceholder() {
3373
3493
  const {
@@ -3376,7 +3496,7 @@ var factoryOutput = (() => {
3376
3496
  nationalMode,
3377
3497
  customPlaceholder
3378
3498
  } = this.options;
3379
- const shouldSetPlaceholder = autoPlaceholder === "aggressive" || !this.hadInitialPlaceholder && autoPlaceholder === "polite";
3499
+ const shouldSetPlaceholder = autoPlaceholder === "aggressive" || !this.ui.hadInitialPlaceholder && autoPlaceholder === "polite";
3380
3500
  if (intlTelInput.utils && shouldSetPlaceholder) {
3381
3501
  const numberType = intlTelInput.utils.numberType[placeholderNumberType];
3382
3502
  let placeholder = this.selectedCountryData.iso2 ? intlTelInput.utils.getExampleNumber(
@@ -3388,98 +3508,66 @@ var factoryOutput = (() => {
3388
3508
  if (typeof customPlaceholder === "function") {
3389
3509
  placeholder = customPlaceholder(placeholder, this.selectedCountryData);
3390
3510
  }
3391
- this.telInput.setAttribute("placeholder", placeholder);
3511
+ this.ui.telInput.setAttribute("placeholder", placeholder);
3392
3512
  }
3393
3513
  }
3394
3514
  //* Called when the user selects a list item from the dropdown.
3395
3515
  _selectListItem(listItem) {
3396
- const iso2 = listItem.getAttribute("data-country-code");
3516
+ const iso2 = listItem.dataset.countryCode;
3397
3517
  const countryChanged = this._setCountry(iso2);
3398
3518
  this._closeDropdown();
3399
- const dialCode = listItem.getAttribute("data-dial-code");
3519
+ const dialCode = listItem.dataset.dialCode;
3400
3520
  this._updateDialCode(dialCode);
3401
3521
  if (this.options.formatOnDisplay) {
3402
- this._updateValFromNumber(this.telInput.value);
3522
+ this._updateValFromNumber(this.ui.telInput.value);
3403
3523
  }
3404
- this.telInput.focus();
3524
+ this.ui.telInput.focus();
3405
3525
  if (countryChanged) {
3406
3526
  this._triggerCountryChange();
3407
3527
  }
3408
3528
  }
3409
3529
  //* Close the dropdown and unbind any listeners.
3410
3530
  _closeDropdown() {
3411
- this.dropdownContent.classList.add("iti__hide");
3412
- this.selectedCountry.setAttribute("aria-expanded", "false");
3413
- if (this.highlightedItem) {
3414
- this.highlightedItem.setAttribute("aria-selected", "false");
3531
+ if (this.ui.dropdownContent.classList.contains("iti__hide")) {
3532
+ return;
3415
3533
  }
3416
- if (this.options.countrySearch) {
3417
- this.searchInput.removeAttribute("aria-activedescendant");
3534
+ this.ui.dropdownContent.classList.add("iti__hide");
3535
+ this.ui.selectedCountry.setAttribute("aria-expanded", "false");
3536
+ if (this.ui.highlightedItem) {
3537
+ this.ui.highlightedItem.setAttribute("aria-selected", "false");
3418
3538
  }
3419
- this.dropdownArrow.classList.remove("iti__arrow--up");
3420
3539
  if (this.options.countrySearch) {
3421
- this.searchInput.removeEventListener("input", this._handleSearchChange);
3422
- this.searchClearButton.removeEventListener("click", this._handleSearchClear);
3540
+ this.ui.searchInput.removeAttribute("aria-activedescendant");
3423
3541
  }
3424
- document.removeEventListener("keydown", this._handleKeydownOnDropdown);
3425
- document.documentElement.removeEventListener(
3426
- "click",
3427
- this._handleClickOffToClose
3428
- );
3429
- this.countryList.removeEventListener(
3430
- "mouseover",
3431
- this._handleMouseoverCountryList
3432
- );
3433
- this.countryList.removeEventListener("click", this._handleClickCountryList);
3542
+ this.ui.dropdownArrow.classList.remove("iti__arrow--up");
3543
+ this.dropdownAbortController.abort();
3544
+ this.dropdownAbortController = null;
3434
3545
  if (this.options.dropdownContainer) {
3435
- if (!this.options.useFullscreenPopup) {
3436
- window.removeEventListener("scroll", this._handleWindowScroll);
3437
- }
3438
- if (this.dropdown.parentNode) {
3439
- this.dropdown.parentNode.removeChild(this.dropdown);
3440
- }
3546
+ this.ui.dropdown.remove();
3441
3547
  }
3442
3548
  this._trigger("close:countrydropdown");
3443
3549
  }
3444
- //* Check if an element is visible within it's container, else scroll until it is.
3445
- _scrollTo(element) {
3446
- const container = this.countryList;
3447
- const scrollTop = document.documentElement.scrollTop;
3448
- const containerHeight = container.offsetHeight;
3449
- const containerTop = container.getBoundingClientRect().top + scrollTop;
3450
- const containerBottom = containerTop + containerHeight;
3451
- const elementHeight = element.offsetHeight;
3452
- const elementTop = element.getBoundingClientRect().top + scrollTop;
3453
- const elementBottom = elementTop + elementHeight;
3454
- const newScrollTop = elementTop - containerTop + container.scrollTop;
3455
- if (elementTop < containerTop) {
3456
- container.scrollTop = newScrollTop;
3457
- } else if (elementBottom > containerBottom) {
3458
- const heightDifference = containerHeight - elementHeight;
3459
- container.scrollTop = newScrollTop - heightDifference;
3460
- }
3461
- }
3462
3550
  //* Replace any existing dial code with the new one
3463
3551
  //* Note: called from _selectListItem and setCountry
3464
3552
  _updateDialCode(newDialCodeBare) {
3465
- const inputVal = this.telInput.value;
3553
+ const inputVal = this.ui.telInput.value;
3466
3554
  const newDialCode = `+${newDialCodeBare}`;
3467
3555
  let newNumber;
3468
- if (inputVal.charAt(0) === "+") {
3556
+ if (inputVal.startsWith("+")) {
3469
3557
  const prevDialCode = this._getDialCode(inputVal);
3470
3558
  if (prevDialCode) {
3471
3559
  newNumber = inputVal.replace(prevDialCode, newDialCode);
3472
3560
  } else {
3473
3561
  newNumber = newDialCode;
3474
3562
  }
3475
- this.telInput.value = newNumber;
3563
+ this.ui.telInput.value = newNumber;
3476
3564
  }
3477
3565
  }
3478
3566
  //* Try and extract a valid international dial code from a full telephone number.
3479
3567
  //* Note: returns the raw string inc plus character and any whitespace/dots etc.
3480
3568
  _getDialCode(number, includeAreaCode) {
3481
3569
  let dialCode = "";
3482
- if (number.charAt(0) === "+") {
3570
+ if (number.startsWith("+")) {
3483
3571
  let numericChars = "";
3484
3572
  for (let i = 0; i < number.length; i++) {
3485
3573
  const c = number.charAt(i);
@@ -3505,11 +3593,11 @@ var factoryOutput = (() => {
3505
3593
  }
3506
3594
  //* Get the input val, adding the dial code if separateDialCode is enabled.
3507
3595
  _getFullNumber(overrideVal) {
3508
- const val = overrideVal || this.telInput.value.trim();
3596
+ const val = overrideVal || this.ui.telInput.value.trim();
3509
3597
  const { dialCode } = this.selectedCountryData;
3510
3598
  let prefix;
3511
3599
  const numericVal = getNumeric(val);
3512
- if (this.options.separateDialCode && val.charAt(0) !== "+" && dialCode && numericVal) {
3600
+ if (this.options.separateDialCode && !val.startsWith("+") && dialCode && numericVal) {
3513
3601
  prefix = `+${dialCode}`;
3514
3602
  } else {
3515
3603
  prefix = "";
@@ -3538,7 +3626,7 @@ var factoryOutput = (() => {
3538
3626
  handleAutoCountry() {
3539
3627
  if (this.options.initialCountry === "auto" && intlTelInput.autoCountry) {
3540
3628
  this.defaultCountry = intlTelInput.autoCountry;
3541
- const hasSelectedCountryOrGlobe = this.selectedCountryData.iso2 || this.selectedCountryInner.classList.contains("iti__globe");
3629
+ const hasSelectedCountryOrGlobe = this.selectedCountryData.iso2 || this.ui.selectedCountryInner.classList.contains("iti__globe");
3542
3630
  if (!hasSelectedCountryOrGlobe) {
3543
3631
  this.setCountry(this.defaultCountry);
3544
3632
  }
@@ -3548,8 +3636,8 @@ var factoryOutput = (() => {
3548
3636
  //* This is called when the utils request completes.
3549
3637
  handleUtils() {
3550
3638
  if (intlTelInput.utils) {
3551
- if (this.telInput.value) {
3552
- this._updateValFromNumber(this.telInput.value);
3639
+ if (this.ui.telInput.value) {
3640
+ this._updateValFromNumber(this.ui.telInput.value);
3553
3641
  }
3554
3642
  if (this.selectedCountryData.iso2) {
3555
3643
  this._updatePlaceholder();
@@ -3563,49 +3651,20 @@ var factoryOutput = (() => {
3563
3651
  //********************
3564
3652
  //* Remove plugin.
3565
3653
  destroy() {
3566
- this.telInput.iti = void 0;
3567
- const { allowDropdown, separateDialCode } = this.options;
3568
- if (allowDropdown) {
3569
- this._closeDropdown();
3570
- this.selectedCountry.removeEventListener(
3571
- "click",
3572
- this._handleClickSelectedCountry
3573
- );
3574
- this.countryContainer.removeEventListener(
3575
- "keydown",
3576
- this._handleCountryContainerKeydown
3577
- );
3578
- const label = this.telInput.closest("label");
3579
- if (label) {
3580
- label.removeEventListener("click", this._handleLabelClick);
3581
- }
3582
- }
3583
- const { form } = this.telInput;
3584
- if (this._handleHiddenInputSubmit && form) {
3585
- form.removeEventListener("submit", this._handleHiddenInputSubmit);
3586
- }
3587
- this.telInput.removeEventListener("input", this._handleInputEvent);
3588
- if (this._handleKeydownEvent) {
3589
- this.telInput.removeEventListener("keydown", this._handleKeydownEvent);
3590
- }
3591
- if (this._handlePasteEvent) {
3592
- this.telInput.removeEventListener("paste", this._handlePasteEvent);
3654
+ if (!this.ui.telInput) {
3655
+ return;
3593
3656
  }
3594
- if (this._handlePageLoad) {
3595
- window.removeEventListener("load", this._handlePageLoad);
3657
+ if (this.options.allowDropdown) {
3658
+ this._closeDropdown();
3596
3659
  }
3597
- this.telInput.removeAttribute("data-intl-tel-input-id");
3598
- if (separateDialCode) {
3599
- if (this.isRTL) {
3600
- this.telInput.style.paddingRight = this.originalPaddingRight;
3601
- } else {
3602
- this.telInput.style.paddingLeft = this.originalPaddingLeft;
3603
- }
3660
+ this.abortController.abort();
3661
+ this.abortController = null;
3662
+ this.ui.destroy();
3663
+ if (intlTelInput.instances instanceof Map) {
3664
+ intlTelInput.instances.delete(this.id);
3665
+ } else {
3666
+ delete intlTelInput.instances[this.id];
3604
3667
  }
3605
- const wrapper = this.telInput.parentNode;
3606
- wrapper?.parentNode?.insertBefore(this.telInput, wrapper);
3607
- wrapper?.parentNode?.removeChild(wrapper);
3608
- delete intlTelInput.instances[this.id];
3609
3668
  }
3610
3669
  //* Get the extension from the current number.
3611
3670
  getExtension() {
@@ -3651,19 +3710,34 @@ var factoryOutput = (() => {
3651
3710
  }
3652
3711
  return -99;
3653
3712
  }
3654
- //* Validate the input val (with precise=false)
3713
+ //* Validate the input val using number length only
3655
3714
  isValidNumber() {
3715
+ const { dialCode, iso2 } = this.selectedCountryData;
3716
+ if (dialCode === "44" && intlTelInput.utils) {
3717
+ const number = this._getFullNumber();
3718
+ const coreNumber = intlTelInput.utils.getCoreNumber(number, iso2);
3719
+ if (coreNumber[0] === "7" && coreNumber.length !== 10) {
3720
+ return false;
3721
+ }
3722
+ }
3656
3723
  return this._validateNumber(false);
3657
3724
  }
3658
- //* Validate the input val (with precise=true)
3725
+ //* Validate the input val with precise validation
3659
3726
  isValidNumberPrecise() {
3660
3727
  return this._validateNumber(true);
3661
3728
  }
3662
3729
  _utilsIsPossibleNumber(val) {
3663
- return intlTelInput.utils ? intlTelInput.utils.isPossibleNumber(val, this.selectedCountryData.iso2, this.options.validationNumberTypes) : null;
3730
+ return intlTelInput.utils ? intlTelInput.utils.isPossibleNumber(
3731
+ val,
3732
+ this.selectedCountryData.iso2,
3733
+ this.options.validationNumberTypes
3734
+ ) : null;
3664
3735
  }
3665
3736
  //* Shared internal validation logic to handle alpha character extension rules.
3666
3737
  _validateNumber(precise) {
3738
+ if (!intlTelInput.utils) {
3739
+ return null;
3740
+ }
3667
3741
  if (!this.selectedCountryData.iso2) {
3668
3742
  return false;
3669
3743
  }
@@ -3680,7 +3754,11 @@ var factoryOutput = (() => {
3680
3754
  return testValidity(val);
3681
3755
  }
3682
3756
  _utilsIsValidNumber(val) {
3683
- return intlTelInput.utils ? intlTelInput.utils.isValidNumber(val, this.selectedCountryData.iso2, this.options.validationNumberTypes) : null;
3757
+ return intlTelInput.utils ? intlTelInput.utils.isValidNumber(
3758
+ val,
3759
+ this.selectedCountryData.iso2,
3760
+ this.options.validationNumberTypes
3761
+ ) : null;
3684
3762
  }
3685
3763
  //* Update the selected country, and update the input val accordingly.
3686
3764
  setCountry(iso2) {
@@ -3694,7 +3772,7 @@ var factoryOutput = (() => {
3694
3772
  this._setCountry(iso2Lower);
3695
3773
  this._updateDialCode(this.selectedCountryData.dialCode);
3696
3774
  if (this.options.formatOnDisplay) {
3697
- this._updateValFromNumber(this.telInput.value);
3775
+ this._updateValFromNumber(this.ui.telInput.value);
3698
3776
  }
3699
3777
  this._triggerCountryChange();
3700
3778
  }
@@ -3714,11 +3792,11 @@ var factoryOutput = (() => {
3714
3792
  this._updatePlaceholder();
3715
3793
  }
3716
3794
  setDisabled(disabled) {
3717
- this.telInput.disabled = disabled;
3795
+ this.ui.telInput.disabled = disabled;
3718
3796
  if (disabled) {
3719
- this.selectedCountry.setAttribute("disabled", "true");
3797
+ this.ui.selectedCountry.setAttribute("disabled", "true");
3720
3798
  } else {
3721
- this.selectedCountry.removeAttribute("disabled");
3799
+ this.ui.selectedCountry.removeAttribute("disabled");
3722
3800
  }
3723
3801
  }
3724
3802
  };
@@ -3732,13 +3810,19 @@ var factoryOutput = (() => {
3732
3810
  return Promise.reject(error);
3733
3811
  }
3734
3812
  } else {
3735
- return Promise.reject(new TypeError(`The argument passed to attachUtils must be a function that returns a promise for the utilities module, not ${typeof source}`));
3813
+ return Promise.reject(
3814
+ new TypeError(
3815
+ `The argument passed to attachUtils must be a function that returns a promise for the utilities module, not ${typeof source}`
3816
+ )
3817
+ );
3736
3818
  }
3737
3819
  intlTelInput.startedLoadingUtilsScript = true;
3738
3820
  return loadCall.then((module) => {
3739
3821
  const utils = module?.default;
3740
3822
  if (!utils || typeof utils !== "object") {
3741
- throw new TypeError("The loader function passed to attachUtils did not resolve to a module object with utils as its default export.");
3823
+ throw new TypeError(
3824
+ "The loader function passed to attachUtils did not resolve to a module object with utils as its default export."
3825
+ );
3742
3826
  }
3743
3827
  intlTelInput.utils = utils;
3744
3828
  forEachInstance("handleUtils");
@@ -3750,11 +3834,17 @@ var factoryOutput = (() => {
3750
3834
  }
3751
3835
  return null;
3752
3836
  };
3837
+ var forEachInstance = (method, ...args) => {
3838
+ Object.values(intlTelInput.instances).forEach((instance) => {
3839
+ const fn = instance[method];
3840
+ if (typeof fn === "function") {
3841
+ fn.apply(instance, args);
3842
+ }
3843
+ });
3844
+ };
3753
3845
  var intlTelInput = Object.assign(
3754
3846
  (input, options) => {
3755
3847
  const iti = new Iti(input, options);
3756
- iti._init();
3757
- input.setAttribute("data-intl-tel-input-id", iti.id.toString());
3758
3848
  intlTelInput.instances[iti.id] = iti;
3759
3849
  input.iti = iti;
3760
3850
  return iti;
@@ -3767,7 +3857,7 @@ var factoryOutput = (() => {
3767
3857
  getCountryData: () => data_default,
3768
3858
  //* A getter for the plugin instance.
3769
3859
  getInstance: (input) => {
3770
- const id2 = input.getAttribute("data-intl-tel-input-id");
3860
+ const id2 = input.dataset.intlTelInputId;
3771
3861
  return id2 ? intlTelInput.instances[id2] : null;
3772
3862
  },
3773
3863
  //* A map from instance ID to instance object.
@@ -3775,7 +3865,7 @@ var factoryOutput = (() => {
3775
3865
  attachUtils,
3776
3866
  startedLoadingUtilsScript: false,
3777
3867
  startedLoadingAutoCountry: false,
3778
- version: "25.10.11"
3868
+ version: "25.11.0"
3779
3869
  }
3780
3870
  );
3781
3871
  var intl_tel_input_default = intlTelInput;