intl-tel-input 25.12.5 → 25.13.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/README.md CHANGED
@@ -81,16 +81,16 @@ _Note: We have now dropped support for all versions of Internet Explorer because
81
81
  ## Getting Started (Using a CDN)
82
82
  1. Add the CSS
83
83
  ```html
84
- <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/intl-tel-input@25.12.5/build/css/intlTelInput.css">
84
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/intl-tel-input@25.13.0/build/css/intlTelInput.css">
85
85
  ```
86
86
 
87
87
  2. Add the plugin script and initialise it on your input element
88
88
  ```html
89
- <script src="https://cdn.jsdelivr.net/npm/intl-tel-input@25.12.5/build/js/intlTelInput.min.js"></script>
89
+ <script src="https://cdn.jsdelivr.net/npm/intl-tel-input@25.13.0/build/js/intlTelInput.min.js"></script>
90
90
  <script>
91
91
  const input = document.querySelector("#phone");
92
92
  window.intlTelInput(input, {
93
- loadUtils: () => import("https://cdn.jsdelivr.net/npm/intl-tel-input@25.12.5/build/js/utils.js"),
93
+ loadUtils: () => import("https://cdn.jsdelivr.net/npm/intl-tel-input@25.13.0/build/js/utils.js"),
94
94
  });
95
95
  </script>
96
96
  ```
@@ -328,12 +328,12 @@ Set the initial country selection by specifying its country code, e.g. `"us"` fo
328
328
  Type: `() => Promise<module>` Default: `null`
329
329
  This is one way to lazy load the included utils.js (to enable formatting/validation, etc) - see [Loading The Utilities Script](#loading-the-utilities-script) for more options.
330
330
 
331
- The `loadUtils` option takes a function that returns a Promise resolving to the utils module (see example code below). You can `import` the utils module in different ways: (A) from a CDN, (B) from your own hosted version of [utils.js](https://cdn.jsdelivr.net/npm/intl-tel-input@25.12.5/build/js/utils.js), or (C) if you use a bundler like Webpack, Vite or Parcel, you can import it directly from the package.
331
+ The `loadUtils` option takes a function that returns a Promise resolving to the utils module (see example code below). You can `import` the utils module in different ways: (A) from a CDN, (B) from your own hosted version of [utils.js](https://cdn.jsdelivr.net/npm/intl-tel-input@25.13.0/build/js/utils.js), or (C) if you use a bundler like Webpack, Vite or Parcel, you can import it directly from the package.
332
332
 
333
333
  ```js
334
334
  // (A) import utils module from a CDN
335
335
  intlTelInput(htmlInputElement, {
336
- loadUtils: () => import("https://cdn.jsdelivr.net/npm/intl-tel-input@25.12.5/build/js/utils.js"),
336
+ loadUtils: () => import("https://cdn.jsdelivr.net/npm/intl-tel-input@25.13.0/build/js/utils.js"),
337
337
  });
338
338
 
339
339
  // (B) import utils module from your own hosted version of utils.js
package/angular/README.md CHANGED
@@ -54,7 +54,7 @@ import "intl-tel-input/styles";
54
54
 
55
55
  See the [validation demo](https://github.com/jackocnr/intl-tel-input/blob/master/angular/demo/validation/validation.component.ts) for a more fleshed-out example of how to handle validation, or check out the [form demo](https://github.com/jackocnr/intl-tel-input/blob/master/angular/demo/form/form.component.ts) for an alternative approach using `ReactiveFormsModule`.
56
56
 
57
- A note on the utils script (~260KB): if you're lazy loading the IntlTelInput chunk (and so less worried about filesize) then you can just `import { IntlTelInputComponent } from "intl-tel-input/angularWithUtils"`, to include the utils script. Alternatively, if you use the main `"intl-tel-input/angular"` import, then you should couple this with the `loadUtils` initialisation option - you will need to host the [utils.js](https://github.com/jackocnr/intl-tel-input/blob/master/build/js/utils.js) file, and then set the `loadUtils` option to that URL, or alternatively just point it to a CDN hosted version e.g. `"https://cdn.jsdelivr.net/npm/intl-tel-input@25.12.5/build/js/utils.js"`.
57
+ A note on the utils script (~260KB): if you're lazy loading the IntlTelInput chunk (and so less worried about filesize) then you can just `import { IntlTelInputComponent } from "intl-tel-input/angularWithUtils"`, to include the utils script. Alternatively, if you use the main `"intl-tel-input/angular"` import, then you should couple this with the `loadUtils` initialisation option - you will need to host the [utils.js](https://github.com/jackocnr/intl-tel-input/blob/master/build/js/utils.js) file, and then set the `loadUtils` option to that URL, or alternatively just point it to a CDN hosted version e.g. `"https://cdn.jsdelivr.net/npm/intl-tel-input@25.13.0/build/js/utils.js"`.
58
58
 
59
59
  ## Props
60
60
 
@@ -2805,6 +2805,45 @@ var Iti = class _Iti {
2805
2805
  static _getIsAndroid() {
2806
2806
  return typeof navigator !== "undefined" ? /Android/i.test(navigator.userAgent) : false;
2807
2807
  }
2808
+ _updateNumeralSet(str) {
2809
+ if (/[\u0660-\u0669]/.test(str)) {
2810
+ this.userNumeralSet = "arabic-indic";
2811
+ } else if (/[\u06F0-\u06F9]/.test(str)) {
2812
+ this.userNumeralSet = "persian";
2813
+ } else {
2814
+ this.userNumeralSet = "ascii";
2815
+ }
2816
+ }
2817
+ _mapAsciiToUserNumerals(str) {
2818
+ if (!this.userNumeralSet) {
2819
+ this._updateNumeralSet(this.ui.telInput.value);
2820
+ }
2821
+ if (this.userNumeralSet === "ascii") {
2822
+ return str;
2823
+ }
2824
+ const base = this.userNumeralSet === "arabic-indic" ? 1632 : 1776;
2825
+ return str.replace(/[0-9]/g, (d) => String.fromCharCode(base + Number(d)));
2826
+ }
2827
+ // Normalize Eastern Arabic (U+0660-0669) and Persian/Extended Arabic-Indic (U+06F0-06F9) numerals to ASCII 0-9
2828
+ _normaliseNumerals(str) {
2829
+ if (!str) {
2830
+ return "";
2831
+ }
2832
+ this._updateNumeralSet(str);
2833
+ if (this.userNumeralSet === "ascii") {
2834
+ return str;
2835
+ }
2836
+ const base = this.userNumeralSet === "arabic-indic" ? 1632 : 1776;
2837
+ const regex = this.userNumeralSet === "arabic-indic" ? /[\u0660-\u0669]/g : /[\u06F0-\u06F9]/g;
2838
+ return str.replace(regex, (ch) => String.fromCharCode(48 + (ch.charCodeAt(0) - base)));
2839
+ }
2840
+ _getTelInputValue() {
2841
+ const inputValue = this.ui.telInput.value.trim();
2842
+ return this._normaliseNumerals(inputValue);
2843
+ }
2844
+ _setTelInputValue(asciiValue) {
2845
+ this.ui.telInput.value = this._mapAsciiToUserNumerals(asciiValue);
2846
+ }
2808
2847
  _createInitPromises() {
2809
2848
  const autoCountryPromise = new Promise((resolve, reject) => {
2810
2849
  this.resolveAutoCountryPromise = resolve;
@@ -2839,8 +2878,9 @@ var Iti = class _Iti {
2839
2878
  //* 1. Extracting a dial code from the given number
2840
2879
  //* 2. Using explicit initialCountry
2841
2880
  _setInitialState(overrideAutoCountry = false) {
2842
- const attributeValue = this.ui.telInput.getAttribute("value");
2843
- const inputValue = this.ui.telInput.value;
2881
+ const attributeValueRaw = this.ui.telInput.getAttribute("value");
2882
+ const attributeValue = this._normaliseNumerals(attributeValueRaw);
2883
+ const inputValue = this._getTelInputValue();
2844
2884
  const useAttribute = attributeValue && attributeValue.startsWith("+") && (!inputValue || !inputValue.startsWith("+"));
2845
2885
  const val = useAttribute ? attributeValue : inputValue;
2846
2886
  const dialCode = this._getDialCode(val);
@@ -2992,38 +3032,40 @@ var Iti = class _Iti {
2992
3032
  _bindInputListener() {
2993
3033
  const { strictMode, formatAsYouType, separateDialCode, allowDropdown, countrySearch } = this.options;
2994
3034
  let userOverrideFormatting = false;
2995
- if (REGEX.ALPHA_UNICODE.test(this.ui.telInput.value)) {
3035
+ if (REGEX.ALPHA_UNICODE.test(this._getTelInputValue())) {
2996
3036
  userOverrideFormatting = true;
2997
3037
  }
2998
3038
  const handleInputEvent = (e) => {
3039
+ const inputValue = this._getTelInputValue();
2999
3040
  if (this.isAndroid && (e === null || e === void 0 ? void 0 : e.data) === "+" && separateDialCode && allowDropdown && countrySearch) {
3000
3041
  const currentCaretPos = this.ui.telInput.selectionStart || 0;
3001
- const valueBeforeCaret = this.ui.telInput.value.substring(0, currentCaretPos - 1);
3002
- const valueAfterCaret = this.ui.telInput.value.substring(currentCaretPos);
3003
- this.ui.telInput.value = valueBeforeCaret + valueAfterCaret;
3042
+ const valueBeforeCaret = inputValue.substring(0, currentCaretPos - 1);
3043
+ const valueAfterCaret = inputValue.substring(currentCaretPos);
3044
+ this._setTelInputValue(valueBeforeCaret + valueAfterCaret);
3004
3045
  this._openDropdownWithPlus();
3005
3046
  return;
3006
3047
  }
3007
- if (this._updateCountryFromNumber(this.ui.telInput.value)) {
3048
+ if (this._updateCountryFromNumber(inputValue)) {
3008
3049
  this._triggerCountryChange();
3009
3050
  }
3010
3051
  const isFormattingChar = (e === null || e === void 0 ? void 0 : e.data) && REGEX.NON_PLUS_NUMERIC.test(e.data);
3011
- const isPaste = (e === null || e === void 0 ? void 0 : e.inputType) === INPUT_TYPES.PASTE && this.ui.telInput.value;
3052
+ const isPaste = (e === null || e === void 0 ? void 0 : e.inputType) === INPUT_TYPES.PASTE && inputValue;
3012
3053
  if (isFormattingChar || isPaste && !strictMode) {
3013
3054
  userOverrideFormatting = true;
3014
- } else if (!REGEX.NON_PLUS_NUMERIC.test(this.ui.telInput.value)) {
3055
+ } else if (!REGEX.NON_PLUS_NUMERIC.test(inputValue)) {
3015
3056
  userOverrideFormatting = false;
3016
3057
  }
3017
3058
  const isSetNumber = (e === null || e === void 0 ? void 0 : e.detail) && e.detail["isSetNumber"];
3018
- if (formatAsYouType && !userOverrideFormatting && !isSetNumber) {
3059
+ const isAscii = this.userNumeralSet === "ascii";
3060
+ if (formatAsYouType && !userOverrideFormatting && !isSetNumber && isAscii) {
3019
3061
  const currentCaretPos = this.ui.telInput.selectionStart || 0;
3020
- const valueBeforeCaret = this.ui.telInput.value.substring(0, currentCaretPos);
3062
+ const valueBeforeCaret = inputValue.substring(0, currentCaretPos);
3021
3063
  const relevantCharsBeforeCaret = valueBeforeCaret.replace(REGEX.NON_PLUS_NUMERIC_GLOBAL, "").length;
3022
3064
  const isDeleteForwards = (e === null || e === void 0 ? void 0 : e.inputType) === INPUT_TYPES.DELETE_FWD;
3023
3065
  const fullNumber = this._getFullNumber();
3024
- const formattedValue = formatNumberAsYouType(fullNumber, this.ui.telInput.value, intlTelInput.utils, this.selectedCountryData, this.options.separateDialCode);
3066
+ const formattedValue = formatNumberAsYouType(fullNumber, inputValue, intlTelInput.utils, this.selectedCountryData, this.options.separateDialCode);
3025
3067
  const newCaretPos = translateCursorPosition(relevantCharsBeforeCaret, formattedValue, currentCaretPos, isDeleteForwards);
3026
- this.ui.telInput.value = formattedValue;
3068
+ this._setTelInputValue(formattedValue);
3027
3069
  this.ui.telInput.setSelectionRange(newCaretPos, newCaretPos);
3028
3070
  }
3029
3071
  };
@@ -3042,12 +3084,18 @@ var Iti = class _Iti {
3042
3084
  return;
3043
3085
  }
3044
3086
  if (strictMode) {
3045
- const value = this.ui.telInput.value;
3046
- const alreadyHasPlus = value.startsWith("+");
3087
+ const inputValue = this._getTelInputValue();
3088
+ const alreadyHasPlus = inputValue.startsWith("+");
3047
3089
  const isInitialPlus = !alreadyHasPlus && this.ui.telInput.selectionStart === 0 && e.key === "+";
3048
- const isNumeric = /^[0-9]$/.test(e.key);
3090
+ const normalisedKey = this._normaliseNumerals(e.key);
3091
+ const isNumeric = /^[0-9]$/.test(normalisedKey);
3049
3092
  const isAllowedChar = separateDialCode ? isNumeric : isInitialPlus || isNumeric;
3050
- const newValue = value.slice(0, this.ui.telInput.selectionStart) + e.key + value.slice(this.ui.telInput.selectionEnd);
3093
+ const input = this.ui.telInput;
3094
+ const selStart = input.selectionStart;
3095
+ const selEnd = input.selectionEnd;
3096
+ const before = inputValue.slice(0, selStart);
3097
+ const after = inputValue.slice(selEnd);
3098
+ const newValue = before + e.key + after;
3051
3099
  const newFullNumber = this._getFullNumber(newValue);
3052
3100
  const coreNumber = intlTelInput.utils.getCoreNumber(newFullNumber, this.selectedCountryData.iso2);
3053
3101
  const hasExceededMaxLength = this.maxCoreNumberLength && coreNumber.length > this.maxCoreNumberLength;
@@ -3071,34 +3119,38 @@ var Iti = class _Iti {
3071
3119
  const input = this.ui.telInput;
3072
3120
  const selStart = input.selectionStart;
3073
3121
  const selEnd = input.selectionEnd;
3074
- const before = input.value.slice(0, selStart);
3075
- const after = input.value.slice(selEnd);
3122
+ const inputValue = this._getTelInputValue();
3123
+ const before = inputValue.slice(0, selStart);
3124
+ const after = inputValue.slice(selEnd);
3076
3125
  const iso2 = this.selectedCountryData.iso2;
3077
- const pasted = e.clipboardData.getData("text");
3126
+ const pastedRaw = e.clipboardData.getData("text");
3127
+ const pasted = this._normaliseNumerals(pastedRaw);
3078
3128
  const initialCharSelected = selStart === 0 && selEnd > 0;
3079
- const allowLeadingPlus = !input.value.startsWith("+") || initialCharSelected;
3129
+ const allowLeadingPlus = !inputValue.startsWith("+") || initialCharSelected;
3080
3130
  const allowedChars = pasted.replace(REGEX.NON_PLUS_NUMERIC_GLOBAL, "");
3081
3131
  const hasLeadingPlus = allowedChars.startsWith("+");
3082
3132
  const numerics = allowedChars.replace(/\+/g, "");
3083
3133
  const sanitised = hasLeadingPlus && allowLeadingPlus ? `+${numerics}` : numerics;
3084
3134
  let newVal = before + sanitised + after;
3085
- let coreNumber = intlTelInput.utils.getCoreNumber(newVal, iso2);
3086
- while (coreNumber.length === 0 && newVal.length > 0) {
3087
- newVal = newVal.slice(0, -1);
3088
- coreNumber = intlTelInput.utils.getCoreNumber(newVal, iso2);
3089
- }
3090
- if (!coreNumber) {
3091
- return;
3092
- }
3093
- if (this.maxCoreNumberLength && coreNumber.length > this.maxCoreNumberLength) {
3094
- if (input.selectionEnd === input.value.length) {
3095
- const trimLength = coreNumber.length - this.maxCoreNumberLength;
3096
- newVal = newVal.slice(0, newVal.length - trimLength);
3097
- } else {
3135
+ if (newVal.length > 5) {
3136
+ let coreNumber = intlTelInput.utils.getCoreNumber(newVal, iso2);
3137
+ while (coreNumber.length === 0 && newVal.length > 0) {
3138
+ newVal = newVal.slice(0, -1);
3139
+ coreNumber = intlTelInput.utils.getCoreNumber(newVal, iso2);
3140
+ }
3141
+ if (!coreNumber) {
3098
3142
  return;
3099
3143
  }
3144
+ if (this.maxCoreNumberLength && coreNumber.length > this.maxCoreNumberLength) {
3145
+ if (input.selectionEnd === inputValue.length) {
3146
+ const trimLength = coreNumber.length - this.maxCoreNumberLength;
3147
+ newVal = newVal.slice(0, newVal.length - trimLength);
3148
+ } else {
3149
+ return;
3150
+ }
3151
+ }
3100
3152
  }
3101
- input.value = newVal;
3153
+ this._setTelInputValue(newVal);
3102
3154
  const caretPos = selStart + sanitised.length;
3103
3155
  input.setSelectionRange(caretPos, caretPos);
3104
3156
  input.dispatchEvent(new InputEvent("input", { bubbles: true }));
@@ -3237,6 +3289,7 @@ var Iti = class _Iti {
3237
3289
  this._handleEnterKey();
3238
3290
  } else if (e.key === KEYS.ESC) {
3239
3291
  this._closeDropdown();
3292
+ this.ui.selectedCountry.focus();
3240
3293
  }
3241
3294
  }
3242
3295
  if (!this.options.countrySearch && REGEX.HIDDEN_SEARCH_CHAR.test(e.key)) {
@@ -3334,7 +3387,7 @@ var Iti = class _Iti {
3334
3387
  number = intlTelInput.utils.formatNumber(number, this.selectedCountryData.iso2, format);
3335
3388
  }
3336
3389
  number = this._beforeSetNumber(number);
3337
- this.ui.telInput.value = number;
3390
+ this._setTelInputValue(number);
3338
3391
  }
3339
3392
  //* Check if need to select a new country based on the given number
3340
3393
  //* Note: called from _setInitialState, keyup handler, setNumber.
@@ -3488,7 +3541,8 @@ var Iti = class _Iti {
3488
3541
  const dialCode = listItem.dataset[DATA_KEYS.DIAL_CODE];
3489
3542
  this._updateDialCode(dialCode);
3490
3543
  if (this.options.formatOnDisplay) {
3491
- this._updateValFromNumber(this.ui.telInput.value);
3544
+ const inputValue = this._getTelInputValue();
3545
+ this._updateValFromNumber(inputValue);
3492
3546
  }
3493
3547
  this.ui.telInput.focus();
3494
3548
  if (countryChanged) {
@@ -3519,7 +3573,7 @@ var Iti = class _Iti {
3519
3573
  //* Replace any existing dial code with the new one
3520
3574
  //* Note: called from _selectListItem and setCountry
3521
3575
  _updateDialCode(newDialCodeBare) {
3522
- const inputVal = this.ui.telInput.value;
3576
+ const inputVal = this._getTelInputValue();
3523
3577
  const newDialCode = `+${newDialCodeBare}`;
3524
3578
  let newNumber;
3525
3579
  if (inputVal.startsWith("+")) {
@@ -3529,7 +3583,7 @@ var Iti = class _Iti {
3529
3583
  } else {
3530
3584
  newNumber = newDialCode;
3531
3585
  }
3532
- this.ui.telInput.value = newNumber;
3586
+ this._setTelInputValue(newNumber);
3533
3587
  }
3534
3588
  }
3535
3589
  //* Try and extract a valid international dial code from a full telephone number.
@@ -3566,7 +3620,7 @@ var Iti = class _Iti {
3566
3620
  }
3567
3621
  //* Get the input val, adding the dial code if separateDialCode is enabled.
3568
3622
  _getFullNumber(overrideVal) {
3569
- const val = overrideVal || this.ui.telInput.value.trim();
3623
+ const val = overrideVal ? this._normaliseNumerals(overrideVal) : this._getTelInputValue();
3570
3624
  const { dialCode } = this.selectedCountryData;
3571
3625
  let prefix;
3572
3626
  const numericVal = getNumeric(val);
@@ -3604,8 +3658,9 @@ var Iti = class _Iti {
3604
3658
  //* This is called when the utils request completes.
3605
3659
  handleUtils() {
3606
3660
  if (intlTelInput.utils) {
3607
- if (this.ui.telInput.value) {
3608
- this._updateValFromNumber(this.ui.telInput.value);
3661
+ const inputValue = this._getTelInputValue();
3662
+ if (inputValue) {
3663
+ this._updateValFromNumber(inputValue);
3609
3664
  }
3610
3665
  if (this.selectedCountryData.iso2) {
3611
3666
  this._updatePlaceholder();
@@ -3645,7 +3700,9 @@ var Iti = class _Iti {
3645
3700
  getNumber(format) {
3646
3701
  if (intlTelInput.utils) {
3647
3702
  const { iso2 } = this.selectedCountryData;
3648
- return intlTelInput.utils.formatNumber(this._getFullNumber(), iso2, format);
3703
+ const fullNumber = this._getFullNumber();
3704
+ const formattedNumber = intlTelInput.utils.formatNumber(fullNumber, iso2, format);
3705
+ return this._mapAsciiToUserNumerals(formattedNumber);
3649
3706
  }
3650
3707
  return "";
3651
3708
  }
@@ -3722,15 +3779,17 @@ var Iti = class _Iti {
3722
3779
  this._setCountry(iso2Lower);
3723
3780
  this._updateDialCode(this.selectedCountryData.dialCode);
3724
3781
  if (this.options.formatOnDisplay) {
3725
- this._updateValFromNumber(this.ui.telInput.value);
3782
+ const inputValue = this._getTelInputValue();
3783
+ this._updateValFromNumber(inputValue);
3726
3784
  }
3727
3785
  this._triggerCountryChange();
3728
3786
  }
3729
3787
  }
3730
3788
  //* Set the input value and update the country.
3731
3789
  setNumber(number) {
3732
- const countryChanged = this._updateCountryFromNumber(number);
3733
- this._updateValFromNumber(number);
3790
+ const normalisedNumber = this._normaliseNumerals(number);
3791
+ const countryChanged = this._updateCountryFromNumber(normalisedNumber);
3792
+ this._updateValFromNumber(normalisedNumber);
3734
3793
  if (countryChanged) {
3735
3794
  this._triggerCountryChange();
3736
3795
  }
@@ -3807,7 +3866,7 @@ var intlTelInput = Object.assign((input, options) => {
3807
3866
  attachUtils,
3808
3867
  startedLoadingUtilsScript: false,
3809
3868
  startedLoadingAutoCountry: false,
3810
- version: "25.12.5"
3869
+ version: "25.13.0"
3811
3870
  });
3812
3871
  var intl_tel_input_default = intlTelInput;
3813
3872