@aurodesignsystem/auro-formkit 5.10.0 → 5.11.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 (77) hide show
  1. package/CHANGELOG.md +55 -15
  2. package/components/bibtemplate/dist/auro-bibtemplate.d.ts +6 -0
  3. package/components/bibtemplate/dist/index.js +12 -0
  4. package/components/bibtemplate/dist/registered.js +12 -0
  5. package/components/checkbox/demo/api.min.js +3 -3
  6. package/components/checkbox/demo/index.min.js +3 -3
  7. package/components/checkbox/dist/index.js +3 -3
  8. package/components/checkbox/dist/registered.js +3 -3
  9. package/components/combobox/demo/api.min.js +1140 -305
  10. package/components/combobox/demo/index.min.js +1140 -305
  11. package/components/combobox/dist/auro-combobox.d.ts +24 -1
  12. package/components/combobox/dist/comboboxKeyboardStrategy.d.ts +6 -0
  13. package/components/combobox/dist/index.js +1082 -264
  14. package/components/combobox/dist/registered.js +1082 -264
  15. package/components/counter/demo/api.min.js +583 -172
  16. package/components/counter/demo/index.min.js +583 -172
  17. package/components/counter/dist/auro-counter.d.ts +8 -0
  18. package/components/counter/dist/buttonVersion.d.ts +1 -1
  19. package/components/counter/dist/iconVersion.d.ts +1 -1
  20. package/components/counter/dist/index.js +583 -172
  21. package/components/counter/dist/registered.js +583 -172
  22. package/components/datepicker/demo/api.md +108 -85
  23. package/components/datepicker/demo/api.min.js +872 -257
  24. package/components/datepicker/demo/index.md +18 -12
  25. package/components/datepicker/demo/index.min.js +872 -257
  26. package/components/datepicker/dist/auro-calendar.d.ts +6 -0
  27. package/components/datepicker/dist/auro-datepicker.d.ts +11 -1
  28. package/components/datepicker/dist/index.js +819 -208
  29. package/components/datepicker/dist/registered.js +819 -208
  30. package/components/dropdown/demo/api.md +15 -17
  31. package/components/dropdown/demo/api.min.js +537 -183
  32. package/components/dropdown/demo/index.min.js +537 -183
  33. package/components/dropdown/dist/auro-dropdown.d.ts +27 -1
  34. package/components/dropdown/dist/auro-dropdownBib.d.ts +87 -0
  35. package/components/dropdown/dist/index.js +514 -160
  36. package/components/dropdown/dist/keyboardUtils.d.ts +18 -0
  37. package/components/dropdown/dist/registered.js +514 -160
  38. package/components/form/README.md +47 -2
  39. package/components/form/demo/api.js +2 -0
  40. package/components/form/demo/api.md +303 -30
  41. package/components/form/demo/api.min.js +69256 -62
  42. package/components/form/demo/index.html +0 -1
  43. package/components/form/demo/index.js +1 -0
  44. package/components/form/demo/index.md +1 -275
  45. package/components/form/demo/index.min.js +69255 -62
  46. package/components/form/demo/readme.md +47 -2
  47. package/components/form/demo/working.html +123 -32
  48. package/components/form/dist/auro-form.d.ts +98 -61
  49. package/components/form/dist/index.js +135 -51
  50. package/components/form/dist/registered.js +135 -51
  51. package/components/input/demo/api.md +1 -0
  52. package/components/input/demo/api.min.js +78 -24
  53. package/components/input/demo/index.min.js +78 -24
  54. package/components/input/dist/base-input.d.ts +34 -0
  55. package/components/input/dist/index.js +78 -24
  56. package/components/input/dist/registered.js +78 -24
  57. package/components/menu/demo/api.md +4 -10
  58. package/components/menu/demo/api.min.js +18 -5
  59. package/components/menu/demo/index.min.js +18 -5
  60. package/components/menu/dist/auro-menuoption.d.ts +0 -8
  61. package/components/menu/dist/iconVersion.d.ts +1 -1
  62. package/components/menu/dist/index.js +18 -5
  63. package/components/menu/dist/registered.js +18 -5
  64. package/components/radio/demo/api.min.js +3 -3
  65. package/components/radio/demo/index.min.js +3 -3
  66. package/components/radio/dist/index.js +3 -3
  67. package/components/radio/dist/registered.js +3 -3
  68. package/components/select/demo/api.js +2 -0
  69. package/components/select/demo/api.md +333 -78
  70. package/components/select/demo/api.min.js +945 -282
  71. package/components/select/demo/index.min.js +933 -282
  72. package/components/select/dist/auro-select.d.ts +26 -0
  73. package/components/select/dist/index.js +881 -247
  74. package/components/select/dist/registered.js +881 -247
  75. package/components/select/dist/selectKeyboardStrategy.d.ts +8 -0
  76. package/custom-elements.json +596 -89
  77. package/package.json +7 -5
@@ -300,7 +300,7 @@ let p$3 = class p{registerComponent(t,a){customElements.get(t)||customElements.d
300
300
  </div>
301
301
  `}};
302
302
 
303
- var iconVersion$2 = '9.1.0';
303
+ var iconVersion$2 = '9.1.2';
304
304
 
305
305
  class DateFormatter {
306
306
 
@@ -1058,7 +1058,7 @@ class AuroFormValidation {
1058
1058
  }
1059
1059
  }
1060
1060
 
1061
- if (!hasValue && elem.required && elem.touched) {
1061
+ if (!hasValue && elem.required && (force || elem.touched)) {
1062
1062
  elem.validity = 'valueMissing';
1063
1063
  elem.errorMessage = elem.setCustomValidityValueMissing || elem.setCustomValidity || '';
1064
1064
  } else if (hasValue && this.runtimeUtils.elementMatch(elem, 'auro-input')) {
@@ -1082,7 +1082,7 @@ class AuroFormValidation {
1082
1082
  if (!isCombobox || isCombobox && !elem.persistInput) {
1083
1083
 
1084
1084
  // run validation on all inputs since we're going to use them to set the validity of this component
1085
- this.auroInputElements.forEach(input => input.validate());
1085
+ this.auroInputElements.forEach(input => input.validate(force));
1086
1086
 
1087
1087
  // Reset element validity to the validity of the input
1088
1088
  elem.validity = this.auroInputElements[0].validity;
@@ -1173,6 +1173,34 @@ class AuroFormValidation {
1173
1173
  }
1174
1174
  }
1175
1175
 
1176
+ /**
1177
+ * Announces text to screen readers via an `aria-live` region inside the given shadow root.
1178
+ *
1179
+ * Expects the shadow root to contain an element with `id="srAnnouncement"`.
1180
+ * The text is cleared and re-set inside a `requestAnimationFrame` so that
1181
+ * repeated identical announcements still fire, and is cleared again after
1182
+ * {@link ANNOUNCEMENT_DURATION_MS} so VoiceOver cannot swipe to stale text.
1183
+ *
1184
+ * @param {ShadowRoot} shadowRoot - The shadow root containing the live region.
1185
+ * @param {string} text - The text to announce.
1186
+ */
1187
+
1188
+
1189
+ /**
1190
+ * Schedules a callback after two animation frames.
1191
+ *
1192
+ * Used when opening a fullscreen dialog to wait for the dialog to render
1193
+ * (first frame) and then for a Lit update cycle to complete (second frame)
1194
+ * before performing an action like focusing the close button.
1195
+ *
1196
+ * @param {Function} fn - The callback to execute after two animation frames.
1197
+ */
1198
+ function doubleRaf(fn) {
1199
+ requestAnimationFrame(() => {
1200
+ requestAnimationFrame(fn);
1201
+ });
1202
+ }
1203
+
1176
1204
  // Copyright (c) Alaska Air. All right reserved. Licensed under the Apache-2.0 license
1177
1205
  // See LICENSE in the project root for license information.
1178
1206
 
@@ -1442,7 +1470,7 @@ let AuroHelpText$1 = class AuroHelpText extends i$2 {
1442
1470
  }
1443
1471
  };
1444
1472
 
1445
- var formkitVersion$1 = '202602140013';
1473
+ var formkitVersion$1 = '202603102257';
1446
1474
 
1447
1475
  // Copyright (c) 2025 Alaska Airlines. All right reserved. Licensed under the Apache-2.0 license
1448
1476
  // See LICENSE in the project root for license information.
@@ -1459,6 +1487,13 @@ var formkitVersion$1 = '202602140013';
1459
1487
  * @slot description - Descriptive content for the counter.
1460
1488
  */
1461
1489
  class AuroCounter extends i$2 {
1490
+ static get shadowRootOptions() {
1491
+ return {
1492
+ ...i$2.shadowRootOptions,
1493
+ delegatesFocus: true,
1494
+ };
1495
+ }
1496
+
1462
1497
  constructor() {
1463
1498
  super();
1464
1499
 
@@ -1505,14 +1540,6 @@ class AuroCounter extends i$2 {
1505
1540
  */
1506
1541
  this.runtimeUtils = new AuroLibraryRuntimeUtils$4();
1507
1542
 
1508
- /**
1509
- * @private
1510
- * @property {boolean} delegatesFocus - Whether the shadow root delegates focus.
1511
- */
1512
- this.constructor.shadowRootOptions = {
1513
- ...i$2.shadowRootOptions,
1514
- delegatesFocus: true,
1515
- };
1516
1543
  }
1517
1544
 
1518
1545
  connectedCallback() {
@@ -1827,7 +1854,7 @@ class AuroCounter extends i$2 {
1827
1854
  aria-valuemax="${this.max}"
1828
1855
  aria-valuemin="${this.min}"
1829
1856
  aria-valuenow="${this.value}"
1830
- aria-valuetext="${this.value !== undefined ? this.value : this.min}"
1857
+ aria-valuetext="'${this.value !== undefined ? this.value : this.min}'"
1831
1858
  role="spinbutton"
1832
1859
  tabindex="${this.disabled ? '-1' : '0'}"
1833
1860
  >
@@ -3612,11 +3639,9 @@ const computePosition = (reference, floating, options) => {
3612
3639
  /* eslint-disable line-comment-position, no-inline-comments */
3613
3640
 
3614
3641
 
3615
-
3616
3642
  const MAX_CONFIGURATION_COUNT = 10;
3617
3643
 
3618
3644
  class AuroFloatingUI {
3619
-
3620
3645
  /**
3621
3646
  * @private
3622
3647
  */
@@ -3631,7 +3656,11 @@ class AuroFloatingUI {
3631
3656
  * @private
3632
3657
  */
3633
3658
  static setupMousePressChecker() {
3634
- if (!AuroFloatingUI.isMousePressHandlerInitialized && window && window.addEventListener) {
3659
+ if (
3660
+ !AuroFloatingUI.isMousePressHandlerInitialized &&
3661
+ window &&
3662
+ window.addEventListener
3663
+ ) {
3635
3664
  AuroFloatingUI.isMousePressHandlerInitialized = true;
3636
3665
 
3637
3666
  // Track timeout for isMousePressed reset to avoid race conditions
@@ -3639,7 +3668,7 @@ class AuroFloatingUI {
3639
3668
  AuroFloatingUI._mousePressedTimeout = null;
3640
3669
  }
3641
3670
  const mouseEventGlobalHandler = (event) => {
3642
- const isPressed = event.type === 'mousedown';
3671
+ const isPressed = event.type === "mousedown";
3643
3672
  if (isPressed) {
3644
3673
  // Clear any pending timeout to prevent race condition
3645
3674
  if (AuroFloatingUI._mousePressedTimeout !== null) {
@@ -3658,8 +3687,8 @@ class AuroFloatingUI {
3658
3687
  }
3659
3688
  };
3660
3689
 
3661
- window.addEventListener('mousedown', mouseEventGlobalHandler);
3662
- window.addEventListener('mouseup', mouseEventGlobalHandler);
3690
+ window.addEventListener("mousedown", mouseEventGlobalHandler);
3691
+ window.addEventListener("mouseup", mouseEventGlobalHandler);
3663
3692
  }
3664
3693
  }
3665
3694
 
@@ -3707,11 +3736,12 @@ class AuroFloatingUI {
3707
3736
  // mirror the boxsize from bibSizer
3708
3737
  if (this.element.bibSizer && this.element.matchWidth) {
3709
3738
  const sizerStyle = window.getComputedStyle(this.element.bibSizer);
3710
- const bibContent = this.element.bib.shadowRoot.querySelector(".container");
3711
- if (sizerStyle.width !== '0px') {
3739
+ const bibContent =
3740
+ this.element.bib.shadowRoot.querySelector(".container");
3741
+ if (sizerStyle.width !== "0px") {
3712
3742
  bibContent.style.width = sizerStyle.width;
3713
3743
  }
3714
- if (sizerStyle.height !== '0px') {
3744
+ if (sizerStyle.height !== "0px") {
3715
3745
  bibContent.style.height = sizerStyle.height;
3716
3746
  }
3717
3747
  bibContent.style.maxWidth = sizerStyle.maxWidth;
@@ -3729,28 +3759,34 @@ class AuroFloatingUI {
3729
3759
  * @returns {String} The positioning strategy, one of 'fullscreen', 'floating', 'cover'.
3730
3760
  */
3731
3761
  getPositioningStrategy() {
3732
- const breakpoint = this.element.bib.mobileFullscreenBreakpoint || this.element.floaterConfig?.fullscreenBreakpoint;
3762
+ const breakpoint =
3763
+ this.element.bib.mobileFullscreenBreakpoint ||
3764
+ this.element.floaterConfig?.fullscreenBreakpoint;
3733
3765
  switch (this.behavior) {
3734
3766
  case "tooltip":
3735
3767
  return "floating";
3736
3768
  case "dialog":
3737
3769
  case "drawer":
3738
3770
  if (breakpoint) {
3739
- const smallerThanBreakpoint = window.matchMedia(`(max-width: ${breakpoint})`).matches;
3771
+ const smallerThanBreakpoint = window.matchMedia(
3772
+ `(max-width: ${breakpoint})`,
3773
+ ).matches;
3740
3774
 
3741
3775
  this.element.expanded = smallerThanBreakpoint;
3742
3776
  }
3743
3777
  if (this.element.nested) {
3744
3778
  return "cover";
3745
3779
  }
3746
- return 'fullscreen';
3780
+ return "fullscreen";
3747
3781
  case "dropdown":
3748
3782
  case undefined:
3749
3783
  case null:
3750
3784
  if (breakpoint) {
3751
- const smallerThanBreakpoint = window.matchMedia(`(max-width: ${breakpoint})`).matches;
3785
+ const smallerThanBreakpoint = window.matchMedia(
3786
+ `(max-width: ${breakpoint})`,
3787
+ ).matches;
3752
3788
  if (smallerThanBreakpoint) {
3753
- return 'fullscreen';
3789
+ return "fullscreen";
3754
3790
  }
3755
3791
  }
3756
3792
  return "floating";
@@ -3771,37 +3807,39 @@ class AuroFloatingUI {
3771
3807
  const strategy = this.getPositioningStrategy();
3772
3808
  this.configureBibStrategy(strategy);
3773
3809
 
3774
- if (strategy === 'floating') {
3810
+ if (strategy === "floating") {
3775
3811
  this.mirrorSize();
3776
3812
  // Define the middlware for the floater configuration
3777
3813
  const middleware = [
3778
3814
  offset(this.element.floaterConfig?.offset || 0),
3779
- ...this.element.floaterConfig?.shift ? [shift()] : [], // Add shift middleware if shift is enabled.
3780
- ...this.element.floaterConfig?.flip ? [flip()] : [], // Add flip middleware if flip is enabled.
3781
- ...this.element.floaterConfig?.autoPlacement ? [autoPlacement()] : [], // Add autoPlacement middleware if autoPlacement is enabled.
3815
+ ...(this.element.floaterConfig?.shift ? [shift()] : []), // Add shift middleware if shift is enabled.
3816
+ ...(this.element.floaterConfig?.flip ? [flip()] : []), // Add flip middleware if flip is enabled.
3817
+ ...(this.element.floaterConfig?.autoPlacement ? [autoPlacement()] : []), // Add autoPlacement middleware if autoPlacement is enabled.
3782
3818
  ];
3783
3819
 
3784
3820
  // Compute the position of the bib
3785
3821
  computePosition(this.element.trigger, this.element.bib, {
3786
- strategy: this.element.floaterConfig?.strategy || 'fixed',
3822
+ strategy: this.element.floaterConfig?.strategy || "fixed",
3787
3823
  placement: this.element.floaterConfig?.placement,
3788
- middleware: middleware || []
3789
- }).then(({ x, y }) => { // eslint-disable-line id-length
3824
+ middleware: middleware || [],
3825
+ }).then(({ x, y }) => {
3826
+ // eslint-disable-line id-length
3790
3827
  Object.assign(this.element.bib.style, {
3791
3828
  left: `${x}px`,
3792
3829
  top: `${y}px`,
3793
3830
  });
3794
3831
  });
3795
- } else if (strategy === 'cover') {
3832
+ } else if (strategy === "cover") {
3796
3833
  // Compute the position of the bib
3797
3834
  computePosition(this.element.parentNode, this.element.bib, {
3798
- placement: 'bottom-start'
3799
- }).then(({ x, y }) => { // eslint-disable-line id-length
3835
+ placement: "bottom-start",
3836
+ }).then(({ x, y }) => {
3837
+ // eslint-disable-line id-length
3800
3838
  Object.assign(this.element.bib.style, {
3801
3839
  left: `${x}px`,
3802
3840
  top: `${y - this.element.parentNode.offsetHeight}px`,
3803
3841
  width: `${this.element.parentNode.offsetWidth}px`,
3804
- height: `${this.element.parentNode.offsetHeight}px`
3842
+ height: `${this.element.parentNode.offsetHeight}px`,
3805
3843
  });
3806
3844
  });
3807
3845
  }
@@ -3814,12 +3852,12 @@ class AuroFloatingUI {
3814
3852
  */
3815
3853
  lockScroll(lock = true) {
3816
3854
  if (lock) {
3817
- document.body.style.overflow = 'hidden'; // hide body's scrollbar
3855
+ document.body.style.overflow = "hidden"; // hide body's scrollbar
3818
3856
 
3819
3857
  // Move `bib` by the amount the viewport is shifted to stay aligned in fullscreen.
3820
3858
  this.element.bib.style.transform = `translateY(${window?.visualViewport?.offsetTop}px)`;
3821
3859
  } else {
3822
- document.body.style.overflow = '';
3860
+ document.body.style.overflow = "";
3823
3861
  }
3824
3862
  }
3825
3863
 
@@ -3833,23 +3871,24 @@ class AuroFloatingUI {
3833
3871
  * @param {string} strategy - The positioning strategy ('fullscreen' or 'floating').
3834
3872
  */
3835
3873
  configureBibStrategy(value) {
3836
- if (value === 'fullscreen') {
3874
+ if (value === "fullscreen") {
3837
3875
  this.element.isBibFullscreen = true;
3838
3876
  // reset the prev position
3839
- this.element.bib.setAttribute('isfullscreen', "");
3840
- this.element.bib.style.position = 'fixed';
3877
+ this.element.bib.setAttribute("isfullscreen", "");
3878
+ this.element.bib.style.position = "fixed";
3841
3879
  this.element.bib.style.top = "0px";
3842
3880
  this.element.bib.style.left = "0px";
3843
- this.element.bib.style.width = '';
3844
- this.element.bib.style.height = '';
3845
- this.element.style.contain = '';
3881
+ this.element.bib.style.width = "";
3882
+ this.element.bib.style.height = "";
3883
+ this.element.style.contain = "";
3846
3884
 
3847
3885
  // reset the size that was mirroring `size` css-part
3848
- const bibContent = this.element.bib.shadowRoot.querySelector(".container");
3886
+ const bibContent =
3887
+ this.element.bib.shadowRoot.querySelector(".container");
3849
3888
  if (bibContent) {
3850
- bibContent.style.width = '';
3851
- bibContent.style.height = '';
3852
- bibContent.style.maxWidth = '';
3889
+ bibContent.style.width = "";
3890
+ bibContent.style.height = "";
3891
+ bibContent.style.maxWidth = "";
3853
3892
  bibContent.style.maxHeight = `${window?.visualViewport?.height}px`;
3854
3893
  this.configureTrial = 0;
3855
3894
  } else if (this.configureTrial < MAX_CONFIGURATION_COUNT) {
@@ -3864,21 +3903,26 @@ class AuroFloatingUI {
3864
3903
  this.lockScroll(true);
3865
3904
  }
3866
3905
  } else {
3867
- this.element.bib.style.position = '';
3868
- this.element.bib.removeAttribute('isfullscreen');
3906
+ this.element.bib.style.position = "";
3907
+ this.element.bib.removeAttribute("isfullscreen");
3869
3908
  this.element.isBibFullscreen = false;
3870
- this.element.style.contain = 'layout';
3909
+ this.element.style.contain = "layout";
3871
3910
  }
3872
3911
 
3873
3912
  const isChanged = this.strategy && this.strategy !== value;
3874
3913
  this.strategy = value;
3875
3914
  if (isChanged) {
3876
- const event = new CustomEvent(this.eventPrefix ? `${this.eventPrefix}-strategy-change` : 'strategy-change', {
3877
- detail: {
3878
- value,
3915
+ const event = new CustomEvent(
3916
+ this.eventPrefix
3917
+ ? `${this.eventPrefix}-strategy-change`
3918
+ : "strategy-change",
3919
+ {
3920
+ detail: {
3921
+ value,
3922
+ },
3923
+ composed: true,
3879
3924
  },
3880
- composed: true
3881
- });
3925
+ );
3882
3926
 
3883
3927
  this.element.dispatchEvent(event);
3884
3928
  }
@@ -3910,19 +3954,24 @@ class AuroFloatingUI {
3910
3954
  return;
3911
3955
  }
3912
3956
 
3913
- if (this.element.noHideOnThisFocusLoss ||
3914
- this.element.hasAttribute('noHideOnThisFocusLoss')) {
3957
+ if (
3958
+ this.element.noHideOnThisFocusLoss ||
3959
+ this.element.hasAttribute("noHideOnThisFocusLoss")
3960
+ ) {
3915
3961
  return;
3916
3962
  }
3917
3963
 
3918
3964
  const { activeElement } = document;
3919
3965
  // if focus is still inside of trigger or bib, do not close
3920
- if (this.element.contains(activeElement) || this.element.bib?.contains(activeElement)) {
3966
+ if (
3967
+ this.element.contains(activeElement) ||
3968
+ this.element.bib?.contains(activeElement)
3969
+ ) {
3921
3970
  return;
3922
3971
  }
3923
3972
 
3924
3973
  // if fullscreen bib is in fullscreen mode, do not close
3925
- if (this.element.bib.hasAttribute('isfullscreen')) {
3974
+ if (this.element.bib.hasAttribute("isfullscreen")) {
3926
3975
  return;
3927
3976
  }
3928
3977
 
@@ -3934,12 +3983,27 @@ class AuroFloatingUI {
3934
3983
  this.focusHandler = () => this.handleFocusLoss();
3935
3984
 
3936
3985
  this.clickHandler = (evt) => {
3937
- if ((!evt.composedPath().includes(this.element.trigger) &&
3938
- !evt.composedPath().includes(this.element.bib)) ||
3939
- (this.element.bib.backdrop && evt.composedPath().includes(this.element.bib.backdrop))) {
3940
- const existedVisibleFloatingUI = document.expandedAuroFormkitDropdown || document.expandedAuroFloater;
3986
+ // When the bib is fullscreen (modal dialog), don't close on outside
3987
+ // clicks. VoiceOver's synthetic click events inside a top-layer modal
3988
+ // <dialog> may not include the bib in composedPath(), causing false
3989
+ // positives. This mirrors the fullscreen guard in handleFocusLoss().
3990
+ if (this.element.bib && this.element.bib.hasAttribute("isfullscreen")) {
3991
+ return;
3992
+ }
3941
3993
 
3942
- if (existedVisibleFloatingUI && existedVisibleFloatingUI.element.isPopoverVisible) {
3994
+ if (
3995
+ (!evt.composedPath().includes(this.element.trigger) &&
3996
+ !evt.composedPath().includes(this.element.bib)) ||
3997
+ (this.element.bib.backdrop &&
3998
+ evt.composedPath().includes(this.element.bib.backdrop))
3999
+ ) {
4000
+ const existedVisibleFloatingUI =
4001
+ document.expandedAuroFormkitDropdown || document.expandedAuroFloater;
4002
+
4003
+ if (
4004
+ existedVisibleFloatingUI &&
4005
+ existedVisibleFloatingUI.element.isPopoverVisible
4006
+ ) {
3943
4007
  // if something else is open, close that
3944
4008
  existedVisibleFloatingUI.hideBib();
3945
4009
  document.expandedAuroFormkitDropdown = null;
@@ -3952,9 +4016,14 @@ class AuroFloatingUI {
3952
4016
 
3953
4017
  // ESC key handler
3954
4018
  this.keyDownHandler = (evt) => {
3955
- if (evt.key === 'Escape' && this.element.isPopoverVisible) {
3956
- const existedVisibleFloatingUI = document.expandedAuroFormkitDropdown || document.expandedAuroFloater;
3957
- if (existedVisibleFloatingUI && existedVisibleFloatingUI !== this && existedVisibleFloatingUI.element.isPopoverVisible) {
4019
+ if (evt.key === "Escape" && this.element.isPopoverVisible) {
4020
+ const existedVisibleFloatingUI =
4021
+ document.expandedAuroFormkitDropdown || document.expandedAuroFloater;
4022
+ if (
4023
+ existedVisibleFloatingUI &&
4024
+ existedVisibleFloatingUI !== this &&
4025
+ existedVisibleFloatingUI.element.isPopoverVisible
4026
+ ) {
3958
4027
  // if something else is open, let it handle itself
3959
4028
  return;
3960
4029
  }
@@ -3962,17 +4031,17 @@ class AuroFloatingUI {
3962
4031
  }
3963
4032
  };
3964
4033
 
3965
- if (this.behavior !== 'drawer' && this.behavior !== 'dialog') {
4034
+ if (this.behavior !== "drawer" && this.behavior !== "dialog") {
3966
4035
  // Add event listeners using the stored references
3967
- document.addEventListener('focusin', this.focusHandler);
4036
+ document.addEventListener("focusin", this.focusHandler);
3968
4037
  }
3969
4038
 
3970
- document.addEventListener('keydown', this.keyDownHandler);
4039
+ document.addEventListener("keydown", this.keyDownHandler);
3971
4040
 
3972
4041
  // send this task to the end of queue to prevent conflicting
3973
4042
  // it conflicts if showBib gets call from a button that's not this.element.trigger
3974
4043
  setTimeout(() => {
3975
- window.addEventListener('click', this.clickHandler);
4044
+ window.addEventListener("click", this.clickHandler);
3976
4045
  }, 0);
3977
4046
  }
3978
4047
 
@@ -3980,34 +4049,38 @@ class AuroFloatingUI {
3980
4049
  // Remove event listeners if they exist
3981
4050
 
3982
4051
  if (this.focusHandler) {
3983
- document.removeEventListener('focusin', this.focusHandler);
4052
+ document.removeEventListener("focusin", this.focusHandler);
3984
4053
  this.focusHandler = null;
3985
4054
  }
3986
4055
 
3987
4056
  if (this.clickHandler) {
3988
- window.removeEventListener('click', this.clickHandler);
4057
+ window.removeEventListener("click", this.clickHandler);
3989
4058
  this.clickHandler = null;
3990
4059
  }
3991
4060
 
3992
4061
  if (this.keyDownHandler) {
3993
- document.removeEventListener('keydown', this.keyDownHandler);
4062
+ document.removeEventListener("keydown", this.keyDownHandler);
3994
4063
  this.keyDownHandler = null;
3995
4064
  }
3996
4065
  }
3997
4066
 
3998
4067
  handleUpdate(changedProperties) {
3999
- if (changedProperties.has('isPopoverVisible')) {
4068
+ if (changedProperties.has("isPopoverVisible")) {
4000
4069
  this.updateState();
4001
4070
  }
4002
4071
  }
4003
4072
 
4004
4073
  updateCurrentExpandedDropdown() {
4005
4074
  // Close any other dropdown that is already open
4006
- const existedVisibleFloatingUI = document.expandedAuroFormkitDropdown || document.expandedAuroFloater;
4007
- if (existedVisibleFloatingUI && existedVisibleFloatingUI !== this &&
4075
+ const existedVisibleFloatingUI =
4076
+ document.expandedAuroFormkitDropdown || document.expandedAuroFloater;
4077
+ if (
4078
+ existedVisibleFloatingUI &&
4079
+ existedVisibleFloatingUI !== this &&
4008
4080
  existedVisibleFloatingUI.element.isPopoverVisible &&
4009
- document.expandedAuroFloater.eventPrefix === this.eventPrefix) {
4010
- document.expandedAuroFloater.hideBib();
4081
+ existedVisibleFloatingUI.eventPrefix === this.eventPrefix
4082
+ ) {
4083
+ existedVisibleFloatingUI.hideBib();
4011
4084
  }
4012
4085
 
4013
4086
  document.expandedAuroFloater = this;
@@ -4016,7 +4089,7 @@ class AuroFloatingUI {
4016
4089
  showBib() {
4017
4090
  if (!this.element.disabled && !this.showing) {
4018
4091
  this.updateCurrentExpandedDropdown();
4019
- this.element.triggerChevron?.setAttribute('data-expanded', true);
4092
+ this.element.triggerChevron?.setAttribute("data-expanded", true);
4020
4093
 
4021
4094
  // prevent double showing: isPopovervisible gets first and showBib gets called later
4022
4095
  if (!this.showing) {
@@ -4030,9 +4103,13 @@ class AuroFloatingUI {
4030
4103
  }
4031
4104
 
4032
4105
  // Setup auto update to handle resize and scroll
4033
- this.element.cleanup = autoUpdate(this.element.trigger || this.element.parentNode, this.element.bib, () => {
4034
- this.position();
4035
- });
4106
+ this.element.cleanup = autoUpdate(
4107
+ this.element.trigger || this.element.parentNode,
4108
+ this.element.bib,
4109
+ () => {
4110
+ this.position();
4111
+ },
4112
+ );
4036
4113
  }
4037
4114
  }
4038
4115
 
@@ -4043,7 +4120,7 @@ class AuroFloatingUI {
4043
4120
  hideBib(eventType = "unknown") {
4044
4121
  if (!this.element.disabled && !this.element.noToggle) {
4045
4122
  this.lockScroll(false);
4046
- this.element.triggerChevron?.removeAttribute('data-expanded');
4123
+ this.element.triggerChevron?.removeAttribute("data-expanded");
4047
4124
 
4048
4125
  if (this.element.isPopoverVisible) {
4049
4126
  this.element.isPopoverVisible = false;
@@ -4063,13 +4140,16 @@ class AuroFloatingUI {
4063
4140
  * @param {String} eventType - The event type that triggered the toggle action.
4064
4141
  */
4065
4142
  dispatchEventDropdownToggle(eventType) {
4066
- const event = new CustomEvent(this.eventPrefix ? `${this.eventPrefix}-toggled` : 'toggled', {
4067
- detail: {
4068
- expanded: this.showing,
4069
- eventType: eventType || "unknown",
4143
+ const event = new CustomEvent(
4144
+ this.eventPrefix ? `${this.eventPrefix}-toggled` : "toggled",
4145
+ {
4146
+ detail: {
4147
+ expanded: this.showing,
4148
+ eventType: eventType || "unknown",
4149
+ },
4150
+ composed: true,
4070
4151
  },
4071
- composed: true
4072
- });
4152
+ );
4073
4153
 
4074
4154
  this.element.dispatchEvent(event);
4075
4155
  }
@@ -4081,12 +4161,15 @@ class AuroFloatingUI {
4081
4161
  this.showBib();
4082
4162
  }
4083
4163
 
4084
- const event = new CustomEvent(this.eventPrefix ? `${this.eventPrefix}-triggerClick` : "triggerClick", {
4085
- composed: true,
4086
- detail: {
4087
- expanded: this.element.isPopoverVisible
4088
- }
4089
- });
4164
+ const event = new CustomEvent(
4165
+ this.eventPrefix ? `${this.eventPrefix}-triggerClick` : "triggerClick",
4166
+ {
4167
+ composed: true,
4168
+ detail: {
4169
+ expanded: this.element.isPopoverVisible,
4170
+ },
4171
+ },
4172
+ );
4090
4173
 
4091
4174
  this.element.dispatchEvent(event);
4092
4175
  }
@@ -4094,30 +4177,32 @@ class AuroFloatingUI {
4094
4177
  handleEvent(event) {
4095
4178
  if (!this.element.disableEventShow) {
4096
4179
  switch (event.type) {
4097
- case 'keydown':
4180
+ case "keydown": {
4098
4181
  // Support both Enter and Space keys for accessibility
4099
4182
  // Space is included as it's expected behavior for interactive elements
4100
4183
 
4101
4184
  const origin = event.composedPath()[0];
4102
- if (event.key === 'Enter' || event.key === ' ' && (!origin || origin.tagName !== "INPUT")) {
4103
-
4185
+ if (
4186
+ event.key === "Enter" ||
4187
+ (event.key === " " && (!origin || origin.tagName !== "INPUT"))
4188
+ ) {
4104
4189
  event.preventDefault();
4105
4190
  this.handleClick();
4106
4191
  }
4107
4192
  break;
4108
- case 'mouseenter':
4193
+ }
4194
+ case "mouseenter":
4109
4195
  if (this.element.hoverToggle) {
4110
4196
  this.showBib();
4111
4197
  }
4112
4198
  break;
4113
- case 'mouseleave':
4199
+ case "mouseleave":
4114
4200
  if (this.element.hoverToggle) {
4115
4201
  this.hideBib("mouseleave");
4116
4202
  }
4117
4203
  break;
4118
- case 'focus':
4204
+ case "focus":
4119
4205
  if (this.element.focusShow) {
4120
-
4121
4206
  /*
4122
4207
  This needs to better handle clicking that gives focus -
4123
4208
  currently it shows and then immediately hides the bib
@@ -4125,12 +4210,12 @@ class AuroFloatingUI {
4125
4210
  this.showBib();
4126
4211
  }
4127
4212
  break;
4128
- case 'blur':
4213
+ case "blur":
4129
4214
  // send this task 100ms later queue to
4130
4215
  // wait a frame in case focus moves within the floating element/bib
4131
4216
  setTimeout(() => this.handleFocusLoss(), 0);
4132
4217
  break;
4133
- case 'click':
4218
+ case "click":
4134
4219
  if (document.activeElement === document.body) {
4135
4220
  event.currentTarget.focus();
4136
4221
  }
@@ -4149,15 +4234,15 @@ class AuroFloatingUI {
4149
4234
  */
4150
4235
  handleTriggerTabIndex() {
4151
4236
  const focusableElementSelectors = [
4152
- 'a',
4153
- 'button',
4237
+ "a",
4238
+ "button",
4154
4239
  'input:not([type="hidden"])',
4155
- 'select',
4156
- 'textarea',
4240
+ "select",
4241
+ "textarea",
4157
4242
  '[tabindex]:not([tabindex="-1"])',
4158
- 'auro-button',
4159
- 'auro-input',
4160
- 'auro-hyperlink'
4243
+ "auro-button",
4244
+ "auro-input",
4245
+ "auro-hyperlink",
4161
4246
  ];
4162
4247
 
4163
4248
  const triggerNode = this.element.querySelectorAll('[slot="trigger"]')[0];
@@ -4185,10 +4270,10 @@ class AuroFloatingUI {
4185
4270
  * @param {*} eventPrefix
4186
4271
  */
4187
4272
  regenerateBibId() {
4188
- this.id = this.element.getAttribute('id');
4273
+ this.id = this.element.getAttribute("id");
4189
4274
  if (!this.id) {
4190
4275
  this.id = window.crypto.randomUUID();
4191
- this.element.setAttribute('id', this.id);
4276
+ this.element.setAttribute("id", this.id);
4192
4277
  }
4193
4278
 
4194
4279
  this.element.bib.setAttribute("id", `${this.id}-floater-bib`);
@@ -4209,11 +4294,15 @@ class AuroFloatingUI {
4209
4294
  if (this.element.trigger) {
4210
4295
  this.disconnect();
4211
4296
  }
4212
- this.element.trigger = this.element.triggerElement || this.element.shadowRoot.querySelector('#trigger') || this.element.trigger;
4213
- this.element.bib = this.element.shadowRoot.querySelector('#bib') || this.element.bib;
4214
- this.element.bibSizer = this.element.shadowRoot.querySelector('#bibSizer');
4215
- this.element.triggerChevron = this.element.shadowRoot.querySelector('#showStateIcon');
4216
-
4297
+ this.element.trigger =
4298
+ this.element.triggerElement ||
4299
+ this.element.shadowRoot.querySelector("#trigger") ||
4300
+ this.element.trigger;
4301
+ this.element.bib =
4302
+ this.element.shadowRoot.querySelector("#bib") || this.element.bib;
4303
+ this.element.bibSizer = this.element.shadowRoot.querySelector("#bibSizer");
4304
+ this.element.triggerChevron =
4305
+ this.element.shadowRoot.querySelector("#showStateIcon");
4217
4306
 
4218
4307
  if (this.element.floaterConfig) {
4219
4308
  this.element.hoverToggle = this.element.floaterConfig.hoverToggle;
@@ -4224,12 +4313,12 @@ class AuroFloatingUI {
4224
4313
 
4225
4314
  this.handleEvent = this.handleEvent.bind(this);
4226
4315
  if (this.element.trigger) {
4227
- this.element.trigger.addEventListener('keydown', this.handleEvent);
4228
- this.element.trigger.addEventListener('click', this.handleEvent);
4229
- this.element.trigger.addEventListener('mouseenter', this.handleEvent);
4230
- this.element.trigger.addEventListener('mouseleave', this.handleEvent);
4231
- this.element.trigger.addEventListener('focus', this.handleEvent);
4232
- this.element.trigger.addEventListener('blur', this.handleEvent);
4316
+ this.element.trigger.addEventListener("keydown", this.handleEvent);
4317
+ this.element.trigger.addEventListener("click", this.handleEvent);
4318
+ this.element.trigger.addEventListener("mouseenter", this.handleEvent);
4319
+ this.element.trigger.addEventListener("mouseleave", this.handleEvent);
4320
+ this.element.trigger.addEventListener("focus", this.handleEvent);
4321
+ this.element.trigger.addEventListener("blur", this.handleEvent);
4233
4322
  }
4234
4323
  }
4235
4324
 
@@ -4244,12 +4333,18 @@ class AuroFloatingUI {
4244
4333
 
4245
4334
  // Remove event & keyboard listeners
4246
4335
  if (this.element?.trigger) {
4247
- this.element.trigger.removeEventListener('keydown', this.handleEvent);
4248
- this.element.trigger.removeEventListener('click', this.handleEvent);
4249
- this.element.trigger.removeEventListener('mouseenter', this.handleEvent);
4250
- this.element.trigger.removeEventListener('mouseleave', this.handleEvent);
4251
- this.element.trigger.removeEventListener('focus', this.handleEvent);
4252
- this.element.trigger.removeEventListener('blur', this.handleEvent);
4336
+ this.element.trigger.removeEventListener("keydown", this.handleEvent);
4337
+ this.element.trigger.removeEventListener("click", this.handleEvent);
4338
+ this.element.trigger.removeEventListener(
4339
+ "mouseenter",
4340
+ this.handleEvent,
4341
+ );
4342
+ this.element.trigger.removeEventListener(
4343
+ "mouseleave",
4344
+ this.handleEvent,
4345
+ );
4346
+ this.element.trigger.removeEventListener("focus", this.handleEvent);
4347
+ this.element.trigger.removeEventListener("blur", this.handleEvent);
4253
4348
  }
4254
4349
  }
4255
4350
  }
@@ -4696,7 +4791,7 @@ let p$2 = class p{registerComponent(t,a){customElements.get(t)||customElements.d
4696
4791
 
4697
4792
  var iconVersion$1 = '9.1.2';
4698
4793
 
4699
- var styleCss$2 = i$5`:host{position:fixed;z-index:var(--depth-tooltip, 400);display:none;isolation:isolate}:host(:not([matchWidth])) .container{min-width:fit-content}:host([isfullscreen]){position:fixed;top:0;left:0}:host([isfullscreen]) .container{width:100dvw;max-width:none;height:100dvh;max-height:none;border-radius:unset;margin-top:0;box-shadow:unset;overscroll-behavior:contain}:host([data-show]){display:flex}:host([common]:not([isfullscreen])) .container,:host([rounded]:not([isfullscreen])) .container{border-radius:var(--ds-border-radius, 0.375rem)}:host([common][isfullscreen]) .container,:host([rounded][isfullscreen]) .container{border-radius:unset;box-shadow:unset}:host(:not([isfullscreen])) .container.shape-box{border-radius:unset}:host(:not([isfullscreen])) .container[class*=shape-pill],:host(:not([isfullscreen])) .container[class*=shape-snowflake]{border-radius:30px}:host(:not([isfullscreen])) .container[class*=shape-rounded]{border-radius:16px}.container{display:inline-block;overflow:auto;box-sizing:border-box;border-radius:var(--ds-border-radius, 0.375rem);margin:var(--ds-size-50, 0.25rem) 0}`;
4794
+ var styleCss$2 = i$5`:host{position:fixed;z-index:var(--depth-tooltip, 400);display:none;isolation:isolate}:host dialog{width:auto;max-width:none;height:auto;max-height:none;padding:0;border:none;margin:0;outline:none;transform:translateZ(0)}:host dialog::backdrop{background:transparent}:host(:not([isfullscreen])) dialog{position:relative;inset:unset}:host(:not([isfullscreen])) .container.shape-box{border-radius:unset}:host(:not([isfullscreen])) .container[class*=shape-pill],:host(:not([isfullscreen])) .container[class*=shape-snowflake]{border-radius:30px}:host(:not([isfullscreen])) .container[class*=shape-rounded]{border-radius:16px}:host(:not([matchWidth])) .container{min-width:fit-content}:host([isfullscreen]){position:fixed;top:0;left:0}:host([isfullscreen]) .container{width:100dvw;max-width:none;height:100dvh;max-height:none;border-radius:unset;margin-top:0;box-shadow:unset;overscroll-behavior:contain}:host([isfullscreen]) .container::backdrop{background:var(--ds-color-background-primary, #fff)}:host([data-show]){display:flex}:host([common]:not([isfullscreen])) .container,:host([rounded]:not([isfullscreen])) .container{border-radius:var(--ds-border-radius, 0.375rem)}:host([common][isfullscreen]) .container,:host([rounded][isfullscreen]) .container{border-radius:unset;box-shadow:unset}.container{display:inline-block;overflow:auto;box-sizing:border-box;border-radius:var(--ds-border-radius, 0.375rem);margin:var(--ds-size-50, 0.25rem) 0}.util_displayHiddenVisually{position:absolute;overflow:hidden;width:1px;height:1px;padding:0;border:0;margin:-1px;clip-path:inset(50%);white-space:nowrap}`;
4700
4795
 
4701
4796
  var colorCss$2 = i$5`.container{background-color:var(--ds-auro-dropdownbib-container-color);box-shadow:var(--ds-auro-dropdownbib-boxshadow-color);color:var(--ds-auro-dropdownbib-text-color)}`;
4702
4797
 
@@ -4704,6 +4799,8 @@ var tokensCss$1 = i$5`:host(:not([ondark])),:host(:not([appearance=inverse])){--
4704
4799
 
4705
4800
  // Copyright (c) 2020 Alaska Airlines. All right reserved. Licensed under the Apache-2.0 license
4706
4801
  // See LICENSE in the project root for license information.
4802
+ /* eslint-disable max-lines */
4803
+ // ---------------------------------------------------------------------
4707
4804
 
4708
4805
 
4709
4806
  const DESIGN_TOKEN_BREAKPOINT_PREFIX = '--ds-grid-breakpoint-';
@@ -4798,6 +4895,28 @@ class AuroDropdownBib extends i$2 {
4798
4895
  shape: {
4799
4896
  type: String,
4800
4897
  reflect: true
4898
+ },
4899
+
4900
+ /**
4901
+ * Accessible label for the dialog element, used when displayed as a modal.
4902
+ * Applied via aria-labelledby on a visually hidden element rather than
4903
+ * aria-label because iOS VoiceOver does not reliably read aria-label
4904
+ * on <dialog> elements.
4905
+ * @private
4906
+ */
4907
+ dialogLabel: {
4908
+ type: String
4909
+ },
4910
+
4911
+ /**
4912
+ * Overrides the native role of the dialog element.
4913
+ * For example, set to `"presentation"` on desktop combobox to prevent
4914
+ * VoiceOver from announcing "listbox inside of a dialog".
4915
+ * When `undefined`, the dialog keeps its native role.
4916
+ * @private
4917
+ */
4918
+ dialogRole: {
4919
+ type: String
4801
4920
  }
4802
4921
  };
4803
4922
  }
@@ -4865,7 +4984,10 @@ class AuroDropdownBib extends i$2 {
4865
4984
  firstUpdated(changedProperties) {
4866
4985
  super.firstUpdated(changedProperties);
4867
4986
 
4868
- // Dispatch a custom event when the component is connected
4987
+ const dialog = this.shadowRoot.querySelector('dialog');
4988
+ this._setupCancelHandler(dialog);
4989
+ this._setupKeyboardBridge(dialog);
4990
+
4869
4991
  this.dispatchEvent(new CustomEvent('auro-dropdownbib-connected', {
4870
4992
  bubbles: true,
4871
4993
  composed: true,
@@ -4875,6 +4997,189 @@ class AuroDropdownBib extends i$2 {
4875
4997
  }));
4876
4998
  }
4877
4999
 
5000
+ /**
5001
+ * Forwards the dialog's native `cancel` event (fired on ESC) as
5002
+ * an `auro-bib-cancel` custom event so parent components can close.
5003
+ * @param {HTMLDialogElement} dialog
5004
+ * @private
5005
+ */
5006
+ _setupCancelHandler(dialog) {
5007
+ dialog.addEventListener('cancel', (event) => {
5008
+ event.preventDefault();
5009
+ this.dispatchEvent(new CustomEvent('auro-bib-cancel', {
5010
+ bubbles: true,
5011
+ composed: true
5012
+ }));
5013
+ });
5014
+ }
5015
+
5016
+ /**
5017
+ * showModal() creates a closed focus scope — keyboard events inside
5018
+ * the dialog's shadow DOM do NOT bubble out to the combobox/select
5019
+ * keydown handlers in the parent shadow DOM. This handler bridges
5020
+ * that gap by re-dispatching navigation keys so they cross the
5021
+ * shadow boundary and reach the menu navigation logic in the parent
5022
+ * component.
5023
+ *
5024
+ * The trade-off: intercepting these keys means native keyboard
5025
+ * behaviors that would normally "just work" must be manually
5026
+ * re-implemented here:
5027
+ *
5028
+ * - Enter on buttons: Custom elements (auro-button) don't get the
5029
+ * native Enter→click that <button> provides, so we call .click()
5030
+ * directly when Enter is pressed on a button-like element.
5031
+ *
5032
+ * - Tab: Intercepted and re-dispatched so parent components
5033
+ * (select/combobox) can select the active option and close the
5034
+ * dialog. The <dialog> provides containment and isolation
5035
+ * (inert background, VoiceOver focus trapping, top layer), while
5036
+ * the content inside is a role="listbox" navigated via
5037
+ * aria-activedescendant (options are not focusable). Tab keyboard
5038
+ * behavior follows listbox conventions (select + close) because
5039
+ * the dialog's native Tab trap only cycles between the close
5040
+ * button and browser chrome.
5041
+ *
5042
+ * - Escape: The native <dialog> fires a `cancel` event on ESC
5043
+ * (handled by _setupCancelHandler), so the re-dispatched Escape
5044
+ * is a secondary path for parent components that also listen for
5045
+ * Escape keydown.
5046
+ *
5047
+ * @param {HTMLDialogElement} dialog
5048
+ * @private
5049
+ */
5050
+ _setupKeyboardBridge(dialog) {
5051
+ const navKeys = new Set([
5052
+ 'ArrowUp',
5053
+ 'ArrowDown',
5054
+ 'Enter',
5055
+ 'Escape',
5056
+ 'Tab'
5057
+ ]);
5058
+
5059
+ dialog.addEventListener('keydown', (event) => {
5060
+ if (!navKeys.has(event.key)) {
5061
+ return;
5062
+ }
5063
+
5064
+ // Custom elements (auro-button) don't get the native Enter→click
5065
+ // behavior that <button> has. Find the button in the composed path
5066
+ // and click it directly.
5067
+ if (event.key === 'Enter') {
5068
+ const buttonSelector = 'button, [role="button"], auro-button, [auro-button]';
5069
+ const btn = event.composedPath().find((el) => el.matches && el.matches(buttonSelector));
5070
+ if (btn) {
5071
+ event.preventDefault();
5072
+ event.stopPropagation();
5073
+ btn.click();
5074
+ return;
5075
+ }
5076
+ }
5077
+
5078
+ event.preventDefault();
5079
+ event.stopPropagation();
5080
+ const newEvent = new KeyboardEvent('keydown', {
5081
+ key: event.key,
5082
+ code: event.code,
5083
+ shiftKey: event.shiftKey,
5084
+ altKey: event.altKey,
5085
+ ctrlKey: event.ctrlKey,
5086
+ metaKey: event.metaKey,
5087
+ bubbles: true,
5088
+ composed: true,
5089
+ cancelable: true
5090
+ });
5091
+ this.dispatchEvent(newEvent);
5092
+ });
5093
+ }
5094
+
5095
+ /**
5096
+ * Blocks touch-driven page scroll while a fullscreen modal dialog is open.
5097
+ *
5098
+ * The showModal() function places the dialog in the browser's **top layer**,
5099
+ * which is a separate rendering layer above the normal DOM. On mobile, the
5100
+ * compositor processes visual-viewport panning before top-layer touch
5101
+ * handling. This means the entire viewport — including the top-layer dialog
5102
+ * — can be panned by a touch gesture, causing the page behind the dialog to
5103
+ * scroll into view. To prevent this, we add a touchmove listener that cancels
5104
+ * the event if the touch started outside the dialog or any scrollable child within it.
5105
+ *
5106
+ * @private
5107
+ */
5108
+ _lockTouchScroll() {
5109
+ const dialog = this.shadowRoot.querySelector('dialog');
5110
+
5111
+ this._touchMoveHandler = (event) => {
5112
+ // Walk the composed path (which crosses shadow DOM boundaries) to
5113
+ // check whether the touch started inside a scrollable element that
5114
+ // lives within the dialog. If so, allow the scroll.
5115
+ for (const el of event.composedPath()) {
5116
+ if (el === dialog) {
5117
+ // Reached the dialog boundary without finding a scrollable child.
5118
+ break;
5119
+ }
5120
+ if (el instanceof HTMLElement && el.scrollHeight > el.clientHeight) {
5121
+ const { overflowY } = getComputedStyle(el);
5122
+ if (overflowY === 'auto' || overflowY === 'scroll') {
5123
+ return;
5124
+ }
5125
+ }
5126
+ }
5127
+
5128
+ event.preventDefault();
5129
+ };
5130
+
5131
+ document.addEventListener('touchmove', this._touchMoveHandler, { passive: false });
5132
+ }
5133
+
5134
+ /**
5135
+ * Removes the touchmove listener added by _lockTouchScroll().
5136
+ * @private
5137
+ */
5138
+ _unlockTouchScroll() {
5139
+ if (this._touchMoveHandler) {
5140
+ document.removeEventListener('touchmove', this._touchMoveHandler);
5141
+ this._touchMoveHandler = undefined;
5142
+ }
5143
+ }
5144
+
5145
+ open(modal = true) {
5146
+ const dialog = this.shadowRoot.querySelector('dialog');
5147
+ if (dialog && !dialog.open) {
5148
+ if (modal) {
5149
+ // Prevent showModal() from scrolling the page to bring the dialog
5150
+ // into view. Locking overflow on <html> blocks the viewport scroll
5151
+ // that browsers perform natively; we release it immediately after
5152
+ // so it doesn't interfere with the modal's focus management.
5153
+ const { documentElement } = document;
5154
+ const prevOverflow = documentElement.style.overflow;
5155
+ documentElement.style.overflow = 'hidden';
5156
+
5157
+ dialog.showModal();
5158
+
5159
+ documentElement.style.overflow = prevOverflow;
5160
+
5161
+ this._lockTouchScroll();
5162
+
5163
+ } else {
5164
+ // Use setAttribute instead of dialog.show() to avoid the dialog
5165
+ // focusing steps which steal focus from the trigger and cause
5166
+ // the floater's handleFocusLoss() to immediately hide the bib.
5167
+ dialog.setAttribute('open', '');
5168
+ }
5169
+ }
5170
+ }
5171
+
5172
+ /**
5173
+ * Closes the dialog.
5174
+ */
5175
+ close() {
5176
+ const dialog = this.shadowRoot.querySelector('dialog');
5177
+ if (dialog && dialog.open) {
5178
+ this._unlockTouchScroll();
5179
+ dialog.close();
5180
+ }
5181
+ }
5182
+
4878
5183
  // function that renders the HTML and CSS into the scope of the component
4879
5184
  render() {
4880
5185
  const classes = {
@@ -4886,9 +5191,10 @@ class AuroDropdownBib extends i$2 {
4886
5191
  classes[`shape-${this.shape}`] = true;
4887
5192
 
4888
5193
  return u$5`
4889
- <div class="${e$2(classes)}" part="bibContainer">
5194
+ <dialog class="${e$2(classes)}" part="bibContainer" role="${o$2(this.dialogRole)}" aria-labelledby="${o$2(this.dialogLabel ? 'dialogLabel' : undefined)}">
5195
+ ${this.dialogLabel ? u$5`<span id="dialogLabel" class="util_displayHiddenVisually" aria-hidden="true">${this.dialogLabel}</span>` : ''}
4890
5196
  <slot></slot>
4891
- </div>
5197
+ </dialog>
4892
5198
  `;
4893
5199
  }
4894
5200
  }
@@ -4897,7 +5203,7 @@ var shapeSizeCss = i$5`.shape-classic-xl,.shape-classic-lg,.shape-classic-md,.sh
4897
5203
 
4898
5204
  var colorCss$1$1 = i$5`:host(:not([layout*=classic])){--ds-auro-dropdown-trigger-border-color: transparent}:host(:not([disabled],[onDark])) .wrapper:focus-within,:host(:not([disabled],[onDark])) .wrapper:active,:host(:not([disabled],[appearance=inverse])) .wrapper:focus-within,:host(:not([disabled],[appearance=inverse])) .wrapper:active{--ds-auro-dropdown-trigger-border-color: var(--ds-advanced-color-state-focused, #01426a);--ds-auro-dropdown-trigger-outline-color: var(--ds-advanced-color-state-focused, #01426a)}:host(:not([disabled],[onDark])) .wrapper:hover,:host(:not([disabled],[appearance=inverse])) .wrapper:hover{--ds-auro-dropdown-trigger-background-color: var(--ds-auro-dropdown-trigger-hover-background-color)}:host(:not([ondark])) .wrapper,:host(:not([appearance=inverse])) .wrapper{border-color:var(--ds-auro-dropdown-trigger-border-color);background-color:var(--ds-auro-dropdown-trigger-background-color);color:var(--ds-auro-dropdown-trigger-text-color)}:host(:not([onDark])[disabled]),:host(:not([appearance=inverse])[disabled]){--ds-auro-dropdown-trigger-text-color: var(--ds-basic-color-texticon-disabled, #d0d0d0);--ds-auro-dropdown-label-text-color: var(--ds-basic-color-texticon-disabled, #d0d0d0);--ds-auro-dropdown-trigger-border-color: var(--ds-basic-color-border-subtle, #dddddd)}:host(:not([onDark])[disabled]) #triggerLabel,:host(:not([appearance=inverse])[disabled]) #triggerLabel{cursor:default}:host(:not([ondark])[error]),:host(:not([appearance=inverse])[error]){--ds-auro-dropdown-trigger-border-color: var(--ds-basic-color-status-error, #e31f26)}:host(:not([disabled])[onDark]) .wrapper:focus-within,:host(:not([disabled])[onDark]) .wrapper:active,:host(:not([disabled])[appearance=inverse]) .wrapper:focus-within,:host(:not([disabled])[appearance=inverse]) .wrapper:active{--ds-auro-dropdown-trigger-border-color: var(--ds-advanced-color-state-focused-inverse, #ffffff);--ds-auro-dropdown-trigger-outline-color: var(--ds-advanced-color-state-focused-inverse, #ffffff)}:host(:not([disabled])[onDark]) .wrapper:hover,:host(:not([disabled])[appearance=inverse]) .wrapper:hover{--ds-auro-dropdown-trigger-background-color: var(--ds-auro-dropdown-trigger-hover-background-color)}:host([onDark]) .label,:host([onDark]) .helpText,:host([appearance=inverse]) .label,:host([appearance=inverse]) .helpText{color:var(--ds-auro-dropdown-label-text-color)}:host([onDark]) .wrapper,:host([appearance=inverse]) .wrapper{border-color:var(--ds-auro-dropdown-trigger-border-color);background-color:var(--ds-auro-dropdown-trigger-background-color);color:var(--ds-auro-dropdown-trigger-text-color)}:host([onDark][disabled]),:host([appearance=inverse][disabled]){--ds-auro-dropdown-trigger-text-color: var(--ds-basic-color-texticon-inverse-disabled, #7e8894);--ds-auro-dropdown-label-text-color: var(--ds-basic-color-texticon-inverse-disabled, #7e8894);--ds-auro-dropdown-trigger-container-color: var(--ds-advanced-color-shared-background-inverse-disabled, rgba(255, 255, 255, 0.1))}:host([onDark][disabled]) #triggerLabel,:host([appearance=inverse][disabled]) #triggerLabel{cursor:default}:host([ondark][error]),:host([appearance=inverse][error]){--ds-auro-dropdown-trigger-border-color: var(--ds-advanced-color-state-error-inverse, #f9a4a8)}`;
4899
5205
 
4900
- var styleCss$1$1 = i$5`:host{position:relative;display:block;text-align:left}[popover=manual]{overflow:visible;padding:0;border:inherit;margin:0;background:inherit;outline:inherit}:host([open]){z-index:var(--depth-tooltip, 400)}.wrapper{display:flex;flex:1;flex-direction:row;align-items:center;justify-content:center;outline:none}.triggerContentWrapper{display:flex;overflow:hidden;width:100%;flex:1;align-items:center;justify-content:center;text-overflow:ellipsis;white-space:nowrap}:host([matchwidth]) #bibSizer{width:100%}`;
5206
+ var styleCss$1$1 = i$5`:host{position:relative;display:block;text-align:left}:host([open]){z-index:var(--depth-tooltip, 400)}.wrapper{display:flex;flex:1;flex-direction:row;align-items:center;justify-content:center;outline:none}.triggerContentWrapper{display:flex;overflow:hidden;width:100%;flex:1;align-items:center;justify-content:center;text-overflow:ellipsis;white-space:nowrap}:host([matchwidth]) #bibSizer{width:100%}`;
4901
5207
 
4902
5208
  var classicColorCss = i$5``;
4903
5209
 
@@ -5135,7 +5441,7 @@ class AuroHelpText extends i$2 {
5135
5441
  }
5136
5442
  }
5137
5443
 
5138
- var formkitVersion = '202602140013';
5444
+ var formkitVersion = '202603102257';
5139
5445
 
5140
5446
  let AuroElement$1 = class AuroElement extends i$2 {
5141
5447
  static get properties() {
@@ -5249,7 +5555,7 @@ let AuroElement$1 = class AuroElement extends i$2 {
5249
5555
  * The `auro-dropdown` element provides a way to place content in a bib that can be toggled.
5250
5556
  * @customElement auro-dropdown
5251
5557
  *
5252
- * @slot - Default slot for the popover content.
5558
+ * @slot - Default slot for the dropdown bib content.
5253
5559
  * @slot helpText - Defines the content of the helpText.
5254
5560
  * @slot trigger - Defines the content of the trigger.
5255
5561
  * @csspart trigger - The trigger content container.
@@ -5261,6 +5567,13 @@ let AuroElement$1 = class AuroElement extends i$2 {
5261
5567
  * @event auroDropdown-idAdded - Notifies consumers that the unique ID for the dropdown bib has been generated.
5262
5568
  */
5263
5569
  class AuroDropdown extends AuroElement$1 {
5570
+ static get shadowRootOptions() {
5571
+ return {
5572
+ ...AuroElement$1.shadowRootOptions,
5573
+ delegatesFocus: true,
5574
+ };
5575
+ }
5576
+
5264
5577
  constructor() {
5265
5578
  super();
5266
5579
 
@@ -5326,15 +5639,6 @@ class AuroDropdown extends AuroElement$1 {
5326
5639
  this.shift = false;
5327
5640
  this.autoPlacement = false;
5328
5641
 
5329
- /**
5330
- * @private
5331
- * @property {boolean} delegatesFocus - Whether the shadow root delegates focus.
5332
- */
5333
- this.constructor.shadowRootOptions = {
5334
- ...i$2.shadowRootOptions,
5335
- delegatesFocus: true,
5336
- };
5337
-
5338
5642
  /**
5339
5643
  * @private
5340
5644
  */
@@ -5408,6 +5712,18 @@ class AuroDropdown extends AuroElement$1 {
5408
5712
  */
5409
5713
  show() {
5410
5714
  this.floater.showBib();
5715
+
5716
+ // Open dialog synchronously so callers remain in the user gesture
5717
+ // chain. This is critical for mobile browsers (iOS Safari) to keep
5718
+ // the virtual keyboard open when transitioning from the trigger
5719
+ // input to an input inside the fullscreen dialog. Without this,
5720
+ // showModal() fires asynchronously via Lit's update cycle, which
5721
+ // falls outside the user activation window and causes iOS to
5722
+ // dismiss the keyboard.
5723
+ if (this.isBibFullscreen && this.bibElement && this.bibElement.value) {
5724
+ const useModal = !this.disableFocusTrap;
5725
+ this.bibElement.value.open(useModal);
5726
+ }
5411
5727
  }
5412
5728
 
5413
5729
  /**
@@ -5415,13 +5731,37 @@ class AuroDropdown extends AuroElement$1 {
5415
5731
  * If not, trigger element will get focus.
5416
5732
  */
5417
5733
  focus() {
5418
- if (this.isPopoverVisible && this.focusTrap) {
5419
- this.focusTrap.focusFirstElement();
5734
+ if (this.isPopoverVisible && this.bibContent) {
5735
+ const focusables = getFocusableElements(this.bibContent);
5736
+ if (focusables.length > 0) {
5737
+ focusables[0].focus();
5738
+ }
5420
5739
  } else {
5421
5740
  this.trigger.focus();
5422
5741
  }
5423
5742
  }
5424
5743
 
5744
+ /**
5745
+ * Sets the active descendant element for accessibility.
5746
+ * Uses ariaActiveDescendantElement to cross shadow DOM boundaries.
5747
+ * This function is used in components that contain `auro-dropdown` to set the active descendant.
5748
+ * @private
5749
+ * @param {HTMLElement|null} element - The element to set as the active descendant, or null to clear.
5750
+ * @returns {void}
5751
+ */
5752
+ setActiveDescendant(element) {
5753
+ if (!this.trigger) {
5754
+ return;
5755
+ }
5756
+
5757
+ if (element) {
5758
+ this.trigger.ariaActiveDescendantElement = element;
5759
+ } else {
5760
+ this.trigger.ariaActiveDescendantElement = null;
5761
+ this.trigger.removeAttribute('aria-activedescendant');
5762
+ }
5763
+ }
5764
+
5425
5765
  // function to define props used within the scope of this component
5426
5766
  static get properties() {
5427
5767
  return {
@@ -5679,6 +6019,16 @@ class AuroDropdown extends AuroElement$1 {
5679
6019
  */
5680
6020
  tabIndex: {
5681
6021
  type: Number
6022
+ },
6023
+
6024
+ /**
6025
+ * Accessible label for the dropdown bib dialog element.
6026
+ * @private
6027
+ */
6028
+ bibDialogLabel: {
6029
+ type: String,
6030
+ attribute: false,
6031
+ reflect: false
5682
6032
  }
5683
6033
  };
5684
6034
  }
@@ -5730,7 +6080,10 @@ class AuroDropdown extends AuroElement$1 {
5730
6080
 
5731
6081
  disconnectedCallback() {
5732
6082
  super.disconnectedCallback();
5733
- this.floater.disconnect();
6083
+ if (this.floater) {
6084
+ this.floater.hideBib('disconnect');
6085
+ this.floater.disconnect();
6086
+ }
5734
6087
  this.clearTriggerFocusEventBinding();
5735
6088
  }
5736
6089
 
@@ -5752,11 +6105,22 @@ class AuroDropdown extends AuroElement$1 {
5752
6105
 
5753
6106
  if (changedProperties.has('isPopoverVisible') && this.bibElement.value) {
5754
6107
  if (this.isPopoverVisible) {
5755
- this.bibElement.value.showPopover();
6108
+ // Fullscreen: use showModal() for native accessibility (inert outside, focus trap)
6109
+ // Desktop: use show() for Floating UI positioning + FocusTrap for focus management
6110
+ const useModal = this.isBibFullscreen && !this.disableFocusTrap;
6111
+ this.bibElement.value.open(useModal);
5756
6112
  } else {
5757
- this.bibElement.value.hidePopover();
6113
+ this.bibElement.value.close();
5758
6114
  }
5759
6115
  }
6116
+
6117
+ // When fullscreen strategy changes while open, re-open dialog with correct mode
6118
+ // (e.g. resizing from desktop → mobile while dropdown is open)
6119
+ if (changedProperties.has('isBibFullscreen') && this.isPopoverVisible && this.bibElement.value) {
6120
+ const useModal = this.isBibFullscreen && !this.disableFocusTrap;
6121
+ this.bibElement.value.close();
6122
+ this.bibElement.value.open(useModal);
6123
+ }
5760
6124
  }
5761
6125
 
5762
6126
  /**
@@ -5774,11 +6138,28 @@ class AuroDropdown extends AuroElement$1 {
5774
6138
  }
5775
6139
 
5776
6140
  firstUpdated() {
5777
-
5778
6141
  // Configure the floater to, this will generate the ID for the bib
5779
6142
  this.floater.configure(this, 'auroDropdown');
6143
+
6144
+ // Prevent `contain: layout` on the dropdown host. Layout containment
6145
+ // creates a containing block for position:fixed descendants (the bib),
6146
+ // which clips the bib inside ancestor overflow contexts such as a
6147
+ // <dialog> element. Without it, the bib's position:fixed is relative
6148
+ // to the viewport, letting Floating UI's flip middleware detect
6149
+ // viewport boundaries and the bib escape overflow clipping.
6150
+ const origConfigureBibStrategy = this.floater.configureBibStrategy.bind(this.floater);
6151
+ this.floater.configureBibStrategy = (value) => {
6152
+ origConfigureBibStrategy(value);
6153
+ this.style.contain = '';
6154
+ };
6155
+
5780
6156
  this.addEventListener('auroDropdown-toggled', this.handleDropdownToggle);
5781
6157
 
6158
+ // Handle ESC key from dialog's cancel event
6159
+ this.addEventListener('auro-bib-cancel', () => {
6160
+ this.floater.hideBib('keydown');
6161
+ });
6162
+
5782
6163
  /**
5783
6164
  * @description Let subscribers know that the dropdown ID ha been generated and added.
5784
6165
  * @event auroDropdown-idAdded
@@ -5786,9 +6167,9 @@ class AuroDropdown extends AuroElement$1 {
5786
6167
  */
5787
6168
  this.dispatchEvent(new CustomEvent('auroDropdown-idAdded', {detail: {id: this.floater.element.id}}));
5788
6169
 
5789
- // Set the bib ID locally if the user hasn't provided a focusable trigger
6170
+ // Set the bib ID locally for aria-controls (must be in the same shadow root as the trigger)
5790
6171
  if (!this.triggerContentFocusable) {
5791
- this.dropdownId = this.floater.element.id;
6172
+ this.dropdownId = this.floater.element.bib.id;
5792
6173
  }
5793
6174
 
5794
6175
  this.bibContent = this.floater.element.bib;
@@ -5848,21 +6229,20 @@ class AuroDropdown extends AuroElement$1 {
5848
6229
  * @private
5849
6230
  */
5850
6231
  updateFocusTrap() {
5851
- // If the dropdown is open, create a focus trap and focus the first element
5852
6232
  if (this.isPopoverVisible && !this.disableFocusTrap) {
5853
- this.focusTrap = new FocusTrap(this.bibContent);
5854
- this.focusTrap.focusFirstElement();
6233
+ if (!this.isBibFullscreen) {
6234
+ // Desktop: show() doesn't trap focus, so use FocusTrap
6235
+ this.focusTrap = new FocusTrap(this.bibContent);
6236
+ this.focusTrap.focusFirstElement();
6237
+ }
6238
+ // Fullscreen: showModal() provides native focus trapping
5855
6239
  return;
5856
6240
  }
5857
6241
 
5858
- // Guard Clause: Ensure there is a focus trap currently active before continuing
5859
- if (!this.focusTrap) {
5860
- return;
6242
+ if (this.focusTrap) {
6243
+ this.focusTrap.disconnect();
6244
+ this.focusTrap = undefined;
5861
6245
  }
5862
-
5863
- // If the dropdown is not open, disconnect the focus trap if it exists
5864
- this.focusTrap.disconnect();
5865
- this.focusTrap = undefined;
5866
6246
  }
5867
6247
 
5868
6248
  /**
@@ -6078,13 +6458,14 @@ class AuroDropdown extends AuroElement$1 {
6078
6458
  <div
6079
6459
  id="showStateIcon"
6080
6460
  class="chevron"
6081
- part="chevron">
6461
+ part="chevron"
6462
+ aria-hidden="true">
6082
6463
  <${this.iconTag}
6083
6464
  category="interface"
6084
6465
  name="${this.isPopoverVisible ? 'chevron-up' : `chevron-down`}"
6085
6466
  appearance="${this.onDark ? 'inverse' : this.appearance}"
6086
- variant="${this.disabled ? 'disabled' : 'muted'}">
6087
- >
6467
+ variant="${this.disabled ? 'disabled' : 'muted'}"
6468
+ ariaHidden="true">
6088
6469
  </${this.iconTag}>
6089
6470
  </div>
6090
6471
  ` : undefined }
@@ -6098,8 +6479,8 @@ class AuroDropdown extends AuroElement$1 {
6098
6479
  shape="${this.shape}"
6099
6480
  ?data-show="${this.isPopoverVisible}"
6100
6481
  ?isfullscreen="${this.isBibFullscreen}"
6482
+ .dialogLabel="${this.bibDialogLabel}"
6101
6483
  ${n$1(this.bibElement)}
6102
- popover="manual"
6103
6484
  >
6104
6485
  <div class="slotContent">
6105
6486
  <slot @slotchange="${this.handleDefaultSlot}"></slot>
@@ -6506,6 +6887,18 @@ class AuroBibtemplate extends i$2 {
6506
6887
  this.removeEventListener('touchmove', this.preventBodyScroll, { passive: false });
6507
6888
  }
6508
6889
 
6890
+ /**
6891
+ * Focuses the close button inside the bibtemplate's shadow DOM.
6892
+ * Used by parent components to set initial focus when the fullscreen dialog opens.
6893
+ * @returns {void}
6894
+ */
6895
+ focusCloseButton() {
6896
+ const closeBtn = this.shadowRoot.querySelector('#closeButton');
6897
+ if (closeBtn) {
6898
+ closeBtn.focus();
6899
+ }
6900
+ }
6901
+
6509
6902
  onCloseButtonClick() {
6510
6903
  this.dispatchEvent(new Event("close-click", { bubbles: true,
6511
6904
  composed: true }));
@@ -7182,6 +7575,24 @@ class AuroCounterGroup extends AuroElement {
7182
7575
  this.dropdown.hide();
7183
7576
  }
7184
7577
  });
7578
+
7579
+ // Focus close button when fullscreen dialog opens
7580
+ this.dropdown.addEventListener('auroDropdown-toggled', () => {
7581
+ if (this.dropdown.isPopoverVisible && this.dropdown.isBibFullscreen) {
7582
+ doubleRaf(() => {
7583
+ this.bibtemplate.focusCloseButton();
7584
+ });
7585
+ }
7586
+ });
7587
+
7588
+ // Tab closes the fullscreen dialog
7589
+ // The dialog event bridge intercepts Tab and re-dispatches it as a
7590
+ // composed keydown; this listener catches the re-dispatched event.
7591
+ this.addEventListener('keydown', (evt) => {
7592
+ if (evt.key === 'Tab' && this.dropdown.isPopoverVisible && this.dropdown.isBibFullscreen) {
7593
+ this.dropdown.hide();
7594
+ }
7595
+ });
7185
7596
  }
7186
7597
 
7187
7598
  /**