@react-aria/focus 3.6.0 → 3.8.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/dist/main.js +208 -87
- package/dist/main.js.map +1 -1
- package/dist/module.js +197 -68
- package/dist/module.js.map +1 -1
- package/dist/types.d.ts +24 -24
- package/dist/types.d.ts.map +1 -1
- package/package.json +5 -5
- package/src/FocusRing.tsx +1 -1
- package/src/FocusScope.tsx +298 -104
- package/src/focusSafely.ts +2 -1
- package/src/index.ts +10 -5
- package/src/useFocusRing.ts +6 -5
- package/src/useFocusable.tsx +10 -10
package/dist/main.js
CHANGED
|
@@ -3,37 +3,22 @@ var $aB6Cp$reactariautils = require("@react-aria/utils");
|
|
|
3
3
|
var $aB6Cp$reactariainteractions = require("@react-aria/interactions");
|
|
4
4
|
var $aB6Cp$clsx = require("clsx");
|
|
5
5
|
|
|
6
|
-
function $parcel$
|
|
7
|
-
Object.
|
|
8
|
-
if (key === 'default' || key === '__esModule' || dest.hasOwnProperty(key)) {
|
|
9
|
-
return;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
Object.defineProperty(dest, key, {
|
|
13
|
-
enumerable: true,
|
|
14
|
-
get: function get() {
|
|
15
|
-
return source[key];
|
|
16
|
-
}
|
|
17
|
-
});
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
return dest;
|
|
6
|
+
function $parcel$export(e, n, v, s) {
|
|
7
|
+
Object.defineProperty(e, n, {get: v, set: s, enumerable: true, configurable: true});
|
|
21
8
|
}
|
|
22
9
|
function $parcel$interopDefault(a) {
|
|
23
10
|
return a && a.__esModule ? a.default : a;
|
|
24
11
|
}
|
|
25
|
-
function $parcel$export(e, n, v, s) {
|
|
26
|
-
Object.defineProperty(e, n, {get: v, set: s, enumerable: true, configurable: true});
|
|
27
|
-
}
|
|
28
|
-
var $a7a032acae3ddda9$exports = {};
|
|
29
|
-
|
|
30
|
-
$parcel$export($a7a032acae3ddda9$exports, "FocusScope", () => $a7a032acae3ddda9$export$20e40289641fbbb6);
|
|
31
|
-
$parcel$export($a7a032acae3ddda9$exports, "useFocusManager", () => $a7a032acae3ddda9$export$10c5169755ce7bd7);
|
|
32
|
-
$parcel$export($a7a032acae3ddda9$exports, "getFocusableTreeWalker", () => $a7a032acae3ddda9$export$2d6ec8fc375ceafa);
|
|
33
|
-
$parcel$export($a7a032acae3ddda9$exports, "createFocusManager", () => $a7a032acae3ddda9$export$c5251b9e124bf29);
|
|
34
|
-
var $1c7f9157d722357d$exports = {};
|
|
35
12
|
|
|
36
|
-
$parcel$export(
|
|
13
|
+
$parcel$export(module.exports, "FocusScope", () => $a7a032acae3ddda9$export$20e40289641fbbb6);
|
|
14
|
+
$parcel$export(module.exports, "useFocusManager", () => $a7a032acae3ddda9$export$10c5169755ce7bd7);
|
|
15
|
+
$parcel$export(module.exports, "getFocusableTreeWalker", () => $a7a032acae3ddda9$export$2d6ec8fc375ceafa);
|
|
16
|
+
$parcel$export(module.exports, "createFocusManager", () => $a7a032acae3ddda9$export$c5251b9e124bf29);
|
|
17
|
+
$parcel$export(module.exports, "FocusRing", () => $dfd8c70b928eb1b3$export$1a38b4ad7f578e1d);
|
|
18
|
+
$parcel$export(module.exports, "FocusableProvider", () => $fb504d83237fd6ac$export$13f3202a3e5ddd5);
|
|
19
|
+
$parcel$export(module.exports, "useFocusable", () => $fb504d83237fd6ac$export$4c014de7c8940b4c);
|
|
20
|
+
$parcel$export(module.exports, "useFocusRing", () => $581a96d6eb128c1b$export$4e328f61c538687f);
|
|
21
|
+
$parcel$export(module.exports, "focusSafely", () => $1c7f9157d722357d$export$80f3e147d781571c);
|
|
37
22
|
|
|
38
23
|
|
|
39
24
|
function $1c7f9157d722357d$export$80f3e147d781571c(element) {
|
|
@@ -85,14 +70,15 @@ function $d5156037ad898a4d$export$e989c0fffaa6b27a(element, childElement) {
|
|
|
85
70
|
|
|
86
71
|
const $a7a032acae3ddda9$var$FocusContext = /*#__PURE__*/ ($parcel$interopDefault($aB6Cp$react)).createContext(null);
|
|
87
72
|
let $a7a032acae3ddda9$var$activeScope = null;
|
|
88
|
-
let $a7a032acae3ddda9$var$scopes = new Map();
|
|
89
73
|
function $a7a032acae3ddda9$export$20e40289641fbbb6(props) {
|
|
90
74
|
let { children: children , contain: contain , restoreFocus: restoreFocus , autoFocus: autoFocus } = props;
|
|
91
75
|
let startRef = $aB6Cp$react.useRef();
|
|
92
76
|
let endRef = $aB6Cp$react.useRef();
|
|
93
77
|
let scopeRef = $aB6Cp$react.useRef([]);
|
|
94
78
|
let ctx = $aB6Cp$react.useContext($a7a032acae3ddda9$var$FocusContext);
|
|
95
|
-
|
|
79
|
+
var ref;
|
|
80
|
+
// if there is no scopeRef on the context, then the parent is the focusScopeTree's root, represented by null
|
|
81
|
+
let parentScope = (ref = ctx === null || ctx === void 0 ? void 0 : ctx.scopeRef) !== null && ref !== void 0 ? ref : null;
|
|
96
82
|
$aB6Cp$reactariautils.useLayoutEffect(()=>{
|
|
97
83
|
// Find all rendered nodes between the sentinels and add them to the scope.
|
|
98
84
|
let node = startRef.current.nextSibling;
|
|
@@ -106,22 +92,27 @@ function $a7a032acae3ddda9$export$20e40289641fbbb6(props) {
|
|
|
106
92
|
children,
|
|
107
93
|
parentScope
|
|
108
94
|
]);
|
|
95
|
+
// add to the focus scope tree in render order because useEffects/useLayoutEffects run children first whereas render runs parent first
|
|
96
|
+
// which matters when constructing a tree
|
|
97
|
+
if ($a7a032acae3ddda9$export$d06fae2ee68b101e.getTreeNode(parentScope) && !$a7a032acae3ddda9$export$d06fae2ee68b101e.getTreeNode(scopeRef)) $a7a032acae3ddda9$export$d06fae2ee68b101e.addTreeNode(scopeRef, parentScope);
|
|
98
|
+
let node1 = $a7a032acae3ddda9$export$d06fae2ee68b101e.getTreeNode(scopeRef);
|
|
99
|
+
node1.contain = contain;
|
|
100
|
+
$a7a032acae3ddda9$var$useFocusContainment(scopeRef, contain);
|
|
101
|
+
$a7a032acae3ddda9$var$useRestoreFocus(scopeRef, restoreFocus, contain);
|
|
102
|
+
$a7a032acae3ddda9$var$useAutoFocus(scopeRef, autoFocus);
|
|
103
|
+
// this layout effect needs to run last so that focusScopeTree cleanup happens at the last moment possible
|
|
109
104
|
$aB6Cp$reactariautils.useLayoutEffect(()=>{
|
|
110
|
-
|
|
111
|
-
return ()=>{
|
|
105
|
+
if (scopeRef && (parentScope || parentScope == null)) return ()=>{
|
|
112
106
|
// Restore the active scope on unmount if this scope or a descendant scope is active.
|
|
113
107
|
// Parent effect cleanups run before children, so we need to check if the
|
|
114
108
|
// parent scope actually still exists before restoring the active scope to it.
|
|
115
|
-
if ((scopeRef === $a7a032acae3ddda9$var$activeScope || $a7a032acae3ddda9$var$isAncestorScope(scopeRef, $a7a032acae3ddda9$var$activeScope)) && (!parentScope || $a7a032acae3ddda9$
|
|
116
|
-
$a7a032acae3ddda9$
|
|
109
|
+
if ((scopeRef === $a7a032acae3ddda9$var$activeScope || $a7a032acae3ddda9$var$isAncestorScope(scopeRef, $a7a032acae3ddda9$var$activeScope)) && (!parentScope || $a7a032acae3ddda9$export$d06fae2ee68b101e.getTreeNode(parentScope))) $a7a032acae3ddda9$var$activeScope = parentScope;
|
|
110
|
+
$a7a032acae3ddda9$export$d06fae2ee68b101e.removeTreeNode(scopeRef);
|
|
117
111
|
};
|
|
118
112
|
}, [
|
|
119
113
|
scopeRef,
|
|
120
114
|
parentScope
|
|
121
115
|
]);
|
|
122
|
-
$a7a032acae3ddda9$var$useFocusContainment(scopeRef, contain);
|
|
123
|
-
$a7a032acae3ddda9$var$useRestoreFocus(scopeRef, restoreFocus, contain);
|
|
124
|
-
$a7a032acae3ddda9$var$useAutoFocus(scopeRef, autoFocus);
|
|
125
116
|
let focusManager = $a7a032acae3ddda9$var$createFocusManagerForScope(scopeRef);
|
|
126
117
|
return(/*#__PURE__*/ ($parcel$interopDefault($aB6Cp$react)).createElement($a7a032acae3ddda9$var$FocusContext.Provider, {
|
|
127
118
|
value: {
|
|
@@ -147,11 +138,12 @@ function $a7a032acae3ddda9$var$createFocusManagerForScope(scopeRef) {
|
|
|
147
138
|
focusNext (opts = {
|
|
148
139
|
}) {
|
|
149
140
|
let scope = scopeRef.current;
|
|
150
|
-
let { from: from , tabbable: tabbable , wrap: wrap } = opts;
|
|
141
|
+
let { from: from , tabbable: tabbable , wrap: wrap , accept: accept } = opts;
|
|
151
142
|
let node = from || document.activeElement;
|
|
152
143
|
let sentinel = scope[0].previousElementSibling;
|
|
153
144
|
let walker = $a7a032acae3ddda9$export$2d6ec8fc375ceafa($a7a032acae3ddda9$var$getScopeRoot(scope), {
|
|
154
|
-
tabbable: tabbable
|
|
145
|
+
tabbable: tabbable,
|
|
146
|
+
accept: accept
|
|
155
147
|
}, scope);
|
|
156
148
|
walker.currentNode = $a7a032acae3ddda9$var$isElementInScope(node, scope) ? node : sentinel;
|
|
157
149
|
let nextNode = walker.nextNode();
|
|
@@ -165,11 +157,12 @@ function $a7a032acae3ddda9$var$createFocusManagerForScope(scopeRef) {
|
|
|
165
157
|
focusPrevious (opts = {
|
|
166
158
|
}) {
|
|
167
159
|
let scope = scopeRef.current;
|
|
168
|
-
let { from: from , tabbable: tabbable , wrap: wrap } = opts;
|
|
160
|
+
let { from: from , tabbable: tabbable , wrap: wrap , accept: accept } = opts;
|
|
169
161
|
let node = from || document.activeElement;
|
|
170
162
|
let sentinel = scope[scope.length - 1].nextElementSibling;
|
|
171
163
|
let walker = $a7a032acae3ddda9$export$2d6ec8fc375ceafa($a7a032acae3ddda9$var$getScopeRoot(scope), {
|
|
172
|
-
tabbable: tabbable
|
|
164
|
+
tabbable: tabbable,
|
|
165
|
+
accept: accept
|
|
173
166
|
}, scope);
|
|
174
167
|
walker.currentNode = $a7a032acae3ddda9$var$isElementInScope(node, scope) ? node : sentinel;
|
|
175
168
|
let previousNode = walker.previousNode();
|
|
@@ -183,9 +176,10 @@ function $a7a032acae3ddda9$var$createFocusManagerForScope(scopeRef) {
|
|
|
183
176
|
focusFirst (opts = {
|
|
184
177
|
}) {
|
|
185
178
|
let scope = scopeRef.current;
|
|
186
|
-
let { tabbable: tabbable } = opts;
|
|
179
|
+
let { tabbable: tabbable , accept: accept } = opts;
|
|
187
180
|
let walker = $a7a032acae3ddda9$export$2d6ec8fc375ceafa($a7a032acae3ddda9$var$getScopeRoot(scope), {
|
|
188
|
-
tabbable: tabbable
|
|
181
|
+
tabbable: tabbable,
|
|
182
|
+
accept: accept
|
|
189
183
|
}, scope);
|
|
190
184
|
walker.currentNode = scope[0].previousElementSibling;
|
|
191
185
|
let nextNode = walker.nextNode();
|
|
@@ -195,9 +189,10 @@ function $a7a032acae3ddda9$var$createFocusManagerForScope(scopeRef) {
|
|
|
195
189
|
focusLast (opts = {
|
|
196
190
|
}) {
|
|
197
191
|
let scope = scopeRef.current;
|
|
198
|
-
let { tabbable: tabbable } = opts;
|
|
192
|
+
let { tabbable: tabbable , accept: accept } = opts;
|
|
199
193
|
let walker = $a7a032acae3ddda9$export$2d6ec8fc375ceafa($a7a032acae3ddda9$var$getScopeRoot(scope), {
|
|
200
|
-
tabbable: tabbable
|
|
194
|
+
tabbable: tabbable,
|
|
195
|
+
accept: accept
|
|
201
196
|
}, scope);
|
|
202
197
|
walker.currentNode = scope[scope.length - 1].nextElementSibling;
|
|
203
198
|
let previousNode = walker.previousNode();
|
|
@@ -227,15 +222,30 @@ const $a7a032acae3ddda9$var$TABBABLE_ELEMENT_SELECTOR = $a7a032acae3ddda9$var$fo
|
|
|
227
222
|
function $a7a032acae3ddda9$var$getScopeRoot(scope) {
|
|
228
223
|
return scope[0].parentElement;
|
|
229
224
|
}
|
|
225
|
+
function $a7a032acae3ddda9$var$shouldContainFocus(scopeRef) {
|
|
226
|
+
let scope = $a7a032acae3ddda9$export$d06fae2ee68b101e.getTreeNode($a7a032acae3ddda9$var$activeScope);
|
|
227
|
+
while(scope && scope.scopeRef !== scopeRef){
|
|
228
|
+
if (scope.contain) return false;
|
|
229
|
+
scope = scope.parent;
|
|
230
|
+
}
|
|
231
|
+
return true;
|
|
232
|
+
}
|
|
230
233
|
function $a7a032acae3ddda9$var$useFocusContainment(scopeRef, contain) {
|
|
231
234
|
let focusedNode = $aB6Cp$react.useRef();
|
|
232
235
|
let raf = $aB6Cp$react.useRef(null);
|
|
233
236
|
$aB6Cp$reactariautils.useLayoutEffect(()=>{
|
|
234
237
|
let scope1 = scopeRef.current;
|
|
235
|
-
if (!contain)
|
|
238
|
+
if (!contain) {
|
|
239
|
+
// if contain was changed, then we should cancel any ongoing waits to pull focus back into containment
|
|
240
|
+
if (raf.current) {
|
|
241
|
+
cancelAnimationFrame(raf.current);
|
|
242
|
+
raf.current = null;
|
|
243
|
+
}
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
236
246
|
// Handle the Tab key to contain focus within the scope
|
|
237
247
|
let onKeyDown = (e)=>{
|
|
238
|
-
if (e.key !== 'Tab' || e.altKey || e.ctrlKey || e.metaKey ||
|
|
248
|
+
if (e.key !== 'Tab' || e.altKey || e.ctrlKey || e.metaKey || !$a7a032acae3ddda9$var$shouldContainFocus(scopeRef)) return;
|
|
239
249
|
let focusedElement = document.activeElement;
|
|
240
250
|
let scope = scopeRef.current;
|
|
241
251
|
if (!$a7a032acae3ddda9$var$isElementInScope(focusedElement, scope)) return;
|
|
@@ -257,21 +267,23 @@ function $a7a032acae3ddda9$var$useFocusContainment(scopeRef, contain) {
|
|
|
257
267
|
if (!$a7a032acae3ddda9$var$activeScope || $a7a032acae3ddda9$var$isAncestorScope($a7a032acae3ddda9$var$activeScope, scopeRef)) {
|
|
258
268
|
$a7a032acae3ddda9$var$activeScope = scopeRef;
|
|
259
269
|
focusedNode.current = e.target;
|
|
260
|
-
} else if (
|
|
270
|
+
} else if ($a7a032acae3ddda9$var$shouldContainFocus(scopeRef) && !$a7a032acae3ddda9$var$isElementInChildScope(e.target, scopeRef)) {
|
|
261
271
|
// If a focus event occurs outside the active scope (e.g. user tabs from browser location bar),
|
|
262
272
|
// restore focus to the previously focused node or the first tabbable element in the active scope.
|
|
263
273
|
if (focusedNode.current) focusedNode.current.focus();
|
|
264
274
|
else if ($a7a032acae3ddda9$var$activeScope) $a7a032acae3ddda9$var$focusFirstInScope($a7a032acae3ddda9$var$activeScope.current);
|
|
265
|
-
} else if (
|
|
275
|
+
} else if ($a7a032acae3ddda9$var$shouldContainFocus(scopeRef)) focusedNode.current = e.target;
|
|
266
276
|
};
|
|
267
277
|
let onBlur = (e)=>{
|
|
268
278
|
// Firefox doesn't shift focus back to the Dialog properly without this
|
|
269
279
|
raf.current = requestAnimationFrame(()=>{
|
|
270
280
|
// Use document.activeElement instead of e.relatedTarget so we can tell if user clicked into iframe
|
|
271
|
-
if (
|
|
281
|
+
if ($a7a032acae3ddda9$var$shouldContainFocus(scopeRef) && !$a7a032acae3ddda9$var$isElementInChildScope(document.activeElement, scopeRef)) {
|
|
272
282
|
$a7a032acae3ddda9$var$activeScope = scopeRef;
|
|
273
|
-
|
|
274
|
-
|
|
283
|
+
if (document.body.contains(e.target)) {
|
|
284
|
+
focusedNode.current = e.target;
|
|
285
|
+
focusedNode.current.focus();
|
|
286
|
+
} else if ($a7a032acae3ddda9$var$activeScope) $a7a032acae3ddda9$var$focusFirstInScope($a7a032acae3ddda9$var$activeScope.current);
|
|
275
287
|
}
|
|
276
288
|
});
|
|
277
289
|
};
|
|
@@ -295,35 +307,36 @@ function $a7a032acae3ddda9$var$useFocusContainment(scopeRef, contain) {
|
|
|
295
307
|
]);
|
|
296
308
|
// eslint-disable-next-line arrow-body-style
|
|
297
309
|
$aB6Cp$react.useEffect(()=>{
|
|
298
|
-
return ()=>
|
|
299
|
-
|
|
310
|
+
return ()=>{
|
|
311
|
+
if (raf.current) cancelAnimationFrame(raf.current);
|
|
312
|
+
};
|
|
300
313
|
}, [
|
|
301
314
|
raf
|
|
302
315
|
]);
|
|
303
316
|
}
|
|
304
317
|
function $a7a032acae3ddda9$var$isElementInAnyScope(element) {
|
|
305
|
-
|
|
306
|
-
if ($a7a032acae3ddda9$var$isElementInScope(element, scope.current)) return true;
|
|
307
|
-
}
|
|
308
|
-
return false;
|
|
318
|
+
return $a7a032acae3ddda9$var$isElementInChildScope(element);
|
|
309
319
|
}
|
|
310
320
|
function $a7a032acae3ddda9$var$isElementInScope(element, scope) {
|
|
311
321
|
return scope.some((node)=>node.contains(element)
|
|
312
322
|
);
|
|
313
323
|
}
|
|
314
|
-
function $a7a032acae3ddda9$var$isElementInChildScope(element, scope) {
|
|
324
|
+
function $a7a032acae3ddda9$var$isElementInChildScope(element, scope = null) {
|
|
315
325
|
// node.contains in isElementInScope covers child scopes that are also DOM children,
|
|
316
326
|
// but does not cover child scopes in portals.
|
|
317
|
-
for (let s of $a7a032acae3ddda9$
|
|
318
|
-
if (
|
|
327
|
+
for (let { scopeRef: s } of $a7a032acae3ddda9$export$d06fae2ee68b101e.traverse($a7a032acae3ddda9$export$d06fae2ee68b101e.getTreeNode(scope))){
|
|
328
|
+
if ($a7a032acae3ddda9$var$isElementInScope(element, s.current)) return true;
|
|
319
329
|
}
|
|
320
330
|
return false;
|
|
321
331
|
}
|
|
322
332
|
function $a7a032acae3ddda9$var$isAncestorScope(ancestor, scope) {
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
333
|
+
var ref;
|
|
334
|
+
let parent = (ref = $a7a032acae3ddda9$export$d06fae2ee68b101e.getTreeNode(scope)) === null || ref === void 0 ? void 0 : ref.parent;
|
|
335
|
+
while(parent){
|
|
336
|
+
if (parent.scopeRef === ancestor) return true;
|
|
337
|
+
parent = parent.parent;
|
|
338
|
+
}
|
|
339
|
+
return false;
|
|
327
340
|
}
|
|
328
341
|
function $a7a032acae3ddda9$var$focusElement(element, scroll = false) {
|
|
329
342
|
if (element != null && !scroll) try {
|
|
@@ -337,13 +350,22 @@ function $a7a032acae3ddda9$var$focusElement(element, scroll = false) {
|
|
|
337
350
|
// ignore
|
|
338
351
|
}
|
|
339
352
|
}
|
|
340
|
-
function $a7a032acae3ddda9$var$focusFirstInScope(scope) {
|
|
353
|
+
function $a7a032acae3ddda9$var$focusFirstInScope(scope, tabbable = true) {
|
|
341
354
|
let sentinel = scope[0].previousElementSibling;
|
|
342
355
|
let walker = $a7a032acae3ddda9$export$2d6ec8fc375ceafa($a7a032acae3ddda9$var$getScopeRoot(scope), {
|
|
343
|
-
tabbable:
|
|
356
|
+
tabbable: tabbable
|
|
344
357
|
}, scope);
|
|
345
358
|
walker.currentNode = sentinel;
|
|
346
|
-
|
|
359
|
+
let nextNode = walker.nextNode();
|
|
360
|
+
// If the scope does not contain a tabbable element, use the first focusable element.
|
|
361
|
+
if (tabbable && !nextNode) {
|
|
362
|
+
walker = $a7a032acae3ddda9$export$2d6ec8fc375ceafa($a7a032acae3ddda9$var$getScopeRoot(scope), {
|
|
363
|
+
tabbable: false
|
|
364
|
+
}, scope);
|
|
365
|
+
walker.currentNode = sentinel;
|
|
366
|
+
nextNode = walker.nextNode();
|
|
367
|
+
}
|
|
368
|
+
$a7a032acae3ddda9$var$focusElement(nextNode);
|
|
347
369
|
}
|
|
348
370
|
function $a7a032acae3ddda9$var$useAutoFocus(scopeRef, autoFocus) {
|
|
349
371
|
const autoFocusRef = ($parcel$interopDefault($aB6Cp$react)).useRef(autoFocus);
|
|
@@ -353,14 +375,38 @@ function $a7a032acae3ddda9$var$useAutoFocus(scopeRef, autoFocus) {
|
|
|
353
375
|
if (!$a7a032acae3ddda9$var$isElementInScope(document.activeElement, $a7a032acae3ddda9$var$activeScope.current)) $a7a032acae3ddda9$var$focusFirstInScope(scopeRef.current);
|
|
354
376
|
}
|
|
355
377
|
autoFocusRef.current = false;
|
|
356
|
-
}, [
|
|
378
|
+
}, [
|
|
379
|
+
scopeRef
|
|
380
|
+
]);
|
|
357
381
|
}
|
|
358
382
|
function $a7a032acae3ddda9$var$useRestoreFocus(scopeRef, restoreFocus, contain) {
|
|
359
383
|
// create a ref during render instead of useLayoutEffect so the active element is saved before a child with autoFocus=true mounts.
|
|
360
384
|
const nodeToRestoreRef = $aB6Cp$react.useRef(typeof document !== 'undefined' ? document.activeElement : null);
|
|
385
|
+
// restoring scopes should all track if they are active regardless of contain, but contain already tracks it plus logic to contain the focus
|
|
386
|
+
// restoring-non-containing scopes should only care if they become active so they can perform the restore
|
|
387
|
+
$aB6Cp$reactariautils.useLayoutEffect(()=>{
|
|
388
|
+
let scope = scopeRef.current;
|
|
389
|
+
if (!restoreFocus || contain) return;
|
|
390
|
+
let onFocus = ()=>{
|
|
391
|
+
// If focusing an element in a child scope of the currently active scope, the child becomes active.
|
|
392
|
+
// Moving out of the active scope to an ancestor is not allowed.
|
|
393
|
+
if (!$a7a032acae3ddda9$var$activeScope || $a7a032acae3ddda9$var$isAncestorScope($a7a032acae3ddda9$var$activeScope, scopeRef)) $a7a032acae3ddda9$var$activeScope = scopeRef;
|
|
394
|
+
};
|
|
395
|
+
document.addEventListener('focusin', onFocus, false);
|
|
396
|
+
scope.forEach((element)=>element.addEventListener('focusin', onFocus, false)
|
|
397
|
+
);
|
|
398
|
+
return ()=>{
|
|
399
|
+
document.removeEventListener('focusin', onFocus, false);
|
|
400
|
+
scope.forEach((element)=>element.removeEventListener('focusin', onFocus, false)
|
|
401
|
+
);
|
|
402
|
+
};
|
|
403
|
+
}, [
|
|
404
|
+
scopeRef,
|
|
405
|
+
contain
|
|
406
|
+
]);
|
|
361
407
|
// useLayoutEffect instead of useEffect so the active element is saved synchronously instead of asynchronously.
|
|
362
408
|
$aB6Cp$reactariautils.useLayoutEffect(()=>{
|
|
363
|
-
|
|
409
|
+
$a7a032acae3ddda9$export$d06fae2ee68b101e.getTreeNode(scopeRef).nodeToRestore = nodeToRestoreRef.current;
|
|
364
410
|
if (!restoreFocus) return;
|
|
365
411
|
// Handle the Tab key so that tabbing out of the scope goes to the next element
|
|
366
412
|
// after the node that had focus when the scope mounted. This is important when
|
|
@@ -370,6 +416,7 @@ function $a7a032acae3ddda9$var$useRestoreFocus(scopeRef, restoreFocus, contain)
|
|
|
370
416
|
if (e.key !== 'Tab' || e.altKey || e.ctrlKey || e.metaKey) return;
|
|
371
417
|
let focusedElement = document.activeElement;
|
|
372
418
|
if (!$a7a032acae3ddda9$var$isElementInScope(focusedElement, scopeRef.current)) return;
|
|
419
|
+
let nodeToRestore = $a7a032acae3ddda9$export$d06fae2ee68b101e.getTreeNode(scopeRef).nodeToRestore;
|
|
373
420
|
// Create a DOM tree walker that matches all tabbable elements
|
|
374
421
|
let walker = $a7a032acae3ddda9$export$2d6ec8fc375ceafa(document.body, {
|
|
375
422
|
tabbable: true
|
|
@@ -377,7 +424,10 @@ function $a7a032acae3ddda9$var$useRestoreFocus(scopeRef, restoreFocus, contain)
|
|
|
377
424
|
// Find the next tabbable element after the currently focused element
|
|
378
425
|
walker.currentNode = focusedElement;
|
|
379
426
|
let nextElement = e.shiftKey ? walker.previousNode() : walker.nextNode();
|
|
380
|
-
if (!document.body.contains(nodeToRestore) || nodeToRestore === document.body)
|
|
427
|
+
if (!document.body.contains(nodeToRestore) || nodeToRestore === document.body) {
|
|
428
|
+
nodeToRestore = null;
|
|
429
|
+
$a7a032acae3ddda9$export$d06fae2ee68b101e.getTreeNode(scopeRef).nodeToRestore = null;
|
|
430
|
+
}
|
|
381
431
|
// If there is no next element, or it is outside the current scope, move focus to the
|
|
382
432
|
// next element after the node to restore to instead.
|
|
383
433
|
if ((!nextElement || !$a7a032acae3ddda9$var$isElementInScope(nextElement, scopeRef.current)) && nodeToRestore) {
|
|
@@ -398,9 +448,26 @@ function $a7a032acae3ddda9$var$useRestoreFocus(scopeRef, restoreFocus, contain)
|
|
|
398
448
|
if (!contain) document.addEventListener('keydown', onKeyDown, true);
|
|
399
449
|
return ()=>{
|
|
400
450
|
if (!contain) document.removeEventListener('keydown', onKeyDown, true);
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
451
|
+
let nodeToRestore = $a7a032acae3ddda9$export$d06fae2ee68b101e.getTreeNode(scopeRef).nodeToRestore;
|
|
452
|
+
// if we already lost focus to the body and this was the active scope, then we should attempt to restore
|
|
453
|
+
if (restoreFocus && nodeToRestore && ($a7a032acae3ddda9$var$isElementInScope(document.activeElement, scopeRef.current) || document.activeElement === document.body && $a7a032acae3ddda9$var$activeScope === scopeRef)) {
|
|
454
|
+
// freeze the focusScopeTree so it persists after the raf, otherwise during unmount nodes are removed from it
|
|
455
|
+
let clonedTree = $a7a032acae3ddda9$export$d06fae2ee68b101e.clone();
|
|
456
|
+
requestAnimationFrame(()=>{
|
|
457
|
+
// Only restore focus if we've lost focus to the body, the alternative is that focus has been purposefully moved elsewhere
|
|
458
|
+
if (document.activeElement === document.body) {
|
|
459
|
+
// look up the tree starting with our scope to find a nodeToRestore still in the DOM
|
|
460
|
+
let treeNode = clonedTree.getTreeNode(scopeRef);
|
|
461
|
+
while(treeNode){
|
|
462
|
+
if (treeNode.nodeToRestore && document.body.contains(treeNode.nodeToRestore)) {
|
|
463
|
+
$a7a032acae3ddda9$var$focusElement(treeNode.nodeToRestore);
|
|
464
|
+
return;
|
|
465
|
+
}
|
|
466
|
+
treeNode = treeNode.parent;
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
});
|
|
470
|
+
}
|
|
404
471
|
};
|
|
405
472
|
}, [
|
|
406
473
|
scopeRef,
|
|
@@ -428,6 +495,7 @@ function $a7a032acae3ddda9$export$c5251b9e124bf29(ref, defaultOptions = {
|
|
|
428
495
|
focusNext (opts = {
|
|
429
496
|
}) {
|
|
430
497
|
let root = ref.current;
|
|
498
|
+
if (!root) return;
|
|
431
499
|
let { from: from , tabbable: tabbable = defaultOptions.tabbable , wrap: wrap = defaultOptions.wrap , accept: accept = defaultOptions.accept } = opts;
|
|
432
500
|
let node = from || document.activeElement;
|
|
433
501
|
let walker = $a7a032acae3ddda9$export$2d6ec8fc375ceafa(root, {
|
|
@@ -445,6 +513,7 @@ function $a7a032acae3ddda9$export$c5251b9e124bf29(ref, defaultOptions = {
|
|
|
445
513
|
},
|
|
446
514
|
focusPrevious (opts = defaultOptions) {
|
|
447
515
|
let root = ref.current;
|
|
516
|
+
if (!root) return;
|
|
448
517
|
let { from: from , tabbable: tabbable = defaultOptions.tabbable , wrap: wrap = defaultOptions.wrap , accept: accept = defaultOptions.accept } = opts;
|
|
449
518
|
let node = from || document.activeElement;
|
|
450
519
|
let walker = $a7a032acae3ddda9$export$2d6ec8fc375ceafa(root, {
|
|
@@ -467,6 +536,7 @@ function $a7a032acae3ddda9$export$c5251b9e124bf29(ref, defaultOptions = {
|
|
|
467
536
|
},
|
|
468
537
|
focusFirst (opts = defaultOptions) {
|
|
469
538
|
let root = ref.current;
|
|
539
|
+
if (!root) return;
|
|
470
540
|
let { tabbable: tabbable = defaultOptions.tabbable , accept: accept = defaultOptions.accept } = opts;
|
|
471
541
|
let walker = $a7a032acae3ddda9$export$2d6ec8fc375ceafa(root, {
|
|
472
542
|
tabbable: tabbable,
|
|
@@ -478,6 +548,7 @@ function $a7a032acae3ddda9$export$c5251b9e124bf29(ref, defaultOptions = {
|
|
|
478
548
|
},
|
|
479
549
|
focusLast (opts = defaultOptions) {
|
|
480
550
|
let root = ref.current;
|
|
551
|
+
if (!root) return;
|
|
481
552
|
let { tabbable: tabbable = defaultOptions.tabbable , accept: accept = defaultOptions.accept } = opts;
|
|
482
553
|
let walker = $a7a032acae3ddda9$export$2d6ec8fc375ceafa(root, {
|
|
483
554
|
tabbable: tabbable,
|
|
@@ -498,17 +569,76 @@ function $a7a032acae3ddda9$var$last(walker) {
|
|
|
498
569
|
}while (last)
|
|
499
570
|
return next;
|
|
500
571
|
}
|
|
572
|
+
class $a7a032acae3ddda9$var$Tree {
|
|
573
|
+
get size() {
|
|
574
|
+
return this.fastMap.size;
|
|
575
|
+
}
|
|
576
|
+
getTreeNode(data) {
|
|
577
|
+
return this.fastMap.get(data);
|
|
578
|
+
}
|
|
579
|
+
addTreeNode(scopeRef, parent, nodeToRestore) {
|
|
580
|
+
let parentNode = this.fastMap.get(parent !== null && parent !== void 0 ? parent : null);
|
|
581
|
+
let node = new $a7a032acae3ddda9$var$TreeNode({
|
|
582
|
+
scopeRef: scopeRef
|
|
583
|
+
});
|
|
584
|
+
parentNode.addChild(node);
|
|
585
|
+
node.parent = parentNode;
|
|
586
|
+
this.fastMap.set(scopeRef, node);
|
|
587
|
+
if (nodeToRestore) node.nodeToRestore = nodeToRestore;
|
|
588
|
+
}
|
|
589
|
+
removeTreeNode(scopeRef) {
|
|
590
|
+
// never remove the root
|
|
591
|
+
if (scopeRef === null) return;
|
|
592
|
+
let node = this.fastMap.get(scopeRef);
|
|
593
|
+
let parentNode = node.parent;
|
|
594
|
+
// when we remove a scope, check if any sibling scopes are trying to restore focus to something inside the scope we're removing
|
|
595
|
+
// if we are, then replace the siblings restore with the restore from the scope we're removing
|
|
596
|
+
for (let current of this.traverse())if (current !== node && node.nodeToRestore && current.nodeToRestore && node.scopeRef.current && $a7a032acae3ddda9$var$isElementInScope(current.nodeToRestore, node.scopeRef.current)) current.nodeToRestore = node.nodeToRestore;
|
|
597
|
+
let children = node.children;
|
|
598
|
+
parentNode.removeChild(node);
|
|
599
|
+
if (children.length > 0) children.forEach((child)=>parentNode.addChild(child)
|
|
600
|
+
);
|
|
601
|
+
this.fastMap.delete(node.scopeRef);
|
|
602
|
+
}
|
|
603
|
+
// Pre Order Depth First
|
|
604
|
+
*traverse(node = this.root) {
|
|
605
|
+
if (node.scopeRef != null) yield node;
|
|
606
|
+
if (node.children.length > 0) for (let child of node.children)yield* this.traverse(child);
|
|
607
|
+
}
|
|
608
|
+
clone() {
|
|
609
|
+
let newTree = new $a7a032acae3ddda9$var$Tree();
|
|
610
|
+
for (let node of this.traverse())newTree.addTreeNode(node.scopeRef, node.parent.scopeRef, node.nodeToRestore);
|
|
611
|
+
return newTree;
|
|
612
|
+
}
|
|
613
|
+
constructor(){
|
|
614
|
+
this.fastMap = new Map();
|
|
615
|
+
this.root = new $a7a032acae3ddda9$var$TreeNode({
|
|
616
|
+
scopeRef: null
|
|
617
|
+
});
|
|
618
|
+
this.fastMap.set(null, this.root);
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
class $a7a032acae3ddda9$var$TreeNode {
|
|
622
|
+
addChild(node) {
|
|
623
|
+
this.children.push(node);
|
|
624
|
+
node.parent = this;
|
|
625
|
+
}
|
|
626
|
+
removeChild(node) {
|
|
627
|
+
this.children.splice(this.children.indexOf(node), 1);
|
|
628
|
+
node.parent = undefined;
|
|
629
|
+
}
|
|
630
|
+
constructor(props){
|
|
631
|
+
this.children = [];
|
|
632
|
+
this.contain = false;
|
|
633
|
+
this.scopeRef = props.scopeRef;
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
let $a7a032acae3ddda9$export$d06fae2ee68b101e = new $a7a032acae3ddda9$var$Tree();
|
|
501
637
|
|
|
502
638
|
|
|
503
|
-
var $dfd8c70b928eb1b3$exports = {};
|
|
504
|
-
|
|
505
|
-
$parcel$export($dfd8c70b928eb1b3$exports, "FocusRing", () => $dfd8c70b928eb1b3$export$1a38b4ad7f578e1d);
|
|
506
|
-
|
|
507
639
|
|
|
508
640
|
|
|
509
|
-
var $581a96d6eb128c1b$exports = {};
|
|
510
641
|
|
|
511
|
-
$parcel$export($581a96d6eb128c1b$exports, "useFocusRing", () => $581a96d6eb128c1b$export$4e328f61c538687f);
|
|
512
642
|
|
|
513
643
|
|
|
514
644
|
|
|
@@ -567,10 +697,6 @@ function $dfd8c70b928eb1b3$export$1a38b4ad7f578e1d(props) {
|
|
|
567
697
|
}
|
|
568
698
|
|
|
569
699
|
|
|
570
|
-
var $fb504d83237fd6ac$exports = {};
|
|
571
|
-
|
|
572
|
-
$parcel$export($fb504d83237fd6ac$exports, "FocusableProvider", () => $fb504d83237fd6ac$export$13f3202a3e5ddd5);
|
|
573
|
-
$parcel$export($fb504d83237fd6ac$exports, "useFocusable", () => $fb504d83237fd6ac$export$4c014de7c8940b4c);
|
|
574
700
|
|
|
575
701
|
|
|
576
702
|
|
|
@@ -622,11 +748,6 @@ function $fb504d83237fd6ac$export$4c014de7c8940b4c(props, domRef) {
|
|
|
622
748
|
|
|
623
749
|
|
|
624
750
|
|
|
625
|
-
$parcel$exportWildcard(module.exports, $a7a032acae3ddda9$exports);
|
|
626
|
-
$parcel$exportWildcard(module.exports, $dfd8c70b928eb1b3$exports);
|
|
627
|
-
$parcel$exportWildcard(module.exports, $fb504d83237fd6ac$exports);
|
|
628
|
-
$parcel$exportWildcard(module.exports, $581a96d6eb128c1b$exports);
|
|
629
|
-
$parcel$exportWildcard(module.exports, $1c7f9157d722357d$exports);
|
|
630
751
|
|
|
631
752
|
|
|
632
753
|
//# sourceMappingURL=main.js.map
|