@aurodesignsystem-dev/auro-formkit 0.0.0-pr1431.2 → 0.0.0-pr1433.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.
Files changed (43) hide show
  1. package/components/checkbox/demo/api.min.js +1 -1
  2. package/components/checkbox/demo/index.min.js +1 -1
  3. package/components/checkbox/dist/index.js +1 -1
  4. package/components/checkbox/dist/registered.js +1 -1
  5. package/components/combobox/demo/api.min.js +235 -47
  6. package/components/combobox/demo/index.min.js +235 -47
  7. package/components/combobox/dist/auro-combobox.d.ts +4 -0
  8. package/components/combobox/dist/index.js +144 -24
  9. package/components/combobox/dist/registered.js +144 -24
  10. package/components/counter/demo/api.min.js +30 -2
  11. package/components/counter/demo/index.min.js +30 -2
  12. package/components/counter/dist/index.js +30 -2
  13. package/components/counter/dist/registered.js +30 -2
  14. package/components/datepicker/demo/api.min.js +33 -3
  15. package/components/datepicker/demo/index.min.js +33 -3
  16. package/components/datepicker/dist/index.js +33 -3
  17. package/components/datepicker/dist/registered.js +33 -3
  18. package/components/dropdown/demo/api.min.js +29 -1
  19. package/components/dropdown/demo/index.min.js +29 -1
  20. package/components/dropdown/dist/index.js +29 -1
  21. package/components/dropdown/dist/registered.js +29 -1
  22. package/components/form/demo/api.min.js +331 -57
  23. package/components/form/demo/index.min.js +331 -57
  24. package/components/input/demo/api.min.js +1 -1
  25. package/components/input/demo/index.min.js +1 -1
  26. package/components/input/dist/index.js +1 -1
  27. package/components/input/dist/registered.js +1 -1
  28. package/components/menu/demo/api.md +1 -1
  29. package/components/menu/demo/api.min.js +91 -23
  30. package/components/menu/demo/index.min.js +91 -23
  31. package/components/menu/dist/auro-menuoption.d.ts +2 -0
  32. package/components/menu/dist/index.js +91 -23
  33. package/components/menu/dist/registered.js +91 -23
  34. package/components/radio/demo/api.min.js +1 -1
  35. package/components/radio/demo/index.min.js +1 -1
  36. package/components/radio/dist/index.js +1 -1
  37. package/components/radio/dist/registered.js +1 -1
  38. package/components/select/demo/api.min.js +121 -25
  39. package/components/select/demo/index.min.js +121 -25
  40. package/components/select/dist/index.js +30 -2
  41. package/components/select/dist/registered.js +30 -2
  42. package/custom-elements.json +422 -411
  43. package/package.json +2 -2
@@ -1687,7 +1687,7 @@ class AuroHelpText extends i$2 {
1687
1687
  }
1688
1688
  }
1689
1689
 
1690
- var formkitVersion = '202604091435';
1690
+ var formkitVersion = '202604100244';
1691
1691
 
1692
1692
  // Copyright (c) 2026 Alaska Airlines. All rights reserved. Licensed under the Apache-2.0 license
1693
1693
  // See LICENSE in the project root for license information.
@@ -1679,7 +1679,7 @@ class AuroHelpText extends i$2 {
1679
1679
  }
1680
1680
  }
1681
1681
 
1682
- var formkitVersion = '202604091435';
1682
+ var formkitVersion = '202604100244';
1683
1683
 
1684
1684
  // Copyright (c) 2026 Alaska Airlines. All rights reserved. Licensed under the Apache-2.0 license
1685
1685
  // See LICENSE in the project root for license information.
@@ -1632,7 +1632,7 @@ class AuroHelpText extends LitElement {
1632
1632
  }
1633
1633
  }
1634
1634
 
1635
- var formkitVersion = '202604091435';
1635
+ var formkitVersion = '202604100244';
1636
1636
 
1637
1637
  // Copyright (c) 2026 Alaska Airlines. All rights reserved. Licensed under the Apache-2.0 license
1638
1638
  // See LICENSE in the project root for license information.
@@ -1632,7 +1632,7 @@ class AuroHelpText extends LitElement {
1632
1632
  }
1633
1633
  }
1634
1634
 
1635
- var formkitVersion = '202604091435';
1635
+ var formkitVersion = '202604100244';
1636
1636
 
1637
1637
  // Copyright (c) 2026 Alaska Airlines. All rights reserved. Licensed under the Apache-2.0 license
1638
1638
  // See LICENSE in the project root for license information.
@@ -3294,6 +3294,7 @@ class AuroFloatingUI {
3294
3294
  this.focusHandler = null;
3295
3295
  this.clickHandler = null;
3296
3296
  this.keyDownHandler = null;
3297
+ this.touchHandler = null;
3297
3298
 
3298
3299
  /**
3299
3300
  * @private
@@ -3711,6 +3712,28 @@ class AuroFloatingUI {
3711
3712
  setTimeout(() => {
3712
3713
  window.addEventListener("click", this.clickHandler);
3713
3714
  }, 0);
3715
+
3716
+ // iOS Safari does not fire `click` on non-interactive elements, so
3717
+ // tapping an inert backdrop never reaches the click handler above.
3718
+ // Mirror the same outside-tap logic with a passive touchstart listener.
3719
+ this.touchHandler = (evt) => {
3720
+ const element = this.element;
3721
+ if (!element?.bib) {
3722
+ return;
3723
+ }
3724
+
3725
+ // fullscreen (modal) dialog handles its own dismissal
3726
+ if (element.bib.hasAttribute("isfullscreen")) {
3727
+ return;
3728
+ }
3729
+
3730
+ const path = evt.composedPath();
3731
+ if (!path.includes(element.trigger) && !path.includes(element.bib)) {
3732
+ this.hideBib("click");
3733
+ }
3734
+ };
3735
+
3736
+ window.addEventListener("touchstart", this.touchHandler, { passive: true });
3714
3737
  }
3715
3738
 
3716
3739
  cleanupHideHandlers() {
@@ -3726,6 +3749,11 @@ class AuroFloatingUI {
3726
3749
  this.clickHandler = null;
3727
3750
  }
3728
3751
 
3752
+ if (this.touchHandler) {
3753
+ window.removeEventListener("touchstart", this.touchHandler);
3754
+ this.touchHandler = null;
3755
+ }
3756
+
3729
3757
  if (this.keyDownHandler) {
3730
3758
  document.removeEventListener("keydown", this.keyDownHandler);
3731
3759
  this.keyDownHandler = null;
@@ -5200,7 +5228,7 @@ let AuroHelpText$2 = class AuroHelpText extends i$4 {
5200
5228
  }
5201
5229
  };
5202
5230
 
5203
- var formkitVersion$2 = '202604091435';
5231
+ var formkitVersion$2 = '202604100244';
5204
5232
 
5205
5233
  let AuroElement$2 = class AuroElement extends i$4 {
5206
5234
  static get properties() {
@@ -12964,7 +12992,7 @@ let AuroHelpText$1 = class AuroHelpText extends i$4 {
12964
12992
  }
12965
12993
  };
12966
12994
 
12967
- var formkitVersion$1 = '202604091435';
12995
+ var formkitVersion$1 = '202604100244';
12968
12996
 
12969
12997
  // Copyright (c) 2025 Alaska Airlines. All right reserved. Licensed under the Apache-2.0 license
12970
12998
  // See LICENSE in the project root for license information.
@@ -14029,11 +14057,11 @@ class AuroBibtemplate extends i$4 {
14029
14057
  }
14030
14058
  }
14031
14059
 
14032
- var formkitVersion = '202604091435';
14060
+ var formkitVersion = '202604100244';
14033
14061
 
14034
14062
  var styleCss$3 = i$7`.util_displayInline{display:inline}.util_displayInlineBlock{display:inline-block}.util_displayBlock{display:block}.util_displayFlex{display:flex}.util_displayHidden{display:none}.util_displayHiddenVisually{position:absolute;overflow:hidden;clip:rect(1px, 1px, 1px, 1px);width:1px;height:1px;padding:0;border:0}:host{display:block;text-align:left}:host [auro-dropdown]{--ds-auro-dropdown-trigger-background-color: transparent}:host #inputInBib::part(wrapper){box-shadow:none}:host #inputInBib::part(accent-left){display:none}:host([layout*=classic]) [auro-input]{width:100%}:host([layout*=classic]) [auro-input]::part(helpText){display:none}:host([layout*=classic]) #slotHolder{display:none}`;
14035
14063
 
14036
- var styleEmphasizedCss = i$7`:host([layout*=emphasized][shape*=pill]) [auro-input]{--ds-auro-input-background-color: var(--ds-advanced-color-dropdown-emphasized-background, rgba(0, 39, 74, 0.1019607843));--ds-auro-input-container-color: var(--ds-advanced-color-dropdown-emphasized-background, rgba(0, 39, 74, 0.1019607843))}:host([layout*=emphasized][shape*=pill]) [auro-input]:hover{--ds-auro-input-background-color: var(--ds-advanced-color-dropdown-emphasized-background, rgba(0, 39, 74, 0.1019607843));--ds-auro-input-container-color: var(--ds-advanced-color-dropdown-emphasized-background, rgba(0, 39, 74, 0.1019607843))}:host([layout*=emphasized][shape*=pill]) [auro-input]{width:100%}:host([layout*=emphasized][shape*=pill]) [auro-input]::part(inputHelpText){display:none}:host([layout=emphasized]) [auro-dropdown]{--ds-auro-dropdown-trigger-background-color: var(--ds-advanced-color-dropdown-emphasized-background, rgba(0, 39, 74, 0.1019607843))}:host([layout=emphasized]) [auro-dropdown]:hover{--ds-auro-dropdown-trigger-hover-background-color: var(--ds-advanced-color-dropdown-emphasized-background, rgba(0, 39, 74, 0.1019607843))}:host([layout=emphasized]) [auro-dropdown][layout*=emphasized]::part(wrapper){--ds-auro-dropdown-trigger-background-color: transparent}`;
14064
+ var styleEmphasizedCss = i$7`:host([layout*=emphasized][shape*=pill]) [auro-input][slot=trigger]{--ds-auro-input-background-color: var(--ds-advanced-color-dropdown-emphasized-background, rgba(0, 39, 74, 0.1019607843));--ds-auro-input-container-color: var(--ds-advanced-color-dropdown-emphasized-background, rgba(0, 39, 74, 0.1019607843))}:host([layout*=emphasized][shape*=pill]) [auro-input][slot=trigger]:hover{--ds-auro-input-background-color: var(--ds-advanced-color-dropdown-emphasized-background, rgba(0, 39, 74, 0.1019607843));--ds-auro-input-container-color: var(--ds-advanced-color-dropdown-emphasized-background, rgba(0, 39, 74, 0.1019607843))}:host([layout*=emphasized][shape*=pill]) [auro-input][slot=trigger]{width:100%}:host([layout*=emphasized][shape*=pill]) [auro-input][slot=trigger]::part(inputHelpText){display:none}:host([layout=emphasized]) [auro-dropdown]{--ds-auro-dropdown-trigger-background-color: var(--ds-advanced-color-dropdown-emphasized-background, rgba(0, 39, 74, 0.1019607843))}:host([layout=emphasized]) [auro-dropdown]:hover{--ds-auro-dropdown-trigger-hover-background-color: var(--ds-advanced-color-dropdown-emphasized-background, rgba(0, 39, 74, 0.1019607843))}:host([layout=emphasized]) [auro-dropdown][layout*=emphasized]::part(wrapper){--ds-auro-dropdown-trigger-background-color: transparent}`;
14037
14065
 
14038
14066
  var styleSnowflakeCss = i$7`:host([layout*=snowflake][shape*=snowflake]) [auro-input]{width:100%}:host([layout*=snowflake][shape*=snowflake]) [auro-input]::part(inputHelpText){display:none}:host([layout*=snowflake][shape*=snowflake])::part(helpText){text-align:center}`;
14039
14067
 
@@ -14892,7 +14920,7 @@ class AuroCombobox extends AuroElement {
14892
14920
  * @returns {void}
14893
14921
  */
14894
14922
  activateFirstEnabledAvailableOption() {
14895
- const firstEnabledOptionIndex = this.availableOptions.findIndex((opt) => !opt.disabled && !opt.noMatch);
14923
+ const firstEnabledOptionIndex = this.availableOptions.findIndex((opt) => !opt.disabled && !opt.hasAttribute('nomatch'));
14896
14924
  this.updateActiveOption(firstEnabledOptionIndex);
14897
14925
  }
14898
14926
 
@@ -14906,7 +14934,7 @@ class AuroCombobox extends AuroElement {
14906
14934
 
14907
14935
  // Work backwards through the available options array to find the last enabled option
14908
14936
  for (let index = this.availableOptions.length - 1; index >= 0; index -= 1) {
14909
- if (!this.availableOptions[index].disabled && !this.availableOptions[index].noMatch) {
14937
+ if (!this.availableOptions[index].disabled && !this.availableOptions[index].hasAttribute('nomatch')) {
14910
14938
  lastEnabledOptionIndex = index;
14911
14939
  break;
14912
14940
  }
@@ -14991,14 +15019,18 @@ class AuroCombobox extends AuroElement {
14991
15019
  /**
14992
15020
  * Update displayValue or input.value, it's called when making a selection.
14993
15021
  * @param {string} label - The label of the selected option.
15022
+ * @param {object} [options={}] - Optional display update settings.
15023
+ * @param {boolean} [options.force=false] - Force display sync while focused.
14994
15024
  * @private
14995
15025
  */
14996
- updateTriggerTextDisplay(label) {
15026
+ updateTriggerTextDisplay(label, options = {}) {
15027
+ const { force = false } = options;
15028
+
14997
15029
  // update the input content if persistInput is false
14998
15030
  // in suggestion mode, do not override input value if no selection has been made and the input currently has focus
14999
15031
  const isInputFocusedWithNoSelection = !this.menu.value && (this.input.matches(':focus-within') || (this.inputInBib && this.inputInBib.matches(':focus-within')));
15000
15032
 
15001
- if (!this.persistInput && !(this.behavior === 'suggestion' && isInputFocusedWithNoSelection)) {
15033
+ if (!this.persistInput && (force || !(this.behavior === 'suggestion' && isInputFocusedWithNoSelection))) {
15002
15034
  this.input.value = label || this.value;
15003
15035
  }
15004
15036
 
@@ -15075,6 +15107,13 @@ class AuroCombobox extends AuroElement {
15075
15107
  * @returns {void}
15076
15108
  */
15077
15109
  showBib() {
15110
+ // Do not auto-open from programmatic value/option updates when the
15111
+ // combobox is not focused. User-driven interactions still open normally
15112
+ // once focus enters the component.
15113
+ if (!this.componentHasFocus && !this.dropdown.isPopoverVisible) {
15114
+ return;
15115
+ }
15116
+
15078
15117
  if (!this.input.value && !this.dropdown.isBibFullscreen) {
15079
15118
  this.dropdown.hide();
15080
15119
  return;
@@ -15363,6 +15402,25 @@ class AuroCombobox extends AuroElement {
15363
15402
 
15364
15403
  // Handle menu option selection like select does
15365
15404
  this.menu.addEventListener('auroMenu-selectedOption', (event) => {
15405
+ const hasMatchingOptionForValue =
15406
+ typeof this.value === 'string' &&
15407
+ this.value.length > 0 &&
15408
+ this.menu && Array.isArray(this.menu.options) &&
15409
+ this.menu.options.some((opt) => opt.value === this.value);
15410
+
15411
+ const isInitNoMatch = event.detail && event.detail.reason === 'no-match' &&
15412
+ this.menu && this.menu.options && this.menu.options.length === 0 &&
15413
+ typeof this.value === 'string' &&
15414
+ this.value.length > 0;
15415
+
15416
+ const isTransientProgrammaticNoMatch = event.detail && event.detail.reason === 'no-match' &&
15417
+ this._suppressNextEmptyInputClear &&
15418
+ hasMatchingOptionForValue;
15419
+
15420
+ if (isInitNoMatch || isTransientProgrammaticNoMatch) {
15421
+ return;
15422
+ }
15423
+
15366
15424
  // Update the optionSelected from the event details, not manually
15367
15425
  [this.optionSelected] = event.detail.options;
15368
15426
 
@@ -15538,7 +15596,18 @@ class AuroCombobox extends AuroElement {
15538
15596
  }
15539
15597
 
15540
15598
  if (!this.input.value) {
15541
- this.clear();
15599
+ const hasCommittedValue = typeof this.value === 'string' && this.value.length > 0;
15600
+ const hasCommittedSelection = Boolean(this.menu && this.menu.optionSelected);
15601
+ const isBlurSideEffect = !this.componentHasFocus && !this.dropdownOpen;
15602
+ const isTransientEmptyInputEvent = this._suppressNextEmptyInputClear && (!event || !event.detail || event.detail.value === null || event.detail.value === undefined);
15603
+
15604
+ // Preserve a committed value when an empty input event is emitted as a
15605
+ // side effect of focus leaving the combobox (e.g., clicking a swap
15606
+ // control between two comboboxes). User-driven empty input while focused
15607
+ // should still clear as before.
15608
+ if (!(isTransientEmptyInputEvent || (isBlurSideEffect && hasCommittedValue && hasCommittedSelection))) {
15609
+ this.clear();
15610
+ }
15542
15611
  }
15543
15612
  this.handleMenuOptions();
15544
15613
 
@@ -15721,6 +15790,19 @@ class AuroCombobox extends AuroElement {
15721
15790
  }
15722
15791
 
15723
15792
  updated(changedProperties) {
15793
+ if (changedProperties.has('typedValue')) {
15794
+ const nextTypedValue = this.typedValue === null || this.typedValue === undefined ? '' : this.typedValue;
15795
+ if (this.input && this.input.value !== nextTypedValue) {
15796
+ this.input.value = nextTypedValue;
15797
+ }
15798
+ if (this.inputInBib && this.inputInBib.value !== nextTypedValue) {
15799
+ this.inputInBib.value = nextTypedValue;
15800
+ }
15801
+ if (this.menu) {
15802
+ this.menu.matchWord = normalizeFilterValue(nextTypedValue);
15803
+ }
15804
+ }
15805
+
15724
15806
  // After the component is ready, send direct value changes to auro-menu.
15725
15807
  if (changedProperties.has('value')) {
15726
15808
  if (this.value && this.value.length > 0) {
@@ -15748,6 +15830,19 @@ class AuroCombobox extends AuroElement {
15748
15830
  this.clear();
15749
15831
  }
15750
15832
  }
15833
+
15834
+ // Keep trigger text synced after value/menu state has settled. Force the
15835
+ // update so external programmatic swaps reflect immediately in the UI
15836
+ // even if the input still technically holds focus during the same tick.
15837
+ if (this.value) {
15838
+ const selectedOption = this.menu && this.menu.optionSelected;
15839
+ const hasMatchingSelectedOption = selectedOption && selectedOption.value === this.value;
15840
+ const selectedOptionLabel = (selectedOption && selectedOption.getAttribute('label')) || (selectedOption && selectedOption.textContent ? selectedOption.textContent.trim() : undefined);
15841
+ const nextDisplayLabel = hasMatchingSelectedOption ? (selectedOptionLabel || this.value) : this.value;
15842
+
15843
+ this.updateTriggerTextDisplay(nextDisplayLabel, { force: true });
15844
+ }
15845
+
15751
15846
  if (this.value && !this.componentHasFocus) {
15752
15847
  // If the value got set programmatically make sure we hide the bib
15753
15848
  // when input is not taking the focus (input can be in dropdown.trigger or in bibtemplate)
@@ -15759,22 +15854,47 @@ class AuroCombobox extends AuroElement {
15759
15854
  this.menu.matchWord = normalizeFilterValue(this.input.value);
15760
15855
  }
15761
15856
 
15762
- this.dispatchEvent(new CustomEvent('input', {
15763
- bubbles: true,
15764
- cancelable: false,
15765
- composed: true,
15766
- detail: {
15767
- optionSelected: this.menu.optionSelected,
15768
- value: this.menu.value
15769
- }
15770
- }));
15857
+ // Only dispatch 'input' when the value transition is meaningful — at least one
15858
+ // of old/new must be a non-empty string. Skipping the event when both are
15859
+ // empty/undefined prevents a feedback loop during SPA navigation where Lit's
15860
+ // initial update cycle fires before the parent framework (e.g. Svelte) has
15861
+ // had a chance to set the preselected value as a property. Without this
15862
+ // guard the event arrives with el.value === undefined, the surrounding
15863
+ // framework reads it as '' and writes that back, permanently obscuring the
15864
+ // intended preselected value.
15865
+ const _oldValue = changedProperties.get('value');
15866
+ const _oldIsNonEmpty = typeof _oldValue === 'string' && _oldValue.length > 0;
15867
+ const _newIsNonEmpty = typeof this.value === 'string' && this.value.length > 0;
15868
+
15869
+ if (_newIsNonEmpty && this.menu && Array.isArray(this.menu.options) && this.menu.options.some((opt) => opt.value === this.value)) {
15870
+ this._suppressNextEmptyInputClear = true;
15871
+ clearTimeout(this._suppressNextEmptyInputClearTimeout);
15872
+ const suppressNextEmptyInputClearDelay = 300;
15873
+ this._suppressNextEmptyInputClearTimeout = setTimeout(() => {
15874
+ this._suppressNextEmptyInputClear = false;
15875
+ }, suppressNextEmptyInputClearDelay);
15876
+ } else {
15877
+ this._suppressNextEmptyInputClear = false;
15878
+ }
15771
15879
 
15772
- // Deprecated, need to be removed.
15773
- this.dispatchEvent(new CustomEvent('auroCombobox-valueSet', {
15774
- bubbles: true,
15775
- cancelable: false,
15776
- composed: true,
15777
- }));
15880
+ if (_oldIsNonEmpty || _newIsNonEmpty) {
15881
+ this.dispatchEvent(new CustomEvent('input', {
15882
+ bubbles: true,
15883
+ cancelable: false,
15884
+ composed: true,
15885
+ detail: {
15886
+ optionSelected: this.menu.optionSelected,
15887
+ value: this.menu.value
15888
+ }
15889
+ }));
15890
+
15891
+ // Deprecated, need to be removed.
15892
+ this.dispatchEvent(new CustomEvent('auroCombobox-valueSet', {
15893
+ bubbles: true,
15894
+ cancelable: false,
15895
+ composed: true,
15896
+ }));
15897
+ }
15778
15898
  }
15779
15899
 
15780
15900
  if (changedProperties.has('availableOptions')) {
@@ -16171,6 +16291,7 @@ class AuroMenuOption extends AuroElement {
16171
16291
  this.selected = false;
16172
16292
  this.noCheckmark = false;
16173
16293
  this.disabled = false;
16294
+ this.noMatch = false;
16174
16295
 
16175
16296
  /**
16176
16297
  * @private
@@ -16251,7 +16372,8 @@ class AuroMenuOption extends AuroElement {
16251
16372
  */
16252
16373
  noMatch: {
16253
16374
  type: Boolean,
16254
- reflect: true
16375
+ reflect: true,
16376
+ attribute: 'nomatch'
16255
16377
  },
16256
16378
 
16257
16379
  /**
@@ -16351,7 +16473,7 @@ class AuroMenuOption extends AuroElement {
16351
16473
  this.setAttribute('aria-selected', this.selected.toString());
16352
16474
 
16353
16475
  // Update menu service selection state if this isn't an internal update
16354
- if (this.internalUpdateInProgress !== true) {
16476
+ if (this.internalUpdateInProgress !== true && this.menuService) {
16355
16477
  this.menuService[this.selected ? 'selectOption' : 'deselectOption'](this);
16356
16478
  }
16357
16479
  }
@@ -16386,9 +16508,10 @@ class AuroMenuOption extends AuroElement {
16386
16508
  }
16387
16509
 
16388
16510
  disconnectedCallback() {
16389
- if (this.menuService) {
16390
- this.menuService.unsubscribe(this.handleMenuChange);
16391
- this.menuService.removeMenuOption(this);
16511
+ const { menuService } = this;
16512
+ if (menuService) {
16513
+ menuService.unsubscribe(this.handleMenuChange);
16514
+ menuService.removeMenuOption(this);
16392
16515
  }
16393
16516
  }
16394
16517
 
@@ -16557,9 +16680,11 @@ class AuroMenuOption extends AuroElement {
16557
16680
  * @private
16558
16681
  */
16559
16682
  handleMouseEnter() {
16560
- if (!this.disabled) {
16561
- this.menuService.setHighlightedOption(this);
16683
+ const { menuService } = this;
16684
+ if (!menuService || this.disabled) {
16685
+ return;
16562
16686
  }
16687
+ menuService.setHighlightedOption(this);
16563
16688
  }
16564
16689
 
16565
16690
  /**
@@ -16963,10 +17088,15 @@ class MenuService {
16963
17088
  return;
16964
17089
  }
16965
17090
 
17091
+ const before = this.selectedOptions || [];
16966
17092
  const optionsSet = new Set(optionsToDeselect);
16967
- this.selectedOptions = (this.selectedOptions || [])
16968
- .filter(opt => !optionsSet.has(opt));
17093
+ const after = before.filter(opt => !optionsSet.has(opt));
17094
+
17095
+ if (this.optionsArraysMatch(after, before)) {
17096
+ return;
17097
+ }
16969
17098
 
17099
+ this.selectedOptions = after;
16970
17100
  this.stageUpdate();
16971
17101
  }
16972
17102
 
@@ -17062,6 +17192,16 @@ class MenuService {
17062
17192
  return;
17063
17193
  }
17064
17194
 
17195
+ const hostValue = this.host && this.host.value;
17196
+ const hostHasValue = hostValue !== undefined &&
17197
+ hostValue !== null &&
17198
+ (!Array.isArray(hostValue) || hostValue.length > 0) &&
17199
+ (typeof hostValue !== 'string' || hostValue.trim() !== '');
17200
+
17201
+ if (hostHasValue && this._pendingValue != null) {
17202
+ return;
17203
+ }
17204
+
17065
17205
  this.clearPendingValue();
17066
17206
 
17067
17207
  if (this.selectedOptions.length > 0) {
@@ -17242,6 +17382,9 @@ class MenuService {
17242
17382
  this.notify({ type: 'optionsChange', options: this._menuOptions });
17243
17383
 
17244
17384
  if (this._pendingValue != null) {
17385
+ // Reset the retry count so a new option registration gives a fresh
17386
+ // budget — the initial retries fired before delayed options arrived.
17387
+ this._pendingRetryCount = 0;
17245
17388
  this.queuePendingValue(this._pendingValue);
17246
17389
  }
17247
17390
  }
@@ -17586,7 +17729,11 @@ class AuroMenu extends AuroElement {
17586
17729
  * @returns {string} - Returns the label of the currently selected option(s).
17587
17730
  */
17588
17731
  get currentLabel() {
17589
- return this.menuService.currentLabel;
17732
+ const { menuService } = this;
17733
+ if (!menuService) {
17734
+ return '';
17735
+ }
17736
+ return menuService.currentLabel;
17590
17737
  };
17591
17738
 
17592
17739
  /**
@@ -17609,7 +17756,12 @@ class AuroMenu extends AuroElement {
17609
17756
  * @param {number} value - Sets the index of the currently active option.
17610
17757
  */
17611
17758
  set index(value) {
17612
- this.menuService.setHighlightedIndex(value);
17759
+ const { menuService } = this;
17760
+ if (!menuService) {
17761
+ return;
17762
+ }
17763
+
17764
+ menuService.setHighlightedIndex(value);
17613
17765
  }
17614
17766
 
17615
17767
  /**
@@ -17631,7 +17783,11 @@ class AuroMenu extends AuroElement {
17631
17783
  * @returns {String|Array<String>}
17632
17784
  */
17633
17785
  get formattedValue() {
17634
- return this.menuService.currentValue;
17786
+ const { menuService } = this;
17787
+ if (!menuService) {
17788
+ return '';
17789
+ }
17790
+ return menuService.currentValue;
17635
17791
  }
17636
17792
 
17637
17793
  /**
@@ -17675,7 +17831,11 @@ class AuroMenu extends AuroElement {
17675
17831
  * @param {HTMLElement} option - The option to set as active.
17676
17832
  */
17677
17833
  updateActiveOption(option) {
17678
- this.menuService.setHighlightedOption(option);
17834
+ const { menuService } = this;
17835
+ if (!menuService) {
17836
+ return;
17837
+ }
17838
+ menuService.setHighlightedOption(option);
17679
17839
  }
17680
17840
 
17681
17841
  /**
@@ -17703,7 +17863,8 @@ class AuroMenu extends AuroElement {
17703
17863
  if (event.type === 'valueChange') {
17704
17864
 
17705
17865
  // New option is array value or first option with fallback to undefined for empty array in all cases
17706
- const newOption = this.multiSelect && event.options.length ? event.options : event.options[0] || undefined;
17866
+ const options = event.options || [];
17867
+ const newOption = this.multiSelect && options.length ? options : options[0] || undefined;
17707
17868
  const newValue = event.stringValue;
17708
17869
 
17709
17870
  // Check if the option or value has actually changed
@@ -17712,8 +17873,11 @@ class AuroMenu extends AuroElement {
17712
17873
  this.setInternalValue(newValue);
17713
17874
  }
17714
17875
 
17715
- // Notify components of selection change
17716
- this.notifySelectionChange(event);
17876
+ // Notify components of selection change (pass normalized options to avoid undefined iterability errors)
17877
+ this.notifySelectionChange({
17878
+ ...event,
17879
+ options
17880
+ });
17717
17881
  }
17718
17882
 
17719
17883
  if (event.type === 'highlightChange') {
@@ -17736,7 +17900,11 @@ class AuroMenu extends AuroElement {
17736
17900
  * @returns {Array<HTMLElement>}
17737
17901
  */
17738
17902
  get selectedOptions() {
17739
- return this.menuService ? this.menuService.selectedOptions : [];
17903
+ const { menuService } = this;
17904
+ if (!menuService) {
17905
+ return [];
17906
+ }
17907
+ return menuService.selectedOptions;
17740
17908
  }
17741
17909
 
17742
17910
  /**
@@ -17744,7 +17912,11 @@ class AuroMenu extends AuroElement {
17744
17912
  * @returns {HTMLElement|null}
17745
17913
  */
17746
17914
  get selectedOption() {
17747
- return this.menuService ? this.menuService.selectedOptions[0] : null;
17915
+ const { menuService } = this;
17916
+ if (!menuService) {
17917
+ return null;
17918
+ }
17919
+ return menuService.selectedOptions[0] || null;
17748
17920
  }
17749
17921
 
17750
17922
  // Lifecycle Methods
@@ -17788,7 +17960,11 @@ class AuroMenu extends AuroElement {
17788
17960
  // keys are not yet resolved (framework mount-order race), selectByValue
17789
17961
  // queues a bounded retry automatically via queuePendingValue.
17790
17962
  if (changedProperties.has('value') && !this.internalUpdateInProgress) {
17791
- this.menuService.selectByValue(this.value);
17963
+ const { menuService } = this;
17964
+ if (!menuService) {
17965
+ return;
17966
+ }
17967
+ menuService.selectByValue(this.value);
17792
17968
  }
17793
17969
 
17794
17970
  // Handle loading state changes
@@ -17853,7 +18029,11 @@ class AuroMenu extends AuroElement {
17853
18029
  * @protected
17854
18030
  */
17855
18031
  makeSelection() {
17856
- this.menuService.selectHighlightedOption();
18032
+ const { menuService } = this;
18033
+ if (!menuService) {
18034
+ return;
18035
+ }
18036
+ menuService.selectHighlightedOption();
17857
18037
  }
17858
18038
 
17859
18039
  /**
@@ -17872,7 +18052,11 @@ class AuroMenu extends AuroElement {
17872
18052
  * @public
17873
18053
  */
17874
18054
  reset() {
17875
- this.menuService.reset();
18055
+ const { menuService } = this;
18056
+ if (!menuService) {
18057
+ return;
18058
+ }
18059
+ menuService.reset();
17876
18060
 
17877
18061
  // Dispatch reset event
17878
18062
  dispatchMenuEvent(this, 'auroMenu-selectValueReset');
@@ -17907,10 +18091,14 @@ class AuroMenu extends AuroElement {
17907
18091
  * @protected
17908
18092
  */
17909
18093
  navigateOptions(direction) {
18094
+ const { menuService } = this;
18095
+ if (!menuService) {
18096
+ return;
18097
+ }
17910
18098
  if (direction === 'up') {
17911
- this.menuService.highlightPrevious();
18099
+ menuService.highlightPrevious();
17912
18100
  } else if (direction === 'down') {
17913
- this.menuService.highlightNext();
18101
+ menuService.highlightNext();
17914
18102
  }
17915
18103
  }
17916
18104