intl-tel-input 27.2.0 → 27.3.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.2.0, update the URL accordingly, e.g. https://github.com/jackocnr/intl-tel-input/releases/tag/v27.2.0
3
+ Or to view a specific version, e.g. v27.3.0, update the URL accordingly, e.g. https://github.com/jackocnr/intl-tel-input/releases/tag/v27.3.0
4
4
 
5
5
  ## Breaking changes
6
6
 
package/README.md CHANGED
@@ -23,20 +23,31 @@ We provide React, Vue, Angular and Svelte (beta) components alongside the regula
23
23
  We have a newly updated website, where you can find [a full set of docs](https://intl-tel-input.com/docs/integrations), a [live playground](https://intl-tel-input.com/playground/) where you can try out all of the options, as well as plenty of [examples](https://intl-tel-input.com/examples/validation-practical.html) of different setups.
24
24
 
25
25
  ## Features
26
- * Automatically select the user's current country using an IP lookup
27
- * Automatically set the input placeholder to an example number for the selected country
28
- * Navigate the country dropdown by typing a country's name, or using the up/down keys
29
- * Automatically format the number as the user types
30
- * Optionally, only allow numeric characters and cap the number at the maximum valid length
31
- * The user types their national number, and the plugin gives you the full standardised international number
32
- * Number validation, including specific error types
33
- * High-resolution flag images
34
- * Accessibility provided via ARIA tags
35
- * Typescript type definitions included
36
- * Easily customise styles by overriding CSS variables, e.g. support dark mode
37
- * React, Vue, Angular and Svelte components also included
38
- * Translations provided in over 40 languages, as well as support for RTL layout and alternative numeral sets
39
- * Lots of initialisation options for customisation, as well as instance methods/events for interaction
26
+
27
+ 🔍 **Fast country picking**
28
+ * Search by country name or dial code
29
+ * Full keyboard navigation
30
+
31
+ **Smart defaults**
32
+ * Optionally auto-detect the user's country via IP lookup
33
+ * Example placeholders per country
34
+
35
+ 📞 **Formatting & output**
36
+ * Formats the number as the user types
37
+ * Extract standard E.164 numbers to store
38
+
39
+ 🛡️ **Validation**
40
+ * Validate numbers with specific error types
41
+ * Strict mode: only allow valid digits and enforce max length
42
+
43
+ 🌍 **International & accessible**
44
+ * Translated into 40+ languages, with support for RTL and alternative numerals
45
+ * Screen reader-friendly ARIA markup
46
+
47
+ 🎛️ **Customisable**
48
+ * Override CSS variables (e.g. dark mode)
49
+ * Optionally display the dial code next to the number
50
+ * Extensive initialisation options, methods, and events
40
51
 
41
52
  ## Contributing
42
53
  See the [contributing guide](https://github.com/jackocnr/intl-tel-input/blob/master/.github/CONTRIBUTING.md) for instructions on setting up the project and making changes, and also on how to update the flag images, or how to add a new translation.
@@ -45,6 +45,7 @@ declare class IntlTelInput implements AfterViewInit, OnDestroy, OnChanges, Contr
45
45
  separateDialCode?: AllOptions["separateDialCode"];
46
46
  showFlags?: AllOptions["showFlags"];
47
47
  strictMode?: AllOptions["strictMode"];
48
+ strictRejectAnimation?: AllOptions["strictRejectAnimation"];
48
49
  useFullscreenPopup?: AllOptions["useFullscreenPopup"];
49
50
  numberChange: EventEmitter<string>;
50
51
  countryChange: EventEmitter<string>;
@@ -61,6 +62,7 @@ declare class IntlTelInput implements AfterViewInit, OnDestroy, OnChanges, Contr
61
62
  click: EventEmitter<MouseEvent>;
62
63
  private iti?;
63
64
  private appliedInputAttrKeys;
65
+ private pluginInputClasses;
64
66
  private lastEmittedNumber?;
65
67
  private lastEmittedCountry?;
66
68
  private lastEmittedValidity?;
@@ -103,6 +105,6 @@ declare class IntlTelInput implements AfterViewInit, OnDestroy, OnChanges, Contr
103
105
  validate(_control: AbstractControl): ValidationErrors | null;
104
106
  registerOnValidatorChange(fn: () => void): void;
105
107
  static ɵfac: i0.ɵɵFactoryDeclaration<IntlTelInput, never>;
106
- static ɵcmp: i0.ɵɵComponentDeclaration<IntlTelInput, "intl-tel-input", never, { "initialValue": { "alias": "initialValue"; "required": false; }; "usePreciseValidation": { "alias": "usePreciseValidation"; "required": false; }; "inputAttributes": { "alias": "inputAttributes"; "required": false; }; "disabled": { "alias": "disabled"; "required": false; }; "readonly": { "alias": "readonly"; "required": false; }; "allowDropdown": { "alias": "allowDropdown"; "required": false; }; "allowedNumberTypes": { "alias": "allowedNumberTypes"; "required": false; }; "allowNumberExtensions": { "alias": "allowNumberExtensions"; "required": false; }; "allowPhonewords": { "alias": "allowPhonewords"; "required": false; }; "autoPlaceholder": { "alias": "autoPlaceholder"; "required": false; }; "containerClass": { "alias": "containerClass"; "required": false; }; "countryNameLocale": { "alias": "countryNameLocale"; "required": false; }; "countryOrder": { "alias": "countryOrder"; "required": false; }; "countrySearch": { "alias": "countrySearch"; "required": false; }; "customPlaceholder": { "alias": "customPlaceholder"; "required": false; }; "dropdownAlwaysOpen": { "alias": "dropdownAlwaysOpen"; "required": false; }; "dropdownContainer": { "alias": "dropdownContainer"; "required": false; }; "excludeCountries": { "alias": "excludeCountries"; "required": false; }; "fixDropdownWidth": { "alias": "fixDropdownWidth"; "required": false; }; "formatAsYouType": { "alias": "formatAsYouType"; "required": false; }; "formatOnDisplay": { "alias": "formatOnDisplay"; "required": false; }; "geoIpLookup": { "alias": "geoIpLookup"; "required": false; }; "hiddenInput": { "alias": "hiddenInput"; "required": false; }; "i18n": { "alias": "i18n"; "required": false; }; "initialCountry": { "alias": "initialCountry"; "required": false; }; "loadUtils": { "alias": "loadUtils"; "required": false; }; "nationalMode": { "alias": "nationalMode"; "required": false; }; "onlyCountries": { "alias": "onlyCountries"; "required": false; }; "placeholderNumberType": { "alias": "placeholderNumberType"; "required": false; }; "searchInputClass": { "alias": "searchInputClass"; "required": false; }; "separateDialCode": { "alias": "separateDialCode"; "required": false; }; "showFlags": { "alias": "showFlags"; "required": false; }; "strictMode": { "alias": "strictMode"; "required": false; }; "useFullscreenPopup": { "alias": "useFullscreenPopup"; "required": false; }; }, { "numberChange": "numberChange"; "countryChange": "countryChange"; "validityChange": "validityChange"; "errorCodeChange": "errorCodeChange"; "openCountryDropdown": "openCountryDropdown"; "closeCountryDropdown": "closeCountryDropdown"; "strictReject": "strictReject"; "blur": "blur"; "focus": "focus"; "keydown": "keydown"; "keyup": "keyup"; "paste": "paste"; "click": "click"; }, never, never, true, never>;
108
+ static ɵcmp: i0.ɵɵComponentDeclaration<IntlTelInput, "intl-tel-input", never, { "initialValue": { "alias": "initialValue"; "required": false; }; "usePreciseValidation": { "alias": "usePreciseValidation"; "required": false; }; "inputAttributes": { "alias": "inputAttributes"; "required": false; }; "disabled": { "alias": "disabled"; "required": false; }; "readonly": { "alias": "readonly"; "required": false; }; "allowDropdown": { "alias": "allowDropdown"; "required": false; }; "allowedNumberTypes": { "alias": "allowedNumberTypes"; "required": false; }; "allowNumberExtensions": { "alias": "allowNumberExtensions"; "required": false; }; "allowPhonewords": { "alias": "allowPhonewords"; "required": false; }; "autoPlaceholder": { "alias": "autoPlaceholder"; "required": false; }; "containerClass": { "alias": "containerClass"; "required": false; }; "countryNameLocale": { "alias": "countryNameLocale"; "required": false; }; "countryOrder": { "alias": "countryOrder"; "required": false; }; "countrySearch": { "alias": "countrySearch"; "required": false; }; "customPlaceholder": { "alias": "customPlaceholder"; "required": false; }; "dropdownAlwaysOpen": { "alias": "dropdownAlwaysOpen"; "required": false; }; "dropdownContainer": { "alias": "dropdownContainer"; "required": false; }; "excludeCountries": { "alias": "excludeCountries"; "required": false; }; "fixDropdownWidth": { "alias": "fixDropdownWidth"; "required": false; }; "formatAsYouType": { "alias": "formatAsYouType"; "required": false; }; "formatOnDisplay": { "alias": "formatOnDisplay"; "required": false; }; "geoIpLookup": { "alias": "geoIpLookup"; "required": false; }; "hiddenInput": { "alias": "hiddenInput"; "required": false; }; "i18n": { "alias": "i18n"; "required": false; }; "initialCountry": { "alias": "initialCountry"; "required": false; }; "loadUtils": { "alias": "loadUtils"; "required": false; }; "nationalMode": { "alias": "nationalMode"; "required": false; }; "onlyCountries": { "alias": "onlyCountries"; "required": false; }; "placeholderNumberType": { "alias": "placeholderNumberType"; "required": false; }; "searchInputClass": { "alias": "searchInputClass"; "required": false; }; "separateDialCode": { "alias": "separateDialCode"; "required": false; }; "showFlags": { "alias": "showFlags"; "required": false; }; "strictMode": { "alias": "strictMode"; "required": false; }; "strictRejectAnimation": { "alias": "strictRejectAnimation"; "required": false; }; "useFullscreenPopup": { "alias": "useFullscreenPopup"; "required": false; }; }, { "numberChange": "numberChange"; "countryChange": "countryChange"; "validityChange": "validityChange"; "errorCodeChange": "errorCodeChange"; "openCountryDropdown": "openCountryDropdown"; "closeCountryDropdown": "closeCountryDropdown"; "strictReject": "strictReject"; "blur": "blur"; "focus": "focus"; "keydown": "keydown"; "keyup": "keyup"; "paste": "paste"; "click": "click"; }, never, never, true, never>;
107
109
  }
108
110
  export default IntlTelInput;
@@ -1,4 +1,4 @@
1
- // dist/js/intlTelInput.mjs
1
+ // src/js/data.ts
2
2
  var rawCountryData = [
3
3
  [
4
4
  "af",
@@ -1755,6 +1755,8 @@ for (const c of rawCountryData) {
1755
1755
  var iso2Set = new Set(allCountries.map((c) => c.iso2));
1756
1756
  var isIso2 = (val) => iso2Set.has(val);
1757
1757
  var data_default = allCountries;
1758
+
1759
+ // src/js/constants.ts
1758
1760
  var EVENTS = {
1759
1761
  OPEN_COUNTRY_DROPDOWN: "open:countrydropdown",
1760
1762
  CLOSE_COUNTRY_DROPDOWN: "close:countrydropdown",
@@ -1879,6 +1881,8 @@ var ARIA = {
1879
1881
  AUTOCOMPLETE: "aria-autocomplete",
1880
1882
  MODAL: "aria-modal"
1881
1883
  };
1884
+
1885
+ // src/js/i18n/en.ts
1882
1886
  var interfaceTranslations = {
1883
1887
  selectedCountryAriaLabel: "Change country for phone number, currently selected ${countryName} (${dialCode})",
1884
1888
  noCountrySelected: "Select country for phone number",
@@ -1897,6 +1901,8 @@ var interfaceTranslations = {
1897
1901
  }
1898
1902
  };
1899
1903
  var en_default = interfaceTranslations;
1904
+
1905
+ // src/js/core/options.ts
1900
1906
  var mediaQuery = (q) => typeof window !== "undefined" && typeof window.matchMedia === "function" && window.matchMedia(q).matches;
1901
1907
  var isNarrowViewport = () => mediaQuery(`(max-width: ${LAYOUT.NARROW_VIEWPORT_WIDTH}px)`);
1902
1908
  var computeDefaultUseFullscreenPopup = () => {
@@ -1960,6 +1966,8 @@ var defaults = {
1960
1966
  searchInputClass: "",
1961
1967
  //* Display the international dial code next to the selected flag.
1962
1968
  separateDialCode: false,
1969
+ //* When strictMode rejects a key (etc), play a short feedback animation
1970
+ strictRejectAnimation: false,
1963
1971
  //* Show flags - for both the selected country, and in the country dropdown
1964
1972
  showFlags: true,
1965
1973
  //* Only allow certain chars e.g. a plus followed by numeric digits, and cap at max valid length.
@@ -2035,6 +2043,7 @@ var validateOptions = (customOptions) => {
2035
2043
  case "showFlags":
2036
2044
  case "separateDialCode":
2037
2045
  case "strictMode":
2046
+ case "strictRejectAnimation":
2038
2047
  case "useFullscreenPopup":
2039
2048
  if (typeof value !== "boolean") {
2040
2049
  warnOption(key, "a boolean", value);
@@ -2205,8 +2214,12 @@ var applyOptionSideEffects = (o) => {
2205
2214
  }
2206
2215
  o.i18n = { ...en_default, ...o.i18n };
2207
2216
  };
2217
+
2218
+ // src/js/helpers/string.ts
2208
2219
  var getNumeric = (s) => s.replace(/\D/g, "");
2209
2220
  var normaliseString = (s = "") => s.normalize("NFD").replace(/[\u0300-\u036f]/g, "").toLowerCase();
2221
+
2222
+ // src/js/helpers/dom.ts
2210
2223
  var buildClassNames = (flags) => Object.keys(flags).filter((k) => Boolean(flags[k])).join(" ");
2211
2224
  var createEl = (tagName, attrs, container) => {
2212
2225
  const el = document.createElement(tagName);
@@ -2220,6 +2233,8 @@ var createEl = (tagName, attrs, container) => {
2220
2233
  }
2221
2234
  return el;
2222
2235
  };
2236
+
2237
+ // src/js/core/icons.ts
2223
2238
  var buildSearchIcon = () => `
2224
2239
  <svg class="iti__search-icon-svg" width="14" height="14" viewBox="0 0 24 24" focusable="false" ${ARIA.HIDDEN}="true">
2225
2240
  <circle cx="11" cy="11" r="7" />
@@ -2245,6 +2260,8 @@ var buildGlobeIcon = () => `
2245
2260
  <path d="M508 213a240 240 0 0 0-449-87l-2 5-2 5c-8 14-13 30-17 46a65 65 0 0 1 56 4c16-10 35-19 56-27l9-3c-6 23-10 48-10 74h-16l4 6c3 4 5 8 6 13h6c0 22 3 44 8 65l2 10-25-10-4 5 12 18 9 3 6 2 8 3 9 26 1 2 16-7h1l-5-13-1-2c24 6 49 9 75 10v26l11 10 7 7v-30l1-13c22 0 44-3 65-8l10-2-21 48-1 1a317 317 0 0 1-14 23l-21 5h-2c6 16 7 33 1 50a240 240 0 0 0 211-265m-401-56-11 6c19-44 54-79 98-98-11 20-21 44-29 69-21 6-40 15-58 23m154 182v4c-29-1-57-6-81-13-7-25-12-52-13-81h94zm0-109h-94c1-29 6-56 13-81 24-7 52-12 81-13zm0-112c-22 1-44 4-65 8l-10 2 12-30 9-17 1-2a332 332 0 0 1 13-23c13-4 26-6 40-7zm187 69 6 4c4 12 6 25 6 38v1h-68c-1-26-4-51-10-74l48 20 1 1 14 8zm-14-44 10 20c-20-11-43-21-68-29-8-25-18-49-29-69 37 16 67 44 87 78M279 49h1c13 1 27 3 39 7l14 23 1 2a343 343 0 0 1 12 26l2 5 6 16c-23-6-48-9-74-10h-1zm0 87h1c29 1 56 6 81 13 7 24 12 51 12 80v1h-94zm2 207h-2v-94h95c-1 29-6 56-13 81-24 7-51 12-80 13m86 60-20 10c11-20 21-43 29-68 25-8 48-18 68-29-16 37-43 67-77 87m87-115-7 5-16 9-2 1a337 337 0 0 1-47 21c6-24 9-49 10-75h68c0 13-2 27-6 39"/>
2246
2261
  <path d="m261 428-2-2-22-21a40 40 0 0 0-32-11h-1a37 37 0 0 0-18 8l-1 1-4 2-2 2-5 4c-9-3-36-31-47-44s-32-45-34-55l3-2a151 151 0 0 0 11-9v-1a39 39 0 0 0 5-48l-3-3-11-19-3-4-5-7h-1l-3-3-4-3-5-2a35 35 0 0 0-16-3h-5c-4 1-14 5-24 11l-4 2-4 3-4 2c-9 8-17 17-18 27a380 380 0 0 0 212 259h3c12 0 25-10 36-21l10-12 6-11a39 39 0 0 0-8-40"/>
2247
2262
  </svg>`;
2263
+
2264
+ // src/js/core/countrySearch.ts
2248
2265
  var getMatchedCountries = (countries, query) => {
2249
2266
  const normalisedQuery = normaliseString(query);
2250
2267
  const iso2Matches = [];
@@ -2288,6 +2305,8 @@ var findFirstCountryStartingWith = (countries, query) => {
2288
2305
  }
2289
2306
  return null;
2290
2307
  };
2308
+
2309
+ // src/js/core/ui.ts
2291
2310
  var UI = class _UI {
2292
2311
  // private
2293
2312
  #options;
@@ -3216,6 +3235,8 @@ var UI = class _UI {
3216
3235
  this.#listItemByIso2.clear();
3217
3236
  }
3218
3237
  };
3238
+
3239
+ // src/js/data/country-data.ts
3219
3240
  var processAllCountries = (options) => {
3220
3241
  const { onlyCountries, excludeCountries } = options;
3221
3242
  if (onlyCountries?.length) {
@@ -3321,6 +3342,8 @@ var cacheSearchTokens = (countries) => {
3321
3342
  c.dialCodePlus = `+${c.dialCode}`;
3322
3343
  }
3323
3344
  };
3345
+
3346
+ // src/js/data/intl-regionless.ts
3324
3347
  var regionlessDialCodes = /* @__PURE__ */ new Set([
3325
3348
  "800",
3326
3349
  "808",
@@ -3335,6 +3358,8 @@ var hasRegionlessDialCode = (number) => {
3335
3358
  const dialCode = getNumeric(number).slice(0, 3);
3336
3359
  return number.startsWith("+") && regionlessDialCodes.has(dialCode);
3337
3360
  };
3361
+
3362
+ // src/js/format/formatting.ts
3338
3363
  var stripSeparateDialCode = (fullNumber, hasValidDialCode, separateDialCode, selectedCountryData) => {
3339
3364
  if (!separateDialCode || !hasValidDialCode) {
3340
3365
  return fullNumber;
@@ -3352,6 +3377,8 @@ var formatNumberAsYouType = (fullNumber, telInputValue, utils, selectedCountryDa
3352
3377
  }
3353
3378
  return result;
3354
3379
  };
3380
+
3381
+ // src/js/format/caret.ts
3355
3382
  var computeNewCaretPosition = (relevantChars, formattedValue, prevCaretPos, isDeleteForwards) => {
3356
3383
  if (prevCaretPos === 0 && !isDeleteForwards) {
3357
3384
  return 0;
@@ -3370,6 +3397,8 @@ var computeNewCaretPosition = (relevantChars, formattedValue, prevCaretPos, isDe
3370
3397
  }
3371
3398
  return formattedValue.length;
3372
3399
  };
3400
+
3401
+ // src/js/data/nanp-regionless.ts
3373
3402
  var regionlessNanpAreaCodes = /* @__PURE__ */ new Set([
3374
3403
  "800",
3375
3404
  "822",
@@ -3397,6 +3426,8 @@ var isRegionlessNanp = (number) => {
3397
3426
  }
3398
3427
  return false;
3399
3428
  };
3429
+
3430
+ // src/js/core/numerals.ts
3400
3431
  var Numerals = class {
3401
3432
  #userNumeralSet;
3402
3433
  constructor(initialValue) {
@@ -3443,6 +3474,8 @@ var Numerals = class {
3443
3474
  return !this.#userNumeralSet || this.#userNumeralSet === "ascii";
3444
3475
  }
3445
3476
  };
3477
+
3478
+ // src/js/intlTelInput.ts
3446
3479
  var nextId = 0;
3447
3480
  var ensureUtils = (methodName) => {
3448
3481
  if (!intlTelInput.utils) {
@@ -3499,9 +3532,7 @@ var Iti = class _Iti {
3499
3532
  this.#numerals = new Numerals(input.value);
3500
3533
  this.promise = this.#createInitPromise(this.#options);
3501
3534
  this.#countries = processAllCountries(this.#options);
3502
- const { dialCodes, dialCodeMaxLength, dialCodeToIso2Map } = processDialCodes(
3503
- this.#countries
3504
- );
3535
+ const { dialCodes, dialCodeMaxLength, dialCodeToIso2Map } = processDialCodes(this.#countries);
3505
3536
  this.#dialCodes = dialCodes;
3506
3537
  this.#dialCodeMaxLength = dialCodeMaxLength;
3507
3538
  this.#dialCodeToIso2Map = dialCodeToIso2Map;
@@ -3683,6 +3714,7 @@ var Iti = class _Iti {
3683
3714
  #handleAndroidStrictReject(inputValue, rejectedInput) {
3684
3715
  const newCaretPos = this.#removeJustTypedChar(inputValue);
3685
3716
  this.#ui.telInputEl.setSelectionRange(newCaretPos, newCaretPos);
3717
+ this.#playStrictRejectAnimation();
3686
3718
  this.#dispatchEvent(EVENTS.STRICT_REJECT, {
3687
3719
  source: "key",
3688
3720
  rejectedInput,
@@ -3742,7 +3774,13 @@ var Iti = class _Iti {
3742
3774
  //* On input event: (1) Update selected country, (2) Format-as-you-type.
3743
3775
  //* Note that this fires AFTER the input is updated.
3744
3776
  #handleInputEvent = (e) => {
3745
- const { strictMode, formatAsYouType, separateDialCode, allowDropdown, countrySearch } = this.#options;
3777
+ const {
3778
+ strictMode,
3779
+ formatAsYouType,
3780
+ separateDialCode,
3781
+ allowDropdown,
3782
+ countrySearch
3783
+ } = this.#options;
3746
3784
  const detail = e?.detail;
3747
3785
  if (detail?.["isCountryChange"]) {
3748
3786
  return;
@@ -3824,6 +3862,7 @@ var Iti = class _Iti {
3824
3862
  const newCountry = this.#resolveCountryChangeFromNumber(newFullNumber);
3825
3863
  const isChangingDialCode = newCountry !== null;
3826
3864
  if (!isAllowedChar || hasExceededMaxLength && !isChangingDialCode && !isInitialPlus) {
3865
+ this.#playStrictRejectAnimation();
3827
3866
  this.#dispatchEvent(EVENTS.STRICT_REJECT, {
3828
3867
  source: "key",
3829
3868
  rejectedInput: e.key,
@@ -3866,6 +3905,7 @@ var Iti = class _Iti {
3866
3905
  coreNumber = intlTelInput.utils.getCoreNumber(newValue, iso2);
3867
3906
  }
3868
3907
  if (!coreNumber) {
3908
+ this.#playStrictRejectAnimation();
3869
3909
  this.#dispatchEvent(EVENTS.STRICT_REJECT, {
3870
3910
  source: "paste",
3871
3911
  rejectedInput: pastedRaw,
@@ -3879,6 +3919,7 @@ var Iti = class _Iti {
3879
3919
  newValue = newValue.slice(0, newValue.length - trimLength);
3880
3920
  rejectReason = "max-length";
3881
3921
  } else {
3922
+ this.#playStrictRejectAnimation();
3882
3923
  this.#dispatchEvent(EVENTS.STRICT_REJECT, {
3883
3924
  source: "paste",
3884
3925
  rejectedInput: pastedRaw,
@@ -3893,6 +3934,9 @@ var Iti = class _Iti {
3893
3934
  input.setSelectionRange(caretPos, caretPos);
3894
3935
  input.dispatchEvent(new InputEvent("input", { bubbles: true }));
3895
3936
  if (rejectReason) {
3937
+ if (pasted.length > 0 && sanitised.length === 0) {
3938
+ this.#playStrictRejectAnimation();
3939
+ }
3896
3940
  this.#dispatchEvent(EVENTS.STRICT_REJECT, {
3897
3941
  source: "paste",
3898
3942
  rejectedInput: pastedRaw,
@@ -3905,6 +3949,21 @@ var Iti = class _Iti {
3905
3949
  const max = Number(this.#ui.telInputEl.getAttribute("maxlength"));
3906
3950
  return max && number.length > max ? number.substring(0, max) : number;
3907
3951
  }
3952
+ //* Play the strict-reject animation (shake, or background-colour flash under prefers-reduced-motion) on the wrapper.
3953
+ //* Called when strictMode rejects the whole input (keystroke, or whole paste).
3954
+ //* Uses the wrapper (not the input) so any separateDialCode / country button move together with the input.
3955
+ #playStrictRejectAnimation() {
3956
+ if (!this.#options.strictRejectAnimation) {
3957
+ return;
3958
+ }
3959
+ const wrapperEl = this.#ui.telInputEl.parentElement;
3960
+ if (!wrapperEl) {
3961
+ return;
3962
+ }
3963
+ wrapperEl.classList.remove("iti__strict-reject-animation");
3964
+ void wrapperEl.offsetWidth;
3965
+ wrapperEl.classList.add("iti__strict-reject-animation");
3966
+ }
3908
3967
  //* Trigger a custom event on the input (typed via ItiEventMap).
3909
3968
  #dispatchEvent(name, detailProps = {}) {
3910
3969
  const e = new CustomEvent(name, {
@@ -4541,7 +4600,7 @@ var intlTelInput = Object.assign(
4541
4600
  attachUtils,
4542
4601
  startedLoadingUtils: false,
4543
4602
  startedLoadingAutoCountry: false,
4544
- version: "27.2.0"
4603
+ version: "27.3.0"
4545
4604
  }
4546
4605
  );
4547
4606
  var intlTelInput_default = intlTelInput;
@@ -4591,6 +4650,7 @@ var IntlTelInput = class _IntlTelInput {
4591
4650
  separateDialCode;
4592
4651
  showFlags;
4593
4652
  strictMode;
4653
+ strictRejectAnimation;
4594
4654
  useFullscreenPopup;
4595
4655
  numberChange = new EventEmitter();
4596
4656
  countryChange = new EventEmitter();
@@ -4607,6 +4667,8 @@ var IntlTelInput = class _IntlTelInput {
4607
4667
  click = new EventEmitter();
4608
4668
  iti;
4609
4669
  appliedInputAttrKeys = /* @__PURE__ */ new Set();
4670
+ // Classes the plugin adds directly to the input (e.g. iti__tel-input)
4671
+ pluginInputClasses = "";
4610
4672
  lastEmittedNumber;
4611
4673
  lastEmittedCountry;
4612
4674
  lastEmittedValidity;
@@ -4631,6 +4693,7 @@ var IntlTelInput = class _IntlTelInput {
4631
4693
  };
4632
4694
  ngAfterViewInit() {
4633
4695
  this.iti = intlTelInput_default(this.inputRef.nativeElement, this.buildInitOptions());
4696
+ this.pluginInputClasses = this.inputRef.nativeElement.className;
4634
4697
  this.inputRef.nativeElement.addEventListener("open:countrydropdown", this.handleOpenDropdown);
4635
4698
  this.inputRef.nativeElement.addEventListener("close:countrydropdown", this.handleCloseDropdown);
4636
4699
  this.inputRef.nativeElement.addEventListener("strict:reject", this.handleStrictReject);
@@ -4689,6 +4752,7 @@ var IntlTelInput = class _IntlTelInput {
4689
4752
  separateDialCode: this.separateDialCode,
4690
4753
  showFlags: this.showFlags,
4691
4754
  strictMode: this.strictMode,
4755
+ strictRejectAnimation: this.strictRejectAnimation,
4692
4756
  useFullscreenPopup: this.useFullscreenPopup
4693
4757
  };
4694
4758
  return Object.fromEntries(Object.entries(options).filter(([, value]) => value !== void 0));
@@ -4794,7 +4858,8 @@ var IntlTelInput = class _IntlTelInput {
4794
4858
  warnInputAttr(key);
4795
4859
  } else {
4796
4860
  currentKeys.add(key);
4797
- this.inputRef.nativeElement.setAttribute(key, value);
4861
+ const next = key === "class" && this.pluginInputClasses ? `${this.pluginInputClasses} ${value}` : value;
4862
+ this.inputRef.nativeElement.setAttribute(key, next);
4798
4863
  }
4799
4864
  });
4800
4865
  this.appliedInputAttrKeys.forEach((key) => {
@@ -4855,7 +4920,7 @@ var IntlTelInput = class _IntlTelInput {
4855
4920
  let _t;
4856
4921
  i0.\u0275\u0275queryRefresh(_t = i0.\u0275\u0275loadQuery()) && (ctx.inputRef = _t.first);
4857
4922
  }
4858
- }, inputs: { initialValue: "initialValue", usePreciseValidation: "usePreciseValidation", inputAttributes: "inputAttributes", disabled: "disabled", readonly: "readonly", allowDropdown: "allowDropdown", allowedNumberTypes: "allowedNumberTypes", allowNumberExtensions: "allowNumberExtensions", allowPhonewords: "allowPhonewords", autoPlaceholder: "autoPlaceholder", containerClass: "containerClass", countryNameLocale: "countryNameLocale", countryOrder: "countryOrder", countrySearch: "countrySearch", customPlaceholder: "customPlaceholder", dropdownAlwaysOpen: "dropdownAlwaysOpen", dropdownContainer: "dropdownContainer", excludeCountries: "excludeCountries", fixDropdownWidth: "fixDropdownWidth", formatAsYouType: "formatAsYouType", formatOnDisplay: "formatOnDisplay", geoIpLookup: "geoIpLookup", hiddenInput: "hiddenInput", i18n: "i18n", initialCountry: "initialCountry", loadUtils: "loadUtils", nationalMode: "nationalMode", onlyCountries: "onlyCountries", placeholderNumberType: "placeholderNumberType", searchInputClass: "searchInputClass", separateDialCode: "separateDialCode", showFlags: "showFlags", strictMode: "strictMode", useFullscreenPopup: "useFullscreenPopup" }, outputs: { numberChange: "numberChange", countryChange: "countryChange", validityChange: "validityChange", errorCodeChange: "errorCodeChange", openCountryDropdown: "openCountryDropdown", closeCountryDropdown: "closeCountryDropdown", strictReject: "strictReject", blur: "blur", focus: "focus", keydown: "keydown", keyup: "keyup", paste: "paste", click: "click" }, features: [i0.\u0275\u0275ProvidersFeature([
4923
+ }, inputs: { initialValue: "initialValue", usePreciseValidation: "usePreciseValidation", inputAttributes: "inputAttributes", disabled: "disabled", readonly: "readonly", allowDropdown: "allowDropdown", allowedNumberTypes: "allowedNumberTypes", allowNumberExtensions: "allowNumberExtensions", allowPhonewords: "allowPhonewords", autoPlaceholder: "autoPlaceholder", containerClass: "containerClass", countryNameLocale: "countryNameLocale", countryOrder: "countryOrder", countrySearch: "countrySearch", customPlaceholder: "customPlaceholder", dropdownAlwaysOpen: "dropdownAlwaysOpen", dropdownContainer: "dropdownContainer", excludeCountries: "excludeCountries", fixDropdownWidth: "fixDropdownWidth", formatAsYouType: "formatAsYouType", formatOnDisplay: "formatOnDisplay", geoIpLookup: "geoIpLookup", hiddenInput: "hiddenInput", i18n: "i18n", initialCountry: "initialCountry", loadUtils: "loadUtils", nationalMode: "nationalMode", onlyCountries: "onlyCountries", placeholderNumberType: "placeholderNumberType", searchInputClass: "searchInputClass", separateDialCode: "separateDialCode", showFlags: "showFlags", strictMode: "strictMode", strictRejectAnimation: "strictRejectAnimation", useFullscreenPopup: "useFullscreenPopup" }, outputs: { numberChange: "numberChange", countryChange: "countryChange", validityChange: "validityChange", errorCodeChange: "errorCodeChange", openCountryDropdown: "openCountryDropdown", closeCountryDropdown: "closeCountryDropdown", strictReject: "strictReject", blur: "blur", focus: "focus", keydown: "keydown", keyup: "keyup", paste: "paste", click: "click" }, features: [i0.\u0275\u0275ProvidersFeature([
4859
4924
  {
4860
4925
  provide: NG_VALUE_ACCESSOR,
4861
4926
  useExisting: forwardRef(() => _IntlTelInput),
@@ -4989,6 +5054,8 @@ var IntlTelInput = class _IntlTelInput {
4989
5054
  type: Input
4990
5055
  }], strictMode: [{
4991
5056
  type: Input
5057
+ }], strictRejectAnimation: [{
5058
+ type: Input
4992
5059
  }], useFullscreenPopup: [{
4993
5060
  type: Input
4994
5061
  }], numberChange: [{