@jsenv/dom 0.12.1 → 0.12.3
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/dist/jsenv_dom.js +35 -4
- package/package.json +1 -1
package/dist/jsenv_dom.js
CHANGED
|
@@ -2240,6 +2240,7 @@ const cssSizeUnitSet = new Set([
|
|
|
2240
2240
|
"in",
|
|
2241
2241
|
"pt",
|
|
2242
2242
|
"pc",
|
|
2243
|
+
"cap",
|
|
2243
2244
|
]);
|
|
2244
2245
|
const cssUnitSet = new Set([
|
|
2245
2246
|
...cssSizeUnitSet,
|
|
@@ -5447,10 +5448,36 @@ const performTabNavigation = (
|
|
|
5447
5448
|
return elementIsFocusable(element, { excludeAriaHidden });
|
|
5448
5449
|
};
|
|
5449
5450
|
|
|
5450
|
-
|
|
5451
|
-
|
|
5452
|
-
|
|
5453
|
-
|
|
5451
|
+
// A focus group "owns" the activeElement when activeElement is inside it.
|
|
5452
|
+
// From the inside, Tab should exit the group (skip its remaining children).
|
|
5453
|
+
// From the outside, Tab should enter the group normally (first focusable child).
|
|
5454
|
+
const activeFocusGroup =
|
|
5455
|
+
activeElement.closest?.("[navi-focus-group]") || null;
|
|
5456
|
+
const isOwnedByActiveFocusGroup = (el) =>
|
|
5457
|
+
activeFocusGroup && activeFocusGroup.contains(el);
|
|
5458
|
+
|
|
5459
|
+
const predicate = (candidate, skip) => {
|
|
5460
|
+
if (!isFocusableByTab(candidate)) {
|
|
5461
|
+
return false;
|
|
5462
|
+
}
|
|
5463
|
+
// Focus group roots are composite widgets.
|
|
5464
|
+
if (candidate.hasAttribute("navi-focus-group")) {
|
|
5465
|
+
if (isFocusableByTab(candidate)) {
|
|
5466
|
+
// Root has tabindex="0": it is the single Tab stop for the group.
|
|
5467
|
+
// Skip its children — arrow keys handle internal navigation.
|
|
5468
|
+
skip?.();
|
|
5469
|
+
return true;
|
|
5470
|
+
}
|
|
5471
|
+
// Root is not focusable by Tab: descend into children to allow Tab entry.
|
|
5472
|
+
return false;
|
|
5473
|
+
}
|
|
5474
|
+
// If candidate is inside the focus group that currently owns focus, skip
|
|
5475
|
+
// it — Tab should exit the group. (Going *into* a different focus group
|
|
5476
|
+
// is allowed: only one focus group at a time has the activeElement.)
|
|
5477
|
+
if (isOwnedByActiveFocusGroup(candidate)) {
|
|
5478
|
+
return false;
|
|
5479
|
+
}
|
|
5480
|
+
return true;
|
|
5454
5481
|
};
|
|
5455
5482
|
|
|
5456
5483
|
const activeElementIsRoot = activeElement === rootElement;
|
|
@@ -5594,6 +5621,10 @@ const initFocusGroup = (
|
|
|
5594
5621
|
name, // Store undefined as-is for implicit grouping
|
|
5595
5622
|
});
|
|
5596
5623
|
cleanupCallbackSet.add(removeFocusGroup);
|
|
5624
|
+
element.setAttribute("navi-focus-group", "");
|
|
5625
|
+
cleanupCallbackSet.add(() => {
|
|
5626
|
+
element.removeAttribute("navi-focus-group");
|
|
5627
|
+
});
|
|
5597
5628
|
|
|
5598
5629
|
tab: {
|
|
5599
5630
|
if (!skipTab) {
|