@aurodesignsystem-dev/auro-formkit 0.0.0-pr1552.0 → 0.0.0-pr1553.1

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 (45) hide show
  1. package/components/checkbox/demo/customize.min.js +1 -1
  2. package/components/checkbox/demo/getting-started.min.js +1 -1
  3. package/components/checkbox/demo/index.min.js +1 -1
  4. package/components/checkbox/dist/index.js +1 -1
  5. package/components/checkbox/dist/registered.js +1 -1
  6. package/components/combobox/demo/customize.min.js +46 -207
  7. package/components/combobox/demo/getting-started.min.js +46 -207
  8. package/components/combobox/demo/index.min.js +46 -207
  9. package/components/combobox/dist/index.js +46 -207
  10. package/components/combobox/dist/registered.js +46 -207
  11. package/components/counter/demo/customize.min.js +59 -222
  12. package/components/counter/demo/index.min.js +59 -222
  13. package/components/counter/dist/auro-counter.d.ts +0 -8
  14. package/components/counter/dist/index.js +59 -222
  15. package/components/counter/dist/registered.js +59 -222
  16. package/components/datepicker/demo/customize.min.js +46 -207
  17. package/components/datepicker/demo/index.min.js +46 -207
  18. package/components/datepicker/dist/index.js +46 -207
  19. package/components/datepicker/dist/registered.js +46 -207
  20. package/components/dropdown/demo/customize.min.js +44 -205
  21. package/components/dropdown/demo/getting-started.min.js +44 -205
  22. package/components/dropdown/demo/index.min.js +44 -205
  23. package/components/dropdown/dist/index.js +44 -205
  24. package/components/dropdown/dist/registered.js +44 -205
  25. package/components/form/demo/customize.min.js +199 -845
  26. package/components/form/demo/getting-started.min.js +199 -845
  27. package/components/form/demo/index.min.js +199 -845
  28. package/components/form/demo/registerDemoDeps.min.js +199 -845
  29. package/components/input/demo/customize.min.js +1 -1
  30. package/components/input/demo/getting-started.min.js +1 -1
  31. package/components/input/demo/index.min.js +1 -1
  32. package/components/input/dist/index.js +1 -1
  33. package/components/input/dist/registered.js +1 -1
  34. package/components/radio/demo/customize.min.js +1 -1
  35. package/components/radio/demo/getting-started.min.js +1 -1
  36. package/components/radio/demo/index.min.js +1 -1
  37. package/components/radio/dist/index.js +1 -1
  38. package/components/radio/dist/registered.js +1 -1
  39. package/components/select/demo/customize.min.js +45 -206
  40. package/components/select/demo/getting-started.min.js +45 -206
  41. package/components/select/demo/index.min.js +45 -206
  42. package/components/select/dist/index.js +45 -206
  43. package/components/select/dist/registered.js +45 -206
  44. package/custom-elements.json +1499 -1514
  45. package/package.json +2 -2
@@ -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
 
@@ -3623,7 +3458,7 @@ class AuroDropdownBib extends LitElement {
3623
3458
  classes[`shape-${this.shape}`] = true;
3624
3459
 
3625
3460
  return html$1`
3626
- <dialog class="${classMap(classes)}" part="bibContainer" role="${ifDefined(this.dialogRole)}" aria-labelledby="${ifDefined(this.dialogLabel ? 'dialogLabel' : undefined)}">
3461
+ <dialog tabindex="-1" class="${classMap(classes)}" part="bibContainer" role="${ifDefined(this.dialogRole)}" aria-labelledby="${ifDefined(this.dialogLabel ? 'dialogLabel' : undefined)}">
3627
3462
  ${this.dialogLabel ? html$1`<span id="dialogLabel" class="util_displayHiddenVisually">${this.dialogLabel}</span>` : ''}
3628
3463
  <slot></slot>
3629
3464
  <span id="srAnnouncement" class="util_displayHiddenVisually" aria-live="polite" role="status"></span>
@@ -3874,7 +3709,7 @@ class AuroHelpText extends LitElement {
3874
3709
  }
3875
3710
  }
3876
3711
 
3877
- var formkitVersion = '202607092329';
3712
+ var formkitVersion = '202607102138';
3878
3713
 
3879
3714
  class AuroElement extends LitElement {
3880
3715
  static get properties() {
@@ -4628,7 +4463,10 @@ class AuroDropdown extends AuroElement {
4628
4463
  }
4629
4464
 
4630
4465
 
4631
- if (!this.isPopoverVisible) {
4466
+ // On Tab-driven close (eventType "focusloss"), let focus advance naturally
4467
+ // — restoring to the trigger would trap the user on this dropdown, forcing
4468
+ // an extra Tab to move on. Escape and outside-click still restore.
4469
+ if (!this.isPopoverVisible && eventType !== "focusloss") {
4632
4470
  // wait til the bib gets fully closed and rendered
4633
4471
  setTimeout(() => {
4634
4472
  // Skip if the bib re-opened, or if focus moved intentionally outside the dropdown (not to body).
@@ -4858,15 +4696,16 @@ class AuroDropdown extends AuroElement {
4858
4696
  }
4859
4697
  });
4860
4698
  } else {
4861
- // Normal desktop: use FocusTrap on the bib element.
4862
- // Defer focusFirstElement to the next frame because the popover
4863
- // is positioned asynchronously by Floating UI — calling focus()
4864
- // synchronously here would target elements with zero dimensions
4865
- // and the focus call would be silently ignored.
4866
- this.focusTrap = new FocusTrap(this.bibContent);
4699
+ // Normal desktop (non-modal): move initial focus into the bib but
4700
+ // don't trap Tab. Tab should exit the bib and let the floater's
4701
+ // handleFocusLoss close it, matching native <select>/<details>
4702
+ // behavior. Deferred one frame because Floating UI positions the
4703
+ // popover asynchronously a synchronous focus() would target
4704
+ // zero-dimension elements and be silently ignored.
4867
4705
  requestAnimationFrame(() => {
4868
- if (this.focusTrap) {
4869
- this.focusTrap.focusFirstElement();
4706
+ const focusables = getFocusableElements(this.bibContent);
4707
+ if (focusables.length) {
4708
+ focusables[0].focus();
4870
4709
  }
4871
4710
  });
4872
4711
  }
@@ -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
 
@@ -3623,7 +3458,7 @@ class AuroDropdownBib extends LitElement {
3623
3458
  classes[`shape-${this.shape}`] = true;
3624
3459
 
3625
3460
  return html$1`
3626
- <dialog class="${classMap(classes)}" part="bibContainer" role="${ifDefined(this.dialogRole)}" aria-labelledby="${ifDefined(this.dialogLabel ? 'dialogLabel' : undefined)}">
3461
+ <dialog tabindex="-1" class="${classMap(classes)}" part="bibContainer" role="${ifDefined(this.dialogRole)}" aria-labelledby="${ifDefined(this.dialogLabel ? 'dialogLabel' : undefined)}">
3627
3462
  ${this.dialogLabel ? html$1`<span id="dialogLabel" class="util_displayHiddenVisually">${this.dialogLabel}</span>` : ''}
3628
3463
  <slot></slot>
3629
3464
  <span id="srAnnouncement" class="util_displayHiddenVisually" aria-live="polite" role="status"></span>
@@ -3874,7 +3709,7 @@ class AuroHelpText extends LitElement {
3874
3709
  }
3875
3710
  }
3876
3711
 
3877
- var formkitVersion = '202607092329';
3712
+ var formkitVersion = '202607102138';
3878
3713
 
3879
3714
  class AuroElement extends LitElement {
3880
3715
  static get properties() {
@@ -4628,7 +4463,10 @@ class AuroDropdown extends AuroElement {
4628
4463
  }
4629
4464
 
4630
4465
 
4631
- if (!this.isPopoverVisible) {
4466
+ // On Tab-driven close (eventType "focusloss"), let focus advance naturally
4467
+ // — restoring to the trigger would trap the user on this dropdown, forcing
4468
+ // an extra Tab to move on. Escape and outside-click still restore.
4469
+ if (!this.isPopoverVisible && eventType !== "focusloss") {
4632
4470
  // wait til the bib gets fully closed and rendered
4633
4471
  setTimeout(() => {
4634
4472
  // Skip if the bib re-opened, or if focus moved intentionally outside the dropdown (not to body).
@@ -4858,15 +4696,16 @@ class AuroDropdown extends AuroElement {
4858
4696
  }
4859
4697
  });
4860
4698
  } else {
4861
- // Normal desktop: use FocusTrap on the bib element.
4862
- // Defer focusFirstElement to the next frame because the popover
4863
- // is positioned asynchronously by Floating UI — calling focus()
4864
- // synchronously here would target elements with zero dimensions
4865
- // and the focus call would be silently ignored.
4866
- this.focusTrap = new FocusTrap(this.bibContent);
4699
+ // Normal desktop (non-modal): move initial focus into the bib but
4700
+ // don't trap Tab. Tab should exit the bib and let the floater's
4701
+ // handleFocusLoss close it, matching native <select>/<details>
4702
+ // behavior. Deferred one frame because Floating UI positions the
4703
+ // popover asynchronously a synchronous focus() would target
4704
+ // zero-dimension elements and be silently ignored.
4867
4705
  requestAnimationFrame(() => {
4868
- if (this.focusTrap) {
4869
- this.focusTrap.focusFirstElement();
4706
+ const focusables = getFocusableElements(this.bibContent);
4707
+ if (focusables.length) {
4708
+ focusables[0].focus();
4870
4709
  }
4871
4710
  });
4872
4711
  }