@aurodesignsystem-dev/auro-formkit 0.0.0-pr1503.3 → 0.0.0-pr1503.5

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 (190) hide show
  1. package/components/bibtemplate/dist/index.js +1 -1
  2. package/components/bibtemplate/dist/registered.js +1 -1
  3. package/components/checkbox/demo/accessibility.md +1 -1
  4. package/components/checkbox/demo/customize.html +1 -2
  5. package/components/checkbox/demo/customize.min.js +23 -8
  6. package/components/checkbox/demo/getting-started.min.js +23 -8
  7. package/components/checkbox/demo/index.min.js +23 -8
  8. package/components/checkbox/dist/index.js +23 -8
  9. package/components/checkbox/dist/registered.js +23 -8
  10. package/components/combobox/README.md +1 -1
  11. package/components/combobox/demo/accessibility.md +1 -1
  12. package/components/combobox/demo/api.md +2 -2
  13. package/components/combobox/demo/customize.html +1 -2
  14. package/components/combobox/demo/customize.md +166 -142
  15. package/components/combobox/demo/customize.min.js +2515 -2316
  16. package/components/combobox/demo/getting-started.min.js +2515 -2312
  17. package/components/combobox/demo/index.md +2 -1
  18. package/components/combobox/demo/index.min.js +2515 -2312
  19. package/components/combobox/demo/keyboard-behavior.md +3 -146
  20. package/components/combobox/demo/readme.md +1 -1
  21. package/components/combobox/demo/why-combobox.md +2 -2
  22. package/components/combobox/dist/auro-combobox.d.ts +49 -15
  23. package/components/combobox/dist/index.js +1462 -753
  24. package/components/combobox/dist/registered.js +1462 -753
  25. package/components/counter/demo/customize.min.js +188 -244
  26. package/components/counter/demo/index.min.js +188 -244
  27. package/components/counter/dist/auro-counter.d.ts +0 -8
  28. package/components/counter/dist/index.js +188 -244
  29. package/components/counter/dist/registered.js +188 -244
  30. package/components/datepicker/demo/accessibility.md +20 -10
  31. package/components/datepicker/demo/api.md +65 -62
  32. package/components/datepicker/demo/customize.md +180 -40
  33. package/components/datepicker/demo/customize.min.js +1690 -777
  34. package/components/datepicker/demo/getting-started.md +118 -2
  35. package/components/datepicker/demo/index.min.js +1690 -759
  36. package/components/datepicker/demo/keyboard-behavior.md +3 -3
  37. package/components/datepicker/demo/voiceover.md +4 -4
  38. package/components/datepicker/demo/why-datepicker.md +2 -2
  39. package/components/datepicker/dist/{src/auro-calendar-cell.d.ts → auro-calendar-cell.d.ts} +48 -3
  40. package/components/datepicker/dist/{src/auro-calendar.d.ts → auro-calendar.d.ts} +188 -10
  41. package/components/datepicker/dist/{src/auro-datepicker.d.ts → auro-datepicker.d.ts} +89 -6
  42. package/components/datepicker/dist/blackoutUtils.d.ts +43 -0
  43. package/components/datepicker/dist/index.js +1690 -759
  44. package/components/datepicker/dist/registered.js +1690 -759
  45. package/components/dropdown/demo/customize.html +3 -0
  46. package/components/dropdown/demo/customize.min.js +142 -208
  47. package/components/dropdown/demo/getting-started.min.js +131 -207
  48. package/components/dropdown/demo/index.min.js +131 -207
  49. package/components/dropdown/dist/auro-dropdown.d.ts +17 -1
  50. package/components/dropdown/dist/index.js +131 -207
  51. package/components/dropdown/dist/registered.js +131 -207
  52. package/components/form/demo/api.md +3 -3
  53. package/components/form/demo/customize.html +6 -6
  54. package/components/form/demo/customize.md +535 -135
  55. package/components/form/demo/customize.min.js +6307 -4378
  56. package/components/form/demo/getting-started.md +344 -96
  57. package/components/form/demo/getting-started.min.js +6255 -4378
  58. package/components/form/demo/index.min.js +6206 -4378
  59. package/components/form/demo/registerDemoDeps.min.js +5827 -4333
  60. package/components/form/dist/auro-form.d.ts +128 -10
  61. package/components/form/dist/index.js +377 -43
  62. package/components/form/dist/registered.js +377 -43
  63. package/components/input/demo/accessibility.md +1 -1
  64. package/components/input/demo/api.md +58 -57
  65. package/components/input/demo/customize.html +1 -2
  66. package/components/input/demo/customize.md +62 -61
  67. package/components/input/demo/customize.min.js +396 -275
  68. package/components/input/demo/getting-started.min.js +396 -275
  69. package/components/input/demo/index.min.js +396 -275
  70. package/components/input/dist/auro-input.d.ts +1 -1
  71. package/components/input/dist/base-input.d.ts +60 -81
  72. package/components/input/dist/index.js +409 -276
  73. package/components/input/dist/registered.js +396 -275
  74. package/components/input/dist/utilities.d.ts +10 -1
  75. package/components/menu/demo/accessibility.md +9 -4
  76. package/components/menu/demo/api.md +48 -45
  77. package/components/menu/demo/css-only.md +26 -19
  78. package/components/menu/demo/customize.md +307 -75
  79. package/components/menu/demo/design.md +1 -1
  80. package/components/menu/demo/getting-started.md +144 -7
  81. package/components/menu/demo/index.min.js +961 -1341
  82. package/components/menu/demo/keyboard-behavior.md +83 -4
  83. package/components/menu/demo/voiceover.md +21 -14
  84. package/components/menu/demo/why-menu.md +8 -9
  85. package/components/menu/dist/auro-menu-utils.d.ts +19 -0
  86. package/components/menu/dist/auro-menu.d.ts +97 -116
  87. package/components/menu/dist/auro-menuoption.d.ts +39 -133
  88. package/components/menu/dist/index.js +823 -1309
  89. package/components/menu/dist/registered.js +835 -1309
  90. package/components/radio/demo/accessibility.md +1 -1
  91. package/components/radio/demo/customize.min.js +23 -8
  92. package/components/radio/demo/getting-started.min.js +23 -8
  93. package/components/radio/demo/index.min.js +23 -8
  94. package/components/radio/dist/index.js +23 -8
  95. package/components/radio/dist/registered.js +23 -8
  96. package/components/select/demo/accessibility.md +6 -1
  97. package/components/select/demo/api.md +3 -2
  98. package/components/select/demo/customize.html +1 -2
  99. package/components/select/demo/customize.md +210 -5
  100. package/components/select/demo/customize.min.js +1613 -1854
  101. package/components/select/demo/design.md +10 -10
  102. package/components/select/demo/getting-started.md +1 -1
  103. package/components/select/demo/getting-started.min.js +1617 -1903
  104. package/components/select/demo/index.md +2 -2
  105. package/components/select/demo/index.min.js +1613 -1854
  106. package/components/select/demo/keyboard-behavior.md +81 -54
  107. package/components/select/demo/voiceover.md +28 -15
  108. package/components/select/dist/auro-select.d.ts +70 -12
  109. package/components/select/dist/index.js +580 -315
  110. package/components/select/dist/registered.js +580 -315
  111. package/components/select/dist/selectUtils.d.ts +24 -0
  112. package/custom-elements.json +8071 -7919
  113. package/package.json +7 -3
  114. package/components/checkbox/demo/customize.js +0 -22
  115. package/components/checkbox/demo/demo-support.js +0 -1
  116. package/components/checkbox/demo/getting-started.js +0 -22
  117. package/components/checkbox/demo/index.js +0 -8
  118. package/components/checkbox/demo/styles.scss +0 -1
  119. package/components/combobox/demo/customize.js +0 -24
  120. package/components/combobox/demo/demo-support.js +0 -1
  121. package/components/combobox/demo/getting-started.js +0 -21
  122. package/components/combobox/demo/index.js +0 -23
  123. package/components/combobox/demo/styles.scss +0 -1
  124. package/components/counter/demo/customize.js +0 -21
  125. package/components/counter/demo/demo-support.js +0 -1
  126. package/components/counter/demo/index.js +0 -21
  127. package/components/counter/demo/styles.scss +0 -1
  128. package/components/datepicker/demo/customize.js +0 -19
  129. package/components/datepicker/demo/demo-support.js +0 -1
  130. package/components/datepicker/demo/index.js +0 -23
  131. package/components/datepicker/demo/styles.scss +0 -1
  132. package/components/dropdown/demo/customize.js +0 -9
  133. package/components/dropdown/demo/demo-support.js +0 -1
  134. package/components/dropdown/demo/getting-started.js +0 -9
  135. package/components/dropdown/demo/index.js +0 -16
  136. package/components/dropdown/demo/styles.scss +0 -1
  137. package/components/form/demo/customize.js +0 -9
  138. package/components/form/demo/demo-support.js +0 -1
  139. package/components/form/demo/getting-started.js +0 -9
  140. package/components/form/demo/index.js +0 -5
  141. package/components/form/demo/registerDemoDeps.js +0 -23
  142. package/components/form/demo/styles.scss +0 -1
  143. package/components/input/demo/customize.js +0 -25
  144. package/components/input/demo/demo-support.js +0 -1
  145. package/components/input/demo/getting-started.js +0 -8
  146. package/components/input/demo/index.js +0 -8
  147. package/components/input/demo/styles.css +0 -974
  148. package/components/input/demo/styles.scss +0 -1
  149. package/components/menu/demo/demo-support.js +0 -1
  150. package/components/menu/demo/index.js +0 -25
  151. package/components/menu/demo/styles.scss +0 -1
  152. package/components/menu/dist/auro-menu.context.d.ts +0 -238
  153. package/components/radio/demo/customize.js +0 -22
  154. package/components/radio/demo/demo-support.js +0 -1
  155. package/components/radio/demo/getting-started.js +0 -24
  156. package/components/radio/demo/index.js +0 -8
  157. package/components/radio/demo/styles.scss +0 -1
  158. package/components/select/demo/customize.js +0 -11
  159. package/components/select/demo/demo-support.js +0 -1
  160. package/components/select/demo/getting-started.js +0 -26
  161. package/components/select/demo/index.js +0 -11
  162. package/components/select/demo/styles.scss +0 -1
  163. /package/components/counter/dist/styles/{counter-wrapper-color-css.d.ts → counter-group-color-css.d.ts} +0 -0
  164. /package/components/datepicker/dist/{src/auro-calendar-month.d.ts → auro-calendar-month.d.ts} +0 -0
  165. /package/components/datepicker/dist/{src/buttonVersion.d.ts → buttonVersion.d.ts} +0 -0
  166. /package/components/datepicker/dist/{src/datepickerKeyboardStrategy.d.ts → datepickerKeyboardStrategy.d.ts} +0 -0
  167. /package/components/datepicker/dist/{src/iconVersion.d.ts → iconVersion.d.ts} +0 -0
  168. /package/components/datepicker/dist/{src/index.d.ts → index.d.ts} +0 -0
  169. /package/components/datepicker/dist/{src/popoverVersion.d.ts → popoverVersion.d.ts} +0 -0
  170. /package/components/datepicker/dist/{src/styles → styles}/classic/color-css.d.ts +0 -0
  171. /package/components/datepicker/dist/{src/styles → styles}/classic/style-css.d.ts +0 -0
  172. /package/components/datepicker/dist/{src/styles → styles}/color-calendar-css.d.ts +0 -0
  173. /package/components/datepicker/dist/{src/styles → styles}/color-cell-css.d.ts +0 -0
  174. /package/components/datepicker/dist/{src/styles → styles}/color-css.d.ts +0 -0
  175. /package/components/datepicker/dist/{src/styles → styles}/color-month-css.d.ts +0 -0
  176. /package/components/datepicker/dist/{src/styles → styles}/shapeSize-css.d.ts +0 -0
  177. /package/components/datepicker/dist/{src/styles → styles}/snowflake/color-css.d.ts +0 -0
  178. /package/components/datepicker/dist/{src/styles → styles}/snowflake/style-css.d.ts +0 -0
  179. /package/components/datepicker/dist/{src/styles → styles}/style-auro-calendar-cell-css.d.ts +0 -0
  180. /package/components/datepicker/dist/{src/styles → styles}/style-auro-calendar-css.d.ts +0 -0
  181. /package/components/datepicker/dist/{src/styles → styles}/style-auro-calendar-month-css.d.ts +0 -0
  182. /package/components/datepicker/dist/{src/styles → styles}/style-css.d.ts +0 -0
  183. /package/components/datepicker/dist/{src/styles → styles}/tokens-css.d.ts +0 -0
  184. /package/components/datepicker/dist/{src/utilities.d.ts → utilities.d.ts} +0 -0
  185. /package/components/datepicker/dist/{src/utilitiesCalendar.d.ts → utilitiesCalendar.d.ts} +0 -0
  186. /package/components/datepicker/dist/{src/utilitiesCalendarRender.d.ts → utilitiesCalendarRender.d.ts} +0 -0
  187. /package/components/datepicker/dist/{src/vendor → vendor}/wc-range-datepicker/day.d.ts +0 -0
  188. /package/components/datepicker/dist/{src/vendor → vendor}/wc-range-datepicker/range-datepicker-calendar.d.ts +0 -0
  189. /package/components/datepicker/dist/{src/vendor → vendor}/wc-range-datepicker/range-datepicker-cell.d.ts +0 -0
  190. /package/components/datepicker/dist/{src/vendor → vendor}/wc-range-datepicker/range-datepicker.d.ts +0 -0
@@ -38,7 +38,10 @@
38
38
 
39
39
  <script type="module">
40
40
  import { renderPage } from './demo-support.min.js';
41
+ import { initExamples } from './customize.min.js';
41
42
  await renderPage('./customize.md');
43
+
44
+ initExamples();
42
45
  </script>
43
46
 
44
47
  <!-- If additional elements are needed for the demo, add them here. -->
@@ -2295,12 +2295,40 @@ class AuroFloatingUI {
2295
2295
  return;
2296
2296
  }
2297
2297
 
2298
+ // Chrome-specific: during popover top-layer promotion after a click on a
2299
+ // slotted focusable, :focus-within can briefly evaluate false while the
2300
+ // active element is still structurally inside the trigger/bib. Fall back
2301
+ // to a shadow-piercing ancestry walk from the deep active element before
2302
+ // treating this as a real focus loss.
2303
+ try {
2304
+ let active = document.activeElement;
2305
+ while (active && active.shadowRoot && active.shadowRoot.activeElement) {
2306
+ active = active.shadowRoot.activeElement;
2307
+ }
2308
+ const targets = [element, element.trigger, element.bib].filter(Boolean);
2309
+ let node = active;
2310
+ while (node) {
2311
+ if (targets.includes(node)) {
2312
+ return;
2313
+ }
2314
+ node =
2315
+ node.parentElement ||
2316
+ (node.getRootNode && node.getRootNode().host) ||
2317
+ null;
2318
+ }
2319
+ } catch (e) {
2320
+ // Defensive: fall through to the existing close path if traversal fails.
2321
+ }
2322
+
2298
2323
  // if fullscreen bib is in fullscreen mode, do not close
2299
2324
  if (element.bib.hasAttribute("isfullscreen")) {
2300
2325
  return;
2301
2326
  }
2302
2327
 
2303
- this.hideBib("keydown");
2328
+ // eventType "focusloss" distinguishes a Tab/click-driven close from an
2329
+ // Escape keydown close. Consumers use this to decide whether to restore
2330
+ // focus to the trigger (Escape) or let it advance naturally (Tab).
2331
+ this.hideBib("focusloss");
2304
2332
  }
2305
2333
 
2306
2334
  setupHideHandlers() {
@@ -2970,199 +2998,6 @@ function getFocusableElements(container) {
2970
2998
  return tabIndexedUniqueElements;
2971
2999
  }
2972
3000
 
2973
- /**
2974
- * FocusTrap manages keyboard focus within a specified container element, ensuring that focus does not leave the container when tabbing.
2975
- * It is commonly used for modal dialogs or overlays to improve accessibility by trapping focus within interactive UI components.
2976
- */
2977
- class FocusTrap {
2978
- /**
2979
- * Creates a new FocusTrap instance for the given container element.
2980
- * Initializes event listeners and prepares the container for focus management.
2981
- *
2982
- * @param {HTMLElement} container The DOM element to trap focus within.
2983
- * @param {boolean} [controlTabOrder=false] If true enables manual control of the tab order by the FocusTrap.
2984
- * @throws {Error} If the provided container is not a valid HTMLElement.
2985
- */
2986
- constructor(container, controlTabOrder = false) {
2987
- if (!container || !(container instanceof HTMLElement)) {
2988
- throw new Error("FocusTrap requires a valid HTMLElement.");
2989
- }
2990
-
2991
- this.container = container;
2992
- this.tabDirection = "forward"; // or 'backward';
2993
- this.controlTabOrder = controlTabOrder;
2994
-
2995
- this._init();
2996
- }
2997
-
2998
- /**
2999
- * Initializes the focus trap by setting up event listeners and attributes on the container.
3000
- * Prepares the container for focus management, including support for shadow DOM and inert attributes.
3001
- *
3002
- * @private
3003
- */
3004
- _init() {
3005
- // Add inert attribute to prevent focusing programmatically as well (if supported)
3006
- if ("inert" in HTMLElement.prototype) {
3007
- this.container.inert = false; // Ensure the container isn't inert
3008
- this.container.setAttribute("data-focus-trap-container", true); // Mark for identification
3009
- }
3010
-
3011
- // Track tab direction
3012
- this.container.addEventListener("keydown", this._onKeydown);
3013
- }
3014
-
3015
- /**
3016
- * Gets an array of currently active (focused) elements in the document and shadow DOM.
3017
- * @returns {Array<HTMLElement>} An array of focusable elements within the container.
3018
- * @private
3019
- */
3020
- _getActiveElements() {
3021
- // Get the active element(s) in the document and shadow root
3022
- // This will include the active element in the shadow DOM if it exists
3023
- // Active element may be inside the shadow DOM depending on delegatesFocus, so we need to check both
3024
- let { activeElement } = document;
3025
- const actives = [activeElement];
3026
- while (activeElement?.shadowRoot?.activeElement) {
3027
- actives.push(activeElement.shadowRoot.activeElement);
3028
- activeElement = activeElement.shadowRoot.activeElement;
3029
- }
3030
- return actives;
3031
- }
3032
-
3033
- /**
3034
- * Gets the next focus index based on the current index and focusable elements.
3035
- * @param {number} currentIndex The current index of the focused element.
3036
- * @param {Array<HTMLElement>} focusables The array of focusable elements.
3037
- * @returns {number|null} The next focus index or null if not determined.
3038
- */
3039
- _getNextFocusIndex(currentIndex, focusables, actives) {
3040
- if (this.controlTabOrder) {
3041
- // Calculate the new index based on the current index and tab direction
3042
- let newFocusIndex =
3043
- currentIndex + (this.tabDirection === "forward" ? 1 : -1);
3044
-
3045
- // Wrap-around logic
3046
- if (newFocusIndex < 0) newFocusIndex = focusables.length - 1;
3047
- if (newFocusIndex >= focusables.length) newFocusIndex = 0;
3048
-
3049
- // Early return with the new index
3050
- return newFocusIndex;
3051
- }
3052
-
3053
- // Determine if we need to wrap
3054
- const atFirst =
3055
- actives.includes(focusables[0]) || actives.includes(this.container);
3056
- const atLast = actives.includes(focusables[focusables.length - 1]);
3057
-
3058
- // Only wrap if at the ends
3059
- if (this.tabDirection === "backward" && atFirst) {
3060
- return focusables.length - 1;
3061
- }
3062
-
3063
- if (this.tabDirection === "forward" && atLast) {
3064
- return 0;
3065
- }
3066
-
3067
- // No wrap, so don't change focus, return early
3068
- return null;
3069
- }
3070
-
3071
- /**
3072
- * Handles the Tab key press event to manage focus within the container.
3073
- * @param {KeyboardEvent} e The keyboard event triggered by the user.
3074
- * @returns {void}
3075
- */
3076
- _handleTabKey(e) {
3077
- // Update the focusable elements
3078
- const focusables = this._getFocusableElements();
3079
-
3080
- // If there are no focusable elements, exit
3081
- if (!focusables.length) return;
3082
-
3083
- // Set the tab direction based on the key pressed
3084
- this.tabDirection = e.shiftKey ? "backward" : "forward";
3085
-
3086
- // Get the active elements that are currently focused
3087
- const actives = this._getActiveElements();
3088
-
3089
- // If we're at either end of the focusable elements, wrap around to the other end
3090
- let focusIndex = focusables.findIndex((el) => actives.includes(el));
3091
-
3092
- // Fallback if we have no focused element
3093
- if (focusIndex === -1) focusIndex = 0;
3094
-
3095
- // Get the next focus index based on the current focus index, tab direction, and controlTabOrder setting
3096
- // Is null if no new focus index is determined
3097
- const newFocusIndex = this._getNextFocusIndex(
3098
- focusIndex,
3099
- focusables,
3100
- actives,
3101
- );
3102
-
3103
- // If we have a new focus index, set focus to that element
3104
- if (newFocusIndex !== null) {
3105
- e.preventDefault();
3106
- focusables[newFocusIndex].focus();
3107
- }
3108
- }
3109
-
3110
- /**
3111
- * Catches the keydown event
3112
- * @param {KeyboardEvent} e The keyboard event triggered by user interaction.
3113
- * @private
3114
- */
3115
- _onKeydown = (e) => {
3116
- // Handle tab
3117
- if (e.key === "Tab") this._handleTabKey(e);
3118
- };
3119
-
3120
- /**
3121
- * Retrieves all focusable elements within the container in DOM order, including those in shadow DOM and slots.
3122
- * Returns a unique, ordered array of elements that can receive focus.
3123
- *
3124
- * @returns {Array<HTMLElement>} An array of focusable elements within the container.
3125
- * @private
3126
- */
3127
- _getFocusableElements() {
3128
- // Use the imported utility function to get focusable elements
3129
- const elements = getFocusableElements(this.container);
3130
-
3131
- // Return the elements found
3132
- return elements;
3133
- }
3134
-
3135
- /**
3136
- * Moves focus to the first focusable element within the container.
3137
- * Useful for setting initial focus when activating the focus trap.
3138
- */
3139
- focusFirstElement() {
3140
- const focusables = this._getFocusableElements();
3141
- if (focusables.length) focusables[0].focus();
3142
- }
3143
-
3144
- /**
3145
- * Moves focus to the last focusable element within the container.
3146
- * Useful for setting focus when deactivating or cycling focus in reverse.
3147
- */
3148
- focusLastElement() {
3149
- const focusables = this._getFocusableElements();
3150
- if (focusables.length) focusables[focusables.length - 1].focus();
3151
- }
3152
-
3153
- /**
3154
- * Removes event listeners and attributes added by the focus trap.
3155
- * Call this method to clean up when the focus trap is no longer needed.
3156
- */
3157
- disconnect() {
3158
- if (this.container.hasAttribute("data-focus-trap-container")) {
3159
- this.container.removeAttribute("data-focus-trap-container");
3160
- }
3161
-
3162
- this.container.removeEventListener("keydown", this._onKeydown);
3163
- }
3164
- }
3165
-
3166
3001
  // Copyright (c) Alaska Air. All right reserved. Licensed under the Apache-2.0 license
3167
3002
  // See LICENSE in the project root for license information.
3168
3003
 
@@ -3694,7 +3529,7 @@ class AuroDropdownBib extends i {
3694
3529
  classes[`shape-${this.shape}`] = true;
3695
3530
 
3696
3531
  return u$2`
3697
- <dialog class="${e$4(classes)}" part="bibContainer" role="${o(this.dialogRole)}" aria-labelledby="${o(this.dialogLabel ? 'dialogLabel' : undefined)}">
3532
+ <dialog tabindex="-1" class="${e$4(classes)}" part="bibContainer" role="${o(this.dialogRole)}" aria-labelledby="${o(this.dialogLabel ? 'dialogLabel' : undefined)}">
3698
3533
  ${this.dialogLabel ? u$2`<span id="dialogLabel" class="util_displayHiddenVisually">${this.dialogLabel}</span>` : ''}
3699
3534
  <slot></slot>
3700
3535
  <span id="srAnnouncement" class="util_displayHiddenVisually" aria-live="polite" role="status"></span>
@@ -3945,7 +3780,7 @@ class AuroHelpText extends i {
3945
3780
  }
3946
3781
  }
3947
3782
 
3948
- var formkitVersion = '202606191810';
3783
+ var formkitVersion = '202607221815';
3949
3784
 
3950
3785
  class AuroElement extends i {
3951
3786
  static get properties() {
@@ -4074,7 +3909,6 @@ class AuroDropdown extends AuroElement {
4074
3909
  static get shadowRootOptions() {
4075
3910
  return {
4076
3911
  ...AuroElement.shadowRootOptions,
4077
- delegatesFocus: true,
4078
3912
  };
4079
3913
  }
4080
3914
 
@@ -4086,6 +3920,15 @@ class AuroDropdown extends AuroElement {
4086
3920
  this.matchWidth = false;
4087
3921
  this.noHideOnThisFocusLoss = false;
4088
3922
 
3923
+ /**
3924
+ * When true, the dropdown skips its generic focus restoration on close.
3925
+ * Set by consumers (e.g. combobox) that manage their own focus routing
3926
+ * via setClearBtnFocus / setInputFocus / keyboard strategy.
3927
+ * Separate from noHideOnThisFocusLoss (which controls auto-close behavior).
3928
+ * @private
3929
+ */
3930
+ this.noFocusRestoreOnClose = false;
3931
+
4089
3932
  this.errorMessage = undefined; // TODO - check with Doug if there is still more to do here
4090
3933
 
4091
3934
  // Layout Config
@@ -4241,7 +4084,49 @@ class AuroDropdown extends AuroElement {
4241
4084
  focusables[0].focus();
4242
4085
  }
4243
4086
  } else {
4087
+ this.focusTrigger();
4088
+ }
4089
+ }
4090
+
4091
+ /**
4092
+ * Focus the trigger content. When the trigger wrapper itself is focusable
4093
+ * (has tabindex), focus it directly. Otherwise, focus the first focusable
4094
+ * element slotted into the trigger slot (e.g. the auro-input).
4095
+ * @private
4096
+ */
4097
+ focusTrigger() {
4098
+ if (this.trigger.hasAttribute('tabindex')) {
4244
4099
  this.trigger.focus();
4100
+ } else {
4101
+ // Slotted content isn't a DOM child of the trigger div, so
4102
+ // getFocusableElements can't find it. Query assigned nodes directly.
4103
+ const slot = this.trigger.querySelector('slot[name="trigger"]');
4104
+ if (slot) {
4105
+ const assigned = slot.assignedElements();
4106
+ for (const el of assigned) {
4107
+ if (el.hasAttribute('disabled')) {
4108
+ continue; // eslint-disable-line no-continue
4109
+ }
4110
+ // Try finding a focusable descendant first (handles non-focusable
4111
+ // wrappers like <div> containing a <button>). If none found, try
4112
+ // focusing the element directly (works for custom elements like
4113
+ // auro-input that have delegatesFocus or a custom focus() method).
4114
+ const descendants = getFocusableElements(el);
4115
+ if (descendants.length > 0) {
4116
+ descendants[0].focus();
4117
+ return;
4118
+ }
4119
+ el.focus();
4120
+ if (document.activeElement === el) {
4121
+ return;
4122
+ }
4123
+ }
4124
+ }
4125
+ // Fallback: try DOM children (non-slotted content)
4126
+ const focusables = getFocusableElements(this.trigger);
4127
+ if (focusables.length > 0) {
4128
+ focusables[0].focus();
4129
+ }
4245
4130
  }
4246
4131
  }
4247
4132
 
@@ -4617,10 +4502,17 @@ class AuroDropdown extends AuroElement {
4617
4502
  this.clearTriggerFocusEventBinding();
4618
4503
  }
4619
4504
 
4505
+ // eslint-disable-next-line complexity
4620
4506
  updated(changedProperties) {
4621
4507
  super.updated(changedProperties);
4622
4508
  this.floater.handleUpdate(changedProperties);
4623
4509
 
4510
+ // Close the dropdown if the disabled property is set to true
4511
+ if (changedProperties.has('disabled') && this.disabled && this.isPopoverVisible) {
4512
+ this.hide();
4513
+ this.isPopoverVisible = false;
4514
+ }
4515
+
4624
4516
  // Note: `disabled` is not a breakpoint (it is not a screen size),
4625
4517
  // so it looks like we never consume this - however, dropdownBib handles this in the setter as "undefined"
4626
4518
  if (changedProperties.has('fullscreenBreakpoint')) {
@@ -4694,8 +4586,30 @@ class AuroDropdown extends AuroElement {
4694
4586
  }
4695
4587
 
4696
4588
  const eventType = event.detail.eventType || "unknown";
4697
- if (!this.isPopoverVisible && this.hasFocus && eventType === "keydown") {
4698
- this.trigger.focus();
4589
+ if (!this.isPopoverVisible && this.hasFocus && eventType === "keydown" && !this.noFocusRestoreOnClose) {
4590
+ this.focusTrigger();
4591
+ }
4592
+
4593
+
4594
+ // On Tab-driven close (eventType "focusloss"), let focus advance naturally
4595
+ // — restoring to the trigger would trap the user on this dropdown, forcing
4596
+ // an extra Tab to move on. Escape and outside-click still restore.
4597
+ // When noFocusRestoreOnClose is true, the consumer (e.g. combobox) manages
4598
+ // its own focus restoration — skip the generic trigger focus to avoid races.
4599
+ if (!this.isPopoverVisible && eventType !== "focusloss" && !this.noFocusRestoreOnClose) {
4600
+ // wait til the bib gets fully closed and rendered
4601
+ setTimeout(() => {
4602
+ // Skip if the bib re-opened, or if focus moved intentionally outside the dropdown (not to body).
4603
+ // Restore focus to trigger when focus is still inside the bib (:focus-within) or fell to body.
4604
+ if (this.isPopoverVisible ||
4605
+ // eslint-disable-next-line no-extra-parens
4606
+ (!this.bibContent?.matches(':focus-within') &&
4607
+ document.activeElement !== document.body)) {
4608
+ return;
4609
+ }
4610
+ // Restore focus to the trigger.
4611
+ this.focusTrigger();
4612
+ });
4699
4613
  }
4700
4614
  }
4701
4615
 
@@ -4896,6 +4810,14 @@ class AuroDropdown extends AuroElement {
4896
4810
  };
4897
4811
  this.addEventListener('keydown', this._bibTabHandler);
4898
4812
 
4813
+ // Suppress AuroFloatingUI's auto-hide-on-focus-loss while the
4814
+ // desktopModal trap owns focus management. Without this, the very
4815
+ // first focus move into the bib (from the RAF below) triggers
4816
+ // handleFocusLoss → hideBib, tearing down the trap before the
4817
+ // user can press Tab.
4818
+ this._priorNoHideOnFocusLoss = this.noHideOnThisFocusLoss;
4819
+ this.noHideOnThisFocusLoss = true;
4820
+
4899
4821
  // Move initial focus into the bib content, matching FocusTrap behavior
4900
4822
  requestAnimationFrame(() => {
4901
4823
  const focusables = getFocusableElements(this.bibContent);
@@ -4904,15 +4826,16 @@ class AuroDropdown extends AuroElement {
4904
4826
  }
4905
4827
  });
4906
4828
  } else {
4907
- // Normal desktop: use FocusTrap on the bib element.
4908
- // Defer focusFirstElement to the next frame because the popover
4909
- // is positioned asynchronously by Floating UI — calling focus()
4910
- // synchronously here would target elements with zero dimensions
4911
- // and the focus call would be silently ignored.
4912
- this.focusTrap = new FocusTrap(this.bibContent);
4829
+ // Normal desktop (non-modal): move initial focus into the bib but
4830
+ // don't trap Tab. Tab should exit the bib and let the floater's
4831
+ // handleFocusLoss close it, matching native <select>/<details>
4832
+ // behavior. Deferred one frame because Floating UI positions the
4833
+ // popover asynchronously a synchronous focus() would target
4834
+ // zero-dimension elements and be silently ignored.
4913
4835
  requestAnimationFrame(() => {
4914
- if (this.focusTrap) {
4915
- this.focusTrap.focusFirstElement();
4836
+ const focusables = getFocusableElements(this.bibContent);
4837
+ if (focusables.length) {
4838
+ focusables[0].focus();
4916
4839
  }
4917
4840
  });
4918
4841
  }
@@ -5209,6 +5132,7 @@ class AuroDropdown extends AuroElement {
5209
5132
  role="${o(this.triggerContentFocusable ? undefined : this.a11yRole)}"
5210
5133
  aria-expanded="${o(this.a11yRole === 'button' || this.triggerContentFocusable ? undefined : this.isPopoverVisible)}"
5211
5134
  aria-controls="${o(this.a11yRole === 'button' || this.triggerContentFocusable ? undefined : this.dropdownId)}"
5135
+ aria-haspopup="${o(this.a11yRole === 'combobox' && !this.triggerContentFocusable ? 'listbox' : undefined)}"
5212
5136
  aria-labelledby="${o(this.triggerContentFocusable ? undefined : 'triggerLabel')}"
5213
5137
  aria-disabled="${o(this.disabled ? 'true' : undefined)}"
5214
5138
  @focusin="${this.handleFocusin}"
@@ -5333,13 +5257,23 @@ class AuroDropdown extends AuroElement {
5333
5257
  }
5334
5258
  }
5335
5259
 
5260
+ function fullscreenBreakpointExample() {
5261
+ const btn = document.querySelector('#fullscreenButton');
5262
+ const dropdown = document.querySelector('#fullscreen');
5263
+
5264
+ btn?.addEventListener('click', () => {
5265
+ dropdown?.hide();
5266
+ });
5267
+ }
5268
+
5336
5269
  /* eslint-disable jsdoc/require-jsdoc, no-magic-numbers, no-param-reassign */
5337
5270
 
5338
5271
  AuroDropdown.register();
5339
5272
  AuroDropdown.register('custom-dropdown');
5340
-
5341
5273
  function initExamples() {
5342
5274
  // javascript example function calls to be added here upon creation to test examples
5275
+
5276
+ fullscreenBreakpointExample();
5343
5277
  }
5344
5278
 
5345
5279
  export { initExamples };