@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
@@ -2258,12 +2258,40 @@ class AuroFloatingUI {
2258
2258
  return;
2259
2259
  }
2260
2260
 
2261
+ // Chrome-specific: during popover top-layer promotion after a click on a
2262
+ // slotted focusable, :focus-within can briefly evaluate false while the
2263
+ // active element is still structurally inside the trigger/bib. Fall back
2264
+ // to a shadow-piercing ancestry walk from the deep active element before
2265
+ // treating this as a real focus loss.
2266
+ try {
2267
+ let active = document.activeElement;
2268
+ while (active && active.shadowRoot && active.shadowRoot.activeElement) {
2269
+ active = active.shadowRoot.activeElement;
2270
+ }
2271
+ const targets = [element, element.trigger, element.bib].filter(Boolean);
2272
+ let node = active;
2273
+ while (node) {
2274
+ if (targets.includes(node)) {
2275
+ return;
2276
+ }
2277
+ node =
2278
+ node.parentElement ||
2279
+ (node.getRootNode && node.getRootNode().host) ||
2280
+ null;
2281
+ }
2282
+ } catch (e) {
2283
+ // Defensive: fall through to the existing close path if traversal fails.
2284
+ }
2285
+
2261
2286
  // if fullscreen bib is in fullscreen mode, do not close
2262
2287
  if (element.bib.hasAttribute("isfullscreen")) {
2263
2288
  return;
2264
2289
  }
2265
2290
 
2266
- this.hideBib("keydown");
2291
+ // eventType "focusloss" distinguishes a Tab/click-driven close from an
2292
+ // Escape keydown close. Consumers use this to decide whether to restore
2293
+ // focus to the trigger (Escape) or let it advance naturally (Tab).
2294
+ this.hideBib("focusloss");
2267
2295
  }
2268
2296
 
2269
2297
  setupHideHandlers() {
@@ -2933,199 +2961,6 @@ function getFocusableElements(container) {
2933
2961
  return tabIndexedUniqueElements;
2934
2962
  }
2935
2963
 
2936
- /**
2937
- * FocusTrap manages keyboard focus within a specified container element, ensuring that focus does not leave the container when tabbing.
2938
- * It is commonly used for modal dialogs or overlays to improve accessibility by trapping focus within interactive UI components.
2939
- */
2940
- class FocusTrap {
2941
- /**
2942
- * Creates a new FocusTrap instance for the given container element.
2943
- * Initializes event listeners and prepares the container for focus management.
2944
- *
2945
- * @param {HTMLElement} container The DOM element to trap focus within.
2946
- * @param {boolean} [controlTabOrder=false] If true enables manual control of the tab order by the FocusTrap.
2947
- * @throws {Error} If the provided container is not a valid HTMLElement.
2948
- */
2949
- constructor(container, controlTabOrder = false) {
2950
- if (!container || !(container instanceof HTMLElement)) {
2951
- throw new Error("FocusTrap requires a valid HTMLElement.");
2952
- }
2953
-
2954
- this.container = container;
2955
- this.tabDirection = "forward"; // or 'backward';
2956
- this.controlTabOrder = controlTabOrder;
2957
-
2958
- this._init();
2959
- }
2960
-
2961
- /**
2962
- * Initializes the focus trap by setting up event listeners and attributes on the container.
2963
- * Prepares the container for focus management, including support for shadow DOM and inert attributes.
2964
- *
2965
- * @private
2966
- */
2967
- _init() {
2968
- // Add inert attribute to prevent focusing programmatically as well (if supported)
2969
- if ("inert" in HTMLElement.prototype) {
2970
- this.container.inert = false; // Ensure the container isn't inert
2971
- this.container.setAttribute("data-focus-trap-container", true); // Mark for identification
2972
- }
2973
-
2974
- // Track tab direction
2975
- this.container.addEventListener("keydown", this._onKeydown);
2976
- }
2977
-
2978
- /**
2979
- * Gets an array of currently active (focused) elements in the document and shadow DOM.
2980
- * @returns {Array<HTMLElement>} An array of focusable elements within the container.
2981
- * @private
2982
- */
2983
- _getActiveElements() {
2984
- // Get the active element(s) in the document and shadow root
2985
- // This will include the active element in the shadow DOM if it exists
2986
- // Active element may be inside the shadow DOM depending on delegatesFocus, so we need to check both
2987
- let { activeElement } = document;
2988
- const actives = [activeElement];
2989
- while (activeElement?.shadowRoot?.activeElement) {
2990
- actives.push(activeElement.shadowRoot.activeElement);
2991
- activeElement = activeElement.shadowRoot.activeElement;
2992
- }
2993
- return actives;
2994
- }
2995
-
2996
- /**
2997
- * Gets the next focus index based on the current index and focusable elements.
2998
- * @param {number} currentIndex The current index of the focused element.
2999
- * @param {Array<HTMLElement>} focusables The array of focusable elements.
3000
- * @returns {number|null} The next focus index or null if not determined.
3001
- */
3002
- _getNextFocusIndex(currentIndex, focusables, actives) {
3003
- if (this.controlTabOrder) {
3004
- // Calculate the new index based on the current index and tab direction
3005
- let newFocusIndex =
3006
- currentIndex + (this.tabDirection === "forward" ? 1 : -1);
3007
-
3008
- // Wrap-around logic
3009
- if (newFocusIndex < 0) newFocusIndex = focusables.length - 1;
3010
- if (newFocusIndex >= focusables.length) newFocusIndex = 0;
3011
-
3012
- // Early return with the new index
3013
- return newFocusIndex;
3014
- }
3015
-
3016
- // Determine if we need to wrap
3017
- const atFirst =
3018
- actives.includes(focusables[0]) || actives.includes(this.container);
3019
- const atLast = actives.includes(focusables[focusables.length - 1]);
3020
-
3021
- // Only wrap if at the ends
3022
- if (this.tabDirection === "backward" && atFirst) {
3023
- return focusables.length - 1;
3024
- }
3025
-
3026
- if (this.tabDirection === "forward" && atLast) {
3027
- return 0;
3028
- }
3029
-
3030
- // No wrap, so don't change focus, return early
3031
- return null;
3032
- }
3033
-
3034
- /**
3035
- * Handles the Tab key press event to manage focus within the container.
3036
- * @param {KeyboardEvent} e The keyboard event triggered by the user.
3037
- * @returns {void}
3038
- */
3039
- _handleTabKey(e) {
3040
- // Update the focusable elements
3041
- const focusables = this._getFocusableElements();
3042
-
3043
- // If there are no focusable elements, exit
3044
- if (!focusables.length) return;
3045
-
3046
- // Set the tab direction based on the key pressed
3047
- this.tabDirection = e.shiftKey ? "backward" : "forward";
3048
-
3049
- // Get the active elements that are currently focused
3050
- const actives = this._getActiveElements();
3051
-
3052
- // If we're at either end of the focusable elements, wrap around to the other end
3053
- let focusIndex = focusables.findIndex((el) => actives.includes(el));
3054
-
3055
- // Fallback if we have no focused element
3056
- if (focusIndex === -1) focusIndex = 0;
3057
-
3058
- // Get the next focus index based on the current focus index, tab direction, and controlTabOrder setting
3059
- // Is null if no new focus index is determined
3060
- const newFocusIndex = this._getNextFocusIndex(
3061
- focusIndex,
3062
- focusables,
3063
- actives,
3064
- );
3065
-
3066
- // If we have a new focus index, set focus to that element
3067
- if (newFocusIndex !== null) {
3068
- e.preventDefault();
3069
- focusables[newFocusIndex].focus();
3070
- }
3071
- }
3072
-
3073
- /**
3074
- * Catches the keydown event
3075
- * @param {KeyboardEvent} e The keyboard event triggered by user interaction.
3076
- * @private
3077
- */
3078
- _onKeydown = (e) => {
3079
- // Handle tab
3080
- if (e.key === "Tab") this._handleTabKey(e);
3081
- };
3082
-
3083
- /**
3084
- * Retrieves all focusable elements within the container in DOM order, including those in shadow DOM and slots.
3085
- * Returns a unique, ordered array of elements that can receive focus.
3086
- *
3087
- * @returns {Array<HTMLElement>} An array of focusable elements within the container.
3088
- * @private
3089
- */
3090
- _getFocusableElements() {
3091
- // Use the imported utility function to get focusable elements
3092
- const elements = getFocusableElements(this.container);
3093
-
3094
- // Return the elements found
3095
- return elements;
3096
- }
3097
-
3098
- /**
3099
- * Moves focus to the first focusable element within the container.
3100
- * Useful for setting initial focus when activating the focus trap.
3101
- */
3102
- focusFirstElement() {
3103
- const focusables = this._getFocusableElements();
3104
- if (focusables.length) focusables[0].focus();
3105
- }
3106
-
3107
- /**
3108
- * Moves focus to the last focusable element within the container.
3109
- * Useful for setting focus when deactivating or cycling focus in reverse.
3110
- */
3111
- focusLastElement() {
3112
- const focusables = this._getFocusableElements();
3113
- if (focusables.length) focusables[focusables.length - 1].focus();
3114
- }
3115
-
3116
- /**
3117
- * Removes event listeners and attributes added by the focus trap.
3118
- * Call this method to clean up when the focus trap is no longer needed.
3119
- */
3120
- disconnect() {
3121
- if (this.container.hasAttribute("data-focus-trap-container")) {
3122
- this.container.removeAttribute("data-focus-trap-container");
3123
- }
3124
-
3125
- this.container.removeEventListener("keydown", this._onKeydown);
3126
- }
3127
- }
3128
-
3129
2964
  // Copyright (c) Alaska Air. All right reserved. Licensed under the Apache-2.0 license
3130
2965
  // See LICENSE in the project root for license information.
3131
2966
 
@@ -3626,7 +3461,7 @@ class AuroDropdownBib extends LitElement {
3626
3461
  classes[`shape-${this.shape}`] = true;
3627
3462
 
3628
3463
  return html$1`
3629
- <dialog class="${classMap(classes)}" part="bibContainer" role="${ifDefined(this.dialogRole)}" aria-labelledby="${ifDefined(this.dialogLabel ? 'dialogLabel' : undefined)}">
3464
+ <dialog tabindex="-1" class="${classMap(classes)}" part="bibContainer" role="${ifDefined(this.dialogRole)}" aria-labelledby="${ifDefined(this.dialogLabel ? 'dialogLabel' : undefined)}">
3630
3465
  ${this.dialogLabel ? html$1`<span id="dialogLabel" class="util_displayHiddenVisually">${this.dialogLabel}</span>` : ''}
3631
3466
  <slot></slot>
3632
3467
  <span id="srAnnouncement" class="util_displayHiddenVisually" aria-live="polite" role="status"></span>
@@ -3877,7 +3712,7 @@ class AuroHelpText extends LitElement {
3877
3712
  }
3878
3713
  }
3879
3714
 
3880
- var formkitVersion = '202606191810';
3715
+ var formkitVersion = '202607221815';
3881
3716
 
3882
3717
  class AuroElement extends LitElement {
3883
3718
  static get properties() {
@@ -4006,7 +3841,6 @@ class AuroDropdown extends AuroElement {
4006
3841
  static get shadowRootOptions() {
4007
3842
  return {
4008
3843
  ...AuroElement.shadowRootOptions,
4009
- delegatesFocus: true,
4010
3844
  };
4011
3845
  }
4012
3846
 
@@ -4018,6 +3852,15 @@ class AuroDropdown extends AuroElement {
4018
3852
  this.matchWidth = false;
4019
3853
  this.noHideOnThisFocusLoss = false;
4020
3854
 
3855
+ /**
3856
+ * When true, the dropdown skips its generic focus restoration on close.
3857
+ * Set by consumers (e.g. combobox) that manage their own focus routing
3858
+ * via setClearBtnFocus / setInputFocus / keyboard strategy.
3859
+ * Separate from noHideOnThisFocusLoss (which controls auto-close behavior).
3860
+ * @private
3861
+ */
3862
+ this.noFocusRestoreOnClose = false;
3863
+
4021
3864
  this.errorMessage = undefined; // TODO - check with Doug if there is still more to do here
4022
3865
 
4023
3866
  // Layout Config
@@ -4173,7 +4016,49 @@ class AuroDropdown extends AuroElement {
4173
4016
  focusables[0].focus();
4174
4017
  }
4175
4018
  } else {
4019
+ this.focusTrigger();
4020
+ }
4021
+ }
4022
+
4023
+ /**
4024
+ * Focus the trigger content. When the trigger wrapper itself is focusable
4025
+ * (has tabindex), focus it directly. Otherwise, focus the first focusable
4026
+ * element slotted into the trigger slot (e.g. the auro-input).
4027
+ * @private
4028
+ */
4029
+ focusTrigger() {
4030
+ if (this.trigger.hasAttribute('tabindex')) {
4176
4031
  this.trigger.focus();
4032
+ } else {
4033
+ // Slotted content isn't a DOM child of the trigger div, so
4034
+ // getFocusableElements can't find it. Query assigned nodes directly.
4035
+ const slot = this.trigger.querySelector('slot[name="trigger"]');
4036
+ if (slot) {
4037
+ const assigned = slot.assignedElements();
4038
+ for (const el of assigned) {
4039
+ if (el.hasAttribute('disabled')) {
4040
+ continue; // eslint-disable-line no-continue
4041
+ }
4042
+ // Try finding a focusable descendant first (handles non-focusable
4043
+ // wrappers like <div> containing a <button>). If none found, try
4044
+ // focusing the element directly (works for custom elements like
4045
+ // auro-input that have delegatesFocus or a custom focus() method).
4046
+ const descendants = getFocusableElements(el);
4047
+ if (descendants.length > 0) {
4048
+ descendants[0].focus();
4049
+ return;
4050
+ }
4051
+ el.focus();
4052
+ if (document.activeElement === el) {
4053
+ return;
4054
+ }
4055
+ }
4056
+ }
4057
+ // Fallback: try DOM children (non-slotted content)
4058
+ const focusables = getFocusableElements(this.trigger);
4059
+ if (focusables.length > 0) {
4060
+ focusables[0].focus();
4061
+ }
4177
4062
  }
4178
4063
  }
4179
4064
 
@@ -4549,10 +4434,17 @@ class AuroDropdown extends AuroElement {
4549
4434
  this.clearTriggerFocusEventBinding();
4550
4435
  }
4551
4436
 
4437
+ // eslint-disable-next-line complexity
4552
4438
  updated(changedProperties) {
4553
4439
  super.updated(changedProperties);
4554
4440
  this.floater.handleUpdate(changedProperties);
4555
4441
 
4442
+ // Close the dropdown if the disabled property is set to true
4443
+ if (changedProperties.has('disabled') && this.disabled && this.isPopoverVisible) {
4444
+ this.hide();
4445
+ this.isPopoverVisible = false;
4446
+ }
4447
+
4556
4448
  // Note: `disabled` is not a breakpoint (it is not a screen size),
4557
4449
  // so it looks like we never consume this - however, dropdownBib handles this in the setter as "undefined"
4558
4450
  if (changedProperties.has('fullscreenBreakpoint')) {
@@ -4626,8 +4518,30 @@ class AuroDropdown extends AuroElement {
4626
4518
  }
4627
4519
 
4628
4520
  const eventType = event.detail.eventType || "unknown";
4629
- if (!this.isPopoverVisible && this.hasFocus && eventType === "keydown") {
4630
- this.trigger.focus();
4521
+ if (!this.isPopoverVisible && this.hasFocus && eventType === "keydown" && !this.noFocusRestoreOnClose) {
4522
+ this.focusTrigger();
4523
+ }
4524
+
4525
+
4526
+ // On Tab-driven close (eventType "focusloss"), let focus advance naturally
4527
+ // — restoring to the trigger would trap the user on this dropdown, forcing
4528
+ // an extra Tab to move on. Escape and outside-click still restore.
4529
+ // When noFocusRestoreOnClose is true, the consumer (e.g. combobox) manages
4530
+ // its own focus restoration — skip the generic trigger focus to avoid races.
4531
+ if (!this.isPopoverVisible && eventType !== "focusloss" && !this.noFocusRestoreOnClose) {
4532
+ // wait til the bib gets fully closed and rendered
4533
+ setTimeout(() => {
4534
+ // Skip if the bib re-opened, or if focus moved intentionally outside the dropdown (not to body).
4535
+ // Restore focus to trigger when focus is still inside the bib (:focus-within) or fell to body.
4536
+ if (this.isPopoverVisible ||
4537
+ // eslint-disable-next-line no-extra-parens
4538
+ (!this.bibContent?.matches(':focus-within') &&
4539
+ document.activeElement !== document.body)) {
4540
+ return;
4541
+ }
4542
+ // Restore focus to the trigger.
4543
+ this.focusTrigger();
4544
+ });
4631
4545
  }
4632
4546
  }
4633
4547
 
@@ -4828,6 +4742,14 @@ class AuroDropdown extends AuroElement {
4828
4742
  };
4829
4743
  this.addEventListener('keydown', this._bibTabHandler);
4830
4744
 
4745
+ // Suppress AuroFloatingUI's auto-hide-on-focus-loss while the
4746
+ // desktopModal trap owns focus management. Without this, the very
4747
+ // first focus move into the bib (from the RAF below) triggers
4748
+ // handleFocusLoss → hideBib, tearing down the trap before the
4749
+ // user can press Tab.
4750
+ this._priorNoHideOnFocusLoss = this.noHideOnThisFocusLoss;
4751
+ this.noHideOnThisFocusLoss = true;
4752
+
4831
4753
  // Move initial focus into the bib content, matching FocusTrap behavior
4832
4754
  requestAnimationFrame(() => {
4833
4755
  const focusables = getFocusableElements(this.bibContent);
@@ -4836,15 +4758,16 @@ class AuroDropdown extends AuroElement {
4836
4758
  }
4837
4759
  });
4838
4760
  } else {
4839
- // Normal desktop: use FocusTrap on the bib element.
4840
- // Defer focusFirstElement to the next frame because the popover
4841
- // is positioned asynchronously by Floating UI — calling focus()
4842
- // synchronously here would target elements with zero dimensions
4843
- // and the focus call would be silently ignored.
4844
- this.focusTrap = new FocusTrap(this.bibContent);
4761
+ // Normal desktop (non-modal): move initial focus into the bib but
4762
+ // don't trap Tab. Tab should exit the bib and let the floater's
4763
+ // handleFocusLoss close it, matching native <select>/<details>
4764
+ // behavior. Deferred one frame because Floating UI positions the
4765
+ // popover asynchronously a synchronous focus() would target
4766
+ // zero-dimension elements and be silently ignored.
4845
4767
  requestAnimationFrame(() => {
4846
- if (this.focusTrap) {
4847
- this.focusTrap.focusFirstElement();
4768
+ const focusables = getFocusableElements(this.bibContent);
4769
+ if (focusables.length) {
4770
+ focusables[0].focus();
4848
4771
  }
4849
4772
  });
4850
4773
  }
@@ -5141,6 +5064,7 @@ class AuroDropdown extends AuroElement {
5141
5064
  role="${ifDefined(this.triggerContentFocusable ? undefined : this.a11yRole)}"
5142
5065
  aria-expanded="${ifDefined(this.a11yRole === 'button' || this.triggerContentFocusable ? undefined : this.isPopoverVisible)}"
5143
5066
  aria-controls="${ifDefined(this.a11yRole === 'button' || this.triggerContentFocusable ? undefined : this.dropdownId)}"
5067
+ aria-haspopup="${ifDefined(this.a11yRole === 'combobox' && !this.triggerContentFocusable ? 'listbox' : undefined)}"
5144
5068
  aria-labelledby="${ifDefined(this.triggerContentFocusable ? undefined : 'triggerLabel')}"
5145
5069
  aria-disabled="${ifDefined(this.disabled ? 'true' : undefined)}"
5146
5070
  @focusin="${this.handleFocusin}"
@@ -11,7 +11,7 @@ The `auro-form` element provides users a way to create and manage forms in a con
11
11
  |------------------|-----------|--------------------------------------------------|--------------------------------------------------|
12
12
  | `isInitialState` | readonly | `boolean` | Returns `true` if no form element has been interacted with or had its value changed since the form was initialized or last reset. |
13
13
  | `validity` | readonly | `"valid" \| "invalid" \| null` | Returns `'valid'` if all required and interacted-with form elements are valid, `'invalid'` if any are not, or `null` if the form has not been interacted with yet. |
14
- | `value` | readonly | `Record<string, string \| number \| boolean \| string[] \| null>` | Returns the current values of all named form elements as a key-value object, keyed by each element's `name` attribute. |
14
+ | `value` | readonly | `Record<string, string \| number \| boolean \| string[] \| Record<string, number> \| null>` | Returns the current values of all named, enabled form elements as a key-value object, keyed by each element's `name` attribute. Each value is the child component's own `.value`, so the shape depends on the element type — see that component's documentation for its exact shape (for example, `auro-checkbox-group` yields an array, `auro-counter-group` yields an object keyed by counter name, and `auro-select` with `multiSelect` yields a JSON-encoded string). The one form-specific exception is a `range` `auro-datepicker`, whose `.values` array (`[start, end]`) is stored instead of its single `.value` string. |
15
15
 
16
16
  ## Methods
17
17
 
@@ -26,8 +26,8 @@ The `auro-form` element provides users a way to create and manage forms in a con
26
26
  |----------|--------------------------------------------------|--------------------------------------------------|
27
27
  | `change` | | Fires when a child form element's value changes or the form is initialized. |
28
28
  | `input` | | Fires when a child form element receives user input. |
29
- | `reset` | `CustomEvent<{ previousValue: Record<string, string \| number \| boolean \| string[] \| null>; }>` | Fires when the form is reset. The event detail contains the previous value of the form before reset. |
30
- | `submit` | `CustomEvent<{ value: Record<string, string \| number \| boolean \| string[] \| null>; }>` | Fires when the form is submitted. The event detail contains the current value of the form. |
29
+ | `reset` | `CustomEvent<{ previousValue: Record<string, string \| number \| boolean \| string[] \| Record<string, number> \| null>; }>` | Fires when the form is reset. The event detail contains the previous value of the form before reset. |
30
+ | `submit` | `CustomEvent<{ value: Record<string, string \| number \| boolean \| string[] \| Record<string, number> \| null>; }>` | Fires when the form is submitted. The event detail contains the current value of the form. |
31
31
 
32
32
  ## Slots
33
33
 
@@ -36,11 +36,6 @@
36
36
  <body class="auro-markdown">
37
37
  <main></main>
38
38
 
39
- <script type="module">
40
- import { renderPage } from './demo-support.min.js';
41
- await renderPage('./customize.md');
42
- </script>
43
-
44
39
  <!-- If additional elements are needed for the demo, add them here. -->
45
40
  <script src="https://cdn.jsdelivr.net/npm/@aurodesignsystem/auro-accordion@latest/+esm" type="module"></script>
46
41
  <script src="https://cdn.jsdelivr.net/npm/@aurodesignsystem/auro-nav@latest/+esm" type="module"></script>
@@ -49,6 +44,11 @@
49
44
  <script src="https://cdn.jsdelivr.net/npm/@aurodesignsystem/auro-button@latest/+esm" type="module"></script>
50
45
  <script src="https://cdn.jsdelivr.net/npm/@aurodesignsystem/auro-icon@latest/+esm" type="module"></script>
51
46
 
52
- <script src="./customize.min.js" data-demo-script="true" type="module"></script>
47
+ <script type="module" data-demo-script="true">
48
+ import { renderPage } from './demo-support.min.js';
49
+ await renderPage('./customize.md');
50
+ import { initExamples } from "./customize.min.js";
51
+ initExamples();
52
+ </script>
53
53
  </body>
54
54
  </html>