@aurodesignsystem-dev/auro-formkit 0.0.0-pr1401.0 → 0.0.0-pr1403.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 (42) 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 +94 -115
  6. package/components/combobox/demo/index.min.js +94 -115
  7. package/components/combobox/dist/auro-combobox.d.ts +0 -2
  8. package/components/combobox/dist/index.js +15 -110
  9. package/components/combobox/dist/registered.js +15 -110
  10. package/components/counter/demo/api.min.js +2 -3
  11. package/components/counter/demo/index.min.js +2 -3
  12. package/components/counter/dist/index.js +2 -3
  13. package/components/counter/dist/registered.js +2 -3
  14. package/components/datepicker/demo/api.min.js +3 -4
  15. package/components/datepicker/demo/index.min.js +3 -4
  16. package/components/datepicker/dist/index.js +3 -4
  17. package/components/datepicker/dist/registered.js +3 -4
  18. package/components/dropdown/demo/api.min.js +1 -2
  19. package/components/dropdown/demo/index.min.js +1 -2
  20. package/components/dropdown/dist/index.js +1 -2
  21. package/components/dropdown/dist/registered.js +1 -2
  22. package/components/form/demo/api.min.js +107 -139
  23. package/components/form/demo/index.min.js +107 -139
  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.min.js +79 -5
  29. package/components/menu/demo/index.min.js +79 -5
  30. package/components/menu/dist/auro-menu.context.d.ts +6 -0
  31. package/components/menu/dist/index.js +79 -5
  32. package/components/menu/dist/registered.js +79 -5
  33. package/components/radio/demo/api.min.js +1 -1
  34. package/components/radio/demo/index.min.js +1 -1
  35. package/components/radio/dist/index.js +1 -1
  36. package/components/radio/dist/registered.js +1 -1
  37. package/components/select/demo/api.min.js +84 -19
  38. package/components/select/demo/index.min.js +84 -19
  39. package/components/select/dist/index.js +5 -14
  40. package/components/select/dist/registered.js +5 -14
  41. package/custom-elements.json +14 -1
  42. package/package.json +1 -1
@@ -1687,7 +1687,7 @@ class AuroHelpText extends i$2 {
1687
1687
  }
1688
1688
  }
1689
1689
 
1690
- var formkitVersion = '202603262341';
1690
+ var formkitVersion = '202603270028';
1691
1691
 
1692
1692
  // Copyright (c) 2026 Alaska Airlines. All right 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 = '202603262341';
1682
+ var formkitVersion = '202603270028';
1683
1683
 
1684
1684
  // Copyright (c) 2026 Alaska Airlines. All right 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 = '202603262341';
1635
+ var formkitVersion = '202603270028';
1636
1636
 
1637
1637
  // Copyright (c) 2026 Alaska Airlines. All right 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 = '202603262341';
1635
+ var formkitVersion = '202603270028';
1636
1636
 
1637
1637
  // Copyright (c) 2026 Alaska Airlines. All right reserved. Licensed under the Apache-2.0 license
1638
1638
  // See LICENSE in the project root for license information.
@@ -1300,8 +1300,6 @@ function navigateArrow(component, direction, options = {}) {
1300
1300
  }
1301
1301
  }
1302
1302
 
1303
- /* eslint-disable no-underscore-dangle */
1304
-
1305
1303
  /**
1306
1304
  * Returns the clear button element from the active input's shadow
1307
1305
  * DOM, if available.
@@ -1379,25 +1377,10 @@ const comboboxKeyboardStrategy = {
1379
1377
  if (!ctx.activeInput) {
1380
1378
  return;
1381
1379
  }
1382
-
1383
- // Active option → select immediately and close the dialog.
1384
- // Flag the component so the close handler focuses the trigger's
1385
- // clear button instead of the input. Set flags before makeSelection
1386
- // because the value change triggers showBib via Lit's updated().
1387
- if (component.optionActive) {
1388
- evt.preventDefault();
1389
- component._focusClearBtnAfterClose = true;
1390
- component._clearBtnFocusPending = true;
1391
- component.menu.makeSelection();
1392
- component.hideBib();
1393
- return;
1394
- }
1395
-
1396
1380
  const clearBtn = getClearBtn(ctx);
1397
1381
  const clearBtnHasFocus = isClearBtnFocused(ctx, clearBtn);
1398
1382
 
1399
- // No active option, input has a value, clear button not focused
1400
- // move focus to the dialog's clear button.
1383
+ // Tab from input: if clear button exists and doesn't have focus, focus it
1401
1384
  if (clearBtn && !clearBtnHasFocus && ctx.activeInput.value) {
1402
1385
  // Force clear button container visible to work around Safari not
1403
1386
  // propagating :focus-within through shadow DOM boundaries, which
@@ -1425,17 +1408,18 @@ const comboboxKeyboardStrategy = {
1425
1408
  return;
1426
1409
  }
1427
1410
 
1428
- // No active option, no clear button (or already focused) → just close.
1411
+ // Tab from clear button (or no clear button / no value) →
1412
+ // select the highlighted option if any, then close
1413
+ if (component.optionActive) {
1414
+ component.menu.makeSelection();
1415
+ }
1429
1416
  component.hideBib();
1430
1417
  return;
1431
1418
  }
1432
1419
 
1433
1420
  // Non-fullscreen: select + close
1434
- if (component.optionActive) {
1435
- evt.preventDefault();
1436
- component._focusClearBtnAfterClose = true;
1437
- component._clearBtnFocusPending = true;
1438
- component.menu.makeSelection();
1421
+ if (component.menu.optionActive && component.menu.optionActive.value) {
1422
+ component.menu.value = component.menu.optionActive.value;
1439
1423
  }
1440
1424
  component.hideBib();
1441
1425
  },
@@ -4838,7 +4822,6 @@ class AuroDropdownBib extends i$4 {
4838
4822
  return u$7`
4839
4823
  <dialog class="${e$3(classes)}" part="bibContainer" role="${o(this.dialogRole)}" aria-labelledby="${o(this.dialogLabel ? 'dialogLabel' : undefined)}">
4840
4824
  ${this.dialogLabel ? u$7`<span id="dialogLabel" class="util_displayHiddenVisually">${this.dialogLabel}</span>` : ''}
4841
- <span id="srAnnouncement" class="util_displayHiddenVisually" aria-live="polite" role="status"></span>
4842
4825
  <slot></slot>
4843
4826
  </dialog>
4844
4827
  `;
@@ -5087,7 +5070,7 @@ let AuroHelpText$2 = class AuroHelpText extends i$4 {
5087
5070
  }
5088
5071
  };
5089
5072
 
5090
- var formkitVersion$2 = '202603262341';
5073
+ var formkitVersion$2 = '202603270028';
5091
5074
 
5092
5075
  let AuroElement$2 = class AuroElement extends i$4 {
5093
5076
  static get properties() {
@@ -12851,7 +12834,7 @@ let AuroHelpText$1 = class AuroHelpText extends i$4 {
12851
12834
  }
12852
12835
  };
12853
12836
 
12854
- var formkitVersion$1 = '202603262341';
12837
+ var formkitVersion$1 = '202603270028';
12855
12838
 
12856
12839
  // Copyright (c) 2025 Alaska Airlines. All right reserved. Licensed under the Apache-2.0 license
12857
12840
  // See LICENSE in the project root for license information.
@@ -13890,7 +13873,7 @@ class AuroBibtemplate extends i$4 {
13890
13873
  }
13891
13874
  }
13892
13875
 
13893
- var formkitVersion = '202603262341';
13876
+ var formkitVersion = '202603270028';
13894
13877
 
13895
13878
  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}`;
13896
13879
 
@@ -14900,12 +14883,6 @@ class AuroCombobox extends AuroElement {
14900
14883
  * @returns {void}
14901
14884
  */
14902
14885
  showBib() {
14903
- // Suppress reopening the bib when a Tab selection is in progress —
14904
- // the value change from makeSelection triggers availableOptions update
14905
- // which calls showBib from updated(), but the bib should stay closed.
14906
- if (this._clearBtnFocusPending) {
14907
- return;
14908
- }
14909
14886
  if (!this.input.value && !this.dropdown.isBibFullscreen) {
14910
14887
  this.dropdown.hide();
14911
14888
  return;
@@ -14961,12 +14938,8 @@ class AuroCombobox extends AuroElement {
14961
14938
  // Clear aria-activedescendant when dropdown closes
14962
14939
  if (!this.dropdownOpen && this.input) {
14963
14940
  this.input.setActiveDescendant(null);
14964
- // Also clear on inputInBib since fullscreen mode sets
14965
- // aria-activedescendant on both inputs.
14966
- if (this.inputInBib) {
14967
- this.inputInBib.setActiveDescendant(null);
14968
- }
14969
14941
  this.optionActive = null;
14942
+ this.menu.menuService.clearHighlight();
14970
14943
 
14971
14944
  // Remove the highlighted state from all menu options so re-opening
14972
14945
  // the dropdown doesn't show a stale highlight.
@@ -14981,38 +14954,7 @@ class AuroCombobox extends AuroElement {
14981
14954
  // during fullscreen open to prevent touch pass-through.
14982
14955
  this.menu.style.pointerEvents = '';
14983
14956
 
14984
- const shouldFocusClearBtn = this._focusClearBtnAfterClose;
14985
- this._focusClearBtnAfterClose = false;
14986
-
14987
- if (shouldFocusClearBtn) {
14988
- // Set a guard so duplicate toggle events don't call
14989
- // restoreTriggerAfterClose and steal focus from the clear button.
14990
- this._clearBtnFocusPending = true;
14991
-
14992
- restoreTriggerAfterClose(this.dropdown, this.input);
14993
-
14994
- if (this.input.componentHasFocus) {
14995
- // Desktop: input already has focus, redirect to clear button
14996
- // after restoreTriggerAfterClose's rAF settles.
14997
- requestAnimationFrame(() => {
14998
- this.setClearBtnFocus();
14999
- this._clearBtnFocusPending = false;
15000
- });
15001
- } else {
15002
- // Fullscreen: input will receive focus after dialog.close().
15003
- // Listen for that focus event then redirect to clear button.
15004
- const onFocus = () => {
15005
- this.input.removeEventListener('focusin', onFocus);
15006
- requestAnimationFrame(() => {
15007
- this.setClearBtnFocus();
15008
- this._clearBtnFocusPending = false;
15009
- });
15010
- };
15011
- this.input.addEventListener('focusin', onFocus);
15012
- }
15013
- } else if (!this._clearBtnFocusPending) {
15014
- restoreTriggerAfterClose(this.dropdown, this.input);
15015
- }
14957
+ restoreTriggerAfterClose(this.dropdown, this.input);
15016
14958
  }
15017
14959
 
15018
14960
  if (this.dropdownOpen) {
@@ -15103,27 +15045,7 @@ class AuroCombobox extends AuroElement {
15103
15045
  setClearBtnFocus() {
15104
15046
  const clearBtn = this.input.shadowRoot.querySelector('.clearBtn');
15105
15047
  if (clearBtn) {
15106
- // Force the clear button container visible — without :focus-within
15107
- // the CSS rule `.wrapper:not(:focus-within) .notification.clear`
15108
- // hides the container with display:none, preventing focus.
15109
- const clearContainer = clearBtn.closest('.clear');
15110
- if (clearContainer) {
15111
- clearContainer.style.display = 'flex';
15112
- clearBtn.addEventListener('focusout', () => {
15113
- requestAnimationFrame(() => {
15114
- clearContainer.style.display = '';
15115
- });
15116
- }, { once: true });
15117
- }
15118
-
15119
- // Focus the native button inside auro-button so the browser
15120
- // treats it as a real focusable element.
15121
- const nativeBtn = clearBtn.shadowRoot && clearBtn.shadowRoot.querySelector('button');
15122
- if (nativeBtn) {
15123
- nativeBtn.focus();
15124
- } else {
15125
- clearBtn.focus();
15126
- }
15048
+ clearBtn.focus();
15127
15049
  }
15128
15050
  }
15129
15051
 
@@ -15275,13 +15197,6 @@ class AuroCombobox extends AuroElement {
15275
15197
  this.input.setActiveDescendant(this.optionActive);
15276
15198
  }
15277
15199
 
15278
- // In fullscreen mode, focus is on inputInBib inside the dialog, so
15279
- // aria-activedescendant must also be set there for screen readers to
15280
- // follow the active option from the focused element.
15281
- if (this.inputInBib && this.dropdown.isBibFullscreen) {
15282
- this.inputInBib.setActiveDescendant(this.optionActive);
15283
- }
15284
-
15285
15200
  // Announce the active option for screen readers including position,
15286
15201
  // since shadow DOM boundaries prevent native reading of
15287
15202
  // aria-setsize/aria-posinset via aria-activedescendant.
@@ -15290,17 +15205,7 @@ class AuroCombobox extends AuroElement {
15290
15205
  const selectedState = this.optionActive.hasAttribute('selected') ? ', selected' : ', not selected';
15291
15206
  const optionIndex = this.availableOptions.indexOf(this.optionActive) + 1;
15292
15207
  const optionCount = this.availableOptions.length;
15293
-
15294
- // In fullscreen mode the combobox's live region is outside the modal
15295
- // dialog and inert, so route announcements to the bib's live region
15296
- // which is inside the dialog.
15297
- const bibEl = this.dropdown.bibElement && this.dropdown.bibElement.value;
15298
- const bibShadowRoot = bibEl && bibEl.shadowRoot;
15299
- const announcementRoot = this.dropdown.isBibFullscreen && bibShadowRoot
15300
- ? bibShadowRoot
15301
- : this.shadowRoot;
15302
-
15303
- announceToScreenReader(announcementRoot, `${optionText}${selectedState}, ${optionIndex} of ${optionCount}`);
15208
+ announceToScreenReader(this.shadowRoot, `${optionText}${selectedState}, ${optionIndex} of ${optionCount}`);
15304
15209
  }
15305
15210
 
15306
15211
  // Check if user prefers reduced motion for accessibility
@@ -16503,7 +16408,7 @@ class MenuService {
16503
16408
  * @returns {AuroMenuOption|null}
16504
16409
  */
16505
16410
  get highlightedOption() {
16506
- return this._menuOptions[this.highlightedIndex] || null;
16411
+ return this._highlightedOption;
16507
16412
  }
16508
16413
 
16509
16414
  /**
@@ -16591,6 +16496,7 @@ class MenuService {
16591
16496
  this.selectAllMatchingOptions = undefined;
16592
16497
 
16593
16498
  this.highlightedIndex = -1;
16499
+ this._highlightedOption = null;
16594
16500
 
16595
16501
  this._menuOptions = [];
16596
16502
  this._subscribers = [];
@@ -16641,6 +16547,7 @@ class MenuService {
16641
16547
  this._pendingValue = null;
16642
16548
  this._pendingRetryScheduled = false;
16643
16549
  this._pendingRetryCount = 0;
16550
+ this._highlightedOption = null;
16644
16551
  }
16645
16552
 
16646
16553
  /**
@@ -16698,8 +16605,12 @@ class MenuService {
16698
16605
  */
16699
16606
  moveHighlightedOption(direction) {
16700
16607
 
16701
- // Get the active options
16702
- const activeOptions = this._menuOptions.filter(option => option.isActive);
16608
+ // Build a flattened list of all active options from the full menu subtree in
16609
+ // DOM order so that nested <auro-menu> options participate in traversal.
16610
+ // querySelectorAll walks the entire light-DOM subtree and is not limited to
16611
+ // direct children, which is what caused nested options to be unreachable.
16612
+ const allOptions = Array.from(this.host.querySelectorAll('auro-menuoption, [auro-menuoption]'));
16613
+ const activeOptions = allOptions.filter(option => option.isActive);
16703
16614
 
16704
16615
  // Get the currently active option
16705
16616
  const currentActiveOption = activeOptions[activeOptions.indexOf(this.highlightedOption)];
@@ -16729,15 +16640,39 @@ class MenuService {
16729
16640
 
16730
16641
  if (!option) return;
16731
16642
 
16732
- // Get the index of the option to highlight
16643
+ // If the previously highlighted option belongs to a nested menu's own
16644
+ // MenuService (i.e. not in this._menuOptions), notify() won't reach it —
16645
+ // subscribers are per-service. Deactivate it directly so it loses its
16646
+ // highlighted CSS class before we move on.
16647
+ const prevOption = this._highlightedOption;
16648
+ if (prevOption && !this._menuOptions.includes(prevOption)) {
16649
+ prevOption.active = false;
16650
+ prevOption.updateActiveClasses();
16651
+ }
16652
+
16653
+ // Track by direct reference so nested options (not in _menuOptions) are
16654
+ // correctly remembered for the next navigation call.
16655
+ this._highlightedOption = option;
16656
+
16657
+ // highlightedIndex reflects position within the registered _menuOptions array.
16658
+ // For options that live in a nested menu's own MenuService this will be -1,
16659
+ // which is acceptable — the index is informational only.
16733
16660
  const index = this._menuOptions.indexOf(option);
16734
16661
 
16735
16662
  // Update highlighted index
16736
16663
  this.highlightedIndex = index;
16737
16664
 
16738
- // Notify subscribers of highlight change
16665
+ // Notify root-level subscribers of the highlight change. This correctly
16666
+ // activates/deactivates options that subscribed to THIS service.
16739
16667
  this.notify({ type: 'highlightChange', option, index: this.highlightedIndex });
16740
16668
 
16669
+ // If the new option is nested (not in this._menuOptions), notify() won't
16670
+ // reach it either. Activate it directly so it gains the highlighted class.
16671
+ if (!this._menuOptions.includes(option)) {
16672
+ option.active = true;
16673
+ option.updateActiveClasses();
16674
+ }
16675
+
16741
16676
  // Dispatch the change event
16742
16677
  this.dispatchChangeEvent('auroMenu-activatedOption', option);
16743
16678
  }
@@ -16751,6 +16686,20 @@ class MenuService {
16751
16686
  this.setHighlightedOption(option);
16752
16687
  }
16753
16688
 
16689
+ /**
16690
+ * Clears the highlighted option and removes its active CSS class.
16691
+ * Call this when the dropdown closes so the next open starts from a clean state.
16692
+ */
16693
+ clearHighlight() {
16694
+ const prev = this._highlightedOption;
16695
+ if (prev) {
16696
+ prev.active = false;
16697
+ prev.updateActiveClasses();
16698
+ }
16699
+ this._highlightedOption = null;
16700
+ this.highlightedIndex = -1;
16701
+ }
16702
+
16754
16703
  /**
16755
16704
  * Selects the currently highlighted option.
16756
16705
  */
@@ -16899,6 +16848,26 @@ class MenuService {
16899
16848
  return;
16900
16849
  }
16901
16850
 
16851
+ // Before treating this as a hard miss, scan the full DOM subtree for
16852
+ // nested menuoptions whose keys match. Nested options register with
16853
+ // their own MenuService instance (context isolation), so they never
16854
+ // appear in this._menuOptions.
16855
+ const allOptions = Array.from(this.host.querySelectorAll('auro-menuoption, [auro-menuoption]'));
16856
+ const nestedMatches = allOptions.filter(option =>
16857
+ !this._menuOptions.includes(option) &&
16858
+ option.isActive &&
16859
+ validatedValues.includes(option.key)
16860
+ );
16861
+
16862
+ if (nestedMatches.length) {
16863
+ this.clearPendingValue();
16864
+ const selected = this.multiSelect ? nestedMatches : [nestedMatches[nestedMatches.length - 1]];
16865
+ if (this.optionsArraysMatch(selected, this.selectedOptions)) return;
16866
+ this.selectedOptions = selected;
16867
+ this.stageUpdate();
16868
+ return;
16869
+ }
16870
+
16902
16871
  this.clearPendingValue();
16903
16872
 
16904
16873
  if (this.selectedOptions.length > 0) {
@@ -17025,6 +16994,16 @@ class MenuService {
17025
16994
  selectedOptions: this.selectedOptions,
17026
16995
  ...meta
17027
16996
  });
16997
+
16998
+ // Options subscribed to a nested menu's own service never receive the
16999
+ // notify() broadcast above. Sync their selected state directly so the
17000
+ // DOM attribute stays accurate and dual-selection cannot occur.
17001
+ const allOptions = Array.from(this.host.querySelectorAll('auro-menuoption, [auro-menuoption]'));
17002
+ allOptions.forEach(option => {
17003
+ if (!this._menuOptions.includes(option)) {
17004
+ option.setInternalSelected(this.selectedOptions.includes(option));
17005
+ }
17006
+ });
17028
17007
  }
17029
17008
 
17030
17009
  /**