@aurodesignsystem-dev/auro-formkit 0.0.0-pr1600.3 → 0.0.0-pr1602.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.
- 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 +110 -4
- package/components/combobox/demo/getting-started.md +49 -0
- package/components/combobox/demo/getting-started.min.js +129 -4
- package/components/combobox/demo/index.min.js +110 -4
- package/components/combobox/dist/auro-combobox.d.ts +22 -0
- package/components/combobox/dist/index.js +94 -4
- package/components/combobox/dist/registered.js +94 -4
- package/components/counter/demo/api.md +2 -0
- package/components/counter/demo/customize.min.js +320 -22
- package/components/counter/demo/getting-started.html +3 -1
- package/components/counter/demo/getting-started.md +49 -0
- package/components/counter/demo/getting-started.min.js +8766 -0
- package/components/counter/demo/index.min.js +320 -22
- package/components/counter/dist/auro-counter-group.d.ts +6 -0
- package/components/counter/dist/auro-counter.d.ts +6 -0
- package/components/counter/dist/counterGroupKeyboardStrategy.d.ts +1 -0
- package/components/counter/dist/index.js +320 -22
- package/components/counter/dist/registered.js +320 -22
- package/components/datepicker/demo/customize.min.js +3 -3
- package/components/datepicker/demo/getting-started.html +3 -1
- package/components/datepicker/demo/getting-started.md +39 -0
- package/components/datepicker/demo/getting-started.min.js +37626 -0
- package/components/datepicker/demo/index.min.js +3 -3
- package/components/datepicker/dist/index.js +3 -3
- package/components/datepicker/dist/registered.js +3 -3
- package/components/dropdown/demo/customize.min.js +1 -1
- package/components/dropdown/demo/getting-started.min.js +2 -2
- package/components/dropdown/demo/index.min.js +1 -1
- package/components/dropdown/dist/index.js +1 -1
- package/components/dropdown/dist/registered.js +1 -1
- package/components/form/demo/customize.min.js +444 -35
- package/components/form/demo/getting-started.min.js +444 -35
- package/components/form/demo/index.min.js +444 -35
- package/components/form/demo/registerDemoDeps.min.js +438 -34
- package/components/form/dist/index.js +6 -1
- package/components/form/dist/registered.js +6 -1
- package/components/input/demo/customize.md +0 -37
- package/components/input/demo/customize.min.js +1 -10
- package/components/input/demo/getting-started.md +33 -0
- package/components/input/demo/getting-started.min.js +21 -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/menu/demo/index.min.js +16 -0
- package/components/menu/dist/index.js +16 -0
- package/components/menu/dist/registered.js +16 -0
- 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 +18 -2
- package/components/select/demo/getting-started.md +49 -0
- package/components/select/demo/getting-started.min.js +40 -3
- package/components/select/demo/index.min.js +18 -2
- package/components/select/dist/index.js +2 -2
- package/components/select/dist/registered.js +2 -2
- package/custom-elements.json +606 -566
- package/package.json +1 -1
|
@@ -1127,7 +1127,7 @@ let AuroHelpText$1 = class AuroHelpText extends i$2 {
|
|
|
1127
1127
|
}
|
|
1128
1128
|
};
|
|
1129
1129
|
|
|
1130
|
-
var formkitVersion$1 = '
|
|
1130
|
+
var formkitVersion$1 = '202609021726';
|
|
1131
1131
|
|
|
1132
1132
|
// Copyright (c) 2026 Alaska Airlines. All rights reserved. Licensed under the Apache-2.0 license
|
|
1133
1133
|
// See LICENSE in the project root for license information.
|
|
@@ -1485,6 +1485,17 @@ class AuroCounter extends i$2 {
|
|
|
1485
1485
|
this.validation.validate(this, force);
|
|
1486
1486
|
}
|
|
1487
1487
|
|
|
1488
|
+
/**
|
|
1489
|
+
* Resets the counter to its default state, clearing validity/touched state and returning
|
|
1490
|
+
* the value to `min` — matching the clear-on-reset behavior of the other Auro form elements.
|
|
1491
|
+
* @returns {void}
|
|
1492
|
+
*/
|
|
1493
|
+
reset() {
|
|
1494
|
+
// validation.reset() clears validity/touched and sets value to undefined; initValue() then restores the min floor.
|
|
1495
|
+
this.validation.reset(this);
|
|
1496
|
+
this.initValue();
|
|
1497
|
+
}
|
|
1498
|
+
|
|
1488
1499
|
firstUpdated() {
|
|
1489
1500
|
this.initValue();
|
|
1490
1501
|
this.setTagAttribute("auro-counter");
|
|
@@ -4473,7 +4484,7 @@ class AuroFloatingUI {
|
|
|
4473
4484
|
}
|
|
4474
4485
|
|
|
4475
4486
|
// Selectors for focusable elements
|
|
4476
|
-
const FOCUSABLE_SELECTORS = [
|
|
4487
|
+
const FOCUSABLE_SELECTORS$1 = [
|
|
4477
4488
|
"a[href]",
|
|
4478
4489
|
"button:not([disabled])",
|
|
4479
4490
|
"textarea:not([disabled])",
|
|
@@ -4487,7 +4498,7 @@ const FOCUSABLE_SELECTORS = [
|
|
|
4487
4498
|
];
|
|
4488
4499
|
|
|
4489
4500
|
// List of custom components that are known to be focusable
|
|
4490
|
-
const FOCUSABLE_COMPONENTS = [
|
|
4501
|
+
const FOCUSABLE_COMPONENTS$1 = [
|
|
4491
4502
|
"auro-checkbox",
|
|
4492
4503
|
"auro-radio",
|
|
4493
4504
|
"auro-dropdown",
|
|
@@ -4509,12 +4520,12 @@ const FOCUSABLE_COMPONENTS = [
|
|
|
4509
4520
|
* @param {HTMLElement} element The element to check for focusability.
|
|
4510
4521
|
* @returns {boolean} True if the element is a focusable custom component, false otherwise.
|
|
4511
4522
|
*/
|
|
4512
|
-
function isFocusableComponent(element) {
|
|
4523
|
+
function isFocusableComponent$1(element) {
|
|
4513
4524
|
const componentName = element.tagName.toLowerCase();
|
|
4514
4525
|
|
|
4515
4526
|
// Guard Clause: Element is a focusable component
|
|
4516
4527
|
if (
|
|
4517
|
-
!FOCUSABLE_COMPONENTS.some(
|
|
4528
|
+
!FOCUSABLE_COMPONENTS$1.some(
|
|
4518
4529
|
(name) => element.hasAttribute(name) || componentName === name,
|
|
4519
4530
|
)
|
|
4520
4531
|
)
|
|
@@ -4538,7 +4549,7 @@ function isFocusableComponent(element) {
|
|
|
4538
4549
|
* @param {HTMLElement} element The element whose tabindex to read.
|
|
4539
4550
|
* @returns {?number} The numeric tabindex or null if missing/invalid.
|
|
4540
4551
|
*/
|
|
4541
|
-
function getNumericTabIndex(element) {
|
|
4552
|
+
function getNumericTabIndex$1(element) {
|
|
4542
4553
|
const raw = element.getAttribute("tabindex");
|
|
4543
4554
|
if (raw == null) return null;
|
|
4544
4555
|
|
|
@@ -4554,7 +4565,7 @@ function getNumericTabIndex(element) {
|
|
|
4554
4565
|
* @param {HTMLElement} container The container to search within
|
|
4555
4566
|
* @returns {Array<HTMLElement>} An array of focusable elements within the container.
|
|
4556
4567
|
*/
|
|
4557
|
-
function getFocusableElements(container) {
|
|
4568
|
+
function getFocusableElements$1(container) {
|
|
4558
4569
|
// Get elements in DOM order by walking the tree
|
|
4559
4570
|
const orderedFocusableElements = [];
|
|
4560
4571
|
|
|
@@ -4563,7 +4574,7 @@ function getFocusableElements(container) {
|
|
|
4563
4574
|
// Check if current element is focusable
|
|
4564
4575
|
if (root.nodeType === Node.ELEMENT_NODE) {
|
|
4565
4576
|
// Check if this is a custom component that is focusable
|
|
4566
|
-
const isComponentFocusable = isFocusableComponent(root);
|
|
4577
|
+
const isComponentFocusable = isFocusableComponent$1(root);
|
|
4567
4578
|
|
|
4568
4579
|
if (isComponentFocusable) {
|
|
4569
4580
|
// Add the component itself as a focusable element and don't traverse its shadow DOM
|
|
@@ -4572,7 +4583,7 @@ function getFocusableElements(container) {
|
|
|
4572
4583
|
}
|
|
4573
4584
|
|
|
4574
4585
|
// Check if the element itself matches any selector
|
|
4575
|
-
for (const selector of FOCUSABLE_SELECTORS) {
|
|
4586
|
+
for (const selector of FOCUSABLE_SELECTORS$1) {
|
|
4576
4587
|
if (root.matches?.(selector)) {
|
|
4577
4588
|
orderedFocusableElements.push(root);
|
|
4578
4589
|
break; // Once we know it's focusable, no need to check other selectors
|
|
@@ -4626,20 +4637,20 @@ function getFocusableElements(container) {
|
|
|
4626
4637
|
|
|
4627
4638
|
// First extract elements with valid positive tabindex
|
|
4628
4639
|
const elementsWithTabindex = uniqueElements.filter((el) => {
|
|
4629
|
-
const tabindex = getNumericTabIndex(el);
|
|
4640
|
+
const tabindex = getNumericTabIndex$1(el);
|
|
4630
4641
|
return tabindex !== null && tabindex > 0;
|
|
4631
4642
|
});
|
|
4632
4643
|
|
|
4633
4644
|
// Sort these elements by their tabindex value
|
|
4634
4645
|
elementsWithTabindex.sort((a, b) => {
|
|
4635
|
-
const aIndex = getNumericTabIndex(a) ?? 0;
|
|
4636
|
-
const bIndex = getNumericTabIndex(b) ?? 0;
|
|
4646
|
+
const aIndex = getNumericTabIndex$1(a) ?? 0;
|
|
4647
|
+
const bIndex = getNumericTabIndex$1(b) ?? 0;
|
|
4637
4648
|
return aIndex - bIndex;
|
|
4638
4649
|
});
|
|
4639
4650
|
|
|
4640
4651
|
// Elements without tabindex (preserving their original order)
|
|
4641
4652
|
const elementsWithoutTabindex = uniqueElements.filter((el) => {
|
|
4642
|
-
const tabindex = getNumericTabIndex(el);
|
|
4653
|
+
const tabindex = getNumericTabIndex$1(el);
|
|
4643
4654
|
|
|
4644
4655
|
// Elements without tabindex or with tabindex of 0 stay in DOM order
|
|
4645
4656
|
return tabindex === null || tabindex === 0;
|
|
@@ -5434,7 +5445,7 @@ class AuroHelpText extends i$2 {
|
|
|
5434
5445
|
}
|
|
5435
5446
|
}
|
|
5436
5447
|
|
|
5437
|
-
var formkitVersion = '
|
|
5448
|
+
var formkitVersion = '202609021726';
|
|
5438
5449
|
|
|
5439
5450
|
/**
|
|
5440
5451
|
* AuroElement is the shared base class for layout-aware Auro form components.
|
|
@@ -5734,7 +5745,7 @@ class AuroDropdown extends AuroElement$1 {
|
|
|
5734
5745
|
*/
|
|
5735
5746
|
focus() {
|
|
5736
5747
|
if (this.isPopoverVisible && this.bibContent) {
|
|
5737
|
-
const focusables = getFocusableElements(this.bibContent);
|
|
5748
|
+
const focusables = getFocusableElements$1(this.bibContent);
|
|
5738
5749
|
if (focusables.length > 0) {
|
|
5739
5750
|
focusables[0].focus();
|
|
5740
5751
|
}
|
|
@@ -5766,7 +5777,7 @@ class AuroDropdown extends AuroElement$1 {
|
|
|
5766
5777
|
// wrappers like <div> containing a <button>). If none found, try
|
|
5767
5778
|
// focusing the element directly (works for custom elements like
|
|
5768
5779
|
// auro-input that have delegatesFocus or a custom focus() method).
|
|
5769
|
-
const descendants = getFocusableElements(el);
|
|
5780
|
+
const descendants = getFocusableElements$1(el);
|
|
5770
5781
|
if (descendants.length > 0) {
|
|
5771
5782
|
descendants[0].focus();
|
|
5772
5783
|
return;
|
|
@@ -5778,7 +5789,7 @@ class AuroDropdown extends AuroElement$1 {
|
|
|
5778
5789
|
}
|
|
5779
5790
|
}
|
|
5780
5791
|
// Fallback: try DOM children (non-slotted content)
|
|
5781
|
-
const focusables = getFocusableElements(this.trigger);
|
|
5792
|
+
const focusables = getFocusableElements$1(this.trigger);
|
|
5782
5793
|
if (focusables.length > 0) {
|
|
5783
5794
|
focusables[0].focus();
|
|
5784
5795
|
}
|
|
@@ -6457,7 +6468,7 @@ class AuroDropdown extends AuroElement$1 {
|
|
|
6457
6468
|
}
|
|
6458
6469
|
|
|
6459
6470
|
// Collect focusable elements from the bib content.
|
|
6460
|
-
const focusables = getFocusableElements(this.bibContent);
|
|
6471
|
+
const focusables = getFocusableElements$1(this.bibContent);
|
|
6461
6472
|
|
|
6462
6473
|
// Fallback: try from slotted content directly
|
|
6463
6474
|
if (!focusables.length) {
|
|
@@ -6466,7 +6477,7 @@ class AuroDropdown extends AuroElement$1 {
|
|
|
6466
6477
|
|
|
6467
6478
|
for (const node of assignedNodes) {
|
|
6468
6479
|
if (node.nodeType === Node.ELEMENT_NODE) {
|
|
6469
|
-
focusables.push(...getFocusableElements(node));
|
|
6480
|
+
focusables.push(...getFocusableElements$1(node));
|
|
6470
6481
|
}
|
|
6471
6482
|
}
|
|
6472
6483
|
}
|
|
@@ -6526,7 +6537,7 @@ class AuroDropdown extends AuroElement$1 {
|
|
|
6526
6537
|
|
|
6527
6538
|
// Move initial focus into the bib content, matching FocusTrap behavior
|
|
6528
6539
|
requestAnimationFrame(() => {
|
|
6529
|
-
const focusables = getFocusableElements(this.bibContent);
|
|
6540
|
+
const focusables = getFocusableElements$1(this.bibContent);
|
|
6530
6541
|
if (focusables.length) {
|
|
6531
6542
|
focusables[0].focus();
|
|
6532
6543
|
}
|
|
@@ -6539,7 +6550,7 @@ class AuroDropdown extends AuroElement$1 {
|
|
|
6539
6550
|
// popover asynchronously — a synchronous focus() would target
|
|
6540
6551
|
// zero-dimension elements and be silently ignored.
|
|
6541
6552
|
requestAnimationFrame(() => {
|
|
6542
|
-
const focusables = getFocusableElements(this.bibContent);
|
|
6553
|
+
const focusables = getFocusableElements$1(this.bibContent);
|
|
6543
6554
|
if (focusables.length) {
|
|
6544
6555
|
focusables[0].focus();
|
|
6545
6556
|
}
|
|
@@ -6757,7 +6768,7 @@ class AuroDropdown extends AuroElement$1 {
|
|
|
6757
6768
|
if (triggerContentNodes) {
|
|
6758
6769
|
|
|
6759
6770
|
// See if any of them are focusable elements
|
|
6760
|
-
this.triggerContentFocusable = triggerContentNodes.some((node) => getFocusableElements(node).length > 0);
|
|
6771
|
+
this.triggerContentFocusable = triggerContentNodes.some((node) => getFocusableElements$1(node).length > 0);
|
|
6761
6772
|
|
|
6762
6773
|
// If any of them are focusable elements
|
|
6763
6774
|
if (this.triggerContentFocusable) {
|
|
@@ -7519,9 +7530,241 @@ class AuroElement extends i$2 {
|
|
|
7519
7530
|
}
|
|
7520
7531
|
}
|
|
7521
7532
|
|
|
7533
|
+
// Selectors for focusable elements
|
|
7534
|
+
const FOCUSABLE_SELECTORS = [
|
|
7535
|
+
"a[href]",
|
|
7536
|
+
"button:not([disabled])",
|
|
7537
|
+
"textarea:not([disabled])",
|
|
7538
|
+
"input:not([disabled])",
|
|
7539
|
+
"select:not([disabled])",
|
|
7540
|
+
'[role="tab"]:not([disabled])',
|
|
7541
|
+
'[role="link"]:not([disabled])',
|
|
7542
|
+
'[role="button"]:not([disabled])',
|
|
7543
|
+
'[tabindex]:not([tabindex="-1"])',
|
|
7544
|
+
'[contenteditable]:not([contenteditable="false"])',
|
|
7545
|
+
];
|
|
7546
|
+
|
|
7547
|
+
// List of custom components that are known to be focusable
|
|
7548
|
+
const FOCUSABLE_COMPONENTS = [
|
|
7549
|
+
"auro-checkbox",
|
|
7550
|
+
"auro-radio",
|
|
7551
|
+
"auro-dropdown",
|
|
7552
|
+
"auro-button",
|
|
7553
|
+
"auro-combobox",
|
|
7554
|
+
"auro-input",
|
|
7555
|
+
"auro-counter",
|
|
7556
|
+
// 'auro-menu', // Auro menu is not focusable by default, it uses a different interaction model
|
|
7557
|
+
"auro-select",
|
|
7558
|
+
"auro-datepicker",
|
|
7559
|
+
"auro-hyperlink",
|
|
7560
|
+
"auro-accordion",
|
|
7561
|
+
];
|
|
7562
|
+
|
|
7563
|
+
/**
|
|
7564
|
+
* Determines if a given element is a custom focusable component.
|
|
7565
|
+
* Returns true if the element matches a known focusable component and is not disabled.
|
|
7566
|
+
*
|
|
7567
|
+
* @param {HTMLElement} element The element to check for focusability.
|
|
7568
|
+
* @returns {boolean} True if the element is a focusable custom component, false otherwise.
|
|
7569
|
+
*/
|
|
7570
|
+
function isFocusableComponent(element) {
|
|
7571
|
+
const componentName = element.tagName.toLowerCase();
|
|
7572
|
+
|
|
7573
|
+
// Guard Clause: Element is a focusable component
|
|
7574
|
+
if (
|
|
7575
|
+
!FOCUSABLE_COMPONENTS.some(
|
|
7576
|
+
(name) => element.hasAttribute(name) || componentName === name,
|
|
7577
|
+
)
|
|
7578
|
+
)
|
|
7579
|
+
return false;
|
|
7580
|
+
|
|
7581
|
+
// Guard Clause: Element is not disabled
|
|
7582
|
+
if (element.hasAttribute("disabled")) return false;
|
|
7583
|
+
|
|
7584
|
+
// Guard Clause: The element is a hyperlink and has no href attribute
|
|
7585
|
+
if (componentName.match("hyperlink") && !element.hasAttribute("href"))
|
|
7586
|
+
return false;
|
|
7587
|
+
|
|
7588
|
+
// If all guard clauses pass, the element is a focusable component
|
|
7589
|
+
return true;
|
|
7590
|
+
}
|
|
7591
|
+
|
|
7592
|
+
/**
|
|
7593
|
+
* Safely get a numeric tabindex for an element.
|
|
7594
|
+
* Returns a number if the tabindex is a valid integer, otherwise null.
|
|
7595
|
+
*
|
|
7596
|
+
* @param {HTMLElement} element The element whose tabindex to read.
|
|
7597
|
+
* @returns {?number} The numeric tabindex or null if missing/invalid.
|
|
7598
|
+
*/
|
|
7599
|
+
function getNumericTabIndex(element) {
|
|
7600
|
+
const raw = element.getAttribute("tabindex");
|
|
7601
|
+
if (raw == null) return null;
|
|
7602
|
+
|
|
7603
|
+
const value = Number.parseInt(raw, 10);
|
|
7604
|
+
return Number.isNaN(value) ? null : value;
|
|
7605
|
+
}
|
|
7606
|
+
|
|
7607
|
+
/**
|
|
7608
|
+
* Retrieves all focusable elements within the container in DOM order, including those in shadow DOM and slots.
|
|
7609
|
+
* Returns a unique, ordered array of elements that can receive focus.
|
|
7610
|
+
* Also sorts elements with tabindex first, preserving their order.
|
|
7611
|
+
*
|
|
7612
|
+
* @param {HTMLElement} container The container to search within
|
|
7613
|
+
* @returns {Array<HTMLElement>} An array of focusable elements within the container.
|
|
7614
|
+
*/
|
|
7615
|
+
function getFocusableElements(container) {
|
|
7616
|
+
// Get elements in DOM order by walking the tree
|
|
7617
|
+
const orderedFocusableElements = [];
|
|
7618
|
+
|
|
7619
|
+
// Define a recursive function to collect focusable elements in DOM order
|
|
7620
|
+
const collectFocusableElements = (root) => {
|
|
7621
|
+
// Check if current element is focusable
|
|
7622
|
+
if (root.nodeType === Node.ELEMENT_NODE) {
|
|
7623
|
+
// Check if this is a custom component that is focusable
|
|
7624
|
+
const isComponentFocusable = isFocusableComponent(root);
|
|
7625
|
+
|
|
7626
|
+
if (isComponentFocusable) {
|
|
7627
|
+
// Add the component itself as a focusable element and don't traverse its shadow DOM
|
|
7628
|
+
orderedFocusableElements.push(root);
|
|
7629
|
+
return; // Skip traversing inside this component
|
|
7630
|
+
}
|
|
7631
|
+
|
|
7632
|
+
// Check if the element itself matches any selector
|
|
7633
|
+
for (const selector of FOCUSABLE_SELECTORS) {
|
|
7634
|
+
if (root.matches?.(selector)) {
|
|
7635
|
+
orderedFocusableElements.push(root);
|
|
7636
|
+
break; // Once we know it's focusable, no need to check other selectors
|
|
7637
|
+
}
|
|
7638
|
+
}
|
|
7639
|
+
|
|
7640
|
+
// Process shadow DOM only for non-Auro components
|
|
7641
|
+
if (root.shadowRoot) {
|
|
7642
|
+
// Process shadow DOM children in order
|
|
7643
|
+
if (root.shadowRoot.children) {
|
|
7644
|
+
Array.from(root.shadowRoot.children).forEach((child) => {
|
|
7645
|
+
collectFocusableElements(child);
|
|
7646
|
+
});
|
|
7647
|
+
}
|
|
7648
|
+
}
|
|
7649
|
+
|
|
7650
|
+
// Process slots and their assigned nodes in order
|
|
7651
|
+
if (root.tagName === "SLOT") {
|
|
7652
|
+
const assignedNodes = root.assignedNodes({ flatten: true });
|
|
7653
|
+
for (const node of assignedNodes) {
|
|
7654
|
+
collectFocusableElements(node);
|
|
7655
|
+
}
|
|
7656
|
+
} else {
|
|
7657
|
+
// Process light DOM children in order
|
|
7658
|
+
if (root.children) {
|
|
7659
|
+
Array.from(root.children).forEach((child) => {
|
|
7660
|
+
collectFocusableElements(child);
|
|
7661
|
+
});
|
|
7662
|
+
}
|
|
7663
|
+
}
|
|
7664
|
+
}
|
|
7665
|
+
};
|
|
7666
|
+
|
|
7667
|
+
// Start the traversal from the container
|
|
7668
|
+
collectFocusableElements(container);
|
|
7669
|
+
|
|
7670
|
+
// Remove duplicates that might have been collected through different paths
|
|
7671
|
+
// while preserving order
|
|
7672
|
+
const uniqueElements = [];
|
|
7673
|
+
const seen = new Set();
|
|
7674
|
+
|
|
7675
|
+
for (const element of orderedFocusableElements) {
|
|
7676
|
+
if (!seen.has(element)) {
|
|
7677
|
+
seen.add(element);
|
|
7678
|
+
uniqueElements.push(element);
|
|
7679
|
+
}
|
|
7680
|
+
}
|
|
7681
|
+
|
|
7682
|
+
// Move tab-indexed elements to the front while preserving their order
|
|
7683
|
+
// This ensures that elements with tabindex are prioritized in the focus order
|
|
7684
|
+
|
|
7685
|
+
// First extract elements with valid positive tabindex
|
|
7686
|
+
const elementsWithTabindex = uniqueElements.filter((el) => {
|
|
7687
|
+
const tabindex = getNumericTabIndex(el);
|
|
7688
|
+
return tabindex !== null && tabindex > 0;
|
|
7689
|
+
});
|
|
7690
|
+
|
|
7691
|
+
// Sort these elements by their tabindex value
|
|
7692
|
+
elementsWithTabindex.sort((a, b) => {
|
|
7693
|
+
const aIndex = getNumericTabIndex(a) ?? 0;
|
|
7694
|
+
const bIndex = getNumericTabIndex(b) ?? 0;
|
|
7695
|
+
return aIndex - bIndex;
|
|
7696
|
+
});
|
|
7697
|
+
|
|
7698
|
+
// Elements without tabindex (preserving their original order)
|
|
7699
|
+
const elementsWithoutTabindex = uniqueElements.filter((el) => {
|
|
7700
|
+
const tabindex = getNumericTabIndex(el);
|
|
7701
|
+
|
|
7702
|
+
// Elements without tabindex or with tabindex of 0 stay in DOM order
|
|
7703
|
+
return tabindex === null || tabindex === 0;
|
|
7704
|
+
});
|
|
7705
|
+
|
|
7706
|
+
// Combine both arrays with tabindex elements first
|
|
7707
|
+
const tabIndexedUniqueElements = [
|
|
7708
|
+
...elementsWithTabindex,
|
|
7709
|
+
...elementsWithoutTabindex,
|
|
7710
|
+
];
|
|
7711
|
+
|
|
7712
|
+
return tabIndexedUniqueElements;
|
|
7713
|
+
}
|
|
7714
|
+
|
|
7522
7715
|
// Copyright (c) 2026 Alaska Airlines. All rights reserved. Licensed under the Apache-2.0 license
|
|
7523
7716
|
// See LICENSE in the project root for license information.
|
|
7524
7717
|
|
|
7718
|
+
|
|
7719
|
+
/**
|
|
7720
|
+
* Whether `el` is currently visible enough to receive focus. Prefers the
|
|
7721
|
+
* browser's `checkVisibility()`; otherwise combines a display/visibility check
|
|
7722
|
+
* with an ancestor-hidden probe that keeps position:fixed elements visible.
|
|
7723
|
+
* @param {Element} el - The element to test.
|
|
7724
|
+
* @returns {boolean}
|
|
7725
|
+
*/
|
|
7726
|
+
function isVisibleForFocus(el) {
|
|
7727
|
+
if (typeof el.checkVisibility === 'function') {
|
|
7728
|
+
return el.checkVisibility();
|
|
7729
|
+
}
|
|
7730
|
+
const style = el.ownerDocument.defaultView.getComputedStyle(el);
|
|
7731
|
+
if (style.display === 'none' || style.visibility === 'hidden') {
|
|
7732
|
+
return false;
|
|
7733
|
+
}
|
|
7734
|
+
return el.offsetParent !== null || style.position === 'fixed';
|
|
7735
|
+
}
|
|
7736
|
+
|
|
7737
|
+
/**
|
|
7738
|
+
* Return the tab stop that comes before the counter-group in page tab order,
|
|
7739
|
+
* skipping any hidden entries the walker doesn't filter itself. The group host
|
|
7740
|
+
* itself is not a tab stop; its focusables (the internal dropdown and the
|
|
7741
|
+
* counters) are, so anchor the search on the group's earliest focusable.
|
|
7742
|
+
* @param {Element} component - The auro-counter-group host element.
|
|
7743
|
+
* @returns {Element|null}
|
|
7744
|
+
*/
|
|
7745
|
+
function getPreviousTabStop(component) {
|
|
7746
|
+
const tabStops = getFocusableElements(component.ownerDocument.body);
|
|
7747
|
+
const counters = component.counters || [];
|
|
7748
|
+
const owned = [
|
|
7749
|
+
component,
|
|
7750
|
+
component.dropdown,
|
|
7751
|
+
...counters
|
|
7752
|
+
].filter(Boolean);
|
|
7753
|
+
let groupStart = tabStops.length;
|
|
7754
|
+
owned.forEach((node) => {
|
|
7755
|
+
const index = tabStops.indexOf(node);
|
|
7756
|
+
if (index >= 0 && index < groupStart) {
|
|
7757
|
+
groupStart = index;
|
|
7758
|
+
}
|
|
7759
|
+
});
|
|
7760
|
+
for (let index = groupStart - 1; index >= 0; index -= 1) {
|
|
7761
|
+
if (isVisibleForFocus(tabStops[index])) {
|
|
7762
|
+
return tabStops[index];
|
|
7763
|
+
}
|
|
7764
|
+
}
|
|
7765
|
+
return null;
|
|
7766
|
+
}
|
|
7767
|
+
|
|
7525
7768
|
const counterGroupKeyboardStrategy = {
|
|
7526
7769
|
Escape(component, evt) {
|
|
7527
7770
|
if (!component.dropdown || !component.dropdown.isPopoverVisible) {
|
|
@@ -7535,6 +7778,48 @@ const counterGroupKeyboardStrategy = {
|
|
|
7535
7778
|
|
|
7536
7779
|
component.dropdown.hide();
|
|
7537
7780
|
},
|
|
7781
|
+
|
|
7782
|
+
Tab(component, evt, ctx) {
|
|
7783
|
+
// Forward Tab already exits past the bib content and the focusout handler
|
|
7784
|
+
// closes the bib. Fullscreen relies on the dialog's native focus trapping.
|
|
7785
|
+
if (!ctx.isExpanded || ctx.isModal || !evt.shiftKey) {
|
|
7786
|
+
return;
|
|
7787
|
+
}
|
|
7788
|
+
|
|
7789
|
+
// The trigger precedes the bib content in the flattened tab order, so a
|
|
7790
|
+
// native Shift+Tab off the first counter lands back on the trigger and
|
|
7791
|
+
// leaves the bib open. Only intercept when focus is on the first focusable
|
|
7792
|
+
// in the bib; otherwise let the browser move to the previous counter.
|
|
7793
|
+
// `composedPath()` reports the real event origin through every shadow
|
|
7794
|
+
// boundary, unlike `document.activeElement`, which retargets to the first
|
|
7795
|
+
// slotted counter and cannot tell the counters apart.
|
|
7796
|
+
const focusables = getFocusableElements(component.dropdown.bibContent);
|
|
7797
|
+
if (!focusables.length) {
|
|
7798
|
+
return;
|
|
7799
|
+
}
|
|
7800
|
+
|
|
7801
|
+
const path = evt.composedPath();
|
|
7802
|
+
const activeIndex = focusables.findIndex((el) => path.includes(el));
|
|
7803
|
+
if (activeIndex !== 0) {
|
|
7804
|
+
return;
|
|
7805
|
+
}
|
|
7806
|
+
|
|
7807
|
+
const previousTabStop = getPreviousTabStop(component);
|
|
7808
|
+
|
|
7809
|
+
// Always suppress the native Shift+Tab. Otherwise it fires against the bib
|
|
7810
|
+
// as it is torn down and lands focus on the trigger (which precedes the
|
|
7811
|
+
// first counter), re-opening the exact loop this handler prevents. When
|
|
7812
|
+
// nothing precedes the group, focus falls to the body instead of the
|
|
7813
|
+
// trigger, which reads as exiting the group backward.
|
|
7814
|
+
evt.preventDefault();
|
|
7815
|
+
component.hideBib();
|
|
7816
|
+
|
|
7817
|
+
if (!previousTabStop) {
|
|
7818
|
+
return;
|
|
7819
|
+
}
|
|
7820
|
+
|
|
7821
|
+
doubleRaf(() => previousTabStop.focus());
|
|
7822
|
+
},
|
|
7538
7823
|
};
|
|
7539
7824
|
|
|
7540
7825
|
/* eslint-disable lit/no-invalid-html, lit/binding-positions, max-lines, no-underscore-dangle, arrow-parens, no-confusing-arrow, curly, dot-location, no-inline-comments, line-comment-position,
|
|
@@ -8162,6 +8447,19 @@ class AuroCounterGroup extends AuroElement {
|
|
|
8162
8447
|
this.validation.validate(this, force);
|
|
8163
8448
|
}
|
|
8164
8449
|
|
|
8450
|
+
/**
|
|
8451
|
+
* Resets the counter group to its initial state by resetting each child counter and clearing validity.
|
|
8452
|
+
* Each child reset dispatches an `input` event, which triggers `updateValue()` to recompute `value`/`total`.
|
|
8453
|
+
* @returns {void}
|
|
8454
|
+
*/
|
|
8455
|
+
reset() {
|
|
8456
|
+
if (this.counters) {
|
|
8457
|
+
this.counters.forEach((counter) => counter.reset());
|
|
8458
|
+
}
|
|
8459
|
+
|
|
8460
|
+
this.validation.reset(this);
|
|
8461
|
+
}
|
|
8462
|
+
|
|
8165
8463
|
updated(changedProperties) {
|
|
8166
8464
|
if (changedProperties.has("value")) {
|
|
8167
8465
|
this.validate();
|
|
@@ -346,6 +346,12 @@ export class AuroCounterGroup extends AuroElement {
|
|
|
346
346
|
* @param {boolean} [force=false] - Whether to force validation.
|
|
347
347
|
*/
|
|
348
348
|
validate(force?: boolean): void;
|
|
349
|
+
/**
|
|
350
|
+
* Resets the counter group to its initial state by resetting each child counter and clearing validity.
|
|
351
|
+
* Each child reset dispatches an `input` event, which triggers `updateValue()` to recompute `value`/`total`.
|
|
352
|
+
* @returns {void}
|
|
353
|
+
*/
|
|
354
|
+
reset(): void;
|
|
349
355
|
updated(changedProperties: any): void;
|
|
350
356
|
firstUpdated(): void;
|
|
351
357
|
/**
|
|
@@ -129,6 +129,12 @@ export class AuroCounter extends LitElement {
|
|
|
129
129
|
* @param {boolean} [force=false] - Whether to force validation.
|
|
130
130
|
*/
|
|
131
131
|
validate(force?: boolean): void;
|
|
132
|
+
/**
|
|
133
|
+
* Resets the counter to its default state, clearing validity/touched state and returning
|
|
134
|
+
* the value to `min` — matching the clear-on-reset behavior of the other Auro form elements.
|
|
135
|
+
* @returns {void}
|
|
136
|
+
*/
|
|
137
|
+
reset(): void;
|
|
132
138
|
firstUpdated(): void;
|
|
133
139
|
/**
|
|
134
140
|
* Sets an attribute that matches the default tag name if the tag name is not the default.
|