intl-tel-input 27.0.17 → 27.1.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.
package/CHANGELOG.md CHANGED
@@ -1,6 +1,6 @@
1
1
  See the Github Releases page for changelog: https://github.com/jackocnr/intl-tel-input/releases
2
2
 
3
- Or to view a specific version, e.g. v27.0.17, update the URL accordingly, e.g. https://github.com/jackocnr/intl-tel-input/releases/tag/v27.0.17
3
+ Or to view a specific version, e.g. v27.1.0, update the URL accordingly, e.g. https://github.com/jackocnr/intl-tel-input/releases/tag/v27.1.0
4
4
 
5
5
  ## Breaking changes
6
6
 
@@ -58,7 +58,6 @@ declare class IntlTelInput implements AfterViewInit, OnDestroy, OnChanges, Contr
58
58
  private lastEmittedValidity?;
59
59
  private lastEmittedErrorCode?;
60
60
  private pendingWriteValue?;
61
- private countryChangeHandler;
62
61
  private onChange;
63
62
  private onTouched;
64
63
  private onValidatorChange;
@@ -1758,8 +1758,9 @@ var EVENTS = {
1758
1758
  OPEN_COUNTRY_DROPDOWN: "open:countrydropdown",
1759
1759
  CLOSE_COUNTRY_DROPDOWN: "close:countrydropdown",
1760
1760
  COUNTRY_CHANGE: "countrychange",
1761
- INPUT: "input"
1761
+ INPUT: "input",
1762
1762
  // used for synthetic input trigger
1763
+ STRICT_REJECT: "strict:reject"
1763
1764
  };
1764
1765
  var CLASSES = {
1765
1766
  HIDE: "iti__hide",
@@ -2355,6 +2356,7 @@ var UI = class _UI {
2355
2356
  wrapper.appendChild(this.telInputEl);
2356
2357
  this.#updateInputPaddingAndReveal();
2357
2358
  this.#buildHiddenInputs(wrapper);
2359
+ this.ensureDropdownWidthSet();
2358
2360
  }
2359
2361
  #createWrapperAndInsert() {
2360
2362
  const { allowDropdown, showFlags, containerClass, useFullscreenPopup } = this.#options;
@@ -2712,8 +2714,11 @@ var UI = class _UI {
2712
2714
  }
2713
2715
  //* Pre-fill the search input with "+" and show all countries
2714
2716
  //* (used when user types "+" in the phone input to open the dropdown).
2717
+ //* Explicitly focus the search input (openDropdown skips this when
2718
+ //* dropdownAlwaysOpen, but here we need focus to redirect subsequent keystrokes).
2715
2719
  prefillSearchWithPlus() {
2716
2720
  this.#searchInputEl.value = "+";
2721
+ this.#searchInputEl.focus();
2717
2722
  this.#filterCountriesByQuery("");
2718
2723
  }
2719
2724
  // Search input handlers
@@ -2753,24 +2758,23 @@ var UI = class _UI {
2753
2758
  }
2754
2759
  }
2755
2760
  //* Remove highlighting from the previous list item and highlight the new one.
2756
- #highlightListItem(listItem, shouldFocus) {
2757
- const prevItem = this.#highlightedListItemEl;
2758
- if (prevItem) {
2759
- prevItem.classList.remove(CLASSES.HIGHLIGHT);
2760
- }
2761
- this.#highlightedListItemEl = listItem;
2762
- if (this.#highlightedListItemEl) {
2763
- this.#highlightedListItemEl.classList.add(CLASSES.HIGHLIGHT);
2761
+ #highlightListItem(listItem, doScroll = true) {
2762
+ this.#highlightedListItemEl?.classList.remove(CLASSES.HIGHLIGHT);
2763
+ if (listItem) {
2764
+ listItem.classList.add(CLASSES.HIGHLIGHT);
2764
2765
  if (this.#options.countrySearch) {
2765
- const activeDescendant = this.#highlightedListItemEl.getAttribute("id") || "";
2766
+ const activeDescendant = listItem.getAttribute("id") || "";
2766
2767
  this.#searchInputEl.setAttribute(
2767
2768
  ARIA.ACTIVE_DESCENDANT,
2768
2769
  activeDescendant
2769
2770
  );
2770
2771
  }
2771
- if (shouldFocus) {
2772
- this.#highlightedListItemEl.focus();
2772
+ if (doScroll) {
2773
+ this.#scrollCountryListToItem(listItem);
2773
2774
  }
2775
+ this.#highlightedListItemEl = listItem;
2776
+ } else {
2777
+ this.#highlightedListItemEl = null;
2774
2778
  }
2775
2779
  }
2776
2780
  //* Bind a form-submit listener that syncs the hidden inputs with the current phone number
@@ -2861,8 +2865,7 @@ var UI = class _UI {
2861
2865
  this.#selectedCountryEl.setAttribute(ARIA.EXPANDED, "true");
2862
2866
  const itemToHighlight = this.#selectedListItemEl ?? this.#countryListEl.firstElementChild;
2863
2867
  if (itemToHighlight) {
2864
- this.#highlightListItem(itemToHighlight, false);
2865
- this.#scrollCountryListToItem(itemToHighlight);
2868
+ this.#highlightListItem(itemToHighlight);
2866
2869
  }
2867
2870
  if (countrySearch && !dropdownAlwaysOpen) {
2868
2871
  this.#searchInputEl.focus();
@@ -3003,8 +3006,7 @@ var UI = class _UI {
3003
3006
  const match = findFirstCountryStartingWith(this.#countries, query);
3004
3007
  if (match) {
3005
3008
  const listItem = this.#listItemByIso2.get(match.iso2);
3006
- this.#highlightListItem(listItem, false);
3007
- this.#scrollCountryListToItem(listItem);
3009
+ this.#highlightListItem(listItem);
3008
3010
  }
3009
3011
  }
3010
3012
  //* Highlight the next/prev item in the list (and ensure it is visible).
@@ -3014,8 +3016,7 @@ var UI = class _UI {
3014
3016
  next = key === KEYS.ARROW_UP ? this.#countryListEl.lastElementChild : this.#countryListEl.firstElementChild;
3015
3017
  }
3016
3018
  if (next) {
3017
- this.#scrollCountryListToItem(next);
3018
- this.#highlightListItem(next, false);
3019
+ this.#highlightListItem(next);
3019
3020
  }
3020
3021
  }
3021
3022
  // Update the selected list item in the dropdown
@@ -3038,6 +3039,9 @@ var UI = class _UI {
3038
3039
  );
3039
3040
  checkIcon.innerHTML = buildCheckIcon();
3040
3041
  this.#selectedListItemEl = newListItem;
3042
+ if (this.#options.dropdownAlwaysOpen) {
3043
+ this.#highlightListItem(newListItem);
3044
+ }
3041
3045
  }
3042
3046
  }
3043
3047
  }
@@ -3056,7 +3060,7 @@ var UI = class _UI {
3056
3060
  }
3057
3061
  }
3058
3062
  if (noCountriesAddedYet) {
3059
- this.#highlightListItem(null, false);
3063
+ this.#highlightListItem(null);
3060
3064
  if (this.#noResultsMessageEl) {
3061
3065
  this.#noResultsMessageEl.classList.remove(CLASSES.HIDE);
3062
3066
  }
@@ -3143,6 +3147,9 @@ var UI = class _UI {
3143
3147
  setLoading(isLoading) {
3144
3148
  this.#selectedFlagEl.classList.toggle(CLASSES.LOADING, isLoading);
3145
3149
  }
3150
+ isLoading() {
3151
+ return this.#selectedFlagEl.classList.contains(CLASSES.LOADING);
3152
+ }
3146
3153
  // Set the disabled state of the input and dropdown.
3147
3154
  setDisabled(disabled) {
3148
3155
  this.telInputEl.disabled = disabled;
@@ -3165,10 +3172,6 @@ var UI = class _UI {
3165
3172
  }
3166
3173
  }
3167
3174
  }
3168
- // Whether the selected flag is currently showing the globe icon (no country selected).
3169
- isShowingGlobe() {
3170
- return this.#selectedFlagEl.classList.contains(CLASSES.GLOBE);
3171
- }
3172
3175
  setCountry(selectedCountryData) {
3173
3176
  const { allowDropdown, showFlags, separateDialCode, i18n } = this.#options;
3174
3177
  const name = selectedCountryData?.name;
@@ -3530,7 +3533,6 @@ var Iti = class _Iti {
3530
3533
  this.#processCountryData();
3531
3534
  this.#ui.buildMarkup(this.#countries);
3532
3535
  this.#setInitialState();
3533
- this.#ui.ensureDropdownWidthSet();
3534
3536
  this.#initListeners();
3535
3537
  this.#startAsyncLoads();
3536
3538
  if (this.#options.dropdownAlwaysOpen) {
@@ -3559,22 +3561,23 @@ var Iti = class _Iti {
3559
3561
  const isRegionlessNanpNumber = isRegionlessNanp(value);
3560
3562
  const { initialCountry, geoIpLookup } = this.#options;
3561
3563
  const isAutoCountry = initialCountry === INITIAL_COUNTRY.AUTO && geoIpLookup;
3562
- const doingAutoCountryLookup = isAutoCountry && !overrideAutoCountry;
3563
- const isValidInitialCountry = isIso2(initialCountry);
3564
+ const resolvedInitialCountry = isAutoCountry && intlTelInput.autoCountry ? intlTelInput.autoCountry : initialCountry;
3565
+ const doingAutoCountryLookup = isAutoCountry && !overrideAutoCountry && !intlTelInput.autoCountry;
3566
+ const isValidInitialCountry = isIso2(resolvedInitialCountry);
3564
3567
  if (dialCode) {
3565
3568
  if (isRegionlessNanpNumber) {
3566
3569
  if (isValidInitialCountry) {
3567
- this.#setCountry(initialCountry);
3570
+ this.#updateSelectedCountry(resolvedInitialCountry);
3568
3571
  } else if (!doingAutoCountryLookup) {
3569
- this.#setCountry(US.ISO2);
3572
+ this.#updateSelectedCountry(US.ISO2);
3570
3573
  }
3571
3574
  } else {
3572
3575
  this.#updateCountryFromNumber(value);
3573
3576
  }
3574
3577
  } else if (isValidInitialCountry) {
3575
- this.#setCountry(initialCountry);
3578
+ this.#updateSelectedCountry(resolvedInitialCountry);
3576
3579
  } else if (!doingAutoCountryLookup) {
3577
- this.#setCountry("");
3580
+ this.#updateSelectedCountry("");
3578
3581
  }
3579
3582
  if (value) {
3580
3583
  this.#updateValueFromNumber(value);
@@ -3633,7 +3636,6 @@ var Iti = class _Iti {
3633
3636
  intlTelInput.startedLoadingAutoCountry = true;
3634
3637
  if (typeof this.#options.geoIpLookup === "function") {
3635
3638
  const successCallback = (iso2 = "") => {
3636
- this.#ui.setLoading(false);
3637
3639
  const iso2Lower = iso2.toLowerCase();
3638
3640
  if (isIso2(iso2Lower)) {
3639
3641
  intlTelInput.autoCountry = iso2Lower;
@@ -3643,7 +3645,6 @@ var Iti = class _Iti {
3643
3645
  }
3644
3646
  };
3645
3647
  const failureCallback = () => {
3646
- this.#ui.setLoading(false);
3647
3648
  _Iti.forEachInstance("handleAutoCountryFailure");
3648
3649
  };
3649
3650
  this.#options.geoIpLookup(successCallback, failureCallback);
@@ -3672,6 +3673,9 @@ var Iti = class _Iti {
3672
3673
  userOverrideFormatting = true;
3673
3674
  }
3674
3675
  const handleInputEvent = (e) => {
3676
+ if (e?.detail && e.detail["isCountryChange"]) {
3677
+ return;
3678
+ }
3675
3679
  const inputValue = this.#getTelInputValue();
3676
3680
  if (this.#isAndroid && e?.data === "+" && separateDialCode && allowDropdown && countrySearch) {
3677
3681
  const currentCaretPos = this.#ui.telInputEl.selectionStart || 0;
@@ -3777,6 +3781,11 @@ var Iti = class _Iti {
3777
3781
  const newCountry = this.#resolveCountryChangeFromNumber(newFullNumber);
3778
3782
  const isChangingDialCode = newCountry !== null;
3779
3783
  if (!isAllowedChar || hasExceededMaxLength && !isChangingDialCode && !isInitialPlus) {
3784
+ this.#dispatchEvent(EVENTS.STRICT_REJECT, {
3785
+ source: "key",
3786
+ rejectedInput: e.key,
3787
+ reason: !isAllowedChar ? "invalid" : "max-length"
3788
+ });
3780
3789
  e.preventDefault();
3781
3790
  }
3782
3791
  };
@@ -3806,6 +3815,7 @@ var Iti = class _Iti {
3806
3815
  const numerics = allowedChars.replace(/\+/g, "");
3807
3816
  const sanitised = hasLeadingPlus && allowLeadingPlus ? `+${numerics}` : numerics;
3808
3817
  let newValue = before + sanitised + after;
3818
+ let rejectReason = sanitised !== pasted ? "invalid" : null;
3809
3819
  if (newValue.length > 5 && intlTelInput.utils) {
3810
3820
  let coreNumber = intlTelInput.utils.getCoreNumber(newValue, iso2);
3811
3821
  while (coreNumber.length === 0 && newValue.length > 0) {
@@ -3813,13 +3823,24 @@ var Iti = class _Iti {
3813
3823
  coreNumber = intlTelInput.utils.getCoreNumber(newValue, iso2);
3814
3824
  }
3815
3825
  if (!coreNumber) {
3826
+ this.#dispatchEvent(EVENTS.STRICT_REJECT, {
3827
+ source: "paste",
3828
+ rejectedInput: pastedRaw,
3829
+ reason: "max-length"
3830
+ });
3816
3831
  return;
3817
3832
  }
3818
3833
  if (this.#maxCoreNumberLength && coreNumber.length > this.#maxCoreNumberLength) {
3819
3834
  if (input.selectionEnd === inputValue.length) {
3820
3835
  const trimLength = coreNumber.length - this.#maxCoreNumberLength;
3821
3836
  newValue = newValue.slice(0, newValue.length - trimLength);
3837
+ rejectReason = "max-length";
3822
3838
  } else {
3839
+ this.#dispatchEvent(EVENTS.STRICT_REJECT, {
3840
+ source: "paste",
3841
+ rejectedInput: pastedRaw,
3842
+ reason: "max-length"
3843
+ });
3823
3844
  return;
3824
3845
  }
3825
3846
  }
@@ -3828,6 +3849,13 @@ var Iti = class _Iti {
3828
3849
  const caretPos = selStart + sanitised.length;
3829
3850
  input.setSelectionRange(caretPos, caretPos);
3830
3851
  input.dispatchEvent(new InputEvent("input", { bubbles: true }));
3852
+ if (rejectReason) {
3853
+ this.#dispatchEvent(EVENTS.STRICT_REJECT, {
3854
+ source: "paste",
3855
+ rejectedInput: pastedRaw,
3856
+ reason: rejectReason
3857
+ });
3858
+ }
3831
3859
  };
3832
3860
  this.#ui.telInputEl.addEventListener("paste", handlePasteEvent, {
3833
3861
  signal: this.#abortController.signal
@@ -3879,7 +3907,7 @@ var Iti = class _Iti {
3879
3907
  #updateCountryFromNumber(fullNumber) {
3880
3908
  const iso2 = this.#resolveCountryChangeFromNumber(fullNumber);
3881
3909
  if (iso2 !== null) {
3882
- return this.#setCountry(iso2);
3910
+ return this.#updateSelectedCountry(iso2);
3883
3911
  }
3884
3912
  return false;
3885
3913
  }
@@ -3962,7 +3990,7 @@ var Iti = class _Iti {
3962
3990
  }
3963
3991
  //* Update the selected country, dial code (if separateDialCode), placeholder, title, and selected list item.
3964
3992
  //* Note: called from setInitialState, updateCountryFromNumber, selectListItem, setCountry.
3965
- #setCountry(iso2) {
3993
+ #updateSelectedCountry(iso2) {
3966
3994
  const prevIso2 = this.#selectedCountry?.iso2 || "";
3967
3995
  this.#selectedCountry = iso2 ? this.#countryByIso2.get(iso2) : null;
3968
3996
  if (this.#selectedCountry) {
@@ -4036,7 +4064,7 @@ var Iti = class _Iti {
4036
4064
  return;
4037
4065
  }
4038
4066
  const iso2 = listItem.dataset[DATA_KEYS.ISO2];
4039
- const countryChanged = this.#setCountry(iso2);
4067
+ const countryChanged = this.#updateSelectedCountry(iso2);
4040
4068
  this.#closeDropdown();
4041
4069
  const dialCode = listItem.dataset[DATA_KEYS.DIAL_CODE];
4042
4070
  this.#updateDialCode(dialCode);
@@ -4047,6 +4075,7 @@ var Iti = class _Iti {
4047
4075
  this.#ui.telInputEl.focus();
4048
4076
  if (countryChanged) {
4049
4077
  this.#dispatchCountryChangeEvent();
4078
+ this.#dispatchEvent(EVENTS.INPUT, { isCountryChange: true });
4050
4079
  }
4051
4080
  }
4052
4081
  //* Close the dropdown and unbind any listeners.
@@ -4157,11 +4186,12 @@ var Iti = class _Iti {
4157
4186
  this.#autoCountryDeferred.resolve();
4158
4187
  return;
4159
4188
  }
4160
- this.#fallbackCountryIso2 = intlTelInput.autoCountry;
4161
- const hasSelectedCountryOrGlobe = this.#selectedCountry || this.#ui.isShowingGlobe();
4162
- if (!hasSelectedCountryOrGlobe) {
4163
- this.setCountry(this.#fallbackCountryIso2);
4189
+ if (this.#ui.isLoading()) {
4190
+ this.setCountry(intlTelInput.autoCountry);
4191
+ } else {
4192
+ this.#fallbackCountryIso2 = intlTelInput.autoCountry;
4164
4193
  }
4194
+ this.#ui.setLoading(false);
4165
4195
  this.#autoCountryDeferred.resolve();
4166
4196
  }
4167
4197
  //* Called when the geoip call fails or times out.
@@ -4171,6 +4201,7 @@ var Iti = class _Iti {
4171
4201
  return;
4172
4202
  }
4173
4203
  this.#setInitialState(true);
4204
+ this.#ui.setLoading(false);
4174
4205
  this.#autoCountryDeferred?.reject();
4175
4206
  }
4176
4207
  //* Called when the utils request completes.
@@ -4340,13 +4371,14 @@ var Iti = class _Iti {
4340
4371
  if (!isCountryChange) {
4341
4372
  return;
4342
4373
  }
4343
- this.#setCountry(iso2Lower);
4374
+ this.#updateSelectedCountry(iso2Lower);
4344
4375
  this.#updateDialCode(this.#selectedCountry?.dialCode || "");
4345
4376
  if (this.#options.formatOnDisplay) {
4346
4377
  const inputValue = this.#getTelInputValue();
4347
4378
  this.#updateValueFromNumber(inputValue);
4348
4379
  }
4349
4380
  this.#dispatchCountryChangeEvent();
4381
+ this.#dispatchEvent(EVENTS.INPUT, { isCountryChange: true });
4350
4382
  }
4351
4383
  //* Set the input value and update the country.
4352
4384
  setNumber(number) {
@@ -4470,7 +4502,7 @@ var intlTelInput = Object.assign(
4470
4502
  attachUtils,
4471
4503
  startedLoadingUtils: false,
4472
4504
  startedLoadingAutoCountry: false,
4473
- version: "27.0.17"
4505
+ version: "27.1.0"
4474
4506
  }
4475
4507
  );
4476
4508
  var intlTelInput_default = intlTelInput;
@@ -4539,7 +4571,6 @@ var IntlTelInput = class _IntlTelInput {
4539
4571
  lastEmittedErrorCode;
4540
4572
  // writeValue may be called by Angular forms before utils has loaded; queue it until then
4541
4573
  pendingWriteValue;
4542
- countryChangeHandler = () => this.handleInput();
4543
4574
  // eslint-disable-next-line class-methods-use-this
4544
4575
  onChange = () => {
4545
4576
  };
@@ -4551,7 +4582,6 @@ var IntlTelInput = class _IntlTelInput {
4551
4582
  };
4552
4583
  ngAfterViewInit() {
4553
4584
  this.iti = intlTelInput_default(this.inputRef.nativeElement, this.buildInitOptions());
4554
- this.inputRef.nativeElement.addEventListener("countrychange", this.countryChangeHandler);
4555
4585
  this.applyInputAttrs();
4556
4586
  if (this.disabled) {
4557
4587
  this.iti.setDisabled(this.disabled);
@@ -4685,7 +4715,6 @@ var IntlTelInput = class _IntlTelInput {
4685
4715
  }
4686
4716
  ngOnDestroy() {
4687
4717
  this.iti?.destroy();
4688
- this.inputRef.nativeElement.removeEventListener("countrychange", this.countryChangeHandler);
4689
4718
  }
4690
4719
  ignoredInputAttrs = /* @__PURE__ */ new Set([
4691
4720
  "type",