@intl-tel-input/angular 29.1.3 → 29.2.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.
@@ -21,6 +21,7 @@ declare class IntlTelInput implements AfterViewInit, OnDestroy, OnChanges, Contr
21
21
  allowedNumberTypes?: AllOptions["allowedNumberTypes"];
22
22
  allowNumberExtensions?: AllOptions["allowNumberExtensions"];
23
23
  allowPhonewords?: AllOptions["allowPhonewords"];
24
+ classNames?: AllOptions["classNames"];
24
25
  containerClass?: AllOptions["containerClass"];
25
26
  countryNameLocale?: AllOptions["countryNameLocale"];
26
27
  countryNameOverrides?: AllOptions["countryNameOverrides"];
@@ -68,6 +69,7 @@ declare class IntlTelInput implements AfterViewInit, OnDestroy, OnChanges, Contr
68
69
  private lastEmittedErrorCode?;
69
70
  private pendingWriteValue?;
70
71
  private pendingUpdate;
72
+ private isWritingModelValue;
71
73
  private onChange;
72
74
  private onTouched;
73
75
  private onValidatorChange;
@@ -77,6 +79,7 @@ declare class IntlTelInput implements AfterViewInit, OnDestroy, OnChanges, Contr
77
79
  ngAfterViewInit(): void;
78
80
  private buildInitOptions;
79
81
  ngOnChanges(changes: SimpleChanges): void;
82
+ private setNumberFromModel;
80
83
  handleInput: () => void;
81
84
  handleBlur(event: FocusEvent): void;
82
85
  handleFocus(event: FocusEvent): void;
@@ -104,6 +107,6 @@ declare class IntlTelInput implements AfterViewInit, OnDestroy, OnChanges, Contr
104
107
  validate(_control: AbstractControl): ValidationErrors | null;
105
108
  registerOnValidatorChange(fn: () => void): void;
106
109
  static ɵfac: i0.ɵɵFactoryDeclaration<IntlTelInput, never>;
107
- 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; }; "countrySelectorMode": { "alias": "countrySelectorMode"; "required": false; }; "allowedNumberTypes": { "alias": "allowedNumberTypes"; "required": false; }; "allowNumberExtensions": { "alias": "allowNumberExtensions"; "required": false; }; "allowPhonewords": { "alias": "allowPhonewords"; "required": false; }; "containerClass": { "alias": "containerClass"; "required": false; }; "countryNameLocale": { "alias": "countryNameLocale"; "required": false; }; "countryNameOverrides": { "alias": "countryNameOverrides"; "required": false; }; "countryOrder": { "alias": "countryOrder"; "required": false; }; "countrySearch": { "alias": "countrySearch"; "required": false; }; "customPlaceholder": { "alias": "customPlaceholder"; "required": false; }; "dropdownAlwaysOpen": { "alias": "dropdownAlwaysOpen"; "required": false; }; "dropdownParent": { "alias": "dropdownParent"; "required": false; }; "excludeCountries": { "alias": "excludeCountries"; "required": false; }; "matchDropdownWidth": { "alias": "matchDropdownWidth"; "required": false; }; "formatAsYouType": { "alias": "formatAsYouType"; "required": false; }; "hiddenInputs": { "alias": "hiddenInputs"; "required": false; }; "uiTranslations": { "alias": "uiTranslations"; "required": false; }; "initialCountry": { "alias": "initialCountry"; "required": false; }; "initialCountryLookup": { "alias": "initialCountryLookup"; "required": false; }; "loadUtils": { "alias": "loadUtils"; "required": false; }; "numberDisplayFormat": { "alias": "numberDisplayFormat"; "required": false; }; "onlyCountries": { "alias": "onlyCountries"; "required": false; }; "placeholderNumberPolicy": { "alias": "placeholderNumberPolicy"; "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; }; }, { "numberChange": "numberChange"; "countryChange": "countryChange"; "validityChange": "validityChange"; "errorCodeChange": "errorCodeChange"; "openCountrySelector": "openCountrySelector"; "closeCountrySelector": "closeCountrySelector"; "strictReject": "strictReject"; "blur": "blur"; "focus": "focus"; "keydown": "keydown"; "keyup": "keyup"; "paste": "paste"; "click": "click"; }, never, never, true, never>;
110
+ 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; }; "countrySelectorMode": { "alias": "countrySelectorMode"; "required": false; }; "allowedNumberTypes": { "alias": "allowedNumberTypes"; "required": false; }; "allowNumberExtensions": { "alias": "allowNumberExtensions"; "required": false; }; "allowPhonewords": { "alias": "allowPhonewords"; "required": false; }; "classNames": { "alias": "classNames"; "required": false; }; "containerClass": { "alias": "containerClass"; "required": false; }; "countryNameLocale": { "alias": "countryNameLocale"; "required": false; }; "countryNameOverrides": { "alias": "countryNameOverrides"; "required": false; }; "countryOrder": { "alias": "countryOrder"; "required": false; }; "countrySearch": { "alias": "countrySearch"; "required": false; }; "customPlaceholder": { "alias": "customPlaceholder"; "required": false; }; "dropdownAlwaysOpen": { "alias": "dropdownAlwaysOpen"; "required": false; }; "dropdownParent": { "alias": "dropdownParent"; "required": false; }; "excludeCountries": { "alias": "excludeCountries"; "required": false; }; "matchDropdownWidth": { "alias": "matchDropdownWidth"; "required": false; }; "formatAsYouType": { "alias": "formatAsYouType"; "required": false; }; "hiddenInputs": { "alias": "hiddenInputs"; "required": false; }; "uiTranslations": { "alias": "uiTranslations"; "required": false; }; "initialCountry": { "alias": "initialCountry"; "required": false; }; "initialCountryLookup": { "alias": "initialCountryLookup"; "required": false; }; "loadUtils": { "alias": "loadUtils"; "required": false; }; "numberDisplayFormat": { "alias": "numberDisplayFormat"; "required": false; }; "onlyCountries": { "alias": "onlyCountries"; "required": false; }; "placeholderNumberPolicy": { "alias": "placeholderNumberPolicy"; "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; }; }, { "numberChange": "numberChange"; "countryChange": "countryChange"; "validityChange": "validityChange"; "errorCodeChange": "errorCodeChange"; "openCountrySelector": "openCountrySelector"; "closeCountrySelector": "closeCountrySelector"; "strictReject": "strictReject"; "blur": "blur"; "focus": "focus"; "keydown": "keydown"; "keyup": "keyup"; "paste": "paste"; "click": "click"; }, never, never, true, never>;
108
111
  }
109
112
  export default IntlTelInput;
@@ -1761,6 +1761,29 @@ var EVENTS = {
1761
1761
  // used for synthetic input trigger
1762
1762
  STRICT_REJECT: "strict:reject"
1763
1763
  };
1764
+ var ITI_SLOTS = [
1765
+ "container",
1766
+ "input",
1767
+ "countryContainer",
1768
+ "selectedCountry",
1769
+ "selectedCountryPrimary",
1770
+ "selectedFlag",
1771
+ "arrow",
1772
+ "selectedDialCode",
1773
+ "countrySelector",
1774
+ "countrySelectorContainer",
1775
+ "searchWrapper",
1776
+ "searchIcon",
1777
+ "searchInput",
1778
+ "searchClear",
1779
+ "countryList",
1780
+ "countryListItem",
1781
+ "countryListItemFlag",
1782
+ "countryName",
1783
+ "dialCode",
1784
+ "countryCheck",
1785
+ "noResults"
1786
+ ];
1764
1787
  var CLASSES = {
1765
1788
  HIDE: "iti__hide",
1766
1789
  V_HIDE: "iti__v-hide",
@@ -1937,6 +1960,8 @@ var defaults = {
1937
1960
  allowNumberExtensions: false,
1938
1961
  // Allow alphanumeric "phonewords" (e.g. +1 800 FLOWERS) as valid numbers
1939
1962
  allowPhonewords: false,
1963
+ //* Add custom classes to the elements we generate, keyed by slot name e.g. { selectedCountry: "rounded-l-lg" }.
1964
+ classNames: {},
1940
1965
  //* Add a custom class to the (injected) container element.
1941
1966
  containerClass: "",
1942
1967
  //* Locale for localising country names via Intl.DisplayNames.
@@ -1999,6 +2024,7 @@ var isElLike = (val) => {
1999
2024
  return v.nodeType === 1 && typeof v.tagName === "string" && typeof v.appendChild === "function";
2000
2025
  };
2001
2026
  var placeholderPolicySet = new Set(Object.values(PLACEHOLDER_POLICY));
2027
+ var slotSet = new Set(ITI_SLOTS);
2002
2028
  var warn = (message) => {
2003
2029
  console.warn(`[intl-tel-input] ${message}`);
2004
2030
  };
@@ -2099,6 +2125,26 @@ var validateOptions = (customOptions) => {
2099
2125
  }
2100
2126
  validatedOptions[key] = value;
2101
2127
  break;
2128
+ case "classNames": {
2129
+ if (!isPlainObject(value)) {
2130
+ warnOption("classNames", "an object", value);
2131
+ break;
2132
+ }
2133
+ const validSlots = {};
2134
+ for (const [slot, slotValue] of Object.entries(value)) {
2135
+ if (!slotSet.has(slot)) {
2136
+ warn(
2137
+ `Unknown slot '${slot}' in 'classNames'. Valid slots: ${ITI_SLOTS.join(", ")}. Skipping.`
2138
+ );
2139
+ } else if (typeof slotValue !== "string") {
2140
+ warnOption(`classNames.${slot}`, "a string", slotValue);
2141
+ } else {
2142
+ validSlots[slot] = slotValue.trim().replace(/\s+/g, " ");
2143
+ }
2144
+ }
2145
+ validatedOptions[key] = validSlots;
2146
+ break;
2147
+ }
2102
2148
  case "countryOrder": {
2103
2149
  if (value === null) {
2104
2150
  validatedOptions[key] = value;
@@ -2511,11 +2557,18 @@ var UI = class {
2511
2557
  );
2512
2558
  }
2513
2559
  }
2560
+ //* Append any consumer-supplied classes (via the classNames option) for the given slot to our own classes for that element.
2561
+ #withSlotClass(slot, ourClasses) {
2562
+ const custom = this.#options.classNames[slot];
2563
+ return custom ? `${ourClasses} ${custom}` : ourClasses;
2564
+ }
2514
2565
  //* Generate all of the markup for the core library: the selected country overlay, and the country selector.
2515
2566
  buildMarkup(countries, searchTokens) {
2516
2567
  this.#countries = countries;
2517
2568
  this.#searchTokens = searchTokens;
2518
- this.telInputEl.classList.add("iti__tel-input");
2569
+ this.telInputEl.classList.add(
2570
+ ...this.#withSlotClass("input", "iti__tel-input").split(" ")
2571
+ );
2519
2572
  if (!this.telInputEl.hasAttribute("type")) {
2520
2573
  this.telInputEl.setAttribute("type", "tel");
2521
2574
  }
@@ -2543,7 +2596,9 @@ var UI = class {
2543
2596
  "iti--inline-country-selector": countrySelectorMode !== COUNTRY_SELECTOR_MODE.FULLSCREEN,
2544
2597
  [containerClass]: Boolean(containerClass)
2545
2598
  });
2546
- const wrapper = createEl("div", { class: parentClasses });
2599
+ const wrapper = createEl("div", {
2600
+ class: this.#withSlotClass("container", parentClasses)
2601
+ });
2547
2602
  if (this.#isRTL) {
2548
2603
  wrapper.setAttribute("dir", "ltr");
2549
2604
  }
@@ -2559,7 +2614,12 @@ var UI = class {
2559
2614
  this.#countryContainerEl = createEl(
2560
2615
  "div",
2561
2616
  // visibly hidden until we measure its width to set the input padding correctly
2562
- { class: `iti__country-container ${CLASSES.V_HIDE}` },
2617
+ {
2618
+ class: this.#withSlotClass(
2619
+ "countryContainer",
2620
+ `iti__country-container ${CLASSES.V_HIDE}`
2621
+ )
2622
+ },
2563
2623
  wrapper
2564
2624
  );
2565
2625
  if (enableCountrySelector) {
@@ -2567,7 +2627,7 @@ var UI = class {
2567
2627
  "button",
2568
2628
  {
2569
2629
  type: "button",
2570
- class: "iti__selected-country",
2630
+ class: this.#withSlotClass("selectedCountry", "iti__selected-country"),
2571
2631
  [ARIA.EXPANDED]: "false",
2572
2632
  [ARIA.LABEL]: this.#options.uiTranslations.noCountrySelected,
2573
2633
  [ARIA.HASPOPUP]: "dialog",
@@ -2581,31 +2641,44 @@ var UI = class {
2581
2641
  } else {
2582
2642
  this.#selectedCountryEl = createEl(
2583
2643
  "div",
2584
- { class: "iti__selected-country" },
2644
+ { class: this.#withSlotClass("selectedCountry", "iti__selected-country") },
2585
2645
  this.#countryContainerEl
2586
2646
  );
2587
2647
  }
2588
2648
  const selectedCountryPrimary = createEl(
2589
2649
  "div",
2590
- { class: "iti__selected-country-primary" },
2650
+ {
2651
+ class: this.#withSlotClass(
2652
+ "selectedCountryPrimary",
2653
+ "iti__selected-country-primary"
2654
+ )
2655
+ },
2591
2656
  this.#selectedCountryEl
2592
2657
  );
2593
2658
  this.#selectedFlagEl = createEl(
2594
2659
  "div",
2595
- { class: CLASSES.FLAG },
2660
+ { class: this.#withSlotClass("selectedFlag", CLASSES.FLAG) },
2596
2661
  selectedCountryPrimary
2597
2662
  );
2598
2663
  if (enableCountrySelector) {
2599
2664
  this.#arrowEl = createEl(
2600
2665
  "div",
2601
- { class: "iti__arrow", [ARIA.HIDDEN]: "true" },
2666
+ {
2667
+ class: this.#withSlotClass("arrow", "iti__arrow"),
2668
+ [ARIA.HIDDEN]: "true"
2669
+ },
2602
2670
  selectedCountryPrimary
2603
2671
  );
2604
2672
  }
2605
2673
  if (separateDialCode) {
2606
2674
  this.#selectedDialCodeEl = createEl(
2607
2675
  "div",
2608
- { class: "iti__selected-dial-code" },
2676
+ {
2677
+ class: this.#withSlotClass(
2678
+ "selectedDialCode",
2679
+ "iti__selected-dial-code"
2680
+ )
2681
+ },
2609
2682
  this.#selectedCountryEl
2610
2683
  );
2611
2684
  }
@@ -2636,7 +2709,10 @@ var UI = class {
2636
2709
  const extraClasses = matchDropdownWidth ? "" : "iti--flexible-dropdown-width";
2637
2710
  this.#countrySelectorEl = createEl("div", {
2638
2711
  id: `iti-${this.#id}__country-selector`,
2639
- class: `iti__country-selector ${CLASSES.HIDE} ${extraClasses}`,
2712
+ class: this.#withSlotClass(
2713
+ "countrySelector",
2714
+ `iti__country-selector ${CLASSES.HIDE} ${extraClasses}`
2715
+ ),
2640
2716
  role: "dialog",
2641
2717
  [ARIA.MODAL]: "true"
2642
2718
  });
@@ -2649,7 +2725,7 @@ var UI = class {
2649
2725
  this.#countryListEl = createEl(
2650
2726
  "ul",
2651
2727
  {
2652
- class: "iti__country-list",
2728
+ class: this.#withSlotClass("countryList", "iti__country-list"),
2653
2729
  id: `iti-${this.#id}__country-listbox`,
2654
2730
  role: "listbox",
2655
2731
  [ARIA.LABEL]: uiTranslations.countryListAriaLabel
@@ -2668,7 +2744,9 @@ var UI = class {
2668
2744
  "iti--inline-country-selector": !isFullscreen,
2669
2745
  [containerClass]: Boolean(containerClass)
2670
2746
  });
2671
- this.#detachedCountrySelectorEl = createEl("div", { class: wrapperClasses });
2747
+ this.#detachedCountrySelectorEl = createEl("div", {
2748
+ class: this.#withSlotClass("countrySelectorContainer", wrapperClasses)
2749
+ });
2672
2750
  this.#detachedCountrySelectorEl.appendChild(this.#countrySelectorEl);
2673
2751
  } else {
2674
2752
  this.#countryContainerEl.appendChild(this.#countrySelectorEl);
@@ -2689,13 +2767,13 @@ var UI = class {
2689
2767
  const { uiTranslations, searchInputClass } = this.#options;
2690
2768
  const searchWrapper = createEl(
2691
2769
  "div",
2692
- { class: "iti__search-input-wrapper" },
2770
+ { class: this.#withSlotClass("searchWrapper", "iti__search-input-wrapper") },
2693
2771
  this.#countrySelectorEl
2694
2772
  );
2695
2773
  this.#searchIconEl = createEl(
2696
2774
  "span",
2697
2775
  {
2698
- class: "iti__search-icon",
2776
+ class: this.#withSlotClass("searchIcon", "iti__search-icon"),
2699
2777
  [ARIA.HIDDEN]: "true"
2700
2778
  },
2701
2779
  searchWrapper
@@ -2707,7 +2785,10 @@ var UI = class {
2707
2785
  id: `iti-${this.#id}__search-input`,
2708
2786
  // Chrome says inputs need either a name or an id
2709
2787
  type: "search",
2710
- class: `iti__search-input ${searchInputClass}`,
2788
+ class: this.#withSlotClass(
2789
+ "searchInput",
2790
+ `iti__search-input ${searchInputClass}`
2791
+ ),
2711
2792
  placeholder: uiTranslations.searchPlaceholder,
2712
2793
  // role=combobox + aria-autocomplete=list + aria-activedescendant allows maintaining focus on the search input while allowing users to navigate search results with up/down keyboard keys
2713
2794
  role: "combobox",
@@ -2723,7 +2804,10 @@ var UI = class {
2723
2804
  "button",
2724
2805
  {
2725
2806
  type: "button",
2726
- class: `iti__search-clear ${CLASSES.HIDE}`,
2807
+ class: this.#withSlotClass(
2808
+ "searchClear",
2809
+ `iti__search-clear ${CLASSES.HIDE}`
2810
+ ),
2727
2811
  [ARIA.LABEL]: uiTranslations.clearSearchAriaLabel,
2728
2812
  tabindex: "-1"
2729
2813
  },
@@ -2738,7 +2822,7 @@ var UI = class {
2738
2822
  this.#noResultsMessageEl = createEl(
2739
2823
  "div",
2740
2824
  {
2741
- class: `iti__no-results ${CLASSES.HIDE}`,
2825
+ class: this.#withSlotClass("noResults", `iti__no-results ${CLASSES.HIDE}`),
2742
2826
  [ARIA.HIDDEN]: "true"
2743
2827
  // all a11y messaging happens in this.#searchResultsLiveRegionEl
2744
2828
  },
@@ -2792,11 +2876,9 @@ var UI = class {
2792
2876
  //* For each country: add a country list item <li> to the countryList <ul> container.
2793
2877
  #appendListItems() {
2794
2878
  const frag = document.createDocumentFragment();
2879
+ const liClass = this.#withSlotClass("countryListItem", CLASSES.COUNTRY_ITEM);
2795
2880
  for (let i = 0; i < this.#countries.length; i++) {
2796
2881
  const c = this.#countries[i];
2797
- const liClass = buildClassNames({
2798
- [CLASSES.COUNTRY_ITEM]: true
2799
- });
2800
2882
  const listItem = createEl("li", {
2801
2883
  id: `iti-${this.#id}__item-${c.iso2}`,
2802
2884
  class: liClass,
@@ -2808,11 +2890,28 @@ var UI = class {
2808
2890
  listItem.dataset[DATA_KEYS.ISO2] = c.iso2;
2809
2891
  this.#listItemByIso2.set(c.iso2, listItem);
2810
2892
  if (this.#options.showFlags) {
2811
- createEl("div", { class: `${CLASSES.FLAG} iti__${c.iso2}` }, listItem);
2893
+ createEl(
2894
+ "div",
2895
+ {
2896
+ class: this.#withSlotClass(
2897
+ "countryListItemFlag",
2898
+ `${CLASSES.FLAG} iti__${c.iso2}`
2899
+ )
2900
+ },
2901
+ listItem
2902
+ );
2812
2903
  }
2813
- const nameEl = createEl("span", { class: "iti__country-name" }, listItem);
2904
+ const nameEl = createEl(
2905
+ "span",
2906
+ { class: this.#withSlotClass("countryName", "iti__country-name") },
2907
+ listItem
2908
+ );
2814
2909
  nameEl.textContent = `${c.name} `;
2815
- const dialEl = createEl("span", { class: "iti__dial-code" }, nameEl);
2910
+ const dialEl = createEl(
2911
+ "span",
2912
+ { class: this.#withSlotClass("dialCode", "iti__dial-code") },
2913
+ nameEl
2914
+ );
2816
2915
  if (this.#isRTL) {
2817
2916
  dialEl.setAttribute("dir", "ltr");
2818
2917
  }
@@ -3259,7 +3358,10 @@ var UI = class {
3259
3358
  newListItem.setAttribute(ARIA.SELECTED, "true");
3260
3359
  const checkIcon = createEl(
3261
3360
  "span",
3262
- { class: "iti__country-check", [ARIA.HIDDEN]: "true" },
3361
+ {
3362
+ class: this.#withSlotClass("countryCheck", "iti__country-check"),
3363
+ [ARIA.HIDDEN]: "true"
3364
+ },
3263
3365
  newListItem
3264
3366
  );
3265
3367
  checkIcon.appendChild(buildCheckIcon());
@@ -3446,7 +3548,10 @@ var UI = class {
3446
3548
  this.#updateSelectedListItem(iso2);
3447
3549
  }
3448
3550
  if (this.#selectedCountryEl) {
3449
- const flagClass = iso2 && showFlags ? `${CLASSES.FLAG} iti__${iso2}` : `${CLASSES.FLAG} ${CLASSES.GLOBE}`;
3551
+ const flagClass = this.#withSlotClass(
3552
+ "selectedFlag",
3553
+ iso2 && showFlags ? `${CLASSES.FLAG} iti__${iso2}` : `${CLASSES.FLAG} ${CLASSES.GLOBE}`
3554
+ );
3450
3555
  let ariaLabel, title;
3451
3556
  let flagContent = null;
3452
3557
  if (iso2) {
@@ -4843,7 +4948,7 @@ var intlTelInput = Object.assign(
4843
4948
  attachUtils,
4844
4949
  startedLoadingUtils: false,
4845
4950
  startedLoadingAutoCountry: false,
4846
- version: "29.1.3",
4951
+ version: "29.2.0",
4847
4952
  NUMBER_FORMAT,
4848
4953
  NUMBER_TYPE,
4849
4954
  VALIDATION_ERROR,
@@ -4874,6 +4979,7 @@ var IntlTelInput = class _IntlTelInput {
4874
4979
  allowedNumberTypes;
4875
4980
  allowNumberExtensions;
4876
4981
  allowPhonewords;
4982
+ classNames;
4877
4983
  containerClass;
4878
4984
  countryNameLocale;
4879
4985
  countryNameOverrides;
@@ -4924,6 +5030,10 @@ var IntlTelInput = class _IntlTelInput {
4924
5030
  pendingWriteValue;
4925
5031
  // if an input event fires before utils has loaded, we defer the update until the promise resolves
4926
5032
  pendingUpdate = false;
5033
+ //* setNumber dispatches a synthetic input event, which handleInput would otherwise treat as a
5034
+ //* user edit and report via onChange - and Angular marks a control dirty on any onChange call.
5035
+ //* Set while we write a value that came FROM the form model, so we can skip that callback.
5036
+ isWritingModelValue = false;
4927
5037
  // eslint-disable-next-line class-methods-use-this
4928
5038
  onChange = () => {
4929
5039
  };
@@ -4939,8 +5049,9 @@ var IntlTelInput = class _IntlTelInput {
4939
5049
  this.strictReject.emit(e.detail);
4940
5050
  };
4941
5051
  ngAfterViewInit() {
5052
+ const classesBeforeInit = new Set(this.inputRef.nativeElement.classList);
4942
5053
  this.iti = intlTelInput_default(this.inputRef.nativeElement, this.buildInitOptions());
4943
- this.libraryInputClasses = this.inputRef.nativeElement.className;
5054
+ this.libraryInputClasses = Array.from(this.inputRef.nativeElement.classList).filter((className) => !classesBeforeInit.has(className)).join(" ");
4944
5055
  this.inputRef.nativeElement.addEventListener("input", this.handleInput);
4945
5056
  this.inputRef.nativeElement.addEventListener("open:countryselector", this.handleOpenCountrySelector);
4946
5057
  this.inputRef.nativeElement.addEventListener("close:countryselector", this.handleCloseCountrySelector);
@@ -4957,10 +5068,10 @@ var IntlTelInput = class _IntlTelInput {
4957
5068
  return;
4958
5069
  }
4959
5070
  if (this.pendingWriteValue !== void 0) {
4960
- this.iti.setNumber(this.pendingWriteValue);
5071
+ this.setNumberFromModel(this.pendingWriteValue);
4961
5072
  this.pendingWriteValue = void 0;
4962
5073
  } else if (this.initialValue) {
4963
- this.iti.setNumber(this.initialValue);
5074
+ this.setNumberFromModel(this.initialValue);
4964
5075
  }
4965
5076
  if (this.pendingUpdate) {
4966
5077
  this.pendingUpdate = false;
@@ -4976,6 +5087,7 @@ var IntlTelInput = class _IntlTelInput {
4976
5087
  allowedNumberTypes: this.allowedNumberTypes,
4977
5088
  allowNumberExtensions: this.allowNumberExtensions,
4978
5089
  allowPhonewords: this.allowPhonewords,
5090
+ classNames: this.classNames,
4979
5091
  containerClass: this.containerClass,
4980
5092
  countryNameLocale: this.countryNameLocale,
4981
5093
  countryNameOverrides: this.countryNameOverrides,
@@ -5015,6 +5127,16 @@ var IntlTelInput = class _IntlTelInput {
5015
5127
  this.applyInputAttrs();
5016
5128
  }
5017
5129
  }
5130
+ //* Write a value that came from the form model (writeValue/initialValue), without reporting it
5131
+ //* back to the model as a user change.
5132
+ setNumberFromModel(value) {
5133
+ this.isWritingModelValue = true;
5134
+ try {
5135
+ this.iti?.setNumber(value);
5136
+ } finally {
5137
+ this.isWritingModelValue = false;
5138
+ }
5139
+ }
5018
5140
  handleInput = () => {
5019
5141
  if (!this.iti) {
5020
5142
  return;
@@ -5029,7 +5151,9 @@ var IntlTelInput = class _IntlTelInput {
5029
5151
  if (num !== this.lastEmittedNumber) {
5030
5152
  this.lastEmittedNumber = num;
5031
5153
  this.numberChange.emit(num);
5032
- this.onChange(num);
5154
+ if (!this.isWritingModelValue) {
5155
+ this.onChange(num);
5156
+ }
5033
5157
  hasChanged = true;
5034
5158
  }
5035
5159
  if (countryIso !== this.lastEmittedCountry) {
@@ -5123,7 +5247,7 @@ var IntlTelInput = class _IntlTelInput {
5123
5247
  if (this.iti) {
5124
5248
  this.iti.promise.then(() => {
5125
5249
  if (this.iti?.isActive()) {
5126
- this.iti.setNumber(next);
5250
+ this.setNumberFromModel(next);
5127
5251
  }
5128
5252
  });
5129
5253
  } else {
@@ -5168,7 +5292,7 @@ var IntlTelInput = class _IntlTelInput {
5168
5292
  let _t;
5169
5293
  i0.\u0275\u0275queryRefresh(_t = i0.\u0275\u0275loadQuery()) && (ctx.inputRef = _t.first);
5170
5294
  }
5171
- }, inputs: { initialValue: "initialValue", usePreciseValidation: "usePreciseValidation", inputAttributes: "inputAttributes", disabled: "disabled", readonly: "readonly", countrySelectorMode: "countrySelectorMode", allowedNumberTypes: "allowedNumberTypes", allowNumberExtensions: "allowNumberExtensions", allowPhonewords: "allowPhonewords", containerClass: "containerClass", countryNameLocale: "countryNameLocale", countryNameOverrides: "countryNameOverrides", countryOrder: "countryOrder", countrySearch: "countrySearch", customPlaceholder: "customPlaceholder", dropdownAlwaysOpen: "dropdownAlwaysOpen", dropdownParent: "dropdownParent", excludeCountries: "excludeCountries", matchDropdownWidth: "matchDropdownWidth", formatAsYouType: "formatAsYouType", hiddenInputs: "hiddenInputs", uiTranslations: "uiTranslations", initialCountry: "initialCountry", initialCountryLookup: "initialCountryLookup", loadUtils: "loadUtils", numberDisplayFormat: "numberDisplayFormat", onlyCountries: "onlyCountries", placeholderNumberPolicy: "placeholderNumberPolicy", placeholderNumberType: "placeholderNumberType", searchInputClass: "searchInputClass", separateDialCode: "separateDialCode", showFlags: "showFlags", strictMode: "strictMode", strictRejectAnimation: "strictRejectAnimation" }, outputs: { numberChange: "numberChange", countryChange: "countryChange", validityChange: "validityChange", errorCodeChange: "errorCodeChange", openCountrySelector: "openCountrySelector", closeCountrySelector: "closeCountrySelector", strictReject: "strictReject", blur: "blur", focus: "focus", keydown: "keydown", keyup: "keyup", paste: "paste", click: "click" }, features: [i0.\u0275\u0275ProvidersFeature([
5295
+ }, inputs: { initialValue: "initialValue", usePreciseValidation: "usePreciseValidation", inputAttributes: "inputAttributes", disabled: "disabled", readonly: "readonly", countrySelectorMode: "countrySelectorMode", allowedNumberTypes: "allowedNumberTypes", allowNumberExtensions: "allowNumberExtensions", allowPhonewords: "allowPhonewords", classNames: "classNames", containerClass: "containerClass", countryNameLocale: "countryNameLocale", countryNameOverrides: "countryNameOverrides", countryOrder: "countryOrder", countrySearch: "countrySearch", customPlaceholder: "customPlaceholder", dropdownAlwaysOpen: "dropdownAlwaysOpen", dropdownParent: "dropdownParent", excludeCountries: "excludeCountries", matchDropdownWidth: "matchDropdownWidth", formatAsYouType: "formatAsYouType", hiddenInputs: "hiddenInputs", uiTranslations: "uiTranslations", initialCountry: "initialCountry", initialCountryLookup: "initialCountryLookup", loadUtils: "loadUtils", numberDisplayFormat: "numberDisplayFormat", onlyCountries: "onlyCountries", placeholderNumberPolicy: "placeholderNumberPolicy", placeholderNumberType: "placeholderNumberType", searchInputClass: "searchInputClass", separateDialCode: "separateDialCode", showFlags: "showFlags", strictMode: "strictMode", strictRejectAnimation: "strictRejectAnimation" }, outputs: { numberChange: "numberChange", countryChange: "countryChange", validityChange: "validityChange", errorCodeChange: "errorCodeChange", openCountrySelector: "openCountrySelector", closeCountrySelector: "closeCountrySelector", strictReject: "strictReject", blur: "blur", focus: "focus", keydown: "keydown", keyup: "keyup", paste: "paste", click: "click" }, features: [i0.\u0275\u0275ProvidersFeature([
5172
5296
  {
5173
5297
  provide: NG_VALUE_ACCESSOR,
5174
5298
  useExisting: forwardRef(() => _IntlTelInput),
@@ -5251,6 +5375,8 @@ var IntlTelInput = class _IntlTelInput {
5251
5375
  type: Input
5252
5376
  }], allowPhonewords: [{
5253
5377
  type: Input
5378
+ }], classNames: [{
5379
+ type: Input
5254
5380
  }], containerClass: [{
5255
5381
  type: Input
5256
5382
  }], countryNameLocale: [{
@@ -1761,6 +1761,29 @@ var EVENTS = {
1761
1761
  // used for synthetic input trigger
1762
1762
  STRICT_REJECT: "strict:reject"
1763
1763
  };
1764
+ var ITI_SLOTS = [
1765
+ "container",
1766
+ "input",
1767
+ "countryContainer",
1768
+ "selectedCountry",
1769
+ "selectedCountryPrimary",
1770
+ "selectedFlag",
1771
+ "arrow",
1772
+ "selectedDialCode",
1773
+ "countrySelector",
1774
+ "countrySelectorContainer",
1775
+ "searchWrapper",
1776
+ "searchIcon",
1777
+ "searchInput",
1778
+ "searchClear",
1779
+ "countryList",
1780
+ "countryListItem",
1781
+ "countryListItemFlag",
1782
+ "countryName",
1783
+ "dialCode",
1784
+ "countryCheck",
1785
+ "noResults"
1786
+ ];
1764
1787
  var CLASSES = {
1765
1788
  HIDE: "iti__hide",
1766
1789
  V_HIDE: "iti__v-hide",
@@ -1937,6 +1960,8 @@ var defaults = {
1937
1960
  allowNumberExtensions: false,
1938
1961
  // Allow alphanumeric "phonewords" (e.g. +1 800 FLOWERS) as valid numbers
1939
1962
  allowPhonewords: false,
1963
+ //* Add custom classes to the elements we generate, keyed by slot name e.g. { selectedCountry: "rounded-l-lg" }.
1964
+ classNames: {},
1940
1965
  //* Add a custom class to the (injected) container element.
1941
1966
  containerClass: "",
1942
1967
  //* Locale for localising country names via Intl.DisplayNames.
@@ -1999,6 +2024,7 @@ var isElLike = (val) => {
1999
2024
  return v.nodeType === 1 && typeof v.tagName === "string" && typeof v.appendChild === "function";
2000
2025
  };
2001
2026
  var placeholderPolicySet = new Set(Object.values(PLACEHOLDER_POLICY));
2027
+ var slotSet = new Set(ITI_SLOTS);
2002
2028
  var warn = (message) => {
2003
2029
  console.warn(`[intl-tel-input] ${message}`);
2004
2030
  };
@@ -2099,6 +2125,26 @@ var validateOptions = (customOptions) => {
2099
2125
  }
2100
2126
  validatedOptions[key] = value;
2101
2127
  break;
2128
+ case "classNames": {
2129
+ if (!isPlainObject(value)) {
2130
+ warnOption("classNames", "an object", value);
2131
+ break;
2132
+ }
2133
+ const validSlots = {};
2134
+ for (const [slot, slotValue] of Object.entries(value)) {
2135
+ if (!slotSet.has(slot)) {
2136
+ warn(
2137
+ `Unknown slot '${slot}' in 'classNames'. Valid slots: ${ITI_SLOTS.join(", ")}. Skipping.`
2138
+ );
2139
+ } else if (typeof slotValue !== "string") {
2140
+ warnOption(`classNames.${slot}`, "a string", slotValue);
2141
+ } else {
2142
+ validSlots[slot] = slotValue.trim().replace(/\s+/g, " ");
2143
+ }
2144
+ }
2145
+ validatedOptions[key] = validSlots;
2146
+ break;
2147
+ }
2102
2148
  case "countryOrder": {
2103
2149
  if (value === null) {
2104
2150
  validatedOptions[key] = value;
@@ -2511,11 +2557,18 @@ var UI = class {
2511
2557
  );
2512
2558
  }
2513
2559
  }
2560
+ //* Append any consumer-supplied classes (via the classNames option) for the given slot to our own classes for that element.
2561
+ #withSlotClass(slot, ourClasses) {
2562
+ const custom = this.#options.classNames[slot];
2563
+ return custom ? `${ourClasses} ${custom}` : ourClasses;
2564
+ }
2514
2565
  //* Generate all of the markup for the core library: the selected country overlay, and the country selector.
2515
2566
  buildMarkup(countries, searchTokens) {
2516
2567
  this.#countries = countries;
2517
2568
  this.#searchTokens = searchTokens;
2518
- this.telInputEl.classList.add("iti__tel-input");
2569
+ this.telInputEl.classList.add(
2570
+ ...this.#withSlotClass("input", "iti__tel-input").split(" ")
2571
+ );
2519
2572
  if (!this.telInputEl.hasAttribute("type")) {
2520
2573
  this.telInputEl.setAttribute("type", "tel");
2521
2574
  }
@@ -2543,7 +2596,9 @@ var UI = class {
2543
2596
  "iti--inline-country-selector": countrySelectorMode !== COUNTRY_SELECTOR_MODE.FULLSCREEN,
2544
2597
  [containerClass]: Boolean(containerClass)
2545
2598
  });
2546
- const wrapper = createEl("div", { class: parentClasses });
2599
+ const wrapper = createEl("div", {
2600
+ class: this.#withSlotClass("container", parentClasses)
2601
+ });
2547
2602
  if (this.#isRTL) {
2548
2603
  wrapper.setAttribute("dir", "ltr");
2549
2604
  }
@@ -2559,7 +2614,12 @@ var UI = class {
2559
2614
  this.#countryContainerEl = createEl(
2560
2615
  "div",
2561
2616
  // visibly hidden until we measure its width to set the input padding correctly
2562
- { class: `iti__country-container ${CLASSES.V_HIDE}` },
2617
+ {
2618
+ class: this.#withSlotClass(
2619
+ "countryContainer",
2620
+ `iti__country-container ${CLASSES.V_HIDE}`
2621
+ )
2622
+ },
2563
2623
  wrapper
2564
2624
  );
2565
2625
  if (enableCountrySelector) {
@@ -2567,7 +2627,7 @@ var UI = class {
2567
2627
  "button",
2568
2628
  {
2569
2629
  type: "button",
2570
- class: "iti__selected-country",
2630
+ class: this.#withSlotClass("selectedCountry", "iti__selected-country"),
2571
2631
  [ARIA.EXPANDED]: "false",
2572
2632
  [ARIA.LABEL]: this.#options.uiTranslations.noCountrySelected,
2573
2633
  [ARIA.HASPOPUP]: "dialog",
@@ -2581,31 +2641,44 @@ var UI = class {
2581
2641
  } else {
2582
2642
  this.#selectedCountryEl = createEl(
2583
2643
  "div",
2584
- { class: "iti__selected-country" },
2644
+ { class: this.#withSlotClass("selectedCountry", "iti__selected-country") },
2585
2645
  this.#countryContainerEl
2586
2646
  );
2587
2647
  }
2588
2648
  const selectedCountryPrimary = createEl(
2589
2649
  "div",
2590
- { class: "iti__selected-country-primary" },
2650
+ {
2651
+ class: this.#withSlotClass(
2652
+ "selectedCountryPrimary",
2653
+ "iti__selected-country-primary"
2654
+ )
2655
+ },
2591
2656
  this.#selectedCountryEl
2592
2657
  );
2593
2658
  this.#selectedFlagEl = createEl(
2594
2659
  "div",
2595
- { class: CLASSES.FLAG },
2660
+ { class: this.#withSlotClass("selectedFlag", CLASSES.FLAG) },
2596
2661
  selectedCountryPrimary
2597
2662
  );
2598
2663
  if (enableCountrySelector) {
2599
2664
  this.#arrowEl = createEl(
2600
2665
  "div",
2601
- { class: "iti__arrow", [ARIA.HIDDEN]: "true" },
2666
+ {
2667
+ class: this.#withSlotClass("arrow", "iti__arrow"),
2668
+ [ARIA.HIDDEN]: "true"
2669
+ },
2602
2670
  selectedCountryPrimary
2603
2671
  );
2604
2672
  }
2605
2673
  if (separateDialCode) {
2606
2674
  this.#selectedDialCodeEl = createEl(
2607
2675
  "div",
2608
- { class: "iti__selected-dial-code" },
2676
+ {
2677
+ class: this.#withSlotClass(
2678
+ "selectedDialCode",
2679
+ "iti__selected-dial-code"
2680
+ )
2681
+ },
2609
2682
  this.#selectedCountryEl
2610
2683
  );
2611
2684
  }
@@ -2636,7 +2709,10 @@ var UI = class {
2636
2709
  const extraClasses = matchDropdownWidth ? "" : "iti--flexible-dropdown-width";
2637
2710
  this.#countrySelectorEl = createEl("div", {
2638
2711
  id: `iti-${this.#id}__country-selector`,
2639
- class: `iti__country-selector ${CLASSES.HIDE} ${extraClasses}`,
2712
+ class: this.#withSlotClass(
2713
+ "countrySelector",
2714
+ `iti__country-selector ${CLASSES.HIDE} ${extraClasses}`
2715
+ ),
2640
2716
  role: "dialog",
2641
2717
  [ARIA.MODAL]: "true"
2642
2718
  });
@@ -2649,7 +2725,7 @@ var UI = class {
2649
2725
  this.#countryListEl = createEl(
2650
2726
  "ul",
2651
2727
  {
2652
- class: "iti__country-list",
2728
+ class: this.#withSlotClass("countryList", "iti__country-list"),
2653
2729
  id: `iti-${this.#id}__country-listbox`,
2654
2730
  role: "listbox",
2655
2731
  [ARIA.LABEL]: uiTranslations.countryListAriaLabel
@@ -2668,7 +2744,9 @@ var UI = class {
2668
2744
  "iti--inline-country-selector": !isFullscreen,
2669
2745
  [containerClass]: Boolean(containerClass)
2670
2746
  });
2671
- this.#detachedCountrySelectorEl = createEl("div", { class: wrapperClasses });
2747
+ this.#detachedCountrySelectorEl = createEl("div", {
2748
+ class: this.#withSlotClass("countrySelectorContainer", wrapperClasses)
2749
+ });
2672
2750
  this.#detachedCountrySelectorEl.appendChild(this.#countrySelectorEl);
2673
2751
  } else {
2674
2752
  this.#countryContainerEl.appendChild(this.#countrySelectorEl);
@@ -2689,13 +2767,13 @@ var UI = class {
2689
2767
  const { uiTranslations, searchInputClass } = this.#options;
2690
2768
  const searchWrapper = createEl(
2691
2769
  "div",
2692
- { class: "iti__search-input-wrapper" },
2770
+ { class: this.#withSlotClass("searchWrapper", "iti__search-input-wrapper") },
2693
2771
  this.#countrySelectorEl
2694
2772
  );
2695
2773
  this.#searchIconEl = createEl(
2696
2774
  "span",
2697
2775
  {
2698
- class: "iti__search-icon",
2776
+ class: this.#withSlotClass("searchIcon", "iti__search-icon"),
2699
2777
  [ARIA.HIDDEN]: "true"
2700
2778
  },
2701
2779
  searchWrapper
@@ -2707,7 +2785,10 @@ var UI = class {
2707
2785
  id: `iti-${this.#id}__search-input`,
2708
2786
  // Chrome says inputs need either a name or an id
2709
2787
  type: "search",
2710
- class: `iti__search-input ${searchInputClass}`,
2788
+ class: this.#withSlotClass(
2789
+ "searchInput",
2790
+ `iti__search-input ${searchInputClass}`
2791
+ ),
2711
2792
  placeholder: uiTranslations.searchPlaceholder,
2712
2793
  // role=combobox + aria-autocomplete=list + aria-activedescendant allows maintaining focus on the search input while allowing users to navigate search results with up/down keyboard keys
2713
2794
  role: "combobox",
@@ -2723,7 +2804,10 @@ var UI = class {
2723
2804
  "button",
2724
2805
  {
2725
2806
  type: "button",
2726
- class: `iti__search-clear ${CLASSES.HIDE}`,
2807
+ class: this.#withSlotClass(
2808
+ "searchClear",
2809
+ `iti__search-clear ${CLASSES.HIDE}`
2810
+ ),
2727
2811
  [ARIA.LABEL]: uiTranslations.clearSearchAriaLabel,
2728
2812
  tabindex: "-1"
2729
2813
  },
@@ -2738,7 +2822,7 @@ var UI = class {
2738
2822
  this.#noResultsMessageEl = createEl(
2739
2823
  "div",
2740
2824
  {
2741
- class: `iti__no-results ${CLASSES.HIDE}`,
2825
+ class: this.#withSlotClass("noResults", `iti__no-results ${CLASSES.HIDE}`),
2742
2826
  [ARIA.HIDDEN]: "true"
2743
2827
  // all a11y messaging happens in this.#searchResultsLiveRegionEl
2744
2828
  },
@@ -2792,11 +2876,9 @@ var UI = class {
2792
2876
  //* For each country: add a country list item <li> to the countryList <ul> container.
2793
2877
  #appendListItems() {
2794
2878
  const frag = document.createDocumentFragment();
2879
+ const liClass = this.#withSlotClass("countryListItem", CLASSES.COUNTRY_ITEM);
2795
2880
  for (let i = 0; i < this.#countries.length; i++) {
2796
2881
  const c = this.#countries[i];
2797
- const liClass = buildClassNames({
2798
- [CLASSES.COUNTRY_ITEM]: true
2799
- });
2800
2882
  const listItem = createEl("li", {
2801
2883
  id: `iti-${this.#id}__item-${c.iso2}`,
2802
2884
  class: liClass,
@@ -2808,11 +2890,28 @@ var UI = class {
2808
2890
  listItem.dataset[DATA_KEYS.ISO2] = c.iso2;
2809
2891
  this.#listItemByIso2.set(c.iso2, listItem);
2810
2892
  if (this.#options.showFlags) {
2811
- createEl("div", { class: `${CLASSES.FLAG} iti__${c.iso2}` }, listItem);
2893
+ createEl(
2894
+ "div",
2895
+ {
2896
+ class: this.#withSlotClass(
2897
+ "countryListItemFlag",
2898
+ `${CLASSES.FLAG} iti__${c.iso2}`
2899
+ )
2900
+ },
2901
+ listItem
2902
+ );
2812
2903
  }
2813
- const nameEl = createEl("span", { class: "iti__country-name" }, listItem);
2904
+ const nameEl = createEl(
2905
+ "span",
2906
+ { class: this.#withSlotClass("countryName", "iti__country-name") },
2907
+ listItem
2908
+ );
2814
2909
  nameEl.textContent = `${c.name} `;
2815
- const dialEl = createEl("span", { class: "iti__dial-code" }, nameEl);
2910
+ const dialEl = createEl(
2911
+ "span",
2912
+ { class: this.#withSlotClass("dialCode", "iti__dial-code") },
2913
+ nameEl
2914
+ );
2816
2915
  if (this.#isRTL) {
2817
2916
  dialEl.setAttribute("dir", "ltr");
2818
2917
  }
@@ -3259,7 +3358,10 @@ var UI = class {
3259
3358
  newListItem.setAttribute(ARIA.SELECTED, "true");
3260
3359
  const checkIcon = createEl(
3261
3360
  "span",
3262
- { class: "iti__country-check", [ARIA.HIDDEN]: "true" },
3361
+ {
3362
+ class: this.#withSlotClass("countryCheck", "iti__country-check"),
3363
+ [ARIA.HIDDEN]: "true"
3364
+ },
3263
3365
  newListItem
3264
3366
  );
3265
3367
  checkIcon.appendChild(buildCheckIcon());
@@ -3446,7 +3548,10 @@ var UI = class {
3446
3548
  this.#updateSelectedListItem(iso2);
3447
3549
  }
3448
3550
  if (this.#selectedCountryEl) {
3449
- const flagClass = iso2 && showFlags ? `${CLASSES.FLAG} iti__${iso2}` : `${CLASSES.FLAG} ${CLASSES.GLOBE}`;
3551
+ const flagClass = this.#withSlotClass(
3552
+ "selectedFlag",
3553
+ iso2 && showFlags ? `${CLASSES.FLAG} iti__${iso2}` : `${CLASSES.FLAG} ${CLASSES.GLOBE}`
3554
+ );
3450
3555
  let ariaLabel, title;
3451
3556
  let flagContent = null;
3452
3557
  if (iso2) {
@@ -4843,7 +4948,7 @@ var intlTelInput = Object.assign(
4843
4948
  attachUtils,
4844
4949
  startedLoadingUtils: false,
4845
4950
  startedLoadingAutoCountry: false,
4846
- version: "29.1.3",
4951
+ version: "29.2.0",
4847
4952
  NUMBER_FORMAT,
4848
4953
  NUMBER_TYPE,
4849
4954
  VALIDATION_ERROR,
@@ -10984,6 +11089,7 @@ var IntlTelInput = class _IntlTelInput {
10984
11089
  allowedNumberTypes;
10985
11090
  allowNumberExtensions;
10986
11091
  allowPhonewords;
11092
+ classNames;
10987
11093
  containerClass;
10988
11094
  countryNameLocale;
10989
11095
  countryNameOverrides;
@@ -11034,6 +11140,10 @@ var IntlTelInput = class _IntlTelInput {
11034
11140
  pendingWriteValue;
11035
11141
  // if an input event fires before utils has loaded, we defer the update until the promise resolves
11036
11142
  pendingUpdate = false;
11143
+ //* setNumber dispatches a synthetic input event, which handleInput would otherwise treat as a
11144
+ //* user edit and report via onChange - and Angular marks a control dirty on any onChange call.
11145
+ //* Set while we write a value that came FROM the form model, so we can skip that callback.
11146
+ isWritingModelValue = false;
11037
11147
  // eslint-disable-next-line class-methods-use-this
11038
11148
  onChange = () => {
11039
11149
  };
@@ -11049,8 +11159,9 @@ var IntlTelInput = class _IntlTelInput {
11049
11159
  this.strictReject.emit(e.detail);
11050
11160
  };
11051
11161
  ngAfterViewInit() {
11162
+ const classesBeforeInit = new Set(this.inputRef.nativeElement.classList);
11052
11163
  this.iti = intlTelInput_default(this.inputRef.nativeElement, this.buildInitOptions());
11053
- this.libraryInputClasses = this.inputRef.nativeElement.className;
11164
+ this.libraryInputClasses = Array.from(this.inputRef.nativeElement.classList).filter((className) => !classesBeforeInit.has(className)).join(" ");
11054
11165
  this.inputRef.nativeElement.addEventListener("input", this.handleInput);
11055
11166
  this.inputRef.nativeElement.addEventListener("open:countryselector", this.handleOpenCountrySelector);
11056
11167
  this.inputRef.nativeElement.addEventListener("close:countryselector", this.handleCloseCountrySelector);
@@ -11067,10 +11178,10 @@ var IntlTelInput = class _IntlTelInput {
11067
11178
  return;
11068
11179
  }
11069
11180
  if (this.pendingWriteValue !== void 0) {
11070
- this.iti.setNumber(this.pendingWriteValue);
11181
+ this.setNumberFromModel(this.pendingWriteValue);
11071
11182
  this.pendingWriteValue = void 0;
11072
11183
  } else if (this.initialValue) {
11073
- this.iti.setNumber(this.initialValue);
11184
+ this.setNumberFromModel(this.initialValue);
11074
11185
  }
11075
11186
  if (this.pendingUpdate) {
11076
11187
  this.pendingUpdate = false;
@@ -11086,6 +11197,7 @@ var IntlTelInput = class _IntlTelInput {
11086
11197
  allowedNumberTypes: this.allowedNumberTypes,
11087
11198
  allowNumberExtensions: this.allowNumberExtensions,
11088
11199
  allowPhonewords: this.allowPhonewords,
11200
+ classNames: this.classNames,
11089
11201
  containerClass: this.containerClass,
11090
11202
  countryNameLocale: this.countryNameLocale,
11091
11203
  countryNameOverrides: this.countryNameOverrides,
@@ -11125,6 +11237,16 @@ var IntlTelInput = class _IntlTelInput {
11125
11237
  this.applyInputAttrs();
11126
11238
  }
11127
11239
  }
11240
+ //* Write a value that came from the form model (writeValue/initialValue), without reporting it
11241
+ //* back to the model as a user change.
11242
+ setNumberFromModel(value) {
11243
+ this.isWritingModelValue = true;
11244
+ try {
11245
+ this.iti?.setNumber(value);
11246
+ } finally {
11247
+ this.isWritingModelValue = false;
11248
+ }
11249
+ }
11128
11250
  handleInput = () => {
11129
11251
  if (!this.iti) {
11130
11252
  return;
@@ -11139,7 +11261,9 @@ var IntlTelInput = class _IntlTelInput {
11139
11261
  if (num !== this.lastEmittedNumber) {
11140
11262
  this.lastEmittedNumber = num;
11141
11263
  this.numberChange.emit(num);
11142
- this.onChange(num);
11264
+ if (!this.isWritingModelValue) {
11265
+ this.onChange(num);
11266
+ }
11143
11267
  hasChanged = true;
11144
11268
  }
11145
11269
  if (countryIso !== this.lastEmittedCountry) {
@@ -11233,7 +11357,7 @@ var IntlTelInput = class _IntlTelInput {
11233
11357
  if (this.iti) {
11234
11358
  this.iti.promise.then(() => {
11235
11359
  if (this.iti?.isActive()) {
11236
- this.iti.setNumber(next);
11360
+ this.setNumberFromModel(next);
11237
11361
  }
11238
11362
  });
11239
11363
  } else {
@@ -11278,7 +11402,7 @@ var IntlTelInput = class _IntlTelInput {
11278
11402
  let _t;
11279
11403
  i0.\u0275\u0275queryRefresh(_t = i0.\u0275\u0275loadQuery()) && (ctx.inputRef = _t.first);
11280
11404
  }
11281
- }, inputs: { initialValue: "initialValue", usePreciseValidation: "usePreciseValidation", inputAttributes: "inputAttributes", disabled: "disabled", readonly: "readonly", countrySelectorMode: "countrySelectorMode", allowedNumberTypes: "allowedNumberTypes", allowNumberExtensions: "allowNumberExtensions", allowPhonewords: "allowPhonewords", containerClass: "containerClass", countryNameLocale: "countryNameLocale", countryNameOverrides: "countryNameOverrides", countryOrder: "countryOrder", countrySearch: "countrySearch", customPlaceholder: "customPlaceholder", dropdownAlwaysOpen: "dropdownAlwaysOpen", dropdownParent: "dropdownParent", excludeCountries: "excludeCountries", matchDropdownWidth: "matchDropdownWidth", formatAsYouType: "formatAsYouType", hiddenInputs: "hiddenInputs", uiTranslations: "uiTranslations", initialCountry: "initialCountry", initialCountryLookup: "initialCountryLookup", loadUtils: "loadUtils", numberDisplayFormat: "numberDisplayFormat", onlyCountries: "onlyCountries", placeholderNumberPolicy: "placeholderNumberPolicy", placeholderNumberType: "placeholderNumberType", searchInputClass: "searchInputClass", separateDialCode: "separateDialCode", showFlags: "showFlags", strictMode: "strictMode", strictRejectAnimation: "strictRejectAnimation" }, outputs: { numberChange: "numberChange", countryChange: "countryChange", validityChange: "validityChange", errorCodeChange: "errorCodeChange", openCountrySelector: "openCountrySelector", closeCountrySelector: "closeCountrySelector", strictReject: "strictReject", blur: "blur", focus: "focus", keydown: "keydown", keyup: "keyup", paste: "paste", click: "click" }, features: [i0.\u0275\u0275ProvidersFeature([
11405
+ }, inputs: { initialValue: "initialValue", usePreciseValidation: "usePreciseValidation", inputAttributes: "inputAttributes", disabled: "disabled", readonly: "readonly", countrySelectorMode: "countrySelectorMode", allowedNumberTypes: "allowedNumberTypes", allowNumberExtensions: "allowNumberExtensions", allowPhonewords: "allowPhonewords", classNames: "classNames", containerClass: "containerClass", countryNameLocale: "countryNameLocale", countryNameOverrides: "countryNameOverrides", countryOrder: "countryOrder", countrySearch: "countrySearch", customPlaceholder: "customPlaceholder", dropdownAlwaysOpen: "dropdownAlwaysOpen", dropdownParent: "dropdownParent", excludeCountries: "excludeCountries", matchDropdownWidth: "matchDropdownWidth", formatAsYouType: "formatAsYouType", hiddenInputs: "hiddenInputs", uiTranslations: "uiTranslations", initialCountry: "initialCountry", initialCountryLookup: "initialCountryLookup", loadUtils: "loadUtils", numberDisplayFormat: "numberDisplayFormat", onlyCountries: "onlyCountries", placeholderNumberPolicy: "placeholderNumberPolicy", placeholderNumberType: "placeholderNumberType", searchInputClass: "searchInputClass", separateDialCode: "separateDialCode", showFlags: "showFlags", strictMode: "strictMode", strictRejectAnimation: "strictRejectAnimation" }, outputs: { numberChange: "numberChange", countryChange: "countryChange", validityChange: "validityChange", errorCodeChange: "errorCodeChange", openCountrySelector: "openCountrySelector", closeCountrySelector: "closeCountrySelector", strictReject: "strictReject", blur: "blur", focus: "focus", keydown: "keydown", keyup: "keyup", paste: "paste", click: "click" }, features: [i0.\u0275\u0275ProvidersFeature([
11282
11406
  {
11283
11407
  provide: NG_VALUE_ACCESSOR,
11284
11408
  useExisting: forwardRef(() => _IntlTelInput),
@@ -11361,6 +11485,8 @@ var IntlTelInput = class _IntlTelInput {
11361
11485
  type: Input
11362
11486
  }], allowPhonewords: [{
11363
11487
  type: Input
11488
+ }], classNames: [{
11489
+ type: Input
11364
11490
  }], containerClass: [{
11365
11491
  type: Input
11366
11492
  }], countryNameLocale: [{
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@intl-tel-input/angular",
3
- "version": "29.1.3",
3
+ "version": "29.2.0",
4
4
  "description": "An Angular component for intl-tel-input, for entering, formatting, and validating international telephone numbers",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -34,7 +34,7 @@
34
34
  "README.md"
35
35
  ],
36
36
  "dependencies": {
37
- "intl-tel-input": "^29.1.3"
37
+ "intl-tel-input": "^29.2.0"
38
38
  },
39
39
  "peerDependencies": {
40
40
  "@angular/common": ">=17",