@react-aria/focus 3.15.0 → 3.16.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/dist/import.mjs +44 -34
- package/dist/main.js +44 -34
- package/dist/main.js.map +1 -1
- package/dist/module.js +44 -34
- package/dist/module.js.map +1 -1
- package/dist/types.d.ts.map +1 -1
- package/package.json +5 -5
- package/src/FocusScope.tsx +40 -32
- package/src/focusSafely.ts +4 -3
- package/src/isElementVisible.ts +4 -1
- package/src/useFocusable.tsx +1 -1
package/dist/import.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
import {useLayoutEffect as $6nfFC$useLayoutEffect, getOwnerDocument as $6nfFC$getOwnerDocument, runAfterTransition as $6nfFC$runAfterTransition, focusWithoutScrolling as $6nfFC$focusWithoutScrolling, getOwnerWindow as $6nfFC$getOwnerWindow, mergeProps as $6nfFC$mergeProps, useSyncRef as $6nfFC$useSyncRef, useObjectRef as $6nfFC$useObjectRef} from "@react-aria/utils";
|
|
1
2
|
import $6nfFC$react, {useRef as $6nfFC$useRef, useContext as $6nfFC$useContext, useMemo as $6nfFC$useMemo, useEffect as $6nfFC$useEffect, useState as $6nfFC$useState, useCallback as $6nfFC$useCallback} from "react";
|
|
2
|
-
import {useLayoutEffect as $6nfFC$useLayoutEffect, runAfterTransition as $6nfFC$runAfterTransition, focusWithoutScrolling as $6nfFC$focusWithoutScrolling, mergeProps as $6nfFC$mergeProps, useSyncRef as $6nfFC$useSyncRef, useObjectRef as $6nfFC$useObjectRef} from "@react-aria/utils";
|
|
3
3
|
import {getInteractionModality as $6nfFC$getInteractionModality, isFocusVisible as $6nfFC$isFocusVisible, useFocusVisibleListener as $6nfFC$useFocusVisibleListener, useFocus as $6nfFC$useFocus, useFocusWithin as $6nfFC$useFocusWithin, useKeyboard as $6nfFC$useKeyboard} from "@react-aria/interactions";
|
|
4
4
|
import $6nfFC$clsx from "clsx";
|
|
5
5
|
|
|
@@ -41,16 +41,18 @@ function $6a99195332edec8b$export$80f3e147d781571c(element) {
|
|
|
41
41
|
// the page before shifting focus. This avoids issues with VoiceOver on iOS
|
|
42
42
|
// causing the page to scroll when moving focus if the element is transitioning
|
|
43
43
|
// from off the screen.
|
|
44
|
+
const ownerDocument = (0, $6nfFC$getOwnerDocument)(element);
|
|
44
45
|
if ((0, $6nfFC$getInteractionModality)() === "virtual") {
|
|
45
|
-
let lastFocusedElement =
|
|
46
|
+
let lastFocusedElement = ownerDocument.activeElement;
|
|
46
47
|
(0, $6nfFC$runAfterTransition)(()=>{
|
|
47
48
|
// If focus did not move and the element is still in the document, focus it.
|
|
48
|
-
if (
|
|
49
|
+
if (ownerDocument.activeElement === lastFocusedElement && element.isConnected) (0, $6nfFC$focusWithoutScrolling)(element);
|
|
49
50
|
});
|
|
50
51
|
} else (0, $6nfFC$focusWithoutScrolling)(element);
|
|
51
52
|
}
|
|
52
53
|
|
|
53
54
|
|
|
55
|
+
|
|
54
56
|
/*
|
|
55
57
|
* Copyright 2021 Adobe. All rights reserved.
|
|
56
58
|
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
@@ -61,8 +63,10 @@ function $6a99195332edec8b$export$80f3e147d781571c(element) {
|
|
|
61
63
|
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
|
|
62
64
|
* OF ANY KIND, either express or implied. See the License for the specific language
|
|
63
65
|
* governing permissions and limitations under the License.
|
|
64
|
-
*/
|
|
65
|
-
|
|
66
|
+
*/
|
|
67
|
+
function $645f2e67b85a24c9$var$isStyleVisible(element) {
|
|
68
|
+
const windowObject = (0, $6nfFC$getOwnerWindow)(element);
|
|
69
|
+
if (!(element instanceof windowObject.HTMLElement) && !(element instanceof windowObject.SVGElement)) return false;
|
|
66
70
|
let { display: display, visibility: visibility } = element.style;
|
|
67
71
|
let isVisible = display !== "none" && visibility !== "hidden" && visibility !== "collapse";
|
|
68
72
|
if (isVisible) {
|
|
@@ -81,7 +85,6 @@ function $645f2e67b85a24c9$export$e989c0fffaa6b27a(element, childElement) {
|
|
|
81
85
|
|
|
82
86
|
|
|
83
87
|
|
|
84
|
-
|
|
85
88
|
const $9bf71ea28793e738$var$FocusContext = /*#__PURE__*/ (0, $6nfFC$react).createContext(null);
|
|
86
89
|
let $9bf71ea28793e738$var$activeScope = null;
|
|
87
90
|
function $9bf71ea28793e738$export$20e40289641fbbb6(props) {
|
|
@@ -139,7 +142,7 @@ function $9bf71ea28793e738$export$20e40289641fbbb6(props) {
|
|
|
139
142
|
// This needs to be an effect so that activeScope is updated after the FocusScope tree is complete.
|
|
140
143
|
// It cannot be a useLayoutEffect because the parent of this node hasn't been attached in the tree yet.
|
|
141
144
|
(0, $6nfFC$useEffect)(()=>{
|
|
142
|
-
|
|
145
|
+
const activeElement = (0, $6nfFC$getOwnerDocument)(scopeRef.current ? scopeRef.current[0] : undefined).activeElement;
|
|
143
146
|
let scope = null;
|
|
144
147
|
if ($9bf71ea28793e738$var$isElementInScope(activeElement, scopeRef.current)) {
|
|
145
148
|
// We need to traverse the focusScope tree and find the bottom most scope that
|
|
@@ -193,7 +196,7 @@ function $9bf71ea28793e738$var$createFocusManagerForScope(scopeRef) {
|
|
|
193
196
|
focusNext (opts = {}) {
|
|
194
197
|
let scope = scopeRef.current;
|
|
195
198
|
let { from: from, tabbable: tabbable, wrap: wrap, accept: accept } = opts;
|
|
196
|
-
let node = from ||
|
|
199
|
+
let node = from || (0, $6nfFC$getOwnerDocument)(scope[0]).activeElement;
|
|
197
200
|
let sentinel = scope[0].previousElementSibling;
|
|
198
201
|
let scopeRoot = $9bf71ea28793e738$var$getScopeRoot(scope);
|
|
199
202
|
let walker = $9bf71ea28793e738$export$2d6ec8fc375ceafa(scopeRoot, {
|
|
@@ -212,7 +215,7 @@ function $9bf71ea28793e738$var$createFocusManagerForScope(scopeRef) {
|
|
|
212
215
|
focusPrevious (opts = {}) {
|
|
213
216
|
let scope = scopeRef.current;
|
|
214
217
|
let { from: from, tabbable: tabbable, wrap: wrap, accept: accept } = opts;
|
|
215
|
-
let node = from ||
|
|
218
|
+
let node = from || (0, $6nfFC$getOwnerDocument)(scope[0]).activeElement;
|
|
216
219
|
let sentinel = scope[scope.length - 1].nextElementSibling;
|
|
217
220
|
let scopeRoot = $9bf71ea28793e738$var$getScopeRoot(scope);
|
|
218
221
|
let walker = $9bf71ea28793e738$export$2d6ec8fc375ceafa(scopeRoot, {
|
|
@@ -298,10 +301,11 @@ function $9bf71ea28793e738$var$useFocusContainment(scopeRef, contain) {
|
|
|
298
301
|
}
|
|
299
302
|
return;
|
|
300
303
|
}
|
|
304
|
+
const ownerDocument = (0, $6nfFC$getOwnerDocument)(scope ? scope[0] : undefined);
|
|
301
305
|
// Handle the Tab key to contain focus within the scope
|
|
302
306
|
let onKeyDown = (e)=>{
|
|
303
307
|
if (e.key !== "Tab" || e.altKey || e.ctrlKey || e.metaKey || !$9bf71ea28793e738$var$shouldContainFocus(scopeRef)) return;
|
|
304
|
-
let focusedElement =
|
|
308
|
+
let focusedElement = ownerDocument.activeElement;
|
|
305
309
|
let scope = scopeRef.current;
|
|
306
310
|
if (!scope || !$9bf71ea28793e738$var$isElementInScope(focusedElement, scope)) return;
|
|
307
311
|
let scopeRoot = $9bf71ea28793e738$var$getScopeRoot(scope);
|
|
@@ -336,9 +340,9 @@ function $9bf71ea28793e738$var$useFocusContainment(scopeRef, contain) {
|
|
|
336
340
|
if (raf.current) cancelAnimationFrame(raf.current);
|
|
337
341
|
raf.current = requestAnimationFrame(()=>{
|
|
338
342
|
// Use document.activeElement instead of e.relatedTarget so we can tell if user clicked into iframe
|
|
339
|
-
if (
|
|
343
|
+
if (ownerDocument.activeElement && $9bf71ea28793e738$var$shouldContainFocus(scopeRef) && !$9bf71ea28793e738$var$isElementInChildScope(ownerDocument.activeElement, scopeRef)) {
|
|
340
344
|
$9bf71ea28793e738$var$activeScope = scopeRef;
|
|
341
|
-
if (
|
|
345
|
+
if (ownerDocument.body.contains(e.target)) {
|
|
342
346
|
var _focusedNode_current;
|
|
343
347
|
focusedNode.current = e.target;
|
|
344
348
|
(_focusedNode_current = focusedNode.current) === null || _focusedNode_current === void 0 ? void 0 : _focusedNode_current.focus();
|
|
@@ -346,13 +350,13 @@ function $9bf71ea28793e738$var$useFocusContainment(scopeRef, contain) {
|
|
|
346
350
|
}
|
|
347
351
|
});
|
|
348
352
|
};
|
|
349
|
-
|
|
350
|
-
|
|
353
|
+
ownerDocument.addEventListener("keydown", onKeyDown, false);
|
|
354
|
+
ownerDocument.addEventListener("focusin", onFocus, false);
|
|
351
355
|
scope === null || scope === void 0 ? void 0 : scope.forEach((element)=>element.addEventListener("focusin", onFocus, false));
|
|
352
356
|
scope === null || scope === void 0 ? void 0 : scope.forEach((element)=>element.addEventListener("focusout", onBlur, false));
|
|
353
357
|
return ()=>{
|
|
354
|
-
|
|
355
|
-
|
|
358
|
+
ownerDocument.removeEventListener("keydown", onKeyDown, false);
|
|
359
|
+
ownerDocument.removeEventListener("focusin", onFocus, false);
|
|
356
360
|
scope === null || scope === void 0 ? void 0 : scope.forEach((element)=>element.removeEventListener("focusin", onFocus, false));
|
|
357
361
|
scope === null || scope === void 0 ? void 0 : scope.forEach((element)=>element.removeEventListener("focusout", onBlur, false));
|
|
358
362
|
};
|
|
@@ -436,7 +440,8 @@ function $9bf71ea28793e738$var$useAutoFocus(scopeRef, autoFocus) {
|
|
|
436
440
|
(0, $6nfFC$useEffect)(()=>{
|
|
437
441
|
if (autoFocusRef.current) {
|
|
438
442
|
$9bf71ea28793e738$var$activeScope = scopeRef;
|
|
439
|
-
|
|
443
|
+
const ownerDocument = (0, $6nfFC$getOwnerDocument)(scopeRef.current ? scopeRef.current[0] : undefined);
|
|
444
|
+
if (!$9bf71ea28793e738$var$isElementInScope(ownerDocument.activeElement, $9bf71ea28793e738$var$activeScope.current) && scopeRef.current) $9bf71ea28793e738$var$focusFirstInScope(scopeRef.current);
|
|
440
445
|
}
|
|
441
446
|
autoFocusRef.current = false;
|
|
442
447
|
}, [
|
|
@@ -449,15 +454,16 @@ function $9bf71ea28793e738$var$useActiveScopeTracker(scopeRef, restore, contain)
|
|
|
449
454
|
(0, $6nfFC$useLayoutEffect)(()=>{
|
|
450
455
|
if (restore || contain) return;
|
|
451
456
|
let scope = scopeRef.current;
|
|
457
|
+
const ownerDocument = (0, $6nfFC$getOwnerDocument)(scope ? scope[0] : undefined);
|
|
452
458
|
let onFocus = (e)=>{
|
|
453
459
|
let target = e.target;
|
|
454
460
|
if ($9bf71ea28793e738$var$isElementInScope(target, scopeRef.current)) $9bf71ea28793e738$var$activeScope = scopeRef;
|
|
455
461
|
else if (!$9bf71ea28793e738$var$isElementInAnyScope(target)) $9bf71ea28793e738$var$activeScope = null;
|
|
456
462
|
};
|
|
457
|
-
|
|
463
|
+
ownerDocument.addEventListener("focusin", onFocus, false);
|
|
458
464
|
scope === null || scope === void 0 ? void 0 : scope.forEach((element)=>element.addEventListener("focusin", onFocus, false));
|
|
459
465
|
return ()=>{
|
|
460
|
-
|
|
466
|
+
ownerDocument.removeEventListener("focusin", onFocus, false);
|
|
461
467
|
scope === null || scope === void 0 ? void 0 : scope.forEach((element)=>element.removeEventListener("focusin", onFocus, false));
|
|
462
468
|
};
|
|
463
469
|
}, [
|
|
@@ -476,21 +482,23 @@ function $9bf71ea28793e738$var$shouldRestoreFocus(scopeRef) {
|
|
|
476
482
|
}
|
|
477
483
|
function $9bf71ea28793e738$var$useRestoreFocus(scopeRef, restoreFocus, contain) {
|
|
478
484
|
// create a ref during render instead of useLayoutEffect so the active element is saved before a child with autoFocus=true mounts.
|
|
479
|
-
|
|
485
|
+
// eslint-disable-next-line no-restricted-globals
|
|
486
|
+
const nodeToRestoreRef = (0, $6nfFC$useRef)(typeof document !== "undefined" ? (0, $6nfFC$getOwnerDocument)(scopeRef.current ? scopeRef.current[0] : undefined).activeElement : null);
|
|
480
487
|
// restoring scopes should all track if they are active regardless of contain, but contain already tracks it plus logic to contain the focus
|
|
481
488
|
// restoring-non-containing scopes should only care if they become active so they can perform the restore
|
|
482
489
|
(0, $6nfFC$useLayoutEffect)(()=>{
|
|
483
490
|
let scope = scopeRef.current;
|
|
491
|
+
const ownerDocument = (0, $6nfFC$getOwnerDocument)(scope ? scope[0] : undefined);
|
|
484
492
|
if (!restoreFocus || contain) return;
|
|
485
493
|
let onFocus = ()=>{
|
|
486
494
|
// If focusing an element in a child scope of the currently active scope, the child becomes active.
|
|
487
495
|
// Moving out of the active scope to an ancestor is not allowed.
|
|
488
|
-
if ((!$9bf71ea28793e738$var$activeScope || $9bf71ea28793e738$var$isAncestorScope($9bf71ea28793e738$var$activeScope, scopeRef)) && $9bf71ea28793e738$var$isElementInScope(
|
|
496
|
+
if ((!$9bf71ea28793e738$var$activeScope || $9bf71ea28793e738$var$isAncestorScope($9bf71ea28793e738$var$activeScope, scopeRef)) && $9bf71ea28793e738$var$isElementInScope(ownerDocument.activeElement, scopeRef.current)) $9bf71ea28793e738$var$activeScope = scopeRef;
|
|
489
497
|
};
|
|
490
|
-
|
|
498
|
+
ownerDocument.addEventListener("focusin", onFocus, false);
|
|
491
499
|
scope === null || scope === void 0 ? void 0 : scope.forEach((element)=>element.addEventListener("focusin", onFocus, false));
|
|
492
500
|
return ()=>{
|
|
493
|
-
|
|
501
|
+
ownerDocument.removeEventListener("focusin", onFocus, false);
|
|
494
502
|
scope === null || scope === void 0 ? void 0 : scope.forEach((element)=>element.removeEventListener("focusin", onFocus, false));
|
|
495
503
|
};
|
|
496
504
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
@@ -499,6 +507,7 @@ function $9bf71ea28793e738$var$useRestoreFocus(scopeRef, restoreFocus, contain)
|
|
|
499
507
|
contain
|
|
500
508
|
]);
|
|
501
509
|
(0, $6nfFC$useLayoutEffect)(()=>{
|
|
510
|
+
const ownerDocument = (0, $6nfFC$getOwnerDocument)(scopeRef.current ? scopeRef.current[0] : undefined);
|
|
502
511
|
if (!restoreFocus) return;
|
|
503
512
|
// Handle the Tab key so that tabbing out of the scope goes to the next element
|
|
504
513
|
// after the node that had focus when the scope mounted. This is important when
|
|
@@ -506,19 +515,19 @@ function $9bf71ea28793e738$var$useRestoreFocus(scopeRef, restoreFocus, contain)
|
|
|
506
515
|
// tabbing out of the overlay.
|
|
507
516
|
let onKeyDown = (e)=>{
|
|
508
517
|
if (e.key !== "Tab" || e.altKey || e.ctrlKey || e.metaKey || !$9bf71ea28793e738$var$shouldContainFocus(scopeRef)) return;
|
|
509
|
-
let focusedElement =
|
|
518
|
+
let focusedElement = ownerDocument.activeElement;
|
|
510
519
|
if (!$9bf71ea28793e738$var$isElementInScope(focusedElement, scopeRef.current)) return;
|
|
511
520
|
let treeNode = $9bf71ea28793e738$export$d06fae2ee68b101e.getTreeNode(scopeRef);
|
|
512
521
|
if (!treeNode) return;
|
|
513
522
|
let nodeToRestore = treeNode.nodeToRestore;
|
|
514
523
|
// Create a DOM tree walker that matches all tabbable elements
|
|
515
|
-
let walker = $9bf71ea28793e738$export$2d6ec8fc375ceafa(
|
|
524
|
+
let walker = $9bf71ea28793e738$export$2d6ec8fc375ceafa(ownerDocument.body, {
|
|
516
525
|
tabbable: true
|
|
517
526
|
});
|
|
518
527
|
// Find the next tabbable element after the currently focused element
|
|
519
528
|
walker.currentNode = focusedElement;
|
|
520
529
|
let nextElement = e.shiftKey ? walker.previousNode() : walker.nextNode();
|
|
521
|
-
if (!nodeToRestore || !
|
|
530
|
+
if (!nodeToRestore || !ownerDocument.body.contains(nodeToRestore) || nodeToRestore === ownerDocument.body) {
|
|
522
531
|
nodeToRestore = undefined;
|
|
523
532
|
treeNode.nodeToRestore = undefined;
|
|
524
533
|
}
|
|
@@ -539,9 +548,9 @@ function $9bf71ea28793e738$var$useRestoreFocus(scopeRef, restoreFocus, contain)
|
|
|
539
548
|
else $9bf71ea28793e738$var$focusElement(nodeToRestore, true);
|
|
540
549
|
}
|
|
541
550
|
};
|
|
542
|
-
if (!contain)
|
|
551
|
+
if (!contain) ownerDocument.addEventListener("keydown", onKeyDown, true);
|
|
543
552
|
return ()=>{
|
|
544
|
-
if (!contain)
|
|
553
|
+
if (!contain) ownerDocument.removeEventListener("keydown", onKeyDown, true);
|
|
545
554
|
};
|
|
546
555
|
}, [
|
|
547
556
|
scopeRef,
|
|
@@ -550,6 +559,7 @@ function $9bf71ea28793e738$var$useRestoreFocus(scopeRef, restoreFocus, contain)
|
|
|
550
559
|
]);
|
|
551
560
|
// useLayoutEffect instead of useEffect so the active element is saved synchronously instead of asynchronously.
|
|
552
561
|
(0, $6nfFC$useLayoutEffect)(()=>{
|
|
562
|
+
const ownerDocument = (0, $6nfFC$getOwnerDocument)(scopeRef.current ? scopeRef.current[0] : undefined);
|
|
553
563
|
if (!restoreFocus) return;
|
|
554
564
|
let treeNode = $9bf71ea28793e738$export$d06fae2ee68b101e.getTreeNode(scopeRef);
|
|
555
565
|
if (!treeNode) return;
|
|
@@ -561,16 +571,16 @@ function $9bf71ea28793e738$var$useRestoreFocus(scopeRef, restoreFocus, contain)
|
|
|
561
571
|
let nodeToRestore = treeNode.nodeToRestore;
|
|
562
572
|
// if we already lost focus to the body and this was the active scope, then we should attempt to restore
|
|
563
573
|
if (restoreFocus && nodeToRestore && // eslint-disable-next-line react-hooks/exhaustive-deps
|
|
564
|
-
($9bf71ea28793e738$var$isElementInScope(
|
|
574
|
+
($9bf71ea28793e738$var$isElementInScope(ownerDocument.activeElement, scopeRef.current) || ownerDocument.activeElement === ownerDocument.body && $9bf71ea28793e738$var$shouldRestoreFocus(scopeRef))) {
|
|
565
575
|
// freeze the focusScopeTree so it persists after the raf, otherwise during unmount nodes are removed from it
|
|
566
576
|
let clonedTree = $9bf71ea28793e738$export$d06fae2ee68b101e.clone();
|
|
567
577
|
requestAnimationFrame(()=>{
|
|
568
578
|
// Only restore focus if we've lost focus to the body, the alternative is that focus has been purposefully moved elsewhere
|
|
569
|
-
if (
|
|
579
|
+
if (ownerDocument.activeElement === ownerDocument.body) {
|
|
570
580
|
// look up the tree starting with our scope to find a nodeToRestore still in the DOM
|
|
571
581
|
let treeNode = clonedTree.getTreeNode(scopeRef);
|
|
572
582
|
while(treeNode){
|
|
573
|
-
if (treeNode.nodeToRestore &&
|
|
583
|
+
if (treeNode.nodeToRestore && treeNode.nodeToRestore.isConnected) {
|
|
574
584
|
$9bf71ea28793e738$var$focusElement(treeNode.nodeToRestore);
|
|
575
585
|
return;
|
|
576
586
|
}
|
|
@@ -597,7 +607,7 @@ function $9bf71ea28793e738$var$useRestoreFocus(scopeRef, restoreFocus, contain)
|
|
|
597
607
|
}
|
|
598
608
|
function $9bf71ea28793e738$export$2d6ec8fc375ceafa(root, opts, scope) {
|
|
599
609
|
let selector = (opts === null || opts === void 0 ? void 0 : opts.tabbable) ? $9bf71ea28793e738$var$TABBABLE_ELEMENT_SELECTOR : $9bf71ea28793e738$var$FOCUSABLE_ELEMENT_SELECTOR;
|
|
600
|
-
let walker =
|
|
610
|
+
let walker = (0, $6nfFC$getOwnerDocument)(root).createTreeWalker(root, NodeFilter.SHOW_ELEMENT, {
|
|
601
611
|
acceptNode (node) {
|
|
602
612
|
var _opts_from;
|
|
603
613
|
// Skip nodes inside the starting node.
|
|
@@ -615,7 +625,7 @@ function $9bf71ea28793e738$export$c5251b9e124bf29(ref, defaultOptions = {}) {
|
|
|
615
625
|
let root = ref.current;
|
|
616
626
|
if (!root) return null;
|
|
617
627
|
let { from: from, tabbable: tabbable = defaultOptions.tabbable, wrap: wrap = defaultOptions.wrap, accept: accept = defaultOptions.accept } = opts;
|
|
618
|
-
let node = from ||
|
|
628
|
+
let node = from || (0, $6nfFC$getOwnerDocument)(root).activeElement;
|
|
619
629
|
let walker = $9bf71ea28793e738$export$2d6ec8fc375ceafa(root, {
|
|
620
630
|
tabbable: tabbable,
|
|
621
631
|
accept: accept
|
|
@@ -633,7 +643,7 @@ function $9bf71ea28793e738$export$c5251b9e124bf29(ref, defaultOptions = {}) {
|
|
|
633
643
|
let root = ref.current;
|
|
634
644
|
if (!root) return null;
|
|
635
645
|
let { from: from, tabbable: tabbable = defaultOptions.tabbable, wrap: wrap = defaultOptions.wrap, accept: accept = defaultOptions.accept } = opts;
|
|
636
|
-
let node = from ||
|
|
646
|
+
let node = from || (0, $6nfFC$getOwnerDocument)(root).activeElement;
|
|
637
647
|
let walker = $9bf71ea28793e738$export$2d6ec8fc375ceafa(root, {
|
|
638
648
|
tabbable: tabbable,
|
|
639
649
|
accept: accept
|
package/dist/main.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
var $aB6Cp$react = require("react");
|
|
2
1
|
var $aB6Cp$reactariautils = require("@react-aria/utils");
|
|
2
|
+
var $aB6Cp$react = require("react");
|
|
3
3
|
var $aB6Cp$reactariainteractions = require("@react-aria/interactions");
|
|
4
4
|
var $aB6Cp$clsx = require("clsx");
|
|
5
5
|
|
|
@@ -61,16 +61,18 @@ function $1c7f9157d722357d$export$80f3e147d781571c(element) {
|
|
|
61
61
|
// the page before shifting focus. This avoids issues with VoiceOver on iOS
|
|
62
62
|
// causing the page to scroll when moving focus if the element is transitioning
|
|
63
63
|
// from off the screen.
|
|
64
|
+
const ownerDocument = (0, $aB6Cp$reactariautils.getOwnerDocument)(element);
|
|
64
65
|
if ((0, $aB6Cp$reactariainteractions.getInteractionModality)() === "virtual") {
|
|
65
|
-
let lastFocusedElement =
|
|
66
|
+
let lastFocusedElement = ownerDocument.activeElement;
|
|
66
67
|
(0, $aB6Cp$reactariautils.runAfterTransition)(()=>{
|
|
67
68
|
// If focus did not move and the element is still in the document, focus it.
|
|
68
|
-
if (
|
|
69
|
+
if (ownerDocument.activeElement === lastFocusedElement && element.isConnected) (0, $aB6Cp$reactariautils.focusWithoutScrolling)(element);
|
|
69
70
|
});
|
|
70
71
|
} else (0, $aB6Cp$reactariautils.focusWithoutScrolling)(element);
|
|
71
72
|
}
|
|
72
73
|
|
|
73
74
|
|
|
75
|
+
|
|
74
76
|
/*
|
|
75
77
|
* Copyright 2021 Adobe. All rights reserved.
|
|
76
78
|
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
@@ -81,8 +83,10 @@ function $1c7f9157d722357d$export$80f3e147d781571c(element) {
|
|
|
81
83
|
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
|
|
82
84
|
* OF ANY KIND, either express or implied. See the License for the specific language
|
|
83
85
|
* governing permissions and limitations under the License.
|
|
84
|
-
*/
|
|
85
|
-
|
|
86
|
+
*/
|
|
87
|
+
function $d5156037ad898a4d$var$isStyleVisible(element) {
|
|
88
|
+
const windowObject = (0, $aB6Cp$reactariautils.getOwnerWindow)(element);
|
|
89
|
+
if (!(element instanceof windowObject.HTMLElement) && !(element instanceof windowObject.SVGElement)) return false;
|
|
86
90
|
let { display: display, visibility: visibility } = element.style;
|
|
87
91
|
let isVisible = display !== "none" && visibility !== "hidden" && visibility !== "collapse";
|
|
88
92
|
if (isVisible) {
|
|
@@ -101,7 +105,6 @@ function $d5156037ad898a4d$export$e989c0fffaa6b27a(element, childElement) {
|
|
|
101
105
|
|
|
102
106
|
|
|
103
107
|
|
|
104
|
-
|
|
105
108
|
const $a7a032acae3ddda9$var$FocusContext = /*#__PURE__*/ (0, ($parcel$interopDefault($aB6Cp$react))).createContext(null);
|
|
106
109
|
let $a7a032acae3ddda9$var$activeScope = null;
|
|
107
110
|
function $a7a032acae3ddda9$export$20e40289641fbbb6(props) {
|
|
@@ -159,7 +162,7 @@ function $a7a032acae3ddda9$export$20e40289641fbbb6(props) {
|
|
|
159
162
|
// This needs to be an effect so that activeScope is updated after the FocusScope tree is complete.
|
|
160
163
|
// It cannot be a useLayoutEffect because the parent of this node hasn't been attached in the tree yet.
|
|
161
164
|
(0, $aB6Cp$react.useEffect)(()=>{
|
|
162
|
-
|
|
165
|
+
const activeElement = (0, $aB6Cp$reactariautils.getOwnerDocument)(scopeRef.current ? scopeRef.current[0] : undefined).activeElement;
|
|
163
166
|
let scope = null;
|
|
164
167
|
if ($a7a032acae3ddda9$var$isElementInScope(activeElement, scopeRef.current)) {
|
|
165
168
|
// We need to traverse the focusScope tree and find the bottom most scope that
|
|
@@ -213,7 +216,7 @@ function $a7a032acae3ddda9$var$createFocusManagerForScope(scopeRef) {
|
|
|
213
216
|
focusNext (opts = {}) {
|
|
214
217
|
let scope = scopeRef.current;
|
|
215
218
|
let { from: from, tabbable: tabbable, wrap: wrap, accept: accept } = opts;
|
|
216
|
-
let node = from ||
|
|
219
|
+
let node = from || (0, $aB6Cp$reactariautils.getOwnerDocument)(scope[0]).activeElement;
|
|
217
220
|
let sentinel = scope[0].previousElementSibling;
|
|
218
221
|
let scopeRoot = $a7a032acae3ddda9$var$getScopeRoot(scope);
|
|
219
222
|
let walker = $a7a032acae3ddda9$export$2d6ec8fc375ceafa(scopeRoot, {
|
|
@@ -232,7 +235,7 @@ function $a7a032acae3ddda9$var$createFocusManagerForScope(scopeRef) {
|
|
|
232
235
|
focusPrevious (opts = {}) {
|
|
233
236
|
let scope = scopeRef.current;
|
|
234
237
|
let { from: from, tabbable: tabbable, wrap: wrap, accept: accept } = opts;
|
|
235
|
-
let node = from ||
|
|
238
|
+
let node = from || (0, $aB6Cp$reactariautils.getOwnerDocument)(scope[0]).activeElement;
|
|
236
239
|
let sentinel = scope[scope.length - 1].nextElementSibling;
|
|
237
240
|
let scopeRoot = $a7a032acae3ddda9$var$getScopeRoot(scope);
|
|
238
241
|
let walker = $a7a032acae3ddda9$export$2d6ec8fc375ceafa(scopeRoot, {
|
|
@@ -318,10 +321,11 @@ function $a7a032acae3ddda9$var$useFocusContainment(scopeRef, contain) {
|
|
|
318
321
|
}
|
|
319
322
|
return;
|
|
320
323
|
}
|
|
324
|
+
const ownerDocument = (0, $aB6Cp$reactariautils.getOwnerDocument)(scope ? scope[0] : undefined);
|
|
321
325
|
// Handle the Tab key to contain focus within the scope
|
|
322
326
|
let onKeyDown = (e)=>{
|
|
323
327
|
if (e.key !== "Tab" || e.altKey || e.ctrlKey || e.metaKey || !$a7a032acae3ddda9$var$shouldContainFocus(scopeRef)) return;
|
|
324
|
-
let focusedElement =
|
|
328
|
+
let focusedElement = ownerDocument.activeElement;
|
|
325
329
|
let scope = scopeRef.current;
|
|
326
330
|
if (!scope || !$a7a032acae3ddda9$var$isElementInScope(focusedElement, scope)) return;
|
|
327
331
|
let scopeRoot = $a7a032acae3ddda9$var$getScopeRoot(scope);
|
|
@@ -356,9 +360,9 @@ function $a7a032acae3ddda9$var$useFocusContainment(scopeRef, contain) {
|
|
|
356
360
|
if (raf.current) cancelAnimationFrame(raf.current);
|
|
357
361
|
raf.current = requestAnimationFrame(()=>{
|
|
358
362
|
// Use document.activeElement instead of e.relatedTarget so we can tell if user clicked into iframe
|
|
359
|
-
if (
|
|
363
|
+
if (ownerDocument.activeElement && $a7a032acae3ddda9$var$shouldContainFocus(scopeRef) && !$a7a032acae3ddda9$var$isElementInChildScope(ownerDocument.activeElement, scopeRef)) {
|
|
360
364
|
$a7a032acae3ddda9$var$activeScope = scopeRef;
|
|
361
|
-
if (
|
|
365
|
+
if (ownerDocument.body.contains(e.target)) {
|
|
362
366
|
var _focusedNode_current;
|
|
363
367
|
focusedNode.current = e.target;
|
|
364
368
|
(_focusedNode_current = focusedNode.current) === null || _focusedNode_current === void 0 ? void 0 : _focusedNode_current.focus();
|
|
@@ -366,13 +370,13 @@ function $a7a032acae3ddda9$var$useFocusContainment(scopeRef, contain) {
|
|
|
366
370
|
}
|
|
367
371
|
});
|
|
368
372
|
};
|
|
369
|
-
|
|
370
|
-
|
|
373
|
+
ownerDocument.addEventListener("keydown", onKeyDown, false);
|
|
374
|
+
ownerDocument.addEventListener("focusin", onFocus, false);
|
|
371
375
|
scope === null || scope === void 0 ? void 0 : scope.forEach((element)=>element.addEventListener("focusin", onFocus, false));
|
|
372
376
|
scope === null || scope === void 0 ? void 0 : scope.forEach((element)=>element.addEventListener("focusout", onBlur, false));
|
|
373
377
|
return ()=>{
|
|
374
|
-
|
|
375
|
-
|
|
378
|
+
ownerDocument.removeEventListener("keydown", onKeyDown, false);
|
|
379
|
+
ownerDocument.removeEventListener("focusin", onFocus, false);
|
|
376
380
|
scope === null || scope === void 0 ? void 0 : scope.forEach((element)=>element.removeEventListener("focusin", onFocus, false));
|
|
377
381
|
scope === null || scope === void 0 ? void 0 : scope.forEach((element)=>element.removeEventListener("focusout", onBlur, false));
|
|
378
382
|
};
|
|
@@ -456,7 +460,8 @@ function $a7a032acae3ddda9$var$useAutoFocus(scopeRef, autoFocus) {
|
|
|
456
460
|
(0, $aB6Cp$react.useEffect)(()=>{
|
|
457
461
|
if (autoFocusRef.current) {
|
|
458
462
|
$a7a032acae3ddda9$var$activeScope = scopeRef;
|
|
459
|
-
|
|
463
|
+
const ownerDocument = (0, $aB6Cp$reactariautils.getOwnerDocument)(scopeRef.current ? scopeRef.current[0] : undefined);
|
|
464
|
+
if (!$a7a032acae3ddda9$var$isElementInScope(ownerDocument.activeElement, $a7a032acae3ddda9$var$activeScope.current) && scopeRef.current) $a7a032acae3ddda9$var$focusFirstInScope(scopeRef.current);
|
|
460
465
|
}
|
|
461
466
|
autoFocusRef.current = false;
|
|
462
467
|
}, [
|
|
@@ -469,15 +474,16 @@ function $a7a032acae3ddda9$var$useActiveScopeTracker(scopeRef, restore, contain)
|
|
|
469
474
|
(0, $aB6Cp$reactariautils.useLayoutEffect)(()=>{
|
|
470
475
|
if (restore || contain) return;
|
|
471
476
|
let scope = scopeRef.current;
|
|
477
|
+
const ownerDocument = (0, $aB6Cp$reactariautils.getOwnerDocument)(scope ? scope[0] : undefined);
|
|
472
478
|
let onFocus = (e)=>{
|
|
473
479
|
let target = e.target;
|
|
474
480
|
if ($a7a032acae3ddda9$var$isElementInScope(target, scopeRef.current)) $a7a032acae3ddda9$var$activeScope = scopeRef;
|
|
475
481
|
else if (!$a7a032acae3ddda9$var$isElementInAnyScope(target)) $a7a032acae3ddda9$var$activeScope = null;
|
|
476
482
|
};
|
|
477
|
-
|
|
483
|
+
ownerDocument.addEventListener("focusin", onFocus, false);
|
|
478
484
|
scope === null || scope === void 0 ? void 0 : scope.forEach((element)=>element.addEventListener("focusin", onFocus, false));
|
|
479
485
|
return ()=>{
|
|
480
|
-
|
|
486
|
+
ownerDocument.removeEventListener("focusin", onFocus, false);
|
|
481
487
|
scope === null || scope === void 0 ? void 0 : scope.forEach((element)=>element.removeEventListener("focusin", onFocus, false));
|
|
482
488
|
};
|
|
483
489
|
}, [
|
|
@@ -496,21 +502,23 @@ function $a7a032acae3ddda9$var$shouldRestoreFocus(scopeRef) {
|
|
|
496
502
|
}
|
|
497
503
|
function $a7a032acae3ddda9$var$useRestoreFocus(scopeRef, restoreFocus, contain) {
|
|
498
504
|
// create a ref during render instead of useLayoutEffect so the active element is saved before a child with autoFocus=true mounts.
|
|
499
|
-
|
|
505
|
+
// eslint-disable-next-line no-restricted-globals
|
|
506
|
+
const nodeToRestoreRef = (0, $aB6Cp$react.useRef)(typeof document !== "undefined" ? (0, $aB6Cp$reactariautils.getOwnerDocument)(scopeRef.current ? scopeRef.current[0] : undefined).activeElement : null);
|
|
500
507
|
// restoring scopes should all track if they are active regardless of contain, but contain already tracks it plus logic to contain the focus
|
|
501
508
|
// restoring-non-containing scopes should only care if they become active so they can perform the restore
|
|
502
509
|
(0, $aB6Cp$reactariautils.useLayoutEffect)(()=>{
|
|
503
510
|
let scope = scopeRef.current;
|
|
511
|
+
const ownerDocument = (0, $aB6Cp$reactariautils.getOwnerDocument)(scope ? scope[0] : undefined);
|
|
504
512
|
if (!restoreFocus || contain) return;
|
|
505
513
|
let onFocus = ()=>{
|
|
506
514
|
// If focusing an element in a child scope of the currently active scope, the child becomes active.
|
|
507
515
|
// Moving out of the active scope to an ancestor is not allowed.
|
|
508
|
-
if ((!$a7a032acae3ddda9$var$activeScope || $a7a032acae3ddda9$var$isAncestorScope($a7a032acae3ddda9$var$activeScope, scopeRef)) && $a7a032acae3ddda9$var$isElementInScope(
|
|
516
|
+
if ((!$a7a032acae3ddda9$var$activeScope || $a7a032acae3ddda9$var$isAncestorScope($a7a032acae3ddda9$var$activeScope, scopeRef)) && $a7a032acae3ddda9$var$isElementInScope(ownerDocument.activeElement, scopeRef.current)) $a7a032acae3ddda9$var$activeScope = scopeRef;
|
|
509
517
|
};
|
|
510
|
-
|
|
518
|
+
ownerDocument.addEventListener("focusin", onFocus, false);
|
|
511
519
|
scope === null || scope === void 0 ? void 0 : scope.forEach((element)=>element.addEventListener("focusin", onFocus, false));
|
|
512
520
|
return ()=>{
|
|
513
|
-
|
|
521
|
+
ownerDocument.removeEventListener("focusin", onFocus, false);
|
|
514
522
|
scope === null || scope === void 0 ? void 0 : scope.forEach((element)=>element.removeEventListener("focusin", onFocus, false));
|
|
515
523
|
};
|
|
516
524
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
@@ -519,6 +527,7 @@ function $a7a032acae3ddda9$var$useRestoreFocus(scopeRef, restoreFocus, contain)
|
|
|
519
527
|
contain
|
|
520
528
|
]);
|
|
521
529
|
(0, $aB6Cp$reactariautils.useLayoutEffect)(()=>{
|
|
530
|
+
const ownerDocument = (0, $aB6Cp$reactariautils.getOwnerDocument)(scopeRef.current ? scopeRef.current[0] : undefined);
|
|
522
531
|
if (!restoreFocus) return;
|
|
523
532
|
// Handle the Tab key so that tabbing out of the scope goes to the next element
|
|
524
533
|
// after the node that had focus when the scope mounted. This is important when
|
|
@@ -526,19 +535,19 @@ function $a7a032acae3ddda9$var$useRestoreFocus(scopeRef, restoreFocus, contain)
|
|
|
526
535
|
// tabbing out of the overlay.
|
|
527
536
|
let onKeyDown = (e)=>{
|
|
528
537
|
if (e.key !== "Tab" || e.altKey || e.ctrlKey || e.metaKey || !$a7a032acae3ddda9$var$shouldContainFocus(scopeRef)) return;
|
|
529
|
-
let focusedElement =
|
|
538
|
+
let focusedElement = ownerDocument.activeElement;
|
|
530
539
|
if (!$a7a032acae3ddda9$var$isElementInScope(focusedElement, scopeRef.current)) return;
|
|
531
540
|
let treeNode = $a7a032acae3ddda9$export$d06fae2ee68b101e.getTreeNode(scopeRef);
|
|
532
541
|
if (!treeNode) return;
|
|
533
542
|
let nodeToRestore = treeNode.nodeToRestore;
|
|
534
543
|
// Create a DOM tree walker that matches all tabbable elements
|
|
535
|
-
let walker = $a7a032acae3ddda9$export$2d6ec8fc375ceafa(
|
|
544
|
+
let walker = $a7a032acae3ddda9$export$2d6ec8fc375ceafa(ownerDocument.body, {
|
|
536
545
|
tabbable: true
|
|
537
546
|
});
|
|
538
547
|
// Find the next tabbable element after the currently focused element
|
|
539
548
|
walker.currentNode = focusedElement;
|
|
540
549
|
let nextElement = e.shiftKey ? walker.previousNode() : walker.nextNode();
|
|
541
|
-
if (!nodeToRestore || !
|
|
550
|
+
if (!nodeToRestore || !ownerDocument.body.contains(nodeToRestore) || nodeToRestore === ownerDocument.body) {
|
|
542
551
|
nodeToRestore = undefined;
|
|
543
552
|
treeNode.nodeToRestore = undefined;
|
|
544
553
|
}
|
|
@@ -559,9 +568,9 @@ function $a7a032acae3ddda9$var$useRestoreFocus(scopeRef, restoreFocus, contain)
|
|
|
559
568
|
else $a7a032acae3ddda9$var$focusElement(nodeToRestore, true);
|
|
560
569
|
}
|
|
561
570
|
};
|
|
562
|
-
if (!contain)
|
|
571
|
+
if (!contain) ownerDocument.addEventListener("keydown", onKeyDown, true);
|
|
563
572
|
return ()=>{
|
|
564
|
-
if (!contain)
|
|
573
|
+
if (!contain) ownerDocument.removeEventListener("keydown", onKeyDown, true);
|
|
565
574
|
};
|
|
566
575
|
}, [
|
|
567
576
|
scopeRef,
|
|
@@ -570,6 +579,7 @@ function $a7a032acae3ddda9$var$useRestoreFocus(scopeRef, restoreFocus, contain)
|
|
|
570
579
|
]);
|
|
571
580
|
// useLayoutEffect instead of useEffect so the active element is saved synchronously instead of asynchronously.
|
|
572
581
|
(0, $aB6Cp$reactariautils.useLayoutEffect)(()=>{
|
|
582
|
+
const ownerDocument = (0, $aB6Cp$reactariautils.getOwnerDocument)(scopeRef.current ? scopeRef.current[0] : undefined);
|
|
573
583
|
if (!restoreFocus) return;
|
|
574
584
|
let treeNode = $a7a032acae3ddda9$export$d06fae2ee68b101e.getTreeNode(scopeRef);
|
|
575
585
|
if (!treeNode) return;
|
|
@@ -581,16 +591,16 @@ function $a7a032acae3ddda9$var$useRestoreFocus(scopeRef, restoreFocus, contain)
|
|
|
581
591
|
let nodeToRestore = treeNode.nodeToRestore;
|
|
582
592
|
// if we already lost focus to the body and this was the active scope, then we should attempt to restore
|
|
583
593
|
if (restoreFocus && nodeToRestore && // eslint-disable-next-line react-hooks/exhaustive-deps
|
|
584
|
-
($a7a032acae3ddda9$var$isElementInScope(
|
|
594
|
+
($a7a032acae3ddda9$var$isElementInScope(ownerDocument.activeElement, scopeRef.current) || ownerDocument.activeElement === ownerDocument.body && $a7a032acae3ddda9$var$shouldRestoreFocus(scopeRef))) {
|
|
585
595
|
// freeze the focusScopeTree so it persists after the raf, otherwise during unmount nodes are removed from it
|
|
586
596
|
let clonedTree = $a7a032acae3ddda9$export$d06fae2ee68b101e.clone();
|
|
587
597
|
requestAnimationFrame(()=>{
|
|
588
598
|
// Only restore focus if we've lost focus to the body, the alternative is that focus has been purposefully moved elsewhere
|
|
589
|
-
if (
|
|
599
|
+
if (ownerDocument.activeElement === ownerDocument.body) {
|
|
590
600
|
// look up the tree starting with our scope to find a nodeToRestore still in the DOM
|
|
591
601
|
let treeNode = clonedTree.getTreeNode(scopeRef);
|
|
592
602
|
while(treeNode){
|
|
593
|
-
if (treeNode.nodeToRestore &&
|
|
603
|
+
if (treeNode.nodeToRestore && treeNode.nodeToRestore.isConnected) {
|
|
594
604
|
$a7a032acae3ddda9$var$focusElement(treeNode.nodeToRestore);
|
|
595
605
|
return;
|
|
596
606
|
}
|
|
@@ -617,7 +627,7 @@ function $a7a032acae3ddda9$var$useRestoreFocus(scopeRef, restoreFocus, contain)
|
|
|
617
627
|
}
|
|
618
628
|
function $a7a032acae3ddda9$export$2d6ec8fc375ceafa(root, opts, scope) {
|
|
619
629
|
let selector = (opts === null || opts === void 0 ? void 0 : opts.tabbable) ? $a7a032acae3ddda9$var$TABBABLE_ELEMENT_SELECTOR : $a7a032acae3ddda9$var$FOCUSABLE_ELEMENT_SELECTOR;
|
|
620
|
-
let walker =
|
|
630
|
+
let walker = (0, $aB6Cp$reactariautils.getOwnerDocument)(root).createTreeWalker(root, NodeFilter.SHOW_ELEMENT, {
|
|
621
631
|
acceptNode (node) {
|
|
622
632
|
var _opts_from;
|
|
623
633
|
// Skip nodes inside the starting node.
|
|
@@ -635,7 +645,7 @@ function $a7a032acae3ddda9$export$c5251b9e124bf29(ref, defaultOptions = {}) {
|
|
|
635
645
|
let root = ref.current;
|
|
636
646
|
if (!root) return null;
|
|
637
647
|
let { from: from, tabbable: tabbable = defaultOptions.tabbable, wrap: wrap = defaultOptions.wrap, accept: accept = defaultOptions.accept } = opts;
|
|
638
|
-
let node = from ||
|
|
648
|
+
let node = from || (0, $aB6Cp$reactariautils.getOwnerDocument)(root).activeElement;
|
|
639
649
|
let walker = $a7a032acae3ddda9$export$2d6ec8fc375ceafa(root, {
|
|
640
650
|
tabbable: tabbable,
|
|
641
651
|
accept: accept
|
|
@@ -653,7 +663,7 @@ function $a7a032acae3ddda9$export$c5251b9e124bf29(ref, defaultOptions = {}) {
|
|
|
653
663
|
let root = ref.current;
|
|
654
664
|
if (!root) return null;
|
|
655
665
|
let { from: from, tabbable: tabbable = defaultOptions.tabbable, wrap: wrap = defaultOptions.wrap, accept: accept = defaultOptions.accept } = opts;
|
|
656
|
-
let node = from ||
|
|
666
|
+
let node = from || (0, $aB6Cp$reactariautils.getOwnerDocument)(root).activeElement;
|
|
657
667
|
let walker = $a7a032acae3ddda9$export$2d6ec8fc375ceafa(root, {
|
|
658
668
|
tabbable: tabbable,
|
|
659
669
|
accept: accept
|