@aurodesignsystem-dev/auro-formkit 0.0.0-pr1550.1 → 0.0.0-pr1551.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) 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 +45 -206
  12. package/components/counter/demo/index.min.js +45 -206
  13. package/components/counter/dist/index.js +45 -206
  14. package/components/counter/dist/registered.js +45 -206
  15. package/components/datepicker/demo/customize.min.js +48 -208
  16. package/components/datepicker/demo/index.min.js +48 -208
  17. package/components/datepicker/dist/index.js +48 -208
  18. package/components/datepicker/dist/registered.js +48 -208
  19. package/components/dropdown/demo/customize.min.js +44 -205
  20. package/components/dropdown/demo/getting-started.min.js +44 -205
  21. package/components/dropdown/demo/index.min.js +44 -205
  22. package/components/dropdown/dist/index.js +44 -205
  23. package/components/dropdown/dist/registered.js +44 -205
  24. package/components/form/demo/customize.min.js +187 -830
  25. package/components/form/demo/getting-started.min.js +187 -830
  26. package/components/form/demo/index.min.js +187 -830
  27. package/components/form/demo/registerDemoDeps.min.js +187 -830
  28. package/components/input/demo/customize.min.js +1 -1
  29. package/components/input/demo/getting-started.min.js +1 -1
  30. package/components/input/demo/index.min.js +1 -1
  31. package/components/input/dist/index.js +1 -1
  32. package/components/input/dist/registered.js +1 -1
  33. package/components/radio/demo/customize.min.js +1 -1
  34. package/components/radio/demo/getting-started.min.js +1 -1
  35. package/components/radio/demo/index.min.js +1 -1
  36. package/components/radio/dist/index.js +1 -1
  37. package/components/radio/dist/registered.js +1 -1
  38. package/components/select/demo/customize.min.js +45 -206
  39. package/components/select/demo/getting-started.min.js +45 -206
  40. package/components/select/demo/index.min.js +45 -206
  41. package/components/select/dist/index.js +45 -206
  42. package/components/select/dist/registered.js +45 -206
  43. package/custom-elements.json +1525 -1525
  44. package/package.json +2 -2
@@ -1114,7 +1114,7 @@ let AuroHelpText$1 = class AuroHelpText extends i$2 {
1114
1114
  }
1115
1115
  };
1116
1116
 
1117
- var formkitVersion$1 = '202607091919';
1117
+ var formkitVersion$1 = '202607100029';
1118
1118
 
1119
1119
  // Copyright (c) 2026 Alaska Airlines. All rights reserved. Licensed under the Apache-2.0 license
1120
1120
  // See LICENSE in the project root for license information.
@@ -3844,12 +3844,40 @@ class AuroFloatingUI {
3844
3844
  return;
3845
3845
  }
3846
3846
 
3847
+ // Chrome-specific: during popover top-layer promotion after a click on a
3848
+ // slotted focusable, :focus-within can briefly evaluate false while the
3849
+ // active element is still structurally inside the trigger/bib. Fall back
3850
+ // to a shadow-piercing ancestry walk from the deep active element before
3851
+ // treating this as a real focus loss.
3852
+ try {
3853
+ let active = document.activeElement;
3854
+ while (active && active.shadowRoot && active.shadowRoot.activeElement) {
3855
+ active = active.shadowRoot.activeElement;
3856
+ }
3857
+ const targets = [element, element.trigger, element.bib].filter(Boolean);
3858
+ let node = active;
3859
+ while (node) {
3860
+ if (targets.includes(node)) {
3861
+ return;
3862
+ }
3863
+ node =
3864
+ node.parentElement ||
3865
+ (node.getRootNode && node.getRootNode().host) ||
3866
+ null;
3867
+ }
3868
+ } catch (e) {
3869
+ // Defensive: fall through to the existing close path if traversal fails.
3870
+ }
3871
+
3847
3872
  // if fullscreen bib is in fullscreen mode, do not close
3848
3873
  if (element.bib.hasAttribute("isfullscreen")) {
3849
3874
  return;
3850
3875
  }
3851
3876
 
3852
- this.hideBib("keydown");
3877
+ // eventType "focusloss" distinguishes a Tab/click-driven close from an
3878
+ // Escape keydown close. Consumers use this to decide whether to restore
3879
+ // focus to the trigger (Escape) or let it advance naturally (Tab).
3880
+ this.hideBib("focusloss");
3853
3881
  }
3854
3882
 
3855
3883
  setupHideHandlers() {
@@ -4519,199 +4547,6 @@ function getFocusableElements(container) {
4519
4547
  return tabIndexedUniqueElements;
4520
4548
  }
4521
4549
 
4522
- /**
4523
- * FocusTrap manages keyboard focus within a specified container element, ensuring that focus does not leave the container when tabbing.
4524
- * It is commonly used for modal dialogs or overlays to improve accessibility by trapping focus within interactive UI components.
4525
- */
4526
- class FocusTrap {
4527
- /**
4528
- * Creates a new FocusTrap instance for the given container element.
4529
- * Initializes event listeners and prepares the container for focus management.
4530
- *
4531
- * @param {HTMLElement} container The DOM element to trap focus within.
4532
- * @param {boolean} [controlTabOrder=false] If true enables manual control of the tab order by the FocusTrap.
4533
- * @throws {Error} If the provided container is not a valid HTMLElement.
4534
- */
4535
- constructor(container, controlTabOrder = false) {
4536
- if (!container || !(container instanceof HTMLElement)) {
4537
- throw new Error("FocusTrap requires a valid HTMLElement.");
4538
- }
4539
-
4540
- this.container = container;
4541
- this.tabDirection = "forward"; // or 'backward';
4542
- this.controlTabOrder = controlTabOrder;
4543
-
4544
- this._init();
4545
- }
4546
-
4547
- /**
4548
- * Initializes the focus trap by setting up event listeners and attributes on the container.
4549
- * Prepares the container for focus management, including support for shadow DOM and inert attributes.
4550
- *
4551
- * @private
4552
- */
4553
- _init() {
4554
- // Add inert attribute to prevent focusing programmatically as well (if supported)
4555
- if ("inert" in HTMLElement.prototype) {
4556
- this.container.inert = false; // Ensure the container isn't inert
4557
- this.container.setAttribute("data-focus-trap-container", true); // Mark for identification
4558
- }
4559
-
4560
- // Track tab direction
4561
- this.container.addEventListener("keydown", this._onKeydown);
4562
- }
4563
-
4564
- /**
4565
- * Gets an array of currently active (focused) elements in the document and shadow DOM.
4566
- * @returns {Array<HTMLElement>} An array of focusable elements within the container.
4567
- * @private
4568
- */
4569
- _getActiveElements() {
4570
- // Get the active element(s) in the document and shadow root
4571
- // This will include the active element in the shadow DOM if it exists
4572
- // Active element may be inside the shadow DOM depending on delegatesFocus, so we need to check both
4573
- let { activeElement } = document;
4574
- const actives = [activeElement];
4575
- while (activeElement?.shadowRoot?.activeElement) {
4576
- actives.push(activeElement.shadowRoot.activeElement);
4577
- activeElement = activeElement.shadowRoot.activeElement;
4578
- }
4579
- return actives;
4580
- }
4581
-
4582
- /**
4583
- * Gets the next focus index based on the current index and focusable elements.
4584
- * @param {number} currentIndex The current index of the focused element.
4585
- * @param {Array<HTMLElement>} focusables The array of focusable elements.
4586
- * @returns {number|null} The next focus index or null if not determined.
4587
- */
4588
- _getNextFocusIndex(currentIndex, focusables, actives) {
4589
- if (this.controlTabOrder) {
4590
- // Calculate the new index based on the current index and tab direction
4591
- let newFocusIndex =
4592
- currentIndex + (this.tabDirection === "forward" ? 1 : -1);
4593
-
4594
- // Wrap-around logic
4595
- if (newFocusIndex < 0) newFocusIndex = focusables.length - 1;
4596
- if (newFocusIndex >= focusables.length) newFocusIndex = 0;
4597
-
4598
- // Early return with the new index
4599
- return newFocusIndex;
4600
- }
4601
-
4602
- // Determine if we need to wrap
4603
- const atFirst =
4604
- actives.includes(focusables[0]) || actives.includes(this.container);
4605
- const atLast = actives.includes(focusables[focusables.length - 1]);
4606
-
4607
- // Only wrap if at the ends
4608
- if (this.tabDirection === "backward" && atFirst) {
4609
- return focusables.length - 1;
4610
- }
4611
-
4612
- if (this.tabDirection === "forward" && atLast) {
4613
- return 0;
4614
- }
4615
-
4616
- // No wrap, so don't change focus, return early
4617
- return null;
4618
- }
4619
-
4620
- /**
4621
- * Handles the Tab key press event to manage focus within the container.
4622
- * @param {KeyboardEvent} e The keyboard event triggered by the user.
4623
- * @returns {void}
4624
- */
4625
- _handleTabKey(e) {
4626
- // Update the focusable elements
4627
- const focusables = this._getFocusableElements();
4628
-
4629
- // If there are no focusable elements, exit
4630
- if (!focusables.length) return;
4631
-
4632
- // Set the tab direction based on the key pressed
4633
- this.tabDirection = e.shiftKey ? "backward" : "forward";
4634
-
4635
- // Get the active elements that are currently focused
4636
- const actives = this._getActiveElements();
4637
-
4638
- // If we're at either end of the focusable elements, wrap around to the other end
4639
- let focusIndex = focusables.findIndex((el) => actives.includes(el));
4640
-
4641
- // Fallback if we have no focused element
4642
- if (focusIndex === -1) focusIndex = 0;
4643
-
4644
- // Get the next focus index based on the current focus index, tab direction, and controlTabOrder setting
4645
- // Is null if no new focus index is determined
4646
- const newFocusIndex = this._getNextFocusIndex(
4647
- focusIndex,
4648
- focusables,
4649
- actives,
4650
- );
4651
-
4652
- // If we have a new focus index, set focus to that element
4653
- if (newFocusIndex !== null) {
4654
- e.preventDefault();
4655
- focusables[newFocusIndex].focus();
4656
- }
4657
- }
4658
-
4659
- /**
4660
- * Catches the keydown event
4661
- * @param {KeyboardEvent} e The keyboard event triggered by user interaction.
4662
- * @private
4663
- */
4664
- _onKeydown = (e) => {
4665
- // Handle tab
4666
- if (e.key === "Tab") this._handleTabKey(e);
4667
- };
4668
-
4669
- /**
4670
- * Retrieves all focusable elements within the container in DOM order, including those in shadow DOM and slots.
4671
- * Returns a unique, ordered array of elements that can receive focus.
4672
- *
4673
- * @returns {Array<HTMLElement>} An array of focusable elements within the container.
4674
- * @private
4675
- */
4676
- _getFocusableElements() {
4677
- // Use the imported utility function to get focusable elements
4678
- const elements = getFocusableElements(this.container);
4679
-
4680
- // Return the elements found
4681
- return elements;
4682
- }
4683
-
4684
- /**
4685
- * Moves focus to the first focusable element within the container.
4686
- * Useful for setting initial focus when activating the focus trap.
4687
- */
4688
- focusFirstElement() {
4689
- const focusables = this._getFocusableElements();
4690
- if (focusables.length) focusables[0].focus();
4691
- }
4692
-
4693
- /**
4694
- * Moves focus to the last focusable element within the container.
4695
- * Useful for setting focus when deactivating or cycling focus in reverse.
4696
- */
4697
- focusLastElement() {
4698
- const focusables = this._getFocusableElements();
4699
- if (focusables.length) focusables[focusables.length - 1].focus();
4700
- }
4701
-
4702
- /**
4703
- * Removes event listeners and attributes added by the focus trap.
4704
- * Call this method to clean up when the focus trap is no longer needed.
4705
- */
4706
- disconnect() {
4707
- if (this.container.hasAttribute("data-focus-trap-container")) {
4708
- this.container.removeAttribute("data-focus-trap-container");
4709
- }
4710
-
4711
- this.container.removeEventListener("keydown", this._onKeydown);
4712
- }
4713
- }
4714
-
4715
4550
  // Copyright (c) Alaska Air. All right reserved. Licensed under the Apache-2.0 license
4716
4551
  // See LICENSE in the project root for license information.
4717
4552
 
@@ -5209,7 +5044,7 @@ class AuroDropdownBib extends i$2 {
5209
5044
  classes[`shape-${this.shape}`] = true;
5210
5045
 
5211
5046
  return u$5`
5212
- <dialog class="${e$2(classes)}" part="bibContainer" role="${o$2(this.dialogRole)}" aria-labelledby="${o$2(this.dialogLabel ? 'dialogLabel' : undefined)}">
5047
+ <dialog tabindex="-1" class="${e$2(classes)}" part="bibContainer" role="${o$2(this.dialogRole)}" aria-labelledby="${o$2(this.dialogLabel ? 'dialogLabel' : undefined)}">
5213
5048
  ${this.dialogLabel ? u$5`<span id="dialogLabel" class="util_displayHiddenVisually">${this.dialogLabel}</span>` : ''}
5214
5049
  <slot></slot>
5215
5050
  <span id="srAnnouncement" class="util_displayHiddenVisually" aria-live="polite" role="status"></span>
@@ -5460,7 +5295,7 @@ class AuroHelpText extends i$2 {
5460
5295
  }
5461
5296
  }
5462
5297
 
5463
- var formkitVersion = '202607091919';
5298
+ var formkitVersion = '202607100029';
5464
5299
 
5465
5300
  let AuroElement$1 = class AuroElement extends i$2 {
5466
5301
  static get properties() {
@@ -6214,7 +6049,10 @@ class AuroDropdown extends AuroElement$1 {
6214
6049
  }
6215
6050
 
6216
6051
 
6217
- if (!this.isPopoverVisible) {
6052
+ // On Tab-driven close (eventType "focusloss"), let focus advance naturally
6053
+ // — restoring to the trigger would trap the user on this dropdown, forcing
6054
+ // an extra Tab to move on. Escape and outside-click still restore.
6055
+ if (!this.isPopoverVisible && eventType !== "focusloss") {
6218
6056
  // wait til the bib gets fully closed and rendered
6219
6057
  setTimeout(() => {
6220
6058
  // Skip if the bib re-opened, or if focus moved intentionally outside the dropdown (not to body).
@@ -6444,15 +6282,16 @@ class AuroDropdown extends AuroElement$1 {
6444
6282
  }
6445
6283
  });
6446
6284
  } else {
6447
- // Normal desktop: use FocusTrap on the bib element.
6448
- // Defer focusFirstElement to the next frame because the popover
6449
- // is positioned asynchronously by Floating UI — calling focus()
6450
- // synchronously here would target elements with zero dimensions
6451
- // and the focus call would be silently ignored.
6452
- this.focusTrap = new FocusTrap(this.bibContent);
6285
+ // Normal desktop (non-modal): move initial focus into the bib but
6286
+ // don't trap Tab. Tab should exit the bib and let the floater's
6287
+ // handleFocusLoss close it, matching native <select>/<details>
6288
+ // behavior. Deferred one frame because Floating UI positions the
6289
+ // popover asynchronously a synchronous focus() would target
6290
+ // zero-dimension elements and be silently ignored.
6453
6291
  requestAnimationFrame(() => {
6454
- if (this.focusTrap) {
6455
- this.focusTrap.focusFirstElement();
6292
+ const focusables = getFocusableElements(this.bibContent);
6293
+ if (focusables.length) {
6294
+ focusables[0].focus();
6456
6295
  }
6457
6296
  });
6458
6297
  }
@@ -1064,7 +1064,7 @@ let AuroHelpText$1 = class AuroHelpText extends LitElement {
1064
1064
  }
1065
1065
  };
1066
1066
 
1067
- var formkitVersion$1 = '202607091919';
1067
+ var formkitVersion$1 = '202607100029';
1068
1068
 
1069
1069
  // Copyright (c) 2026 Alaska Airlines. All rights reserved. Licensed under the Apache-2.0 license
1070
1070
  // See LICENSE in the project root for license information.
@@ -3776,12 +3776,40 @@ class AuroFloatingUI {
3776
3776
  return;
3777
3777
  }
3778
3778
 
3779
+ // Chrome-specific: during popover top-layer promotion after a click on a
3780
+ // slotted focusable, :focus-within can briefly evaluate false while the
3781
+ // active element is still structurally inside the trigger/bib. Fall back
3782
+ // to a shadow-piercing ancestry walk from the deep active element before
3783
+ // treating this as a real focus loss.
3784
+ try {
3785
+ let active = document.activeElement;
3786
+ while (active && active.shadowRoot && active.shadowRoot.activeElement) {
3787
+ active = active.shadowRoot.activeElement;
3788
+ }
3789
+ const targets = [element, element.trigger, element.bib].filter(Boolean);
3790
+ let node = active;
3791
+ while (node) {
3792
+ if (targets.includes(node)) {
3793
+ return;
3794
+ }
3795
+ node =
3796
+ node.parentElement ||
3797
+ (node.getRootNode && node.getRootNode().host) ||
3798
+ null;
3799
+ }
3800
+ } catch (e) {
3801
+ // Defensive: fall through to the existing close path if traversal fails.
3802
+ }
3803
+
3779
3804
  // if fullscreen bib is in fullscreen mode, do not close
3780
3805
  if (element.bib.hasAttribute("isfullscreen")) {
3781
3806
  return;
3782
3807
  }
3783
3808
 
3784
- this.hideBib("keydown");
3809
+ // eventType "focusloss" distinguishes a Tab/click-driven close from an
3810
+ // Escape keydown close. Consumers use this to decide whether to restore
3811
+ // focus to the trigger (Escape) or let it advance naturally (Tab).
3812
+ this.hideBib("focusloss");
3785
3813
  }
3786
3814
 
3787
3815
  setupHideHandlers() {
@@ -4451,199 +4479,6 @@ function getFocusableElements(container) {
4451
4479
  return tabIndexedUniqueElements;
4452
4480
  }
4453
4481
 
4454
- /**
4455
- * FocusTrap manages keyboard focus within a specified container element, ensuring that focus does not leave the container when tabbing.
4456
- * It is commonly used for modal dialogs or overlays to improve accessibility by trapping focus within interactive UI components.
4457
- */
4458
- class FocusTrap {
4459
- /**
4460
- * Creates a new FocusTrap instance for the given container element.
4461
- * Initializes event listeners and prepares the container for focus management.
4462
- *
4463
- * @param {HTMLElement} container The DOM element to trap focus within.
4464
- * @param {boolean} [controlTabOrder=false] If true enables manual control of the tab order by the FocusTrap.
4465
- * @throws {Error} If the provided container is not a valid HTMLElement.
4466
- */
4467
- constructor(container, controlTabOrder = false) {
4468
- if (!container || !(container instanceof HTMLElement)) {
4469
- throw new Error("FocusTrap requires a valid HTMLElement.");
4470
- }
4471
-
4472
- this.container = container;
4473
- this.tabDirection = "forward"; // or 'backward';
4474
- this.controlTabOrder = controlTabOrder;
4475
-
4476
- this._init();
4477
- }
4478
-
4479
- /**
4480
- * Initializes the focus trap by setting up event listeners and attributes on the container.
4481
- * Prepares the container for focus management, including support for shadow DOM and inert attributes.
4482
- *
4483
- * @private
4484
- */
4485
- _init() {
4486
- // Add inert attribute to prevent focusing programmatically as well (if supported)
4487
- if ("inert" in HTMLElement.prototype) {
4488
- this.container.inert = false; // Ensure the container isn't inert
4489
- this.container.setAttribute("data-focus-trap-container", true); // Mark for identification
4490
- }
4491
-
4492
- // Track tab direction
4493
- this.container.addEventListener("keydown", this._onKeydown);
4494
- }
4495
-
4496
- /**
4497
- * Gets an array of currently active (focused) elements in the document and shadow DOM.
4498
- * @returns {Array<HTMLElement>} An array of focusable elements within the container.
4499
- * @private
4500
- */
4501
- _getActiveElements() {
4502
- // Get the active element(s) in the document and shadow root
4503
- // This will include the active element in the shadow DOM if it exists
4504
- // Active element may be inside the shadow DOM depending on delegatesFocus, so we need to check both
4505
- let { activeElement } = document;
4506
- const actives = [activeElement];
4507
- while (activeElement?.shadowRoot?.activeElement) {
4508
- actives.push(activeElement.shadowRoot.activeElement);
4509
- activeElement = activeElement.shadowRoot.activeElement;
4510
- }
4511
- return actives;
4512
- }
4513
-
4514
- /**
4515
- * Gets the next focus index based on the current index and focusable elements.
4516
- * @param {number} currentIndex The current index of the focused element.
4517
- * @param {Array<HTMLElement>} focusables The array of focusable elements.
4518
- * @returns {number|null} The next focus index or null if not determined.
4519
- */
4520
- _getNextFocusIndex(currentIndex, focusables, actives) {
4521
- if (this.controlTabOrder) {
4522
- // Calculate the new index based on the current index and tab direction
4523
- let newFocusIndex =
4524
- currentIndex + (this.tabDirection === "forward" ? 1 : -1);
4525
-
4526
- // Wrap-around logic
4527
- if (newFocusIndex < 0) newFocusIndex = focusables.length - 1;
4528
- if (newFocusIndex >= focusables.length) newFocusIndex = 0;
4529
-
4530
- // Early return with the new index
4531
- return newFocusIndex;
4532
- }
4533
-
4534
- // Determine if we need to wrap
4535
- const atFirst =
4536
- actives.includes(focusables[0]) || actives.includes(this.container);
4537
- const atLast = actives.includes(focusables[focusables.length - 1]);
4538
-
4539
- // Only wrap if at the ends
4540
- if (this.tabDirection === "backward" && atFirst) {
4541
- return focusables.length - 1;
4542
- }
4543
-
4544
- if (this.tabDirection === "forward" && atLast) {
4545
- return 0;
4546
- }
4547
-
4548
- // No wrap, so don't change focus, return early
4549
- return null;
4550
- }
4551
-
4552
- /**
4553
- * Handles the Tab key press event to manage focus within the container.
4554
- * @param {KeyboardEvent} e The keyboard event triggered by the user.
4555
- * @returns {void}
4556
- */
4557
- _handleTabKey(e) {
4558
- // Update the focusable elements
4559
- const focusables = this._getFocusableElements();
4560
-
4561
- // If there are no focusable elements, exit
4562
- if (!focusables.length) return;
4563
-
4564
- // Set the tab direction based on the key pressed
4565
- this.tabDirection = e.shiftKey ? "backward" : "forward";
4566
-
4567
- // Get the active elements that are currently focused
4568
- const actives = this._getActiveElements();
4569
-
4570
- // If we're at either end of the focusable elements, wrap around to the other end
4571
- let focusIndex = focusables.findIndex((el) => actives.includes(el));
4572
-
4573
- // Fallback if we have no focused element
4574
- if (focusIndex === -1) focusIndex = 0;
4575
-
4576
- // Get the next focus index based on the current focus index, tab direction, and controlTabOrder setting
4577
- // Is null if no new focus index is determined
4578
- const newFocusIndex = this._getNextFocusIndex(
4579
- focusIndex,
4580
- focusables,
4581
- actives,
4582
- );
4583
-
4584
- // If we have a new focus index, set focus to that element
4585
- if (newFocusIndex !== null) {
4586
- e.preventDefault();
4587
- focusables[newFocusIndex].focus();
4588
- }
4589
- }
4590
-
4591
- /**
4592
- * Catches the keydown event
4593
- * @param {KeyboardEvent} e The keyboard event triggered by user interaction.
4594
- * @private
4595
- */
4596
- _onKeydown = (e) => {
4597
- // Handle tab
4598
- if (e.key === "Tab") this._handleTabKey(e);
4599
- };
4600
-
4601
- /**
4602
- * Retrieves all focusable elements within the container in DOM order, including those in shadow DOM and slots.
4603
- * Returns a unique, ordered array of elements that can receive focus.
4604
- *
4605
- * @returns {Array<HTMLElement>} An array of focusable elements within the container.
4606
- * @private
4607
- */
4608
- _getFocusableElements() {
4609
- // Use the imported utility function to get focusable elements
4610
- const elements = getFocusableElements(this.container);
4611
-
4612
- // Return the elements found
4613
- return elements;
4614
- }
4615
-
4616
- /**
4617
- * Moves focus to the first focusable element within the container.
4618
- * Useful for setting initial focus when activating the focus trap.
4619
- */
4620
- focusFirstElement() {
4621
- const focusables = this._getFocusableElements();
4622
- if (focusables.length) focusables[0].focus();
4623
- }
4624
-
4625
- /**
4626
- * Moves focus to the last focusable element within the container.
4627
- * Useful for setting focus when deactivating or cycling focus in reverse.
4628
- */
4629
- focusLastElement() {
4630
- const focusables = this._getFocusableElements();
4631
- if (focusables.length) focusables[focusables.length - 1].focus();
4632
- }
4633
-
4634
- /**
4635
- * Removes event listeners and attributes added by the focus trap.
4636
- * Call this method to clean up when the focus trap is no longer needed.
4637
- */
4638
- disconnect() {
4639
- if (this.container.hasAttribute("data-focus-trap-container")) {
4640
- this.container.removeAttribute("data-focus-trap-container");
4641
- }
4642
-
4643
- this.container.removeEventListener("keydown", this._onKeydown);
4644
- }
4645
- }
4646
-
4647
4482
  // Copyright (c) Alaska Air. All right reserved. Licensed under the Apache-2.0 license
4648
4483
  // See LICENSE in the project root for license information.
4649
4484
 
@@ -5141,7 +4976,7 @@ class AuroDropdownBib extends LitElement {
5141
4976
  classes[`shape-${this.shape}`] = true;
5142
4977
 
5143
4978
  return html`
5144
- <dialog class="${classMap(classes)}" part="bibContainer" role="${ifDefined(this.dialogRole)}" aria-labelledby="${ifDefined(this.dialogLabel ? 'dialogLabel' : undefined)}">
4979
+ <dialog tabindex="-1" class="${classMap(classes)}" part="bibContainer" role="${ifDefined(this.dialogRole)}" aria-labelledby="${ifDefined(this.dialogLabel ? 'dialogLabel' : undefined)}">
5145
4980
  ${this.dialogLabel ? html`<span id="dialogLabel" class="util_displayHiddenVisually">${this.dialogLabel}</span>` : ''}
5146
4981
  <slot></slot>
5147
4982
  <span id="srAnnouncement" class="util_displayHiddenVisually" aria-live="polite" role="status"></span>
@@ -5392,7 +5227,7 @@ class AuroHelpText extends LitElement {
5392
5227
  }
5393
5228
  }
5394
5229
 
5395
- var formkitVersion = '202607091919';
5230
+ var formkitVersion = '202607100029';
5396
5231
 
5397
5232
  let AuroElement$1 = class AuroElement extends LitElement {
5398
5233
  static get properties() {
@@ -6146,7 +5981,10 @@ class AuroDropdown extends AuroElement$1 {
6146
5981
  }
6147
5982
 
6148
5983
 
6149
- if (!this.isPopoverVisible) {
5984
+ // On Tab-driven close (eventType "focusloss"), let focus advance naturally
5985
+ // — restoring to the trigger would trap the user on this dropdown, forcing
5986
+ // an extra Tab to move on. Escape and outside-click still restore.
5987
+ if (!this.isPopoverVisible && eventType !== "focusloss") {
6150
5988
  // wait til the bib gets fully closed and rendered
6151
5989
  setTimeout(() => {
6152
5990
  // Skip if the bib re-opened, or if focus moved intentionally outside the dropdown (not to body).
@@ -6376,15 +6214,16 @@ class AuroDropdown extends AuroElement$1 {
6376
6214
  }
6377
6215
  });
6378
6216
  } else {
6379
- // Normal desktop: use FocusTrap on the bib element.
6380
- // Defer focusFirstElement to the next frame because the popover
6381
- // is positioned asynchronously by Floating UI — calling focus()
6382
- // synchronously here would target elements with zero dimensions
6383
- // and the focus call would be silently ignored.
6384
- this.focusTrap = new FocusTrap(this.bibContent);
6217
+ // Normal desktop (non-modal): move initial focus into the bib but
6218
+ // don't trap Tab. Tab should exit the bib and let the floater's
6219
+ // handleFocusLoss close it, matching native <select>/<details>
6220
+ // behavior. Deferred one frame because Floating UI positions the
6221
+ // popover asynchronously a synchronous focus() would target
6222
+ // zero-dimension elements and be silently ignored.
6385
6223
  requestAnimationFrame(() => {
6386
- if (this.focusTrap) {
6387
- this.focusTrap.focusFirstElement();
6224
+ const focusables = getFocusableElements(this.bibContent);
6225
+ if (focusables.length) {
6226
+ focusables[0].focus();
6388
6227
  }
6389
6228
  });
6390
6229
  }