@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
@@ -3535,12 +3535,40 @@ class AuroFloatingUI {
3535
3535
  return;
3536
3536
  }
3537
3537
 
3538
+ // Chrome-specific: during popover top-layer promotion after a click on a
3539
+ // slotted focusable, :focus-within can briefly evaluate false while the
3540
+ // active element is still structurally inside the trigger/bib. Fall back
3541
+ // to a shadow-piercing ancestry walk from the deep active element before
3542
+ // treating this as a real focus loss.
3543
+ try {
3544
+ let active = document.activeElement;
3545
+ while (active && active.shadowRoot && active.shadowRoot.activeElement) {
3546
+ active = active.shadowRoot.activeElement;
3547
+ }
3548
+ const targets = [element, element.trigger, element.bib].filter(Boolean);
3549
+ let node = active;
3550
+ while (node) {
3551
+ if (targets.includes(node)) {
3552
+ return;
3553
+ }
3554
+ node =
3555
+ node.parentElement ||
3556
+ (node.getRootNode && node.getRootNode().host) ||
3557
+ null;
3558
+ }
3559
+ } catch (e) {
3560
+ // Defensive: fall through to the existing close path if traversal fails.
3561
+ }
3562
+
3538
3563
  // if fullscreen bib is in fullscreen mode, do not close
3539
3564
  if (element.bib.hasAttribute("isfullscreen")) {
3540
3565
  return;
3541
3566
  }
3542
3567
 
3543
- this.hideBib("keydown");
3568
+ // eventType "focusloss" distinguishes a Tab/click-driven close from an
3569
+ // Escape keydown close. Consumers use this to decide whether to restore
3570
+ // focus to the trigger (Escape) or let it advance naturally (Tab).
3571
+ this.hideBib("focusloss");
3544
3572
  }
3545
3573
 
3546
3574
  setupHideHandlers() {
@@ -4210,199 +4238,6 @@ function getFocusableElements(container) {
4210
4238
  return tabIndexedUniqueElements;
4211
4239
  }
4212
4240
 
4213
- /**
4214
- * FocusTrap manages keyboard focus within a specified container element, ensuring that focus does not leave the container when tabbing.
4215
- * It is commonly used for modal dialogs or overlays to improve accessibility by trapping focus within interactive UI components.
4216
- */
4217
- class FocusTrap {
4218
- /**
4219
- * Creates a new FocusTrap instance for the given container element.
4220
- * Initializes event listeners and prepares the container for focus management.
4221
- *
4222
- * @param {HTMLElement} container The DOM element to trap focus within.
4223
- * @param {boolean} [controlTabOrder=false] If true enables manual control of the tab order by the FocusTrap.
4224
- * @throws {Error} If the provided container is not a valid HTMLElement.
4225
- */
4226
- constructor(container, controlTabOrder = false) {
4227
- if (!container || !(container instanceof HTMLElement)) {
4228
- throw new Error("FocusTrap requires a valid HTMLElement.");
4229
- }
4230
-
4231
- this.container = container;
4232
- this.tabDirection = "forward"; // or 'backward';
4233
- this.controlTabOrder = controlTabOrder;
4234
-
4235
- this._init();
4236
- }
4237
-
4238
- /**
4239
- * Initializes the focus trap by setting up event listeners and attributes on the container.
4240
- * Prepares the container for focus management, including support for shadow DOM and inert attributes.
4241
- *
4242
- * @private
4243
- */
4244
- _init() {
4245
- // Add inert attribute to prevent focusing programmatically as well (if supported)
4246
- if ("inert" in HTMLElement.prototype) {
4247
- this.container.inert = false; // Ensure the container isn't inert
4248
- this.container.setAttribute("data-focus-trap-container", true); // Mark for identification
4249
- }
4250
-
4251
- // Track tab direction
4252
- this.container.addEventListener("keydown", this._onKeydown);
4253
- }
4254
-
4255
- /**
4256
- * Gets an array of currently active (focused) elements in the document and shadow DOM.
4257
- * @returns {Array<HTMLElement>} An array of focusable elements within the container.
4258
- * @private
4259
- */
4260
- _getActiveElements() {
4261
- // Get the active element(s) in the document and shadow root
4262
- // This will include the active element in the shadow DOM if it exists
4263
- // Active element may be inside the shadow DOM depending on delegatesFocus, so we need to check both
4264
- let { activeElement } = document;
4265
- const actives = [activeElement];
4266
- while (activeElement?.shadowRoot?.activeElement) {
4267
- actives.push(activeElement.shadowRoot.activeElement);
4268
- activeElement = activeElement.shadowRoot.activeElement;
4269
- }
4270
- return actives;
4271
- }
4272
-
4273
- /**
4274
- * Gets the next focus index based on the current index and focusable elements.
4275
- * @param {number} currentIndex The current index of the focused element.
4276
- * @param {Array<HTMLElement>} focusables The array of focusable elements.
4277
- * @returns {number|null} The next focus index or null if not determined.
4278
- */
4279
- _getNextFocusIndex(currentIndex, focusables, actives) {
4280
- if (this.controlTabOrder) {
4281
- // Calculate the new index based on the current index and tab direction
4282
- let newFocusIndex =
4283
- currentIndex + (this.tabDirection === "forward" ? 1 : -1);
4284
-
4285
- // Wrap-around logic
4286
- if (newFocusIndex < 0) newFocusIndex = focusables.length - 1;
4287
- if (newFocusIndex >= focusables.length) newFocusIndex = 0;
4288
-
4289
- // Early return with the new index
4290
- return newFocusIndex;
4291
- }
4292
-
4293
- // Determine if we need to wrap
4294
- const atFirst =
4295
- actives.includes(focusables[0]) || actives.includes(this.container);
4296
- const atLast = actives.includes(focusables[focusables.length - 1]);
4297
-
4298
- // Only wrap if at the ends
4299
- if (this.tabDirection === "backward" && atFirst) {
4300
- return focusables.length - 1;
4301
- }
4302
-
4303
- if (this.tabDirection === "forward" && atLast) {
4304
- return 0;
4305
- }
4306
-
4307
- // No wrap, so don't change focus, return early
4308
- return null;
4309
- }
4310
-
4311
- /**
4312
- * Handles the Tab key press event to manage focus within the container.
4313
- * @param {KeyboardEvent} e The keyboard event triggered by the user.
4314
- * @returns {void}
4315
- */
4316
- _handleTabKey(e) {
4317
- // Update the focusable elements
4318
- const focusables = this._getFocusableElements();
4319
-
4320
- // If there are no focusable elements, exit
4321
- if (!focusables.length) return;
4322
-
4323
- // Set the tab direction based on the key pressed
4324
- this.tabDirection = e.shiftKey ? "backward" : "forward";
4325
-
4326
- // Get the active elements that are currently focused
4327
- const actives = this._getActiveElements();
4328
-
4329
- // If we're at either end of the focusable elements, wrap around to the other end
4330
- let focusIndex = focusables.findIndex((el) => actives.includes(el));
4331
-
4332
- // Fallback if we have no focused element
4333
- if (focusIndex === -1) focusIndex = 0;
4334
-
4335
- // Get the next focus index based on the current focus index, tab direction, and controlTabOrder setting
4336
- // Is null if no new focus index is determined
4337
- const newFocusIndex = this._getNextFocusIndex(
4338
- focusIndex,
4339
- focusables,
4340
- actives,
4341
- );
4342
-
4343
- // If we have a new focus index, set focus to that element
4344
- if (newFocusIndex !== null) {
4345
- e.preventDefault();
4346
- focusables[newFocusIndex].focus();
4347
- }
4348
- }
4349
-
4350
- /**
4351
- * Catches the keydown event
4352
- * @param {KeyboardEvent} e The keyboard event triggered by user interaction.
4353
- * @private
4354
- */
4355
- _onKeydown = (e) => {
4356
- // Handle tab
4357
- if (e.key === "Tab") this._handleTabKey(e);
4358
- };
4359
-
4360
- /**
4361
- * Retrieves all focusable elements within the container in DOM order, including those in shadow DOM and slots.
4362
- * Returns a unique, ordered array of elements that can receive focus.
4363
- *
4364
- * @returns {Array<HTMLElement>} An array of focusable elements within the container.
4365
- * @private
4366
- */
4367
- _getFocusableElements() {
4368
- // Use the imported utility function to get focusable elements
4369
- const elements = getFocusableElements(this.container);
4370
-
4371
- // Return the elements found
4372
- return elements;
4373
- }
4374
-
4375
- /**
4376
- * Moves focus to the first focusable element within the container.
4377
- * Useful for setting initial focus when activating the focus trap.
4378
- */
4379
- focusFirstElement() {
4380
- const focusables = this._getFocusableElements();
4381
- if (focusables.length) focusables[0].focus();
4382
- }
4383
-
4384
- /**
4385
- * Moves focus to the last focusable element within the container.
4386
- * Useful for setting focus when deactivating or cycling focus in reverse.
4387
- */
4388
- focusLastElement() {
4389
- const focusables = this._getFocusableElements();
4390
- if (focusables.length) focusables[focusables.length - 1].focus();
4391
- }
4392
-
4393
- /**
4394
- * Removes event listeners and attributes added by the focus trap.
4395
- * Call this method to clean up when the focus trap is no longer needed.
4396
- */
4397
- disconnect() {
4398
- if (this.container.hasAttribute("data-focus-trap-container")) {
4399
- this.container.removeAttribute("data-focus-trap-container");
4400
- }
4401
-
4402
- this.container.removeEventListener("keydown", this._onKeydown);
4403
- }
4404
- }
4405
-
4406
4241
  // Copyright (c) Alaska Air. All right reserved. Licensed under the Apache-2.0 license
4407
4242
  // See LICENSE in the project root for license information.
4408
4243
 
@@ -4900,7 +4735,7 @@ class AuroDropdownBib extends i$3 {
4900
4735
  classes[`shape-${this.shape}`] = true;
4901
4736
 
4902
4737
  return u$7`
4903
- <dialog class="${e$2(classes)}" part="bibContainer" role="${o(this.dialogRole)}" aria-labelledby="${o(this.dialogLabel ? 'dialogLabel' : undefined)}">
4738
+ <dialog tabindex="-1" class="${e$2(classes)}" part="bibContainer" role="${o(this.dialogRole)}" aria-labelledby="${o(this.dialogLabel ? 'dialogLabel' : undefined)}">
4904
4739
  ${this.dialogLabel ? u$7`<span id="dialogLabel" class="util_displayHiddenVisually">${this.dialogLabel}</span>` : ''}
4905
4740
  <slot></slot>
4906
4741
  <span id="srAnnouncement" class="util_displayHiddenVisually" aria-live="polite" role="status"></span>
@@ -5151,7 +4986,7 @@ let AuroHelpText$2 = class AuroHelpText extends i$3 {
5151
4986
  }
5152
4987
  };
5153
4988
 
5154
- var formkitVersion$2 = '202607091919';
4989
+ var formkitVersion$2 = '202607100029';
5155
4990
 
5156
4991
  let AuroElement$2 = class AuroElement extends i$3 {
5157
4992
  static get properties() {
@@ -5905,7 +5740,10 @@ class AuroDropdown extends AuroElement$2 {
5905
5740
  }
5906
5741
 
5907
5742
 
5908
- if (!this.isPopoverVisible) {
5743
+ // On Tab-driven close (eventType "focusloss"), let focus advance naturally
5744
+ // — restoring to the trigger would trap the user on this dropdown, forcing
5745
+ // an extra Tab to move on. Escape and outside-click still restore.
5746
+ if (!this.isPopoverVisible && eventType !== "focusloss") {
5909
5747
  // wait til the bib gets fully closed and rendered
5910
5748
  setTimeout(() => {
5911
5749
  // Skip if the bib re-opened, or if focus moved intentionally outside the dropdown (not to body).
@@ -6135,15 +5973,16 @@ class AuroDropdown extends AuroElement$2 {
6135
5973
  }
6136
5974
  });
6137
5975
  } else {
6138
- // Normal desktop: use FocusTrap on the bib element.
6139
- // Defer focusFirstElement to the next frame because the popover
6140
- // is positioned asynchronously by Floating UI — calling focus()
6141
- // synchronously here would target elements with zero dimensions
6142
- // and the focus call would be silently ignored.
6143
- this.focusTrap = new FocusTrap(this.bibContent);
5976
+ // Normal desktop (non-modal): move initial focus into the bib but
5977
+ // don't trap Tab. Tab should exit the bib and let the floater's
5978
+ // handleFocusLoss close it, matching native <select>/<details>
5979
+ // behavior. Deferred one frame because Floating UI positions the
5980
+ // popover asynchronously a synchronous focus() would target
5981
+ // zero-dimension elements and be silently ignored.
6144
5982
  requestAnimationFrame(() => {
6145
- if (this.focusTrap) {
6146
- this.focusTrap.focusFirstElement();
5983
+ const focusables = getFocusableElements(this.bibContent);
5984
+ if (focusables.length) {
5985
+ focusables[0].focus();
6147
5986
  }
6148
5987
  });
6149
5988
  }
@@ -18776,7 +18615,7 @@ let AuroHelpText$1 = class AuroHelpText extends i$3 {
18776
18615
  }
18777
18616
  };
18778
18617
 
18779
- var formkitVersion$1 = '202607091919';
18618
+ var formkitVersion$1 = '202607100029';
18780
18619
 
18781
18620
  // Copyright (c) 2025 Alaska Airlines. All right reserved. Licensed under the Apache-2.0 license
18782
18621
  // See LICENSE in the project root for license information.
@@ -19897,7 +19736,7 @@ class AuroBibtemplate extends i$3 {
19897
19736
  }
19898
19737
  }
19899
19738
 
19900
- var formkitVersion = '202607091919';
19739
+ var formkitVersion = '202607100029';
19901
19740
 
19902
19741
  var styleCss$3 = i$6`.util_displayInline{display:inline}.util_displayInlineBlock{display:inline-block}.util_displayBlock{display:block}.util_displayFlex{display:flex}.util_displayHidden{display:none}.util_displayHiddenVisually{position:absolute;overflow:hidden;clip:rect(1px, 1px, 1px, 1px);width:1px;height:1px;padding:0;border:0}:host{display:block;text-align:left}:host [auro-dropdown]{--ds-auro-dropdown-trigger-background-color: transparent}:host #inputInBib::part(wrapper){box-shadow:none}:host #inputInBib::part(accent-left){display:none}:host([layout*=classic]) [auro-input]{width:100%}:host([layout*=classic]) [auro-input]::part(helpText){display:none}:host([layout*=classic]) #slotHolder{display:none}`;
19903
19742
 
@@ -3453,12 +3453,40 @@ class AuroFloatingUI {
3453
3453
  return;
3454
3454
  }
3455
3455
 
3456
+ // Chrome-specific: during popover top-layer promotion after a click on a
3457
+ // slotted focusable, :focus-within can briefly evaluate false while the
3458
+ // active element is still structurally inside the trigger/bib. Fall back
3459
+ // to a shadow-piercing ancestry walk from the deep active element before
3460
+ // treating this as a real focus loss.
3461
+ try {
3462
+ let active = document.activeElement;
3463
+ while (active && active.shadowRoot && active.shadowRoot.activeElement) {
3464
+ active = active.shadowRoot.activeElement;
3465
+ }
3466
+ const targets = [element, element.trigger, element.bib].filter(Boolean);
3467
+ let node = active;
3468
+ while (node) {
3469
+ if (targets.includes(node)) {
3470
+ return;
3471
+ }
3472
+ node =
3473
+ node.parentElement ||
3474
+ (node.getRootNode && node.getRootNode().host) ||
3475
+ null;
3476
+ }
3477
+ } catch (e) {
3478
+ // Defensive: fall through to the existing close path if traversal fails.
3479
+ }
3480
+
3456
3481
  // if fullscreen bib is in fullscreen mode, do not close
3457
3482
  if (element.bib.hasAttribute("isfullscreen")) {
3458
3483
  return;
3459
3484
  }
3460
3485
 
3461
- this.hideBib("keydown");
3486
+ // eventType "focusloss" distinguishes a Tab/click-driven close from an
3487
+ // Escape keydown close. Consumers use this to decide whether to restore
3488
+ // focus to the trigger (Escape) or let it advance naturally (Tab).
3489
+ this.hideBib("focusloss");
3462
3490
  }
3463
3491
 
3464
3492
  setupHideHandlers() {
@@ -4128,199 +4156,6 @@ function getFocusableElements(container) {
4128
4156
  return tabIndexedUniqueElements;
4129
4157
  }
4130
4158
 
4131
- /**
4132
- * FocusTrap manages keyboard focus within a specified container element, ensuring that focus does not leave the container when tabbing.
4133
- * It is commonly used for modal dialogs or overlays to improve accessibility by trapping focus within interactive UI components.
4134
- */
4135
- class FocusTrap {
4136
- /**
4137
- * Creates a new FocusTrap instance for the given container element.
4138
- * Initializes event listeners and prepares the container for focus management.
4139
- *
4140
- * @param {HTMLElement} container The DOM element to trap focus within.
4141
- * @param {boolean} [controlTabOrder=false] If true enables manual control of the tab order by the FocusTrap.
4142
- * @throws {Error} If the provided container is not a valid HTMLElement.
4143
- */
4144
- constructor(container, controlTabOrder = false) {
4145
- if (!container || !(container instanceof HTMLElement)) {
4146
- throw new Error("FocusTrap requires a valid HTMLElement.");
4147
- }
4148
-
4149
- this.container = container;
4150
- this.tabDirection = "forward"; // or 'backward';
4151
- this.controlTabOrder = controlTabOrder;
4152
-
4153
- this._init();
4154
- }
4155
-
4156
- /**
4157
- * Initializes the focus trap by setting up event listeners and attributes on the container.
4158
- * Prepares the container for focus management, including support for shadow DOM and inert attributes.
4159
- *
4160
- * @private
4161
- */
4162
- _init() {
4163
- // Add inert attribute to prevent focusing programmatically as well (if supported)
4164
- if ("inert" in HTMLElement.prototype) {
4165
- this.container.inert = false; // Ensure the container isn't inert
4166
- this.container.setAttribute("data-focus-trap-container", true); // Mark for identification
4167
- }
4168
-
4169
- // Track tab direction
4170
- this.container.addEventListener("keydown", this._onKeydown);
4171
- }
4172
-
4173
- /**
4174
- * Gets an array of currently active (focused) elements in the document and shadow DOM.
4175
- * @returns {Array<HTMLElement>} An array of focusable elements within the container.
4176
- * @private
4177
- */
4178
- _getActiveElements() {
4179
- // Get the active element(s) in the document and shadow root
4180
- // This will include the active element in the shadow DOM if it exists
4181
- // Active element may be inside the shadow DOM depending on delegatesFocus, so we need to check both
4182
- let { activeElement } = document;
4183
- const actives = [activeElement];
4184
- while (activeElement?.shadowRoot?.activeElement) {
4185
- actives.push(activeElement.shadowRoot.activeElement);
4186
- activeElement = activeElement.shadowRoot.activeElement;
4187
- }
4188
- return actives;
4189
- }
4190
-
4191
- /**
4192
- * Gets the next focus index based on the current index and focusable elements.
4193
- * @param {number} currentIndex The current index of the focused element.
4194
- * @param {Array<HTMLElement>} focusables The array of focusable elements.
4195
- * @returns {number|null} The next focus index or null if not determined.
4196
- */
4197
- _getNextFocusIndex(currentIndex, focusables, actives) {
4198
- if (this.controlTabOrder) {
4199
- // Calculate the new index based on the current index and tab direction
4200
- let newFocusIndex =
4201
- currentIndex + (this.tabDirection === "forward" ? 1 : -1);
4202
-
4203
- // Wrap-around logic
4204
- if (newFocusIndex < 0) newFocusIndex = focusables.length - 1;
4205
- if (newFocusIndex >= focusables.length) newFocusIndex = 0;
4206
-
4207
- // Early return with the new index
4208
- return newFocusIndex;
4209
- }
4210
-
4211
- // Determine if we need to wrap
4212
- const atFirst =
4213
- actives.includes(focusables[0]) || actives.includes(this.container);
4214
- const atLast = actives.includes(focusables[focusables.length - 1]);
4215
-
4216
- // Only wrap if at the ends
4217
- if (this.tabDirection === "backward" && atFirst) {
4218
- return focusables.length - 1;
4219
- }
4220
-
4221
- if (this.tabDirection === "forward" && atLast) {
4222
- return 0;
4223
- }
4224
-
4225
- // No wrap, so don't change focus, return early
4226
- return null;
4227
- }
4228
-
4229
- /**
4230
- * Handles the Tab key press event to manage focus within the container.
4231
- * @param {KeyboardEvent} e The keyboard event triggered by the user.
4232
- * @returns {void}
4233
- */
4234
- _handleTabKey(e) {
4235
- // Update the focusable elements
4236
- const focusables = this._getFocusableElements();
4237
-
4238
- // If there are no focusable elements, exit
4239
- if (!focusables.length) return;
4240
-
4241
- // Set the tab direction based on the key pressed
4242
- this.tabDirection = e.shiftKey ? "backward" : "forward";
4243
-
4244
- // Get the active elements that are currently focused
4245
- const actives = this._getActiveElements();
4246
-
4247
- // If we're at either end of the focusable elements, wrap around to the other end
4248
- let focusIndex = focusables.findIndex((el) => actives.includes(el));
4249
-
4250
- // Fallback if we have no focused element
4251
- if (focusIndex === -1) focusIndex = 0;
4252
-
4253
- // Get the next focus index based on the current focus index, tab direction, and controlTabOrder setting
4254
- // Is null if no new focus index is determined
4255
- const newFocusIndex = this._getNextFocusIndex(
4256
- focusIndex,
4257
- focusables,
4258
- actives,
4259
- );
4260
-
4261
- // If we have a new focus index, set focus to that element
4262
- if (newFocusIndex !== null) {
4263
- e.preventDefault();
4264
- focusables[newFocusIndex].focus();
4265
- }
4266
- }
4267
-
4268
- /**
4269
- * Catches the keydown event
4270
- * @param {KeyboardEvent} e The keyboard event triggered by user interaction.
4271
- * @private
4272
- */
4273
- _onKeydown = (e) => {
4274
- // Handle tab
4275
- if (e.key === "Tab") this._handleTabKey(e);
4276
- };
4277
-
4278
- /**
4279
- * Retrieves all focusable elements within the container in DOM order, including those in shadow DOM and slots.
4280
- * Returns a unique, ordered array of elements that can receive focus.
4281
- *
4282
- * @returns {Array<HTMLElement>} An array of focusable elements within the container.
4283
- * @private
4284
- */
4285
- _getFocusableElements() {
4286
- // Use the imported utility function to get focusable elements
4287
- const elements = getFocusableElements(this.container);
4288
-
4289
- // Return the elements found
4290
- return elements;
4291
- }
4292
-
4293
- /**
4294
- * Moves focus to the first focusable element within the container.
4295
- * Useful for setting initial focus when activating the focus trap.
4296
- */
4297
- focusFirstElement() {
4298
- const focusables = this._getFocusableElements();
4299
- if (focusables.length) focusables[0].focus();
4300
- }
4301
-
4302
- /**
4303
- * Moves focus to the last focusable element within the container.
4304
- * Useful for setting focus when deactivating or cycling focus in reverse.
4305
- */
4306
- focusLastElement() {
4307
- const focusables = this._getFocusableElements();
4308
- if (focusables.length) focusables[focusables.length - 1].focus();
4309
- }
4310
-
4311
- /**
4312
- * Removes event listeners and attributes added by the focus trap.
4313
- * Call this method to clean up when the focus trap is no longer needed.
4314
- */
4315
- disconnect() {
4316
- if (this.container.hasAttribute("data-focus-trap-container")) {
4317
- this.container.removeAttribute("data-focus-trap-container");
4318
- }
4319
-
4320
- this.container.removeEventListener("keydown", this._onKeydown);
4321
- }
4322
- }
4323
-
4324
4159
  // Copyright (c) Alaska Air. All right reserved. Licensed under the Apache-2.0 license
4325
4160
  // See LICENSE in the project root for license information.
4326
4161
 
@@ -4818,7 +4653,7 @@ class AuroDropdownBib extends LitElement {
4818
4653
  classes[`shape-${this.shape}`] = true;
4819
4654
 
4820
4655
  return html`
4821
- <dialog class="${classMap(classes)}" part="bibContainer" role="${ifDefined(this.dialogRole)}" aria-labelledby="${ifDefined(this.dialogLabel ? 'dialogLabel' : undefined)}">
4656
+ <dialog tabindex="-1" class="${classMap(classes)}" part="bibContainer" role="${ifDefined(this.dialogRole)}" aria-labelledby="${ifDefined(this.dialogLabel ? 'dialogLabel' : undefined)}">
4822
4657
  ${this.dialogLabel ? html`<span id="dialogLabel" class="util_displayHiddenVisually">${this.dialogLabel}</span>` : ''}
4823
4658
  <slot></slot>
4824
4659
  <span id="srAnnouncement" class="util_displayHiddenVisually" aria-live="polite" role="status"></span>
@@ -5069,7 +4904,7 @@ let AuroHelpText$2 = class AuroHelpText extends LitElement {
5069
4904
  }
5070
4905
  };
5071
4906
 
5072
- var formkitVersion$2 = '202607091919';
4907
+ var formkitVersion$2 = '202607100029';
5073
4908
 
5074
4909
  let AuroElement$2 = class AuroElement extends LitElement {
5075
4910
  static get properties() {
@@ -5823,7 +5658,10 @@ class AuroDropdown extends AuroElement$2 {
5823
5658
  }
5824
5659
 
5825
5660
 
5826
- if (!this.isPopoverVisible) {
5661
+ // On Tab-driven close (eventType "focusloss"), let focus advance naturally
5662
+ // — restoring to the trigger would trap the user on this dropdown, forcing
5663
+ // an extra Tab to move on. Escape and outside-click still restore.
5664
+ if (!this.isPopoverVisible && eventType !== "focusloss") {
5827
5665
  // wait til the bib gets fully closed and rendered
5828
5666
  setTimeout(() => {
5829
5667
  // Skip if the bib re-opened, or if focus moved intentionally outside the dropdown (not to body).
@@ -6053,15 +5891,16 @@ class AuroDropdown extends AuroElement$2 {
6053
5891
  }
6054
5892
  });
6055
5893
  } else {
6056
- // Normal desktop: use FocusTrap on the bib element.
6057
- // Defer focusFirstElement to the next frame because the popover
6058
- // is positioned asynchronously by Floating UI — calling focus()
6059
- // synchronously here would target elements with zero dimensions
6060
- // and the focus call would be silently ignored.
6061
- this.focusTrap = new FocusTrap(this.bibContent);
5894
+ // Normal desktop (non-modal): move initial focus into the bib but
5895
+ // don't trap Tab. Tab should exit the bib and let the floater's
5896
+ // handleFocusLoss close it, matching native <select>/<details>
5897
+ // behavior. Deferred one frame because Floating UI positions the
5898
+ // popover asynchronously a synchronous focus() would target
5899
+ // zero-dimension elements and be silently ignored.
6062
5900
  requestAnimationFrame(() => {
6063
- if (this.focusTrap) {
6064
- this.focusTrap.focusFirstElement();
5901
+ const focusables = getFocusableElements(this.bibContent);
5902
+ if (focusables.length) {
5903
+ focusables[0].focus();
6065
5904
  }
6066
5905
  });
6067
5906
  }
@@ -18687,7 +18526,7 @@ let AuroHelpText$1 = class AuroHelpText extends LitElement {
18687
18526
  }
18688
18527
  };
18689
18528
 
18690
- var formkitVersion$1 = '202607091919';
18529
+ var formkitVersion$1 = '202607100029';
18691
18530
 
18692
18531
  // Copyright (c) 2025 Alaska Airlines. All right reserved. Licensed under the Apache-2.0 license
18693
18532
  // See LICENSE in the project root for license information.
@@ -19808,7 +19647,7 @@ class AuroBibtemplate extends LitElement {
19808
19647
  }
19809
19648
  }
19810
19649
 
19811
- var formkitVersion = '202607091919';
19650
+ var formkitVersion = '202607100029';
19812
19651
 
19813
19652
  var styleCss$1 = css`.util_displayInline{display:inline}.util_displayInlineBlock{display:inline-block}.util_displayBlock{display:block}.util_displayFlex{display:flex}.util_displayHidden{display:none}.util_displayHiddenVisually{position:absolute;overflow:hidden;clip:rect(1px, 1px, 1px, 1px);width:1px;height:1px;padding:0;border:0}:host{display:block;text-align:left}:host [auro-dropdown]{--ds-auro-dropdown-trigger-background-color: transparent}:host #inputInBib::part(wrapper){box-shadow:none}:host #inputInBib::part(accent-left){display:none}:host([layout*=classic]) [auro-input]{width:100%}:host([layout*=classic]) [auro-input]::part(helpText){display:none}:host([layout*=classic]) #slotHolder{display:none}`;
19814
19653