@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.
- package/components/checkbox/demo/customize.min.js +1 -1
- package/components/checkbox/demo/getting-started.min.js +1 -1
- package/components/checkbox/demo/index.min.js +1 -1
- package/components/checkbox/dist/index.js +1 -1
- package/components/checkbox/dist/registered.js +1 -1
- package/components/combobox/demo/customize.min.js +46 -207
- package/components/combobox/demo/getting-started.min.js +46 -207
- package/components/combobox/demo/index.min.js +46 -207
- package/components/combobox/dist/index.js +46 -207
- package/components/combobox/dist/registered.js +46 -207
- package/components/counter/demo/customize.min.js +59 -222
- package/components/counter/demo/index.min.js +59 -222
- package/components/counter/dist/auro-counter.d.ts +0 -8
- package/components/counter/dist/index.js +59 -222
- package/components/counter/dist/registered.js +59 -222
- package/components/datepicker/demo/customize.min.js +46 -207
- package/components/datepicker/demo/index.min.js +46 -207
- package/components/datepicker/dist/index.js +46 -207
- package/components/datepicker/dist/registered.js +46 -207
- package/components/dropdown/demo/customize.min.js +44 -205
- package/components/dropdown/demo/getting-started.min.js +44 -205
- package/components/dropdown/demo/index.min.js +44 -205
- package/components/dropdown/dist/index.js +44 -205
- package/components/dropdown/dist/registered.js +44 -205
- package/components/form/demo/customize.min.js +199 -845
- package/components/form/demo/getting-started.min.js +199 -845
- package/components/form/demo/index.min.js +199 -845
- package/components/form/demo/registerDemoDeps.min.js +199 -845
- package/components/input/demo/customize.min.js +1 -1
- package/components/input/demo/getting-started.min.js +1 -1
- package/components/input/demo/index.min.js +1 -1
- package/components/input/dist/index.js +1 -1
- package/components/input/dist/registered.js +1 -1
- package/components/radio/demo/customize.min.js +1 -1
- package/components/radio/demo/getting-started.min.js +1 -1
- package/components/radio/demo/index.min.js +1 -1
- package/components/radio/dist/index.js +1 -1
- package/components/radio/dist/registered.js +1 -1
- package/components/select/demo/customize.min.js +45 -206
- package/components/select/demo/getting-started.min.js +45 -206
- package/components/select/demo/index.min.js +45 -206
- package/components/select/dist/index.js +45 -206
- package/components/select/dist/registered.js +45 -206
- package/custom-elements.json +1499 -1514
- package/package.json +2 -2
|
@@ -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
|
-
|
|
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 = '
|
|
4907
|
+
var formkitVersion$2 = '202607102138';
|
|
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
|
-
|
|
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:
|
|
6057
|
-
//
|
|
6058
|
-
//
|
|
6059
|
-
//
|
|
6060
|
-
//
|
|
6061
|
-
|
|
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
|
-
|
|
6064
|
-
|
|
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 = '
|
|
18529
|
+
var formkitVersion$1 = '202607102138';
|
|
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 = '
|
|
19650
|
+
var formkitVersion = '202607102138';
|
|
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
|
|
|
@@ -1114,7 +1114,7 @@ let AuroHelpText$1 = class AuroHelpText extends i$2 {
|
|
|
1114
1114
|
}
|
|
1115
1115
|
};
|
|
1116
1116
|
|
|
1117
|
-
var formkitVersion$1 = '
|
|
1117
|
+
var formkitVersion$1 = '202607102138';
|
|
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.
|
|
@@ -1455,21 +1455,6 @@ class AuroCounter extends i$2 {
|
|
|
1455
1455
|
}
|
|
1456
1456
|
}
|
|
1457
1457
|
|
|
1458
|
-
/**
|
|
1459
|
-
* Handles the slotchange event for the description slot.
|
|
1460
|
-
* Updates ariaDescribedByElements on the spinbutton.
|
|
1461
|
-
*
|
|
1462
|
-
* @param {Event} event - The slotchange event.
|
|
1463
|
-
* @private
|
|
1464
|
-
*/
|
|
1465
|
-
onDescriptionSlotChange(event) {
|
|
1466
|
-
const spinbutton = this.shadowRoot.querySelector('[role="spinbutton"]');
|
|
1467
|
-
if (spinbutton) {
|
|
1468
|
-
const assigned = event.target.assignedElements();
|
|
1469
|
-
spinbutton.ariaDescribedByElements = assigned.length > 0 ? assigned : [];
|
|
1470
|
-
}
|
|
1471
|
-
}
|
|
1472
|
-
|
|
1473
1458
|
updated(changedProperties) {
|
|
1474
1459
|
if (changedProperties.has("value")) {
|
|
1475
1460
|
this.validate();
|
|
@@ -1525,7 +1510,7 @@ class AuroCounter extends i$2 {
|
|
|
1525
1510
|
<label class="label">
|
|
1526
1511
|
<slot @slotchange="${this.onDefaultSlotChange}"></slot>
|
|
1527
1512
|
</label>
|
|
1528
|
-
<slot name="description" class="body-xs"
|
|
1513
|
+
<slot name="description" class="body-xs"></slot>
|
|
1529
1514
|
</div>
|
|
1530
1515
|
<div
|
|
1531
1516
|
part="counterControl"
|
|
@@ -3844,12 +3829,40 @@ class AuroFloatingUI {
|
|
|
3844
3829
|
return;
|
|
3845
3830
|
}
|
|
3846
3831
|
|
|
3832
|
+
// Chrome-specific: during popover top-layer promotion after a click on a
|
|
3833
|
+
// slotted focusable, :focus-within can briefly evaluate false while the
|
|
3834
|
+
// active element is still structurally inside the trigger/bib. Fall back
|
|
3835
|
+
// to a shadow-piercing ancestry walk from the deep active element before
|
|
3836
|
+
// treating this as a real focus loss.
|
|
3837
|
+
try {
|
|
3838
|
+
let active = document.activeElement;
|
|
3839
|
+
while (active && active.shadowRoot && active.shadowRoot.activeElement) {
|
|
3840
|
+
active = active.shadowRoot.activeElement;
|
|
3841
|
+
}
|
|
3842
|
+
const targets = [element, element.trigger, element.bib].filter(Boolean);
|
|
3843
|
+
let node = active;
|
|
3844
|
+
while (node) {
|
|
3845
|
+
if (targets.includes(node)) {
|
|
3846
|
+
return;
|
|
3847
|
+
}
|
|
3848
|
+
node =
|
|
3849
|
+
node.parentElement ||
|
|
3850
|
+
(node.getRootNode && node.getRootNode().host) ||
|
|
3851
|
+
null;
|
|
3852
|
+
}
|
|
3853
|
+
} catch (e) {
|
|
3854
|
+
// Defensive: fall through to the existing close path if traversal fails.
|
|
3855
|
+
}
|
|
3856
|
+
|
|
3847
3857
|
// if fullscreen bib is in fullscreen mode, do not close
|
|
3848
3858
|
if (element.bib.hasAttribute("isfullscreen")) {
|
|
3849
3859
|
return;
|
|
3850
3860
|
}
|
|
3851
3861
|
|
|
3852
|
-
|
|
3862
|
+
// eventType "focusloss" distinguishes a Tab/click-driven close from an
|
|
3863
|
+
// Escape keydown close. Consumers use this to decide whether to restore
|
|
3864
|
+
// focus to the trigger (Escape) or let it advance naturally (Tab).
|
|
3865
|
+
this.hideBib("focusloss");
|
|
3853
3866
|
}
|
|
3854
3867
|
|
|
3855
3868
|
setupHideHandlers() {
|
|
@@ -4519,199 +4532,6 @@ function getFocusableElements(container) {
|
|
|
4519
4532
|
return tabIndexedUniqueElements;
|
|
4520
4533
|
}
|
|
4521
4534
|
|
|
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
4535
|
// Copyright (c) Alaska Air. All right reserved. Licensed under the Apache-2.0 license
|
|
4716
4536
|
// See LICENSE in the project root for license information.
|
|
4717
4537
|
|
|
@@ -5209,7 +5029,7 @@ class AuroDropdownBib extends i$2 {
|
|
|
5209
5029
|
classes[`shape-${this.shape}`] = true;
|
|
5210
5030
|
|
|
5211
5031
|
return u$5`
|
|
5212
|
-
<dialog class="${e$2(classes)}" part="bibContainer" role="${o$2(this.dialogRole)}" aria-labelledby="${o$2(this.dialogLabel ? 'dialogLabel' : undefined)}">
|
|
5032
|
+
<dialog tabindex="-1" class="${e$2(classes)}" part="bibContainer" role="${o$2(this.dialogRole)}" aria-labelledby="${o$2(this.dialogLabel ? 'dialogLabel' : undefined)}">
|
|
5213
5033
|
${this.dialogLabel ? u$5`<span id="dialogLabel" class="util_displayHiddenVisually">${this.dialogLabel}</span>` : ''}
|
|
5214
5034
|
<slot></slot>
|
|
5215
5035
|
<span id="srAnnouncement" class="util_displayHiddenVisually" aria-live="polite" role="status"></span>
|
|
@@ -5460,7 +5280,7 @@ class AuroHelpText extends i$2 {
|
|
|
5460
5280
|
}
|
|
5461
5281
|
}
|
|
5462
5282
|
|
|
5463
|
-
var formkitVersion = '
|
|
5283
|
+
var formkitVersion = '202607102138';
|
|
5464
5284
|
|
|
5465
5285
|
let AuroElement$1 = class AuroElement extends i$2 {
|
|
5466
5286
|
static get properties() {
|
|
@@ -6214,7 +6034,10 @@ class AuroDropdown extends AuroElement$1 {
|
|
|
6214
6034
|
}
|
|
6215
6035
|
|
|
6216
6036
|
|
|
6217
|
-
|
|
6037
|
+
// On Tab-driven close (eventType "focusloss"), let focus advance naturally
|
|
6038
|
+
// — restoring to the trigger would trap the user on this dropdown, forcing
|
|
6039
|
+
// an extra Tab to move on. Escape and outside-click still restore.
|
|
6040
|
+
if (!this.isPopoverVisible && eventType !== "focusloss") {
|
|
6218
6041
|
// wait til the bib gets fully closed and rendered
|
|
6219
6042
|
setTimeout(() => {
|
|
6220
6043
|
// Skip if the bib re-opened, or if focus moved intentionally outside the dropdown (not to body).
|
|
@@ -6444,15 +6267,16 @@ class AuroDropdown extends AuroElement$1 {
|
|
|
6444
6267
|
}
|
|
6445
6268
|
});
|
|
6446
6269
|
} else {
|
|
6447
|
-
// Normal desktop:
|
|
6448
|
-
//
|
|
6449
|
-
//
|
|
6450
|
-
//
|
|
6451
|
-
//
|
|
6452
|
-
|
|
6270
|
+
// Normal desktop (non-modal): move initial focus into the bib but
|
|
6271
|
+
// don't trap Tab. Tab should exit the bib and let the floater's
|
|
6272
|
+
// handleFocusLoss close it, matching native <select>/<details>
|
|
6273
|
+
// behavior. Deferred one frame because Floating UI positions the
|
|
6274
|
+
// popover asynchronously — a synchronous focus() would target
|
|
6275
|
+
// zero-dimension elements and be silently ignored.
|
|
6453
6276
|
requestAnimationFrame(() => {
|
|
6454
|
-
|
|
6455
|
-
|
|
6277
|
+
const focusables = getFocusableElements(this.bibContent);
|
|
6278
|
+
if (focusables.length) {
|
|
6279
|
+
focusables[0].focus();
|
|
6456
6280
|
}
|
|
6457
6281
|
});
|
|
6458
6282
|
}
|
|
@@ -8050,6 +7874,19 @@ class AuroCounterGroup extends AuroElement {
|
|
|
8050
7874
|
|
|
8051
7875
|
if (this.isDropdown) {
|
|
8052
7876
|
applyKeyboardStrategy$1(this, counterGroupKeyboardStrategy);
|
|
7877
|
+
|
|
7878
|
+
// noHideOnThisFocusLoss=true on the dropdown prevents handleFocusLoss from
|
|
7879
|
+
// closing the bib when focus moves out via Tab. Close explicitly via focusout:
|
|
7880
|
+
// if relatedTarget is outside the counter-group's light DOM, focus has left.
|
|
7881
|
+
this.addEventListener('focusout', (event) => {
|
|
7882
|
+
if (!this.dropdown?.isPopoverVisible || this.dropdown?.isBibFullscreen) {
|
|
7883
|
+
return;
|
|
7884
|
+
}
|
|
7885
|
+
if (event.relatedTarget && this.contains(event.relatedTarget)) {
|
|
7886
|
+
return;
|
|
7887
|
+
}
|
|
7888
|
+
this.hideBib();
|
|
7889
|
+
});
|
|
8053
7890
|
}
|
|
8054
7891
|
}
|
|
8055
7892
|
|