@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
@@ -1,7 +1,7 @@
1
1
  import { unsafeStatic, literal, html as html$1 } from 'lit/static-html.js';
2
2
  import { classMap } from 'lit/directives/class-map.js';
3
- import { css, html, LitElement } from 'lit';
4
3
  import { createRef, ref } from 'lit/directives/ref.js';
4
+ import { css, html, LitElement } from 'lit';
5
5
  import { ifDefined } from 'lit/directives/if-defined.js';
6
6
 
7
7
  // Copyright (c) Alaska Air. All right reserved. Licensed under the Apache-2.0 license
@@ -1731,11 +1731,9 @@ const computePosition = (reference, floating, options) => {
1731
1731
  /* eslint-disable line-comment-position, no-inline-comments */
1732
1732
 
1733
1733
 
1734
-
1735
1734
  const MAX_CONFIGURATION_COUNT = 10;
1736
1735
 
1737
1736
  class AuroFloatingUI {
1738
-
1739
1737
  /**
1740
1738
  * @private
1741
1739
  */
@@ -1750,7 +1748,11 @@ class AuroFloatingUI {
1750
1748
  * @private
1751
1749
  */
1752
1750
  static setupMousePressChecker() {
1753
- if (!AuroFloatingUI.isMousePressHandlerInitialized && window && window.addEventListener) {
1751
+ if (
1752
+ !AuroFloatingUI.isMousePressHandlerInitialized &&
1753
+ window &&
1754
+ window.addEventListener
1755
+ ) {
1754
1756
  AuroFloatingUI.isMousePressHandlerInitialized = true;
1755
1757
 
1756
1758
  // Track timeout for isMousePressed reset to avoid race conditions
@@ -1758,7 +1760,7 @@ class AuroFloatingUI {
1758
1760
  AuroFloatingUI._mousePressedTimeout = null;
1759
1761
  }
1760
1762
  const mouseEventGlobalHandler = (event) => {
1761
- const isPressed = event.type === 'mousedown';
1763
+ const isPressed = event.type === "mousedown";
1762
1764
  if (isPressed) {
1763
1765
  // Clear any pending timeout to prevent race condition
1764
1766
  if (AuroFloatingUI._mousePressedTimeout !== null) {
@@ -1777,8 +1779,8 @@ class AuroFloatingUI {
1777
1779
  }
1778
1780
  };
1779
1781
 
1780
- window.addEventListener('mousedown', mouseEventGlobalHandler);
1781
- window.addEventListener('mouseup', mouseEventGlobalHandler);
1782
+ window.addEventListener("mousedown", mouseEventGlobalHandler);
1783
+ window.addEventListener("mouseup", mouseEventGlobalHandler);
1782
1784
  }
1783
1785
  }
1784
1786
 
@@ -1826,11 +1828,12 @@ class AuroFloatingUI {
1826
1828
  // mirror the boxsize from bibSizer
1827
1829
  if (this.element.bibSizer && this.element.matchWidth) {
1828
1830
  const sizerStyle = window.getComputedStyle(this.element.bibSizer);
1829
- const bibContent = this.element.bib.shadowRoot.querySelector(".container");
1830
- if (sizerStyle.width !== '0px') {
1831
+ const bibContent =
1832
+ this.element.bib.shadowRoot.querySelector(".container");
1833
+ if (sizerStyle.width !== "0px") {
1831
1834
  bibContent.style.width = sizerStyle.width;
1832
1835
  }
1833
- if (sizerStyle.height !== '0px') {
1836
+ if (sizerStyle.height !== "0px") {
1834
1837
  bibContent.style.height = sizerStyle.height;
1835
1838
  }
1836
1839
  bibContent.style.maxWidth = sizerStyle.maxWidth;
@@ -1848,28 +1851,34 @@ class AuroFloatingUI {
1848
1851
  * @returns {String} The positioning strategy, one of 'fullscreen', 'floating', 'cover'.
1849
1852
  */
1850
1853
  getPositioningStrategy() {
1851
- const breakpoint = this.element.bib.mobileFullscreenBreakpoint || this.element.floaterConfig?.fullscreenBreakpoint;
1854
+ const breakpoint =
1855
+ this.element.bib.mobileFullscreenBreakpoint ||
1856
+ this.element.floaterConfig?.fullscreenBreakpoint;
1852
1857
  switch (this.behavior) {
1853
1858
  case "tooltip":
1854
1859
  return "floating";
1855
1860
  case "dialog":
1856
1861
  case "drawer":
1857
1862
  if (breakpoint) {
1858
- const smallerThanBreakpoint = window.matchMedia(`(max-width: ${breakpoint})`).matches;
1863
+ const smallerThanBreakpoint = window.matchMedia(
1864
+ `(max-width: ${breakpoint})`,
1865
+ ).matches;
1859
1866
 
1860
1867
  this.element.expanded = smallerThanBreakpoint;
1861
1868
  }
1862
1869
  if (this.element.nested) {
1863
1870
  return "cover";
1864
1871
  }
1865
- return 'fullscreen';
1872
+ return "fullscreen";
1866
1873
  case "dropdown":
1867
1874
  case undefined:
1868
1875
  case null:
1869
1876
  if (breakpoint) {
1870
- const smallerThanBreakpoint = window.matchMedia(`(max-width: ${breakpoint})`).matches;
1877
+ const smallerThanBreakpoint = window.matchMedia(
1878
+ `(max-width: ${breakpoint})`,
1879
+ ).matches;
1871
1880
  if (smallerThanBreakpoint) {
1872
- return 'fullscreen';
1881
+ return "fullscreen";
1873
1882
  }
1874
1883
  }
1875
1884
  return "floating";
@@ -1890,37 +1899,39 @@ class AuroFloatingUI {
1890
1899
  const strategy = this.getPositioningStrategy();
1891
1900
  this.configureBibStrategy(strategy);
1892
1901
 
1893
- if (strategy === 'floating') {
1902
+ if (strategy === "floating") {
1894
1903
  this.mirrorSize();
1895
1904
  // Define the middlware for the floater configuration
1896
1905
  const middleware = [
1897
1906
  offset(this.element.floaterConfig?.offset || 0),
1898
- ...this.element.floaterConfig?.shift ? [shift()] : [], // Add shift middleware if shift is enabled.
1899
- ...this.element.floaterConfig?.flip ? [flip()] : [], // Add flip middleware if flip is enabled.
1900
- ...this.element.floaterConfig?.autoPlacement ? [autoPlacement()] : [], // Add autoPlacement middleware if autoPlacement is enabled.
1907
+ ...(this.element.floaterConfig?.shift ? [shift()] : []), // Add shift middleware if shift is enabled.
1908
+ ...(this.element.floaterConfig?.flip ? [flip()] : []), // Add flip middleware if flip is enabled.
1909
+ ...(this.element.floaterConfig?.autoPlacement ? [autoPlacement()] : []), // Add autoPlacement middleware if autoPlacement is enabled.
1901
1910
  ];
1902
1911
 
1903
1912
  // Compute the position of the bib
1904
1913
  computePosition(this.element.trigger, this.element.bib, {
1905
- strategy: this.element.floaterConfig?.strategy || 'fixed',
1914
+ strategy: this.element.floaterConfig?.strategy || "fixed",
1906
1915
  placement: this.element.floaterConfig?.placement,
1907
- middleware: middleware || []
1908
- }).then(({ x, y }) => { // eslint-disable-line id-length
1916
+ middleware: middleware || [],
1917
+ }).then(({ x, y }) => {
1918
+ // eslint-disable-line id-length
1909
1919
  Object.assign(this.element.bib.style, {
1910
1920
  left: `${x}px`,
1911
1921
  top: `${y}px`,
1912
1922
  });
1913
1923
  });
1914
- } else if (strategy === 'cover') {
1924
+ } else if (strategy === "cover") {
1915
1925
  // Compute the position of the bib
1916
1926
  computePosition(this.element.parentNode, this.element.bib, {
1917
- placement: 'bottom-start'
1918
- }).then(({ x, y }) => { // eslint-disable-line id-length
1927
+ placement: "bottom-start",
1928
+ }).then(({ x, y }) => {
1929
+ // eslint-disable-line id-length
1919
1930
  Object.assign(this.element.bib.style, {
1920
1931
  left: `${x}px`,
1921
1932
  top: `${y - this.element.parentNode.offsetHeight}px`,
1922
1933
  width: `${this.element.parentNode.offsetWidth}px`,
1923
- height: `${this.element.parentNode.offsetHeight}px`
1934
+ height: `${this.element.parentNode.offsetHeight}px`,
1924
1935
  });
1925
1936
  });
1926
1937
  }
@@ -1933,12 +1944,12 @@ class AuroFloatingUI {
1933
1944
  */
1934
1945
  lockScroll(lock = true) {
1935
1946
  if (lock) {
1936
- document.body.style.overflow = 'hidden'; // hide body's scrollbar
1947
+ document.body.style.overflow = "hidden"; // hide body's scrollbar
1937
1948
 
1938
1949
  // Move `bib` by the amount the viewport is shifted to stay aligned in fullscreen.
1939
1950
  this.element.bib.style.transform = `translateY(${window?.visualViewport?.offsetTop}px)`;
1940
1951
  } else {
1941
- document.body.style.overflow = '';
1952
+ document.body.style.overflow = "";
1942
1953
  }
1943
1954
  }
1944
1955
 
@@ -1952,23 +1963,24 @@ class AuroFloatingUI {
1952
1963
  * @param {string} strategy - The positioning strategy ('fullscreen' or 'floating').
1953
1964
  */
1954
1965
  configureBibStrategy(value) {
1955
- if (value === 'fullscreen') {
1966
+ if (value === "fullscreen") {
1956
1967
  this.element.isBibFullscreen = true;
1957
1968
  // reset the prev position
1958
- this.element.bib.setAttribute('isfullscreen', "");
1959
- this.element.bib.style.position = 'fixed';
1969
+ this.element.bib.setAttribute("isfullscreen", "");
1970
+ this.element.bib.style.position = "fixed";
1960
1971
  this.element.bib.style.top = "0px";
1961
1972
  this.element.bib.style.left = "0px";
1962
- this.element.bib.style.width = '';
1963
- this.element.bib.style.height = '';
1964
- this.element.style.contain = '';
1973
+ this.element.bib.style.width = "";
1974
+ this.element.bib.style.height = "";
1975
+ this.element.style.contain = "";
1965
1976
 
1966
1977
  // reset the size that was mirroring `size` css-part
1967
- const bibContent = this.element.bib.shadowRoot.querySelector(".container");
1978
+ const bibContent =
1979
+ this.element.bib.shadowRoot.querySelector(".container");
1968
1980
  if (bibContent) {
1969
- bibContent.style.width = '';
1970
- bibContent.style.height = '';
1971
- bibContent.style.maxWidth = '';
1981
+ bibContent.style.width = "";
1982
+ bibContent.style.height = "";
1983
+ bibContent.style.maxWidth = "";
1972
1984
  bibContent.style.maxHeight = `${window?.visualViewport?.height}px`;
1973
1985
  this.configureTrial = 0;
1974
1986
  } else if (this.configureTrial < MAX_CONFIGURATION_COUNT) {
@@ -1983,21 +1995,26 @@ class AuroFloatingUI {
1983
1995
  this.lockScroll(true);
1984
1996
  }
1985
1997
  } else {
1986
- this.element.bib.style.position = '';
1987
- this.element.bib.removeAttribute('isfullscreen');
1998
+ this.element.bib.style.position = "";
1999
+ this.element.bib.removeAttribute("isfullscreen");
1988
2000
  this.element.isBibFullscreen = false;
1989
- this.element.style.contain = 'layout';
2001
+ this.element.style.contain = "layout";
1990
2002
  }
1991
2003
 
1992
2004
  const isChanged = this.strategy && this.strategy !== value;
1993
2005
  this.strategy = value;
1994
2006
  if (isChanged) {
1995
- const event = new CustomEvent(this.eventPrefix ? `${this.eventPrefix}-strategy-change` : 'strategy-change', {
1996
- detail: {
1997
- value,
2007
+ const event = new CustomEvent(
2008
+ this.eventPrefix
2009
+ ? `${this.eventPrefix}-strategy-change`
2010
+ : "strategy-change",
2011
+ {
2012
+ detail: {
2013
+ value,
2014
+ },
2015
+ composed: true,
1998
2016
  },
1999
- composed: true
2000
- });
2017
+ );
2001
2018
 
2002
2019
  this.element.dispatchEvent(event);
2003
2020
  }
@@ -2029,19 +2046,24 @@ class AuroFloatingUI {
2029
2046
  return;
2030
2047
  }
2031
2048
 
2032
- if (this.element.noHideOnThisFocusLoss ||
2033
- this.element.hasAttribute('noHideOnThisFocusLoss')) {
2049
+ if (
2050
+ this.element.noHideOnThisFocusLoss ||
2051
+ this.element.hasAttribute("noHideOnThisFocusLoss")
2052
+ ) {
2034
2053
  return;
2035
2054
  }
2036
2055
 
2037
2056
  const { activeElement } = document;
2038
2057
  // if focus is still inside of trigger or bib, do not close
2039
- if (this.element.contains(activeElement) || this.element.bib?.contains(activeElement)) {
2058
+ if (
2059
+ this.element.contains(activeElement) ||
2060
+ this.element.bib?.contains(activeElement)
2061
+ ) {
2040
2062
  return;
2041
2063
  }
2042
2064
 
2043
2065
  // if fullscreen bib is in fullscreen mode, do not close
2044
- if (this.element.bib.hasAttribute('isfullscreen')) {
2066
+ if (this.element.bib.hasAttribute("isfullscreen")) {
2045
2067
  return;
2046
2068
  }
2047
2069
 
@@ -2053,12 +2075,27 @@ class AuroFloatingUI {
2053
2075
  this.focusHandler = () => this.handleFocusLoss();
2054
2076
 
2055
2077
  this.clickHandler = (evt) => {
2056
- if ((!evt.composedPath().includes(this.element.trigger) &&
2057
- !evt.composedPath().includes(this.element.bib)) ||
2058
- (this.element.bib.backdrop && evt.composedPath().includes(this.element.bib.backdrop))) {
2059
- const existedVisibleFloatingUI = document.expandedAuroFormkitDropdown || document.expandedAuroFloater;
2078
+ // When the bib is fullscreen (modal dialog), don't close on outside
2079
+ // clicks. VoiceOver's synthetic click events inside a top-layer modal
2080
+ // <dialog> may not include the bib in composedPath(), causing false
2081
+ // positives. This mirrors the fullscreen guard in handleFocusLoss().
2082
+ if (this.element.bib && this.element.bib.hasAttribute("isfullscreen")) {
2083
+ return;
2084
+ }
2060
2085
 
2061
- if (existedVisibleFloatingUI && existedVisibleFloatingUI.element.isPopoverVisible) {
2086
+ if (
2087
+ (!evt.composedPath().includes(this.element.trigger) &&
2088
+ !evt.composedPath().includes(this.element.bib)) ||
2089
+ (this.element.bib.backdrop &&
2090
+ evt.composedPath().includes(this.element.bib.backdrop))
2091
+ ) {
2092
+ const existedVisibleFloatingUI =
2093
+ document.expandedAuroFormkitDropdown || document.expandedAuroFloater;
2094
+
2095
+ if (
2096
+ existedVisibleFloatingUI &&
2097
+ existedVisibleFloatingUI.element.isPopoverVisible
2098
+ ) {
2062
2099
  // if something else is open, close that
2063
2100
  existedVisibleFloatingUI.hideBib();
2064
2101
  document.expandedAuroFormkitDropdown = null;
@@ -2071,9 +2108,14 @@ class AuroFloatingUI {
2071
2108
 
2072
2109
  // ESC key handler
2073
2110
  this.keyDownHandler = (evt) => {
2074
- if (evt.key === 'Escape' && this.element.isPopoverVisible) {
2075
- const existedVisibleFloatingUI = document.expandedAuroFormkitDropdown || document.expandedAuroFloater;
2076
- if (existedVisibleFloatingUI && existedVisibleFloatingUI !== this && existedVisibleFloatingUI.element.isPopoverVisible) {
2111
+ if (evt.key === "Escape" && this.element.isPopoverVisible) {
2112
+ const existedVisibleFloatingUI =
2113
+ document.expandedAuroFormkitDropdown || document.expandedAuroFloater;
2114
+ if (
2115
+ existedVisibleFloatingUI &&
2116
+ existedVisibleFloatingUI !== this &&
2117
+ existedVisibleFloatingUI.element.isPopoverVisible
2118
+ ) {
2077
2119
  // if something else is open, let it handle itself
2078
2120
  return;
2079
2121
  }
@@ -2081,17 +2123,17 @@ class AuroFloatingUI {
2081
2123
  }
2082
2124
  };
2083
2125
 
2084
- if (this.behavior !== 'drawer' && this.behavior !== 'dialog') {
2126
+ if (this.behavior !== "drawer" && this.behavior !== "dialog") {
2085
2127
  // Add event listeners using the stored references
2086
- document.addEventListener('focusin', this.focusHandler);
2128
+ document.addEventListener("focusin", this.focusHandler);
2087
2129
  }
2088
2130
 
2089
- document.addEventListener('keydown', this.keyDownHandler);
2131
+ document.addEventListener("keydown", this.keyDownHandler);
2090
2132
 
2091
2133
  // send this task to the end of queue to prevent conflicting
2092
2134
  // it conflicts if showBib gets call from a button that's not this.element.trigger
2093
2135
  setTimeout(() => {
2094
- window.addEventListener('click', this.clickHandler);
2136
+ window.addEventListener("click", this.clickHandler);
2095
2137
  }, 0);
2096
2138
  }
2097
2139
 
@@ -2099,34 +2141,38 @@ class AuroFloatingUI {
2099
2141
  // Remove event listeners if they exist
2100
2142
 
2101
2143
  if (this.focusHandler) {
2102
- document.removeEventListener('focusin', this.focusHandler);
2144
+ document.removeEventListener("focusin", this.focusHandler);
2103
2145
  this.focusHandler = null;
2104
2146
  }
2105
2147
 
2106
2148
  if (this.clickHandler) {
2107
- window.removeEventListener('click', this.clickHandler);
2149
+ window.removeEventListener("click", this.clickHandler);
2108
2150
  this.clickHandler = null;
2109
2151
  }
2110
2152
 
2111
2153
  if (this.keyDownHandler) {
2112
- document.removeEventListener('keydown', this.keyDownHandler);
2154
+ document.removeEventListener("keydown", this.keyDownHandler);
2113
2155
  this.keyDownHandler = null;
2114
2156
  }
2115
2157
  }
2116
2158
 
2117
2159
  handleUpdate(changedProperties) {
2118
- if (changedProperties.has('isPopoverVisible')) {
2160
+ if (changedProperties.has("isPopoverVisible")) {
2119
2161
  this.updateState();
2120
2162
  }
2121
2163
  }
2122
2164
 
2123
2165
  updateCurrentExpandedDropdown() {
2124
2166
  // Close any other dropdown that is already open
2125
- const existedVisibleFloatingUI = document.expandedAuroFormkitDropdown || document.expandedAuroFloater;
2126
- if (existedVisibleFloatingUI && existedVisibleFloatingUI !== this &&
2167
+ const existedVisibleFloatingUI =
2168
+ document.expandedAuroFormkitDropdown || document.expandedAuroFloater;
2169
+ if (
2170
+ existedVisibleFloatingUI &&
2171
+ existedVisibleFloatingUI !== this &&
2127
2172
  existedVisibleFloatingUI.element.isPopoverVisible &&
2128
- document.expandedAuroFloater.eventPrefix === this.eventPrefix) {
2129
- document.expandedAuroFloater.hideBib();
2173
+ existedVisibleFloatingUI.eventPrefix === this.eventPrefix
2174
+ ) {
2175
+ existedVisibleFloatingUI.hideBib();
2130
2176
  }
2131
2177
 
2132
2178
  document.expandedAuroFloater = this;
@@ -2135,7 +2181,7 @@ class AuroFloatingUI {
2135
2181
  showBib() {
2136
2182
  if (!this.element.disabled && !this.showing) {
2137
2183
  this.updateCurrentExpandedDropdown();
2138
- this.element.triggerChevron?.setAttribute('data-expanded', true);
2184
+ this.element.triggerChevron?.setAttribute("data-expanded", true);
2139
2185
 
2140
2186
  // prevent double showing: isPopovervisible gets first and showBib gets called later
2141
2187
  if (!this.showing) {
@@ -2149,9 +2195,13 @@ class AuroFloatingUI {
2149
2195
  }
2150
2196
 
2151
2197
  // Setup auto update to handle resize and scroll
2152
- this.element.cleanup = autoUpdate(this.element.trigger || this.element.parentNode, this.element.bib, () => {
2153
- this.position();
2154
- });
2198
+ this.element.cleanup = autoUpdate(
2199
+ this.element.trigger || this.element.parentNode,
2200
+ this.element.bib,
2201
+ () => {
2202
+ this.position();
2203
+ },
2204
+ );
2155
2205
  }
2156
2206
  }
2157
2207
 
@@ -2162,7 +2212,7 @@ class AuroFloatingUI {
2162
2212
  hideBib(eventType = "unknown") {
2163
2213
  if (!this.element.disabled && !this.element.noToggle) {
2164
2214
  this.lockScroll(false);
2165
- this.element.triggerChevron?.removeAttribute('data-expanded');
2215
+ this.element.triggerChevron?.removeAttribute("data-expanded");
2166
2216
 
2167
2217
  if (this.element.isPopoverVisible) {
2168
2218
  this.element.isPopoverVisible = false;
@@ -2182,13 +2232,16 @@ class AuroFloatingUI {
2182
2232
  * @param {String} eventType - The event type that triggered the toggle action.
2183
2233
  */
2184
2234
  dispatchEventDropdownToggle(eventType) {
2185
- const event = new CustomEvent(this.eventPrefix ? `${this.eventPrefix}-toggled` : 'toggled', {
2186
- detail: {
2187
- expanded: this.showing,
2188
- eventType: eventType || "unknown",
2235
+ const event = new CustomEvent(
2236
+ this.eventPrefix ? `${this.eventPrefix}-toggled` : "toggled",
2237
+ {
2238
+ detail: {
2239
+ expanded: this.showing,
2240
+ eventType: eventType || "unknown",
2241
+ },
2242
+ composed: true,
2189
2243
  },
2190
- composed: true
2191
- });
2244
+ );
2192
2245
 
2193
2246
  this.element.dispatchEvent(event);
2194
2247
  }
@@ -2200,12 +2253,15 @@ class AuroFloatingUI {
2200
2253
  this.showBib();
2201
2254
  }
2202
2255
 
2203
- const event = new CustomEvent(this.eventPrefix ? `${this.eventPrefix}-triggerClick` : "triggerClick", {
2204
- composed: true,
2205
- detail: {
2206
- expanded: this.element.isPopoverVisible
2207
- }
2208
- });
2256
+ const event = new CustomEvent(
2257
+ this.eventPrefix ? `${this.eventPrefix}-triggerClick` : "triggerClick",
2258
+ {
2259
+ composed: true,
2260
+ detail: {
2261
+ expanded: this.element.isPopoverVisible,
2262
+ },
2263
+ },
2264
+ );
2209
2265
 
2210
2266
  this.element.dispatchEvent(event);
2211
2267
  }
@@ -2213,30 +2269,32 @@ class AuroFloatingUI {
2213
2269
  handleEvent(event) {
2214
2270
  if (!this.element.disableEventShow) {
2215
2271
  switch (event.type) {
2216
- case 'keydown':
2272
+ case "keydown": {
2217
2273
  // Support both Enter and Space keys for accessibility
2218
2274
  // Space is included as it's expected behavior for interactive elements
2219
2275
 
2220
2276
  const origin = event.composedPath()[0];
2221
- if (event.key === 'Enter' || event.key === ' ' && (!origin || origin.tagName !== "INPUT")) {
2222
-
2277
+ if (
2278
+ event.key === "Enter" ||
2279
+ (event.key === " " && (!origin || origin.tagName !== "INPUT"))
2280
+ ) {
2223
2281
  event.preventDefault();
2224
2282
  this.handleClick();
2225
2283
  }
2226
2284
  break;
2227
- case 'mouseenter':
2285
+ }
2286
+ case "mouseenter":
2228
2287
  if (this.element.hoverToggle) {
2229
2288
  this.showBib();
2230
2289
  }
2231
2290
  break;
2232
- case 'mouseleave':
2291
+ case "mouseleave":
2233
2292
  if (this.element.hoverToggle) {
2234
2293
  this.hideBib("mouseleave");
2235
2294
  }
2236
2295
  break;
2237
- case 'focus':
2296
+ case "focus":
2238
2297
  if (this.element.focusShow) {
2239
-
2240
2298
  /*
2241
2299
  This needs to better handle clicking that gives focus -
2242
2300
  currently it shows and then immediately hides the bib
@@ -2244,12 +2302,12 @@ class AuroFloatingUI {
2244
2302
  this.showBib();
2245
2303
  }
2246
2304
  break;
2247
- case 'blur':
2305
+ case "blur":
2248
2306
  // send this task 100ms later queue to
2249
2307
  // wait a frame in case focus moves within the floating element/bib
2250
2308
  setTimeout(() => this.handleFocusLoss(), 0);
2251
2309
  break;
2252
- case 'click':
2310
+ case "click":
2253
2311
  if (document.activeElement === document.body) {
2254
2312
  event.currentTarget.focus();
2255
2313
  }
@@ -2268,15 +2326,15 @@ class AuroFloatingUI {
2268
2326
  */
2269
2327
  handleTriggerTabIndex() {
2270
2328
  const focusableElementSelectors = [
2271
- 'a',
2272
- 'button',
2329
+ "a",
2330
+ "button",
2273
2331
  'input:not([type="hidden"])',
2274
- 'select',
2275
- 'textarea',
2332
+ "select",
2333
+ "textarea",
2276
2334
  '[tabindex]:not([tabindex="-1"])',
2277
- 'auro-button',
2278
- 'auro-input',
2279
- 'auro-hyperlink'
2335
+ "auro-button",
2336
+ "auro-input",
2337
+ "auro-hyperlink",
2280
2338
  ];
2281
2339
 
2282
2340
  const triggerNode = this.element.querySelectorAll('[slot="trigger"]')[0];
@@ -2304,10 +2362,10 @@ class AuroFloatingUI {
2304
2362
  * @param {*} eventPrefix
2305
2363
  */
2306
2364
  regenerateBibId() {
2307
- this.id = this.element.getAttribute('id');
2365
+ this.id = this.element.getAttribute("id");
2308
2366
  if (!this.id) {
2309
2367
  this.id = window.crypto.randomUUID();
2310
- this.element.setAttribute('id', this.id);
2368
+ this.element.setAttribute("id", this.id);
2311
2369
  }
2312
2370
 
2313
2371
  this.element.bib.setAttribute("id", `${this.id}-floater-bib`);
@@ -2328,11 +2386,15 @@ class AuroFloatingUI {
2328
2386
  if (this.element.trigger) {
2329
2387
  this.disconnect();
2330
2388
  }
2331
- this.element.trigger = this.element.triggerElement || this.element.shadowRoot.querySelector('#trigger') || this.element.trigger;
2332
- this.element.bib = this.element.shadowRoot.querySelector('#bib') || this.element.bib;
2333
- this.element.bibSizer = this.element.shadowRoot.querySelector('#bibSizer');
2334
- this.element.triggerChevron = this.element.shadowRoot.querySelector('#showStateIcon');
2335
-
2389
+ this.element.trigger =
2390
+ this.element.triggerElement ||
2391
+ this.element.shadowRoot.querySelector("#trigger") ||
2392
+ this.element.trigger;
2393
+ this.element.bib =
2394
+ this.element.shadowRoot.querySelector("#bib") || this.element.bib;
2395
+ this.element.bibSizer = this.element.shadowRoot.querySelector("#bibSizer");
2396
+ this.element.triggerChevron =
2397
+ this.element.shadowRoot.querySelector("#showStateIcon");
2336
2398
 
2337
2399
  if (this.element.floaterConfig) {
2338
2400
  this.element.hoverToggle = this.element.floaterConfig.hoverToggle;
@@ -2343,12 +2405,12 @@ class AuroFloatingUI {
2343
2405
 
2344
2406
  this.handleEvent = this.handleEvent.bind(this);
2345
2407
  if (this.element.trigger) {
2346
- this.element.trigger.addEventListener('keydown', this.handleEvent);
2347
- this.element.trigger.addEventListener('click', this.handleEvent);
2348
- this.element.trigger.addEventListener('mouseenter', this.handleEvent);
2349
- this.element.trigger.addEventListener('mouseleave', this.handleEvent);
2350
- this.element.trigger.addEventListener('focus', this.handleEvent);
2351
- this.element.trigger.addEventListener('blur', this.handleEvent);
2408
+ this.element.trigger.addEventListener("keydown", this.handleEvent);
2409
+ this.element.trigger.addEventListener("click", this.handleEvent);
2410
+ this.element.trigger.addEventListener("mouseenter", this.handleEvent);
2411
+ this.element.trigger.addEventListener("mouseleave", this.handleEvent);
2412
+ this.element.trigger.addEventListener("focus", this.handleEvent);
2413
+ this.element.trigger.addEventListener("blur", this.handleEvent);
2352
2414
  }
2353
2415
  }
2354
2416
 
@@ -2363,12 +2425,18 @@ class AuroFloatingUI {
2363
2425
 
2364
2426
  // Remove event & keyboard listeners
2365
2427
  if (this.element?.trigger) {
2366
- this.element.trigger.removeEventListener('keydown', this.handleEvent);
2367
- this.element.trigger.removeEventListener('click', this.handleEvent);
2368
- this.element.trigger.removeEventListener('mouseenter', this.handleEvent);
2369
- this.element.trigger.removeEventListener('mouseleave', this.handleEvent);
2370
- this.element.trigger.removeEventListener('focus', this.handleEvent);
2371
- this.element.trigger.removeEventListener('blur', this.handleEvent);
2428
+ this.element.trigger.removeEventListener("keydown", this.handleEvent);
2429
+ this.element.trigger.removeEventListener("click", this.handleEvent);
2430
+ this.element.trigger.removeEventListener(
2431
+ "mouseenter",
2432
+ this.handleEvent,
2433
+ );
2434
+ this.element.trigger.removeEventListener(
2435
+ "mouseleave",
2436
+ this.handleEvent,
2437
+ );
2438
+ this.element.trigger.removeEventListener("focus", this.handleEvent);
2439
+ this.element.trigger.removeEventListener("blur", this.handleEvent);
2372
2440
  }
2373
2441
  }
2374
2442
  }
@@ -2815,7 +2883,7 @@ class p{registerComponent(t,a){customElements.get(t)||customElements.define(t,cl
2815
2883
 
2816
2884
  var iconVersion = '9.1.2';
2817
2885
 
2818
- var styleCss$2 = css`: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}`;
2886
+ var styleCss$2 = css`: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}`;
2819
2887
 
2820
2888
  var colorCss$2 = css`.container{background-color:var(--ds-auro-dropdownbib-container-color);box-shadow:var(--ds-auro-dropdownbib-boxshadow-color);color:var(--ds-auro-dropdownbib-text-color)}`;
2821
2889
 
@@ -2823,6 +2891,8 @@ var tokensCss$1 = css`:host(:not([ondark])),:host(:not([appearance=inverse])){--
2823
2891
 
2824
2892
  // Copyright (c) 2020 Alaska Airlines. All right reserved. Licensed under the Apache-2.0 license
2825
2893
  // See LICENSE in the project root for license information.
2894
+ /* eslint-disable max-lines */
2895
+ // ---------------------------------------------------------------------
2826
2896
 
2827
2897
 
2828
2898
  const DESIGN_TOKEN_BREAKPOINT_PREFIX = '--ds-grid-breakpoint-';
@@ -2917,6 +2987,28 @@ class AuroDropdownBib extends LitElement {
2917
2987
  shape: {
2918
2988
  type: String,
2919
2989
  reflect: true
2990
+ },
2991
+
2992
+ /**
2993
+ * Accessible label for the dialog element, used when displayed as a modal.
2994
+ * Applied via aria-labelledby on a visually hidden element rather than
2995
+ * aria-label because iOS VoiceOver does not reliably read aria-label
2996
+ * on <dialog> elements.
2997
+ * @private
2998
+ */
2999
+ dialogLabel: {
3000
+ type: String
3001
+ },
3002
+
3003
+ /**
3004
+ * Overrides the native role of the dialog element.
3005
+ * For example, set to `"presentation"` on desktop combobox to prevent
3006
+ * VoiceOver from announcing "listbox inside of a dialog".
3007
+ * When `undefined`, the dialog keeps its native role.
3008
+ * @private
3009
+ */
3010
+ dialogRole: {
3011
+ type: String
2920
3012
  }
2921
3013
  };
2922
3014
  }
@@ -2984,7 +3076,10 @@ class AuroDropdownBib extends LitElement {
2984
3076
  firstUpdated(changedProperties) {
2985
3077
  super.firstUpdated(changedProperties);
2986
3078
 
2987
- // Dispatch a custom event when the component is connected
3079
+ const dialog = this.shadowRoot.querySelector('dialog');
3080
+ this._setupCancelHandler(dialog);
3081
+ this._setupKeyboardBridge(dialog);
3082
+
2988
3083
  this.dispatchEvent(new CustomEvent('auro-dropdownbib-connected', {
2989
3084
  bubbles: true,
2990
3085
  composed: true,
@@ -2994,6 +3089,189 @@ class AuroDropdownBib extends LitElement {
2994
3089
  }));
2995
3090
  }
2996
3091
 
3092
+ /**
3093
+ * Forwards the dialog's native `cancel` event (fired on ESC) as
3094
+ * an `auro-bib-cancel` custom event so parent components can close.
3095
+ * @param {HTMLDialogElement} dialog
3096
+ * @private
3097
+ */
3098
+ _setupCancelHandler(dialog) {
3099
+ dialog.addEventListener('cancel', (event) => {
3100
+ event.preventDefault();
3101
+ this.dispatchEvent(new CustomEvent('auro-bib-cancel', {
3102
+ bubbles: true,
3103
+ composed: true
3104
+ }));
3105
+ });
3106
+ }
3107
+
3108
+ /**
3109
+ * showModal() creates a closed focus scope — keyboard events inside
3110
+ * the dialog's shadow DOM do NOT bubble out to the combobox/select
3111
+ * keydown handlers in the parent shadow DOM. This handler bridges
3112
+ * that gap by re-dispatching navigation keys so they cross the
3113
+ * shadow boundary and reach the menu navigation logic in the parent
3114
+ * component.
3115
+ *
3116
+ * The trade-off: intercepting these keys means native keyboard
3117
+ * behaviors that would normally "just work" must be manually
3118
+ * re-implemented here:
3119
+ *
3120
+ * - Enter on buttons: Custom elements (auro-button) don't get the
3121
+ * native Enter→click that <button> provides, so we call .click()
3122
+ * directly when Enter is pressed on a button-like element.
3123
+ *
3124
+ * - Tab: Intercepted and re-dispatched so parent components
3125
+ * (select/combobox) can select the active option and close the
3126
+ * dialog. The <dialog> provides containment and isolation
3127
+ * (inert background, VoiceOver focus trapping, top layer), while
3128
+ * the content inside is a role="listbox" navigated via
3129
+ * aria-activedescendant (options are not focusable). Tab keyboard
3130
+ * behavior follows listbox conventions (select + close) because
3131
+ * the dialog's native Tab trap only cycles between the close
3132
+ * button and browser chrome.
3133
+ *
3134
+ * - Escape: The native <dialog> fires a `cancel` event on ESC
3135
+ * (handled by _setupCancelHandler), so the re-dispatched Escape
3136
+ * is a secondary path for parent components that also listen for
3137
+ * Escape keydown.
3138
+ *
3139
+ * @param {HTMLDialogElement} dialog
3140
+ * @private
3141
+ */
3142
+ _setupKeyboardBridge(dialog) {
3143
+ const navKeys = new Set([
3144
+ 'ArrowUp',
3145
+ 'ArrowDown',
3146
+ 'Enter',
3147
+ 'Escape',
3148
+ 'Tab'
3149
+ ]);
3150
+
3151
+ dialog.addEventListener('keydown', (event) => {
3152
+ if (!navKeys.has(event.key)) {
3153
+ return;
3154
+ }
3155
+
3156
+ // Custom elements (auro-button) don't get the native Enter→click
3157
+ // behavior that <button> has. Find the button in the composed path
3158
+ // and click it directly.
3159
+ if (event.key === 'Enter') {
3160
+ const buttonSelector = 'button, [role="button"], auro-button, [auro-button]';
3161
+ const btn = event.composedPath().find((el) => el.matches && el.matches(buttonSelector));
3162
+ if (btn) {
3163
+ event.preventDefault();
3164
+ event.stopPropagation();
3165
+ btn.click();
3166
+ return;
3167
+ }
3168
+ }
3169
+
3170
+ event.preventDefault();
3171
+ event.stopPropagation();
3172
+ const newEvent = new KeyboardEvent('keydown', {
3173
+ key: event.key,
3174
+ code: event.code,
3175
+ shiftKey: event.shiftKey,
3176
+ altKey: event.altKey,
3177
+ ctrlKey: event.ctrlKey,
3178
+ metaKey: event.metaKey,
3179
+ bubbles: true,
3180
+ composed: true,
3181
+ cancelable: true
3182
+ });
3183
+ this.dispatchEvent(newEvent);
3184
+ });
3185
+ }
3186
+
3187
+ /**
3188
+ * Blocks touch-driven page scroll while a fullscreen modal dialog is open.
3189
+ *
3190
+ * The showModal() function places the dialog in the browser's **top layer**,
3191
+ * which is a separate rendering layer above the normal DOM. On mobile, the
3192
+ * compositor processes visual-viewport panning before top-layer touch
3193
+ * handling. This means the entire viewport — including the top-layer dialog
3194
+ * — can be panned by a touch gesture, causing the page behind the dialog to
3195
+ * scroll into view. To prevent this, we add a touchmove listener that cancels
3196
+ * the event if the touch started outside the dialog or any scrollable child within it.
3197
+ *
3198
+ * @private
3199
+ */
3200
+ _lockTouchScroll() {
3201
+ const dialog = this.shadowRoot.querySelector('dialog');
3202
+
3203
+ this._touchMoveHandler = (event) => {
3204
+ // Walk the composed path (which crosses shadow DOM boundaries) to
3205
+ // check whether the touch started inside a scrollable element that
3206
+ // lives within the dialog. If so, allow the scroll.
3207
+ for (const el of event.composedPath()) {
3208
+ if (el === dialog) {
3209
+ // Reached the dialog boundary without finding a scrollable child.
3210
+ break;
3211
+ }
3212
+ if (el instanceof HTMLElement && el.scrollHeight > el.clientHeight) {
3213
+ const { overflowY } = getComputedStyle(el);
3214
+ if (overflowY === 'auto' || overflowY === 'scroll') {
3215
+ return;
3216
+ }
3217
+ }
3218
+ }
3219
+
3220
+ event.preventDefault();
3221
+ };
3222
+
3223
+ document.addEventListener('touchmove', this._touchMoveHandler, { passive: false });
3224
+ }
3225
+
3226
+ /**
3227
+ * Removes the touchmove listener added by _lockTouchScroll().
3228
+ * @private
3229
+ */
3230
+ _unlockTouchScroll() {
3231
+ if (this._touchMoveHandler) {
3232
+ document.removeEventListener('touchmove', this._touchMoveHandler);
3233
+ this._touchMoveHandler = undefined;
3234
+ }
3235
+ }
3236
+
3237
+ open(modal = true) {
3238
+ const dialog = this.shadowRoot.querySelector('dialog');
3239
+ if (dialog && !dialog.open) {
3240
+ if (modal) {
3241
+ // Prevent showModal() from scrolling the page to bring the dialog
3242
+ // into view. Locking overflow on <html> blocks the viewport scroll
3243
+ // that browsers perform natively; we release it immediately after
3244
+ // so it doesn't interfere with the modal's focus management.
3245
+ const { documentElement } = document;
3246
+ const prevOverflow = documentElement.style.overflow;
3247
+ documentElement.style.overflow = 'hidden';
3248
+
3249
+ dialog.showModal();
3250
+
3251
+ documentElement.style.overflow = prevOverflow;
3252
+
3253
+ this._lockTouchScroll();
3254
+
3255
+ } else {
3256
+ // Use setAttribute instead of dialog.show() to avoid the dialog
3257
+ // focusing steps which steal focus from the trigger and cause
3258
+ // the floater's handleFocusLoss() to immediately hide the bib.
3259
+ dialog.setAttribute('open', '');
3260
+ }
3261
+ }
3262
+ }
3263
+
3264
+ /**
3265
+ * Closes the dialog.
3266
+ */
3267
+ close() {
3268
+ const dialog = this.shadowRoot.querySelector('dialog');
3269
+ if (dialog && dialog.open) {
3270
+ this._unlockTouchScroll();
3271
+ dialog.close();
3272
+ }
3273
+ }
3274
+
2997
3275
  // function that renders the HTML and CSS into the scope of the component
2998
3276
  render() {
2999
3277
  const classes = {
@@ -3005,9 +3283,10 @@ class AuroDropdownBib extends LitElement {
3005
3283
  classes[`shape-${this.shape}`] = true;
3006
3284
 
3007
3285
  return html$1`
3008
- <div class="${classMap(classes)}" part="bibContainer">
3286
+ <dialog class="${classMap(classes)}" part="bibContainer" role="${ifDefined(this.dialogRole)}" aria-labelledby="${ifDefined(this.dialogLabel ? 'dialogLabel' : undefined)}">
3287
+ ${this.dialogLabel ? html$1`<span id="dialogLabel" class="util_displayHiddenVisually" aria-hidden="true">${this.dialogLabel}</span>` : ''}
3009
3288
  <slot></slot>
3010
- </div>
3289
+ </dialog>
3011
3290
  `;
3012
3291
  }
3013
3292
  }
@@ -3016,7 +3295,7 @@ var shapeSizeCss = css`.shape-classic-xl,.shape-classic-lg,.shape-classic-md,.sh
3016
3295
 
3017
3296
  var colorCss$1 = css`: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)}`;
3018
3297
 
3019
- var styleCss$1 = css`: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%}`;
3298
+ var styleCss$1 = css`: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%}`;
3020
3299
 
3021
3300
  var classicColorCss = css``;
3022
3301
 
@@ -3254,7 +3533,7 @@ class AuroHelpText extends LitElement {
3254
3533
  }
3255
3534
  }
3256
3535
 
3257
- var formkitVersion = '202602140013';
3536
+ var formkitVersion = '202603102257';
3258
3537
 
3259
3538
  class AuroElement extends LitElement {
3260
3539
  static get properties() {
@@ -3368,7 +3647,7 @@ class AuroElement extends LitElement {
3368
3647
  * The `auro-dropdown` element provides a way to place content in a bib that can be toggled.
3369
3648
  * @customElement auro-dropdown
3370
3649
  *
3371
- * @slot - Default slot for the popover content.
3650
+ * @slot - Default slot for the dropdown bib content.
3372
3651
  * @slot helpText - Defines the content of the helpText.
3373
3652
  * @slot trigger - Defines the content of the trigger.
3374
3653
  * @csspart trigger - The trigger content container.
@@ -3380,6 +3659,13 @@ class AuroElement extends LitElement {
3380
3659
  * @event auroDropdown-idAdded - Notifies consumers that the unique ID for the dropdown bib has been generated.
3381
3660
  */
3382
3661
  class AuroDropdown extends AuroElement {
3662
+ static get shadowRootOptions() {
3663
+ return {
3664
+ ...AuroElement.shadowRootOptions,
3665
+ delegatesFocus: true,
3666
+ };
3667
+ }
3668
+
3383
3669
  constructor() {
3384
3670
  super();
3385
3671
 
@@ -3445,15 +3731,6 @@ class AuroDropdown extends AuroElement {
3445
3731
  this.shift = false;
3446
3732
  this.autoPlacement = false;
3447
3733
 
3448
- /**
3449
- * @private
3450
- * @property {boolean} delegatesFocus - Whether the shadow root delegates focus.
3451
- */
3452
- this.constructor.shadowRootOptions = {
3453
- ...LitElement.shadowRootOptions,
3454
- delegatesFocus: true,
3455
- };
3456
-
3457
3734
  /**
3458
3735
  * @private
3459
3736
  */
@@ -3527,6 +3804,18 @@ class AuroDropdown extends AuroElement {
3527
3804
  */
3528
3805
  show() {
3529
3806
  this.floater.showBib();
3807
+
3808
+ // Open dialog synchronously so callers remain in the user gesture
3809
+ // chain. This is critical for mobile browsers (iOS Safari) to keep
3810
+ // the virtual keyboard open when transitioning from the trigger
3811
+ // input to an input inside the fullscreen dialog. Without this,
3812
+ // showModal() fires asynchronously via Lit's update cycle, which
3813
+ // falls outside the user activation window and causes iOS to
3814
+ // dismiss the keyboard.
3815
+ if (this.isBibFullscreen && this.bibElement && this.bibElement.value) {
3816
+ const useModal = !this.disableFocusTrap;
3817
+ this.bibElement.value.open(useModal);
3818
+ }
3530
3819
  }
3531
3820
 
3532
3821
  /**
@@ -3534,13 +3823,37 @@ class AuroDropdown extends AuroElement {
3534
3823
  * If not, trigger element will get focus.
3535
3824
  */
3536
3825
  focus() {
3537
- if (this.isPopoverVisible && this.focusTrap) {
3538
- this.focusTrap.focusFirstElement();
3826
+ if (this.isPopoverVisible && this.bibContent) {
3827
+ const focusables = getFocusableElements(this.bibContent);
3828
+ if (focusables.length > 0) {
3829
+ focusables[0].focus();
3830
+ }
3539
3831
  } else {
3540
3832
  this.trigger.focus();
3541
3833
  }
3542
3834
  }
3543
3835
 
3836
+ /**
3837
+ * Sets the active descendant element for accessibility.
3838
+ * Uses ariaActiveDescendantElement to cross shadow DOM boundaries.
3839
+ * This function is used in components that contain `auro-dropdown` to set the active descendant.
3840
+ * @private
3841
+ * @param {HTMLElement|null} element - The element to set as the active descendant, or null to clear.
3842
+ * @returns {void}
3843
+ */
3844
+ setActiveDescendant(element) {
3845
+ if (!this.trigger) {
3846
+ return;
3847
+ }
3848
+
3849
+ if (element) {
3850
+ this.trigger.ariaActiveDescendantElement = element;
3851
+ } else {
3852
+ this.trigger.ariaActiveDescendantElement = null;
3853
+ this.trigger.removeAttribute('aria-activedescendant');
3854
+ }
3855
+ }
3856
+
3544
3857
  // function to define props used within the scope of this component
3545
3858
  static get properties() {
3546
3859
  return {
@@ -3798,6 +4111,16 @@ class AuroDropdown extends AuroElement {
3798
4111
  */
3799
4112
  tabIndex: {
3800
4113
  type: Number
4114
+ },
4115
+
4116
+ /**
4117
+ * Accessible label for the dropdown bib dialog element.
4118
+ * @private
4119
+ */
4120
+ bibDialogLabel: {
4121
+ type: String,
4122
+ attribute: false,
4123
+ reflect: false
3801
4124
  }
3802
4125
  };
3803
4126
  }
@@ -3849,7 +4172,10 @@ class AuroDropdown extends AuroElement {
3849
4172
 
3850
4173
  disconnectedCallback() {
3851
4174
  super.disconnectedCallback();
3852
- this.floater.disconnect();
4175
+ if (this.floater) {
4176
+ this.floater.hideBib('disconnect');
4177
+ this.floater.disconnect();
4178
+ }
3853
4179
  this.clearTriggerFocusEventBinding();
3854
4180
  }
3855
4181
 
@@ -3871,11 +4197,22 @@ class AuroDropdown extends AuroElement {
3871
4197
 
3872
4198
  if (changedProperties.has('isPopoverVisible') && this.bibElement.value) {
3873
4199
  if (this.isPopoverVisible) {
3874
- this.bibElement.value.showPopover();
4200
+ // Fullscreen: use showModal() for native accessibility (inert outside, focus trap)
4201
+ // Desktop: use show() for Floating UI positioning + FocusTrap for focus management
4202
+ const useModal = this.isBibFullscreen && !this.disableFocusTrap;
4203
+ this.bibElement.value.open(useModal);
3875
4204
  } else {
3876
- this.bibElement.value.hidePopover();
4205
+ this.bibElement.value.close();
3877
4206
  }
3878
4207
  }
4208
+
4209
+ // When fullscreen strategy changes while open, re-open dialog with correct mode
4210
+ // (e.g. resizing from desktop → mobile while dropdown is open)
4211
+ if (changedProperties.has('isBibFullscreen') && this.isPopoverVisible && this.bibElement.value) {
4212
+ const useModal = this.isBibFullscreen && !this.disableFocusTrap;
4213
+ this.bibElement.value.close();
4214
+ this.bibElement.value.open(useModal);
4215
+ }
3879
4216
  }
3880
4217
 
3881
4218
  /**
@@ -3893,11 +4230,28 @@ class AuroDropdown extends AuroElement {
3893
4230
  }
3894
4231
 
3895
4232
  firstUpdated() {
3896
-
3897
4233
  // Configure the floater to, this will generate the ID for the bib
3898
4234
  this.floater.configure(this, 'auroDropdown');
4235
+
4236
+ // Prevent `contain: layout` on the dropdown host. Layout containment
4237
+ // creates a containing block for position:fixed descendants (the bib),
4238
+ // which clips the bib inside ancestor overflow contexts such as a
4239
+ // <dialog> element. Without it, the bib's position:fixed is relative
4240
+ // to the viewport, letting Floating UI's flip middleware detect
4241
+ // viewport boundaries and the bib escape overflow clipping.
4242
+ const origConfigureBibStrategy = this.floater.configureBibStrategy.bind(this.floater);
4243
+ this.floater.configureBibStrategy = (value) => {
4244
+ origConfigureBibStrategy(value);
4245
+ this.style.contain = '';
4246
+ };
4247
+
3899
4248
  this.addEventListener('auroDropdown-toggled', this.handleDropdownToggle);
3900
4249
 
4250
+ // Handle ESC key from dialog's cancel event
4251
+ this.addEventListener('auro-bib-cancel', () => {
4252
+ this.floater.hideBib('keydown');
4253
+ });
4254
+
3901
4255
  /**
3902
4256
  * @description Let subscribers know that the dropdown ID ha been generated and added.
3903
4257
  * @event auroDropdown-idAdded
@@ -3905,9 +4259,9 @@ class AuroDropdown extends AuroElement {
3905
4259
  */
3906
4260
  this.dispatchEvent(new CustomEvent('auroDropdown-idAdded', {detail: {id: this.floater.element.id}}));
3907
4261
 
3908
- // Set the bib ID locally if the user hasn't provided a focusable trigger
4262
+ // Set the bib ID locally for aria-controls (must be in the same shadow root as the trigger)
3909
4263
  if (!this.triggerContentFocusable) {
3910
- this.dropdownId = this.floater.element.id;
4264
+ this.dropdownId = this.floater.element.bib.id;
3911
4265
  }
3912
4266
 
3913
4267
  this.bibContent = this.floater.element.bib;
@@ -3967,21 +4321,20 @@ class AuroDropdown extends AuroElement {
3967
4321
  * @private
3968
4322
  */
3969
4323
  updateFocusTrap() {
3970
- // If the dropdown is open, create a focus trap and focus the first element
3971
4324
  if (this.isPopoverVisible && !this.disableFocusTrap) {
3972
- this.focusTrap = new FocusTrap(this.bibContent);
3973
- this.focusTrap.focusFirstElement();
4325
+ if (!this.isBibFullscreen) {
4326
+ // Desktop: show() doesn't trap focus, so use FocusTrap
4327
+ this.focusTrap = new FocusTrap(this.bibContent);
4328
+ this.focusTrap.focusFirstElement();
4329
+ }
4330
+ // Fullscreen: showModal() provides native focus trapping
3974
4331
  return;
3975
4332
  }
3976
4333
 
3977
- // Guard Clause: Ensure there is a focus trap currently active before continuing
3978
- if (!this.focusTrap) {
3979
- return;
4334
+ if (this.focusTrap) {
4335
+ this.focusTrap.disconnect();
4336
+ this.focusTrap = undefined;
3980
4337
  }
3981
-
3982
- // If the dropdown is not open, disconnect the focus trap if it exists
3983
- this.focusTrap.disconnect();
3984
- this.focusTrap = undefined;
3985
4338
  }
3986
4339
 
3987
4340
  /**
@@ -4197,13 +4550,14 @@ class AuroDropdown extends AuroElement {
4197
4550
  <div
4198
4551
  id="showStateIcon"
4199
4552
  class="chevron"
4200
- part="chevron">
4553
+ part="chevron"
4554
+ aria-hidden="true">
4201
4555
  <${this.iconTag}
4202
4556
  category="interface"
4203
4557
  name="${this.isPopoverVisible ? 'chevron-up' : `chevron-down`}"
4204
4558
  appearance="${this.onDark ? 'inverse' : this.appearance}"
4205
- variant="${this.disabled ? 'disabled' : 'muted'}">
4206
- >
4559
+ variant="${this.disabled ? 'disabled' : 'muted'}"
4560
+ ariaHidden="true">
4207
4561
  </${this.iconTag}>
4208
4562
  </div>
4209
4563
  ` : undefined }
@@ -4217,8 +4571,8 @@ class AuroDropdown extends AuroElement {
4217
4571
  shape="${this.shape}"
4218
4572
  ?data-show="${this.isPopoverVisible}"
4219
4573
  ?isfullscreen="${this.isBibFullscreen}"
4574
+ .dialogLabel="${this.bibDialogLabel}"
4220
4575
  ${ref(this.bibElement)}
4221
- popover="manual"
4222
4576
  >
4223
4577
  <div class="slotContent">
4224
4578
  <slot @slotchange="${this.handleDefaultSlot}"></slot>