UNPKG

36.5 kBJavaScriptView Raw
1import $6nfFC$react, {useRef as $6nfFC$useRef, useContext as $6nfFC$useContext, useEffect as $6nfFC$useEffect, useState as $6nfFC$useState, useCallback as $6nfFC$useCallback} from "react";
2import {useLayoutEffect as $6nfFC$useLayoutEffect, runAfterTransition as $6nfFC$runAfterTransition, focusWithoutScrolling as $6nfFC$focusWithoutScrolling, mergeProps as $6nfFC$mergeProps, useSyncRef as $6nfFC$useSyncRef} from "@react-aria/utils";
3import {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";
4import $6nfFC$clsx from "clsx";
5
6
7
8function $6a99195332edec8b$export$80f3e147d781571c(element) {
9 // If the user is interacting with a virtual cursor, e.g. screen reader, then
10 // wait until after any animated transitions that are currently occurring on
11 // the page before shifting focus. This avoids issues with VoiceOver on iOS
12 // causing the page to scroll when moving focus if the element is transitioning
13 // from off the screen.
14 if ($6nfFC$getInteractionModality() === 'virtual') {
15 let lastFocusedElement = document.activeElement;
16 $6nfFC$runAfterTransition(()=>{
17 // If focus did not move and the element is still in the document, focus it.
18 if (document.activeElement === lastFocusedElement && document.contains(element)) $6nfFC$focusWithoutScrolling(element);
19 });
20 } else $6nfFC$focusWithoutScrolling(element);
21}
22
23
24/*
25 * Copyright 2021 Adobe. All rights reserved.
26 * This file is licensed to you under the Apache License, Version 2.0 (the "License");
27 * you may not use this file except in compliance with the License. You may obtain a copy
28 * of the License at http://www.apache.org/licenses/LICENSE-2.0
29 *
30 * Unless required by applicable law or agreed to in writing, software distributed under
31 * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
32 * OF ANY KIND, either express or implied. See the License for the specific language
33 * governing permissions and limitations under the License.
34 */ function $645f2e67b85a24c9$var$isStyleVisible(element) {
35 if (!(element instanceof HTMLElement) && !(element instanceof SVGElement)) return false;
36 let { display: display , visibility: visibility } = element.style;
37 let isVisible = display !== 'none' && visibility !== 'hidden' && visibility !== 'collapse';
38 if (isVisible) {
39 const { getComputedStyle: getComputedStyle } = element.ownerDocument.defaultView;
40 let { display: computedDisplay , visibility: computedVisibility } = getComputedStyle(element);
41 isVisible = computedDisplay !== 'none' && computedVisibility !== 'hidden' && computedVisibility !== 'collapse';
42 }
43 return isVisible;
44}
45function $645f2e67b85a24c9$var$isAttributeVisible(element, childElement) {
46 return !element.hasAttribute('hidden') && (element.nodeName === 'DETAILS' && childElement && childElement.nodeName !== 'SUMMARY' ? element.hasAttribute('open') : true);
47}
48function $645f2e67b85a24c9$export$e989c0fffaa6b27a(element, childElement) {
49 return element.nodeName !== '#comment' && $645f2e67b85a24c9$var$isStyleVisible(element) && $645f2e67b85a24c9$var$isAttributeVisible(element, childElement) && (!element.parentElement || $645f2e67b85a24c9$export$e989c0fffaa6b27a(element.parentElement, element));
50}
51
52
53
54
55const $9bf71ea28793e738$var$FocusContext = /*#__PURE__*/ $6nfFC$react.createContext(null);
56let $9bf71ea28793e738$var$activeScope = null;
57function $9bf71ea28793e738$export$20e40289641fbbb6(props) {
58 let { children: children , contain: contain , restoreFocus: restoreFocus , autoFocus: autoFocus } = props;
59 let startRef = $6nfFC$useRef();
60 let endRef = $6nfFC$useRef();
61 let scopeRef = $6nfFC$useRef([]);
62 let ctx = $6nfFC$useContext($9bf71ea28793e738$var$FocusContext);
63 var ref;
64 // if there is no scopeRef on the context, then the parent is the focusScopeTree's root, represented by null
65 let parentScope = (ref = ctx === null || ctx === void 0 ? void 0 : ctx.scopeRef) !== null && ref !== void 0 ? ref : null;
66 $6nfFC$useLayoutEffect(()=>{
67 // Find all rendered nodes between the sentinels and add them to the scope.
68 let node = startRef.current.nextSibling;
69 let nodes = [];
70 while(node && node !== endRef.current){
71 nodes.push(node);
72 node = node.nextSibling;
73 }
74 scopeRef.current = nodes;
75 }, [
76 children,
77 parentScope
78 ]);
79 // add to the focus scope tree in render order because useEffects/useLayoutEffects run children first whereas render runs parent first
80 // which matters when constructing a tree
81 if ($9bf71ea28793e738$export$d06fae2ee68b101e.getTreeNode(parentScope) && !$9bf71ea28793e738$export$d06fae2ee68b101e.getTreeNode(scopeRef)) $9bf71ea28793e738$export$d06fae2ee68b101e.addTreeNode(scopeRef, parentScope);
82 let node1 = $9bf71ea28793e738$export$d06fae2ee68b101e.getTreeNode(scopeRef);
83 node1.contain = contain;
84 $9bf71ea28793e738$var$useFocusContainment(scopeRef, contain);
85 $9bf71ea28793e738$var$useRestoreFocus(scopeRef, restoreFocus, contain);
86 $9bf71ea28793e738$var$useAutoFocus(scopeRef, autoFocus);
87 // this layout effect needs to run last so that focusScopeTree cleanup happens at the last moment possible
88 $6nfFC$useLayoutEffect(()=>{
89 if (scopeRef && (parentScope || parentScope == null)) return ()=>{
90 // Restore the active scope on unmount if this scope or a descendant scope is active.
91 // Parent effect cleanups run before children, so we need to check if the
92 // parent scope actually still exists before restoring the active scope to it.
93 if ((scopeRef === $9bf71ea28793e738$var$activeScope || $9bf71ea28793e738$var$isAncestorScope(scopeRef, $9bf71ea28793e738$var$activeScope)) && (!parentScope || $9bf71ea28793e738$export$d06fae2ee68b101e.getTreeNode(parentScope))) $9bf71ea28793e738$var$activeScope = parentScope;
94 $9bf71ea28793e738$export$d06fae2ee68b101e.removeTreeNode(scopeRef);
95 };
96 }, [
97 scopeRef,
98 parentScope
99 ]);
100 let focusManager = $9bf71ea28793e738$var$createFocusManagerForScope(scopeRef);
101 return(/*#__PURE__*/ $6nfFC$react.createElement($9bf71ea28793e738$var$FocusContext.Provider, {
102 value: {
103 scopeRef: scopeRef,
104 focusManager: focusManager
105 }
106 }, /*#__PURE__*/ $6nfFC$react.createElement("span", {
107 "data-focus-scope-start": true,
108 hidden: true,
109 ref: startRef
110 }), children, /*#__PURE__*/ $6nfFC$react.createElement("span", {
111 "data-focus-scope-end": true,
112 hidden: true,
113 ref: endRef
114 })));
115}
116function $9bf71ea28793e738$export$10c5169755ce7bd7() {
117 var ref;
118 return (ref = $6nfFC$useContext($9bf71ea28793e738$var$FocusContext)) === null || ref === void 0 ? void 0 : ref.focusManager;
119}
120function $9bf71ea28793e738$var$createFocusManagerForScope(scopeRef) {
121 return {
122 focusNext (opts = {
123 }) {
124 let scope = scopeRef.current;
125 let { from: from , tabbable: tabbable , wrap: wrap , accept: accept } = opts;
126 let node = from || document.activeElement;
127 let sentinel = scope[0].previousElementSibling;
128 let walker = $9bf71ea28793e738$export$2d6ec8fc375ceafa($9bf71ea28793e738$var$getScopeRoot(scope), {
129 tabbable: tabbable,
130 accept: accept
131 }, scope);
132 walker.currentNode = $9bf71ea28793e738$var$isElementInScope(node, scope) ? node : sentinel;
133 let nextNode = walker.nextNode();
134 if (!nextNode && wrap) {
135 walker.currentNode = sentinel;
136 nextNode = walker.nextNode();
137 }
138 if (nextNode) $9bf71ea28793e738$var$focusElement(nextNode, true);
139 return nextNode;
140 },
141 focusPrevious (opts = {
142 }) {
143 let scope = scopeRef.current;
144 let { from: from , tabbable: tabbable , wrap: wrap , accept: accept } = opts;
145 let node = from || document.activeElement;
146 let sentinel = scope[scope.length - 1].nextElementSibling;
147 let walker = $9bf71ea28793e738$export$2d6ec8fc375ceafa($9bf71ea28793e738$var$getScopeRoot(scope), {
148 tabbable: tabbable,
149 accept: accept
150 }, scope);
151 walker.currentNode = $9bf71ea28793e738$var$isElementInScope(node, scope) ? node : sentinel;
152 let previousNode = walker.previousNode();
153 if (!previousNode && wrap) {
154 walker.currentNode = sentinel;
155 previousNode = walker.previousNode();
156 }
157 if (previousNode) $9bf71ea28793e738$var$focusElement(previousNode, true);
158 return previousNode;
159 },
160 focusFirst (opts = {
161 }) {
162 let scope = scopeRef.current;
163 let { tabbable: tabbable , accept: accept } = opts;
164 let walker = $9bf71ea28793e738$export$2d6ec8fc375ceafa($9bf71ea28793e738$var$getScopeRoot(scope), {
165 tabbable: tabbable,
166 accept: accept
167 }, scope);
168 walker.currentNode = scope[0].previousElementSibling;
169 let nextNode = walker.nextNode();
170 if (nextNode) $9bf71ea28793e738$var$focusElement(nextNode, true);
171 return nextNode;
172 },
173 focusLast (opts = {
174 }) {
175 let scope = scopeRef.current;
176 let { tabbable: tabbable , accept: accept } = opts;
177 let walker = $9bf71ea28793e738$export$2d6ec8fc375ceafa($9bf71ea28793e738$var$getScopeRoot(scope), {
178 tabbable: tabbable,
179 accept: accept
180 }, scope);
181 walker.currentNode = scope[scope.length - 1].nextElementSibling;
182 let previousNode = walker.previousNode();
183 if (previousNode) $9bf71ea28793e738$var$focusElement(previousNode, true);
184 return previousNode;
185 }
186 };
187}
188const $9bf71ea28793e738$var$focusableElements = [
189 'input:not([disabled]):not([type=hidden])',
190 'select:not([disabled])',
191 'textarea:not([disabled])',
192 'button:not([disabled])',
193 'a[href]',
194 'area[href]',
195 'summary',
196 'iframe',
197 'object',
198 'embed',
199 'audio[controls]',
200 'video[controls]',
201 '[contenteditable]'
202];
203const $9bf71ea28793e738$var$FOCUSABLE_ELEMENT_SELECTOR = $9bf71ea28793e738$var$focusableElements.join(':not([hidden]),') + ',[tabindex]:not([disabled]):not([hidden])';
204$9bf71ea28793e738$var$focusableElements.push('[tabindex]:not([tabindex="-1"]):not([disabled])');
205const $9bf71ea28793e738$var$TABBABLE_ELEMENT_SELECTOR = $9bf71ea28793e738$var$focusableElements.join(':not([hidden]):not([tabindex="-1"]),');
206function $9bf71ea28793e738$var$getScopeRoot(scope) {
207 return scope[0].parentElement;
208}
209function $9bf71ea28793e738$var$shouldContainFocus(scopeRef) {
210 let scope = $9bf71ea28793e738$export$d06fae2ee68b101e.getTreeNode($9bf71ea28793e738$var$activeScope);
211 while(scope && scope.scopeRef !== scopeRef){
212 if (scope.contain) return false;
213 scope = scope.parent;
214 }
215 return true;
216}
217function $9bf71ea28793e738$var$useFocusContainment(scopeRef, contain) {
218 let focusedNode = $6nfFC$useRef();
219 let raf = $6nfFC$useRef(null);
220 $6nfFC$useLayoutEffect(()=>{
221 let scope1 = scopeRef.current;
222 if (!contain) {
223 // if contain was changed, then we should cancel any ongoing waits to pull focus back into containment
224 if (raf.current) {
225 cancelAnimationFrame(raf.current);
226 raf.current = null;
227 }
228 return;
229 }
230 // Handle the Tab key to contain focus within the scope
231 let onKeyDown = (e)=>{
232 if (e.key !== 'Tab' || e.altKey || e.ctrlKey || e.metaKey || !$9bf71ea28793e738$var$shouldContainFocus(scopeRef)) return;
233 let focusedElement = document.activeElement;
234 let scope = scopeRef.current;
235 if (!$9bf71ea28793e738$var$isElementInScope(focusedElement, scope)) return;
236 let walker = $9bf71ea28793e738$export$2d6ec8fc375ceafa($9bf71ea28793e738$var$getScopeRoot(scope), {
237 tabbable: true
238 }, scope);
239 walker.currentNode = focusedElement;
240 let nextElement = e.shiftKey ? walker.previousNode() : walker.nextNode();
241 if (!nextElement) {
242 walker.currentNode = e.shiftKey ? scope[scope.length - 1].nextElementSibling : scope[0].previousElementSibling;
243 nextElement = e.shiftKey ? walker.previousNode() : walker.nextNode();
244 }
245 e.preventDefault();
246 if (nextElement) $9bf71ea28793e738$var$focusElement(nextElement, true);
247 };
248 let onFocus = (e)=>{
249 // If focusing an element in a child scope of the currently active scope, the child becomes active.
250 // Moving out of the active scope to an ancestor is not allowed.
251 if (!$9bf71ea28793e738$var$activeScope || $9bf71ea28793e738$var$isAncestorScope($9bf71ea28793e738$var$activeScope, scopeRef)) {
252 $9bf71ea28793e738$var$activeScope = scopeRef;
253 focusedNode.current = e.target;
254 } else if ($9bf71ea28793e738$var$shouldContainFocus(scopeRef) && !$9bf71ea28793e738$var$isElementInChildScope(e.target, scopeRef)) {
255 // If a focus event occurs outside the active scope (e.g. user tabs from browser location bar),
256 // restore focus to the previously focused node or the first tabbable element in the active scope.
257 if (focusedNode.current) focusedNode.current.focus();
258 else if ($9bf71ea28793e738$var$activeScope) $9bf71ea28793e738$var$focusFirstInScope($9bf71ea28793e738$var$activeScope.current);
259 } else if ($9bf71ea28793e738$var$shouldContainFocus(scopeRef)) focusedNode.current = e.target;
260 };
261 let onBlur = (e)=>{
262 // Firefox doesn't shift focus back to the Dialog properly without this
263 raf.current = requestAnimationFrame(()=>{
264 // Use document.activeElement instead of e.relatedTarget so we can tell if user clicked into iframe
265 if ($9bf71ea28793e738$var$shouldContainFocus(scopeRef) && !$9bf71ea28793e738$var$isElementInChildScope(document.activeElement, scopeRef)) {
266 $9bf71ea28793e738$var$activeScope = scopeRef;
267 if (document.body.contains(e.target)) {
268 focusedNode.current = e.target;
269 focusedNode.current.focus();
270 } else if ($9bf71ea28793e738$var$activeScope) $9bf71ea28793e738$var$focusFirstInScope($9bf71ea28793e738$var$activeScope.current);
271 }
272 });
273 };
274 document.addEventListener('keydown', onKeyDown, false);
275 document.addEventListener('focusin', onFocus, false);
276 scope1.forEach((element)=>element.addEventListener('focusin', onFocus, false)
277 );
278 scope1.forEach((element)=>element.addEventListener('focusout', onBlur, false)
279 );
280 return ()=>{
281 document.removeEventListener('keydown', onKeyDown, false);
282 document.removeEventListener('focusin', onFocus, false);
283 scope1.forEach((element)=>element.removeEventListener('focusin', onFocus, false)
284 );
285 scope1.forEach((element)=>element.removeEventListener('focusout', onBlur, false)
286 );
287 };
288 }, [
289 scopeRef,
290 contain
291 ]);
292 // eslint-disable-next-line arrow-body-style
293 $6nfFC$useEffect(()=>{
294 return ()=>{
295 if (raf.current) cancelAnimationFrame(raf.current);
296 };
297 }, [
298 raf
299 ]);
300}
301function $9bf71ea28793e738$var$isElementInAnyScope(element) {
302 return $9bf71ea28793e738$var$isElementInChildScope(element);
303}
304function $9bf71ea28793e738$var$isElementInScope(element, scope) {
305 return scope.some((node)=>node.contains(element)
306 );
307}
308function $9bf71ea28793e738$var$isElementInChildScope(element, scope = null) {
309 // node.contains in isElementInScope covers child scopes that are also DOM children,
310 // but does not cover child scopes in portals.
311 for (let { scopeRef: s } of $9bf71ea28793e738$export$d06fae2ee68b101e.traverse($9bf71ea28793e738$export$d06fae2ee68b101e.getTreeNode(scope))){
312 if ($9bf71ea28793e738$var$isElementInScope(element, s.current)) return true;
313 }
314 return false;
315}
316function $9bf71ea28793e738$var$isAncestorScope(ancestor, scope) {
317 var ref;
318 let parent = (ref = $9bf71ea28793e738$export$d06fae2ee68b101e.getTreeNode(scope)) === null || ref === void 0 ? void 0 : ref.parent;
319 while(parent){
320 if (parent.scopeRef === ancestor) return true;
321 parent = parent.parent;
322 }
323 return false;
324}
325function $9bf71ea28793e738$var$focusElement(element, scroll = false) {
326 if (element != null && !scroll) try {
327 $6a99195332edec8b$export$80f3e147d781571c(element);
328 } catch (err) {
329 // ignore
330 }
331 else if (element != null) try {
332 element.focus();
333 } catch (err1) {
334 // ignore
335 }
336}
337function $9bf71ea28793e738$var$focusFirstInScope(scope, tabbable = true) {
338 let sentinel = scope[0].previousElementSibling;
339 let walker = $9bf71ea28793e738$export$2d6ec8fc375ceafa($9bf71ea28793e738$var$getScopeRoot(scope), {
340 tabbable: tabbable
341 }, scope);
342 walker.currentNode = sentinel;
343 let nextNode = walker.nextNode();
344 // If the scope does not contain a tabbable element, use the first focusable element.
345 if (tabbable && !nextNode) {
346 walker = $9bf71ea28793e738$export$2d6ec8fc375ceafa($9bf71ea28793e738$var$getScopeRoot(scope), {
347 tabbable: false
348 }, scope);
349 walker.currentNode = sentinel;
350 nextNode = walker.nextNode();
351 }
352 $9bf71ea28793e738$var$focusElement(nextNode);
353}
354function $9bf71ea28793e738$var$useAutoFocus(scopeRef, autoFocus) {
355 const autoFocusRef = $6nfFC$react.useRef(autoFocus);
356 $6nfFC$useEffect(()=>{
357 if (autoFocusRef.current) {
358 $9bf71ea28793e738$var$activeScope = scopeRef;
359 if (!$9bf71ea28793e738$var$isElementInScope(document.activeElement, $9bf71ea28793e738$var$activeScope.current)) $9bf71ea28793e738$var$focusFirstInScope(scopeRef.current);
360 }
361 autoFocusRef.current = false;
362 }, [
363 scopeRef
364 ]);
365}
366function $9bf71ea28793e738$var$useRestoreFocus(scopeRef, restoreFocus, contain) {
367 // create a ref during render instead of useLayoutEffect so the active element is saved before a child with autoFocus=true mounts.
368 const nodeToRestoreRef = $6nfFC$useRef(typeof document !== 'undefined' ? document.activeElement : null);
369 // restoring scopes should all track if they are active regardless of contain, but contain already tracks it plus logic to contain the focus
370 // restoring-non-containing scopes should only care if they become active so they can perform the restore
371 $6nfFC$useLayoutEffect(()=>{
372 let scope = scopeRef.current;
373 if (!restoreFocus || contain) return;
374 let onFocus = ()=>{
375 // If focusing an element in a child scope of the currently active scope, the child becomes active.
376 // Moving out of the active scope to an ancestor is not allowed.
377 if (!$9bf71ea28793e738$var$activeScope || $9bf71ea28793e738$var$isAncestorScope($9bf71ea28793e738$var$activeScope, scopeRef)) $9bf71ea28793e738$var$activeScope = scopeRef;
378 };
379 document.addEventListener('focusin', onFocus, false);
380 scope.forEach((element)=>element.addEventListener('focusin', onFocus, false)
381 );
382 return ()=>{
383 document.removeEventListener('focusin', onFocus, false);
384 scope.forEach((element)=>element.removeEventListener('focusin', onFocus, false)
385 );
386 };
387 }, [
388 scopeRef,
389 contain
390 ]);
391 // useLayoutEffect instead of useEffect so the active element is saved synchronously instead of asynchronously.
392 $6nfFC$useLayoutEffect(()=>{
393 $9bf71ea28793e738$export$d06fae2ee68b101e.getTreeNode(scopeRef).nodeToRestore = nodeToRestoreRef.current;
394 if (!restoreFocus) return;
395 // Handle the Tab key so that tabbing out of the scope goes to the next element
396 // after the node that had focus when the scope mounted. This is important when
397 // using portals for overlays, so that focus goes to the expected element when
398 // tabbing out of the overlay.
399 let onKeyDown = (e)=>{
400 if (e.key !== 'Tab' || e.altKey || e.ctrlKey || e.metaKey) return;
401 let focusedElement = document.activeElement;
402 if (!$9bf71ea28793e738$var$isElementInScope(focusedElement, scopeRef.current)) return;
403 let nodeToRestore = $9bf71ea28793e738$export$d06fae2ee68b101e.getTreeNode(scopeRef).nodeToRestore;
404 // Create a DOM tree walker that matches all tabbable elements
405 let walker = $9bf71ea28793e738$export$2d6ec8fc375ceafa(document.body, {
406 tabbable: true
407 });
408 // Find the next tabbable element after the currently focused element
409 walker.currentNode = focusedElement;
410 let nextElement = e.shiftKey ? walker.previousNode() : walker.nextNode();
411 if (!document.body.contains(nodeToRestore) || nodeToRestore === document.body) {
412 nodeToRestore = null;
413 $9bf71ea28793e738$export$d06fae2ee68b101e.getTreeNode(scopeRef).nodeToRestore = null;
414 }
415 // If there is no next element, or it is outside the current scope, move focus to the
416 // next element after the node to restore to instead.
417 if ((!nextElement || !$9bf71ea28793e738$var$isElementInScope(nextElement, scopeRef.current)) && nodeToRestore) {
418 walker.currentNode = nodeToRestore;
419 // Skip over elements within the scope, in case the scope immediately follows the node to restore.
420 do nextElement = e.shiftKey ? walker.previousNode() : walker.nextNode();
421 while ($9bf71ea28793e738$var$isElementInScope(nextElement, scopeRef.current))
422 e.preventDefault();
423 e.stopPropagation();
424 if (nextElement) $9bf71ea28793e738$var$focusElement(nextElement, true);
425 else // If there is no next element and the nodeToRestore isn't within a FocusScope (i.e. we are leaving the top level focus scope)
426 // then move focus to the body.
427 // Otherwise restore focus to the nodeToRestore (e.g menu within a popover -> tabbing to close the menu should move focus to menu trigger)
428 if (!$9bf71ea28793e738$var$isElementInAnyScope(nodeToRestore)) focusedElement.blur();
429 else $9bf71ea28793e738$var$focusElement(nodeToRestore, true);
430 }
431 };
432 if (!contain) document.addEventListener('keydown', onKeyDown, true);
433 return ()=>{
434 if (!contain) document.removeEventListener('keydown', onKeyDown, true);
435 let nodeToRestore = $9bf71ea28793e738$export$d06fae2ee68b101e.getTreeNode(scopeRef).nodeToRestore;
436 // if we already lost focus to the body and this was the active scope, then we should attempt to restore
437 if (restoreFocus && nodeToRestore && ($9bf71ea28793e738$var$isElementInScope(document.activeElement, scopeRef.current) || document.activeElement === document.body && $9bf71ea28793e738$var$activeScope === scopeRef)) {
438 // freeze the focusScopeTree so it persists after the raf, otherwise during unmount nodes are removed from it
439 let clonedTree = $9bf71ea28793e738$export$d06fae2ee68b101e.clone();
440 requestAnimationFrame(()=>{
441 // Only restore focus if we've lost focus to the body, the alternative is that focus has been purposefully moved elsewhere
442 if (document.activeElement === document.body) {
443 // look up the tree starting with our scope to find a nodeToRestore still in the DOM
444 let treeNode = clonedTree.getTreeNode(scopeRef);
445 while(treeNode){
446 if (treeNode.nodeToRestore && document.body.contains(treeNode.nodeToRestore)) {
447 $9bf71ea28793e738$var$focusElement(treeNode.nodeToRestore);
448 return;
449 }
450 treeNode = treeNode.parent;
451 }
452 }
453 });
454 }
455 };
456 }, [
457 scopeRef,
458 restoreFocus,
459 contain
460 ]);
461}
462function $9bf71ea28793e738$export$2d6ec8fc375ceafa(root, opts, scope) {
463 let selector = (opts === null || opts === void 0 ? void 0 : opts.tabbable) ? $9bf71ea28793e738$var$TABBABLE_ELEMENT_SELECTOR : $9bf71ea28793e738$var$FOCUSABLE_ELEMENT_SELECTOR;
464 let walker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT, {
465 acceptNode (node) {
466 var ref;
467 // Skip nodes inside the starting node.
468 if (opts === null || opts === void 0 ? void 0 : (ref = opts.from) === null || ref === void 0 ? void 0 : ref.contains(node)) return NodeFilter.FILTER_REJECT;
469 if (node.matches(selector) && $645f2e67b85a24c9$export$e989c0fffaa6b27a(node) && (!scope || $9bf71ea28793e738$var$isElementInScope(node, scope)) && (!(opts === null || opts === void 0 ? void 0 : opts.accept) || opts.accept(node))) return NodeFilter.FILTER_ACCEPT;
470 return NodeFilter.FILTER_SKIP;
471 }
472 });
473 if (opts === null || opts === void 0 ? void 0 : opts.from) walker.currentNode = opts.from;
474 return walker;
475}
476function $9bf71ea28793e738$export$c5251b9e124bf29(ref, defaultOptions = {
477}) {
478 return {
479 focusNext (opts = {
480 }) {
481 let root = ref.current;
482 if (!root) return;
483 let { from: from , tabbable: tabbable = defaultOptions.tabbable , wrap: wrap = defaultOptions.wrap , accept: accept = defaultOptions.accept } = opts;
484 let node = from || document.activeElement;
485 let walker = $9bf71ea28793e738$export$2d6ec8fc375ceafa(root, {
486 tabbable: tabbable,
487 accept: accept
488 });
489 if (root.contains(node)) walker.currentNode = node;
490 let nextNode = walker.nextNode();
491 if (!nextNode && wrap) {
492 walker.currentNode = root;
493 nextNode = walker.nextNode();
494 }
495 if (nextNode) $9bf71ea28793e738$var$focusElement(nextNode, true);
496 return nextNode;
497 },
498 focusPrevious (opts = defaultOptions) {
499 let root = ref.current;
500 if (!root) return;
501 let { from: from , tabbable: tabbable = defaultOptions.tabbable , wrap: wrap = defaultOptions.wrap , accept: accept = defaultOptions.accept } = opts;
502 let node = from || document.activeElement;
503 let walker = $9bf71ea28793e738$export$2d6ec8fc375ceafa(root, {
504 tabbable: tabbable,
505 accept: accept
506 });
507 if (root.contains(node)) walker.currentNode = node;
508 else {
509 let next = $9bf71ea28793e738$var$last(walker);
510 if (next) $9bf71ea28793e738$var$focusElement(next, true);
511 return next;
512 }
513 let previousNode = walker.previousNode();
514 if (!previousNode && wrap) {
515 walker.currentNode = root;
516 previousNode = $9bf71ea28793e738$var$last(walker);
517 }
518 if (previousNode) $9bf71ea28793e738$var$focusElement(previousNode, true);
519 return previousNode;
520 },
521 focusFirst (opts = defaultOptions) {
522 let root = ref.current;
523 if (!root) return;
524 let { tabbable: tabbable = defaultOptions.tabbable , accept: accept = defaultOptions.accept } = opts;
525 let walker = $9bf71ea28793e738$export$2d6ec8fc375ceafa(root, {
526 tabbable: tabbable,
527 accept: accept
528 });
529 let nextNode = walker.nextNode();
530 if (nextNode) $9bf71ea28793e738$var$focusElement(nextNode, true);
531 return nextNode;
532 },
533 focusLast (opts = defaultOptions) {
534 let root = ref.current;
535 if (!root) return;
536 let { tabbable: tabbable = defaultOptions.tabbable , accept: accept = defaultOptions.accept } = opts;
537 let walker = $9bf71ea28793e738$export$2d6ec8fc375ceafa(root, {
538 tabbable: tabbable,
539 accept: accept
540 });
541 let next = $9bf71ea28793e738$var$last(walker);
542 if (next) $9bf71ea28793e738$var$focusElement(next, true);
543 return next;
544 }
545 };
546}
547function $9bf71ea28793e738$var$last(walker) {
548 let next;
549 let last;
550 do {
551 last = walker.lastChild();
552 if (last) next = last;
553 }while (last)
554 return next;
555}
556class $9bf71ea28793e738$var$Tree {
557 get size() {
558 return this.fastMap.size;
559 }
560 getTreeNode(data) {
561 return this.fastMap.get(data);
562 }
563 addTreeNode(scopeRef, parent, nodeToRestore) {
564 let parentNode = this.fastMap.get(parent !== null && parent !== void 0 ? parent : null);
565 let node = new $9bf71ea28793e738$var$TreeNode({
566 scopeRef: scopeRef
567 });
568 parentNode.addChild(node);
569 node.parent = parentNode;
570 this.fastMap.set(scopeRef, node);
571 if (nodeToRestore) node.nodeToRestore = nodeToRestore;
572 }
573 removeTreeNode(scopeRef) {
574 // never remove the root
575 if (scopeRef === null) return;
576 let node = this.fastMap.get(scopeRef);
577 let parentNode = node.parent;
578 // when we remove a scope, check if any sibling scopes are trying to restore focus to something inside the scope we're removing
579 // if we are, then replace the siblings restore with the restore from the scope we're removing
580 for (let current of this.traverse())if (current !== node && node.nodeToRestore && current.nodeToRestore && node.scopeRef.current && $9bf71ea28793e738$var$isElementInScope(current.nodeToRestore, node.scopeRef.current)) current.nodeToRestore = node.nodeToRestore;
581 let children = node.children;
582 parentNode.removeChild(node);
583 if (children.length > 0) children.forEach((child)=>parentNode.addChild(child)
584 );
585 this.fastMap.delete(node.scopeRef);
586 }
587 // Pre Order Depth First
588 *traverse(node = this.root) {
589 if (node.scopeRef != null) yield node;
590 if (node.children.length > 0) for (let child of node.children)yield* this.traverse(child);
591 }
592 clone() {
593 let newTree = new $9bf71ea28793e738$var$Tree();
594 for (let node of this.traverse())newTree.addTreeNode(node.scopeRef, node.parent.scopeRef, node.nodeToRestore);
595 return newTree;
596 }
597 constructor(){
598 this.fastMap = new Map();
599 this.root = new $9bf71ea28793e738$var$TreeNode({
600 scopeRef: null
601 });
602 this.fastMap.set(null, this.root);
603 }
604}
605class $9bf71ea28793e738$var$TreeNode {
606 addChild(node) {
607 this.children.push(node);
608 node.parent = this;
609 }
610 removeChild(node) {
611 this.children.splice(this.children.indexOf(node), 1);
612 node.parent = undefined;
613 }
614 constructor(props){
615 this.children = [];
616 this.contain = false;
617 this.scopeRef = props.scopeRef;
618 }
619}
620let $9bf71ea28793e738$export$d06fae2ee68b101e = new $9bf71ea28793e738$var$Tree();
621
622
623
624
625
626
627
628
629function $f7dceffc5ad7768b$export$4e328f61c538687f(props = {
630}) {
631 let { autoFocus: autoFocus = false , isTextInput: isTextInput , within: within } = props;
632 let state = $6nfFC$useRef({
633 isFocused: false,
634 isFocusVisible: autoFocus || $6nfFC$isFocusVisible()
635 });
636 let [isFocused1, setFocused] = $6nfFC$useState(false);
637 let [isFocusVisibleState, setFocusVisible] = $6nfFC$useState(()=>state.current.isFocused && state.current.isFocusVisible
638 );
639 let updateState = $6nfFC$useCallback(()=>setFocusVisible(state.current.isFocused && state.current.isFocusVisible)
640 , []);
641 let onFocusChange = $6nfFC$useCallback((isFocused)=>{
642 state.current.isFocused = isFocused;
643 setFocused(isFocused);
644 updateState();
645 }, [
646 updateState
647 ]);
648 $6nfFC$useFocusVisibleListener((isFocusVisible)=>{
649 state.current.isFocusVisible = isFocusVisible;
650 updateState();
651 }, [], {
652 isTextInput: isTextInput
653 });
654 let { focusProps: focusProps } = $6nfFC$useFocus({
655 isDisabled: within,
656 onFocusChange: onFocusChange
657 });
658 let { focusWithinProps: focusWithinProps } = $6nfFC$useFocusWithin({
659 isDisabled: !within,
660 onFocusWithinChange: onFocusChange
661 });
662 return {
663 isFocused: isFocused1,
664 isFocusVisible: state.current.isFocused && isFocusVisibleState,
665 focusProps: within ? focusWithinProps : focusProps
666 };
667}
668
669
670function $907718708eab68af$export$1a38b4ad7f578e1d(props) {
671 let { children: children , focusClass: focusClass , focusRingClass: focusRingClass } = props;
672 let { isFocused: isFocused , isFocusVisible: isFocusVisible , focusProps: focusProps } = $f7dceffc5ad7768b$export$4e328f61c538687f(props);
673 let child = $6nfFC$react.Children.only(children);
674 return(/*#__PURE__*/ $6nfFC$react.cloneElement(child, $6nfFC$mergeProps(child.props, {
675 ...focusProps,
676 className: $6nfFC$clsx({
677 [focusClass || '']: isFocused,
678 [focusRingClass || '']: isFocusVisible
679 })
680 })));
681}
682
683
684
685
686
687
688let $e6afbd83fe6ebbd2$var$FocusableContext = /*#__PURE__*/ $6nfFC$react.createContext(null);
689function $e6afbd83fe6ebbd2$var$useFocusableContext(ref) {
690 let context = $6nfFC$useContext($e6afbd83fe6ebbd2$var$FocusableContext) || {
691 };
692 $6nfFC$useSyncRef(context, ref);
693 // eslint-disable-next-line
694 let { ref: _ , ...otherProps } = context;
695 return otherProps;
696}
697/**
698 * Provides DOM props to the nearest focusable child.
699 */ function $e6afbd83fe6ebbd2$var$FocusableProvider(props, ref) {
700 let { children: children , ...otherProps } = props;
701 let context = {
702 ...otherProps,
703 ref: ref
704 };
705 return(/*#__PURE__*/ $6nfFC$react.createElement($e6afbd83fe6ebbd2$var$FocusableContext.Provider, {
706 value: context
707 }, children));
708}
709let $e6afbd83fe6ebbd2$export$13f3202a3e5ddd5 = /*#__PURE__*/ $6nfFC$react.forwardRef($e6afbd83fe6ebbd2$var$FocusableProvider);
710function $e6afbd83fe6ebbd2$export$4c014de7c8940b4c(props, domRef) {
711 let { focusProps: focusProps } = $6nfFC$useFocus(props);
712 let { keyboardProps: keyboardProps } = $6nfFC$useKeyboard(props);
713 let interactions = $6nfFC$mergeProps(focusProps, keyboardProps);
714 let domProps = $e6afbd83fe6ebbd2$var$useFocusableContext(domRef);
715 let interactionProps = props.isDisabled ? {
716 } : domProps;
717 let autoFocusRef = $6nfFC$useRef(props.autoFocus);
718 $6nfFC$useEffect(()=>{
719 if (autoFocusRef.current && domRef.current) $6a99195332edec8b$export$80f3e147d781571c(domRef.current);
720 autoFocusRef.current = false;
721 }, [
722 domRef
723 ]);
724 return {
725 focusableProps: $6nfFC$mergeProps({
726 ...interactions,
727 tabIndex: props.excludeFromTabOrder && !props.isDisabled ? -1 : undefined
728 }, interactionProps)
729 };
730}
731
732
733
734
735
736
737export {$9bf71ea28793e738$export$20e40289641fbbb6 as FocusScope, $9bf71ea28793e738$export$10c5169755ce7bd7 as useFocusManager, $9bf71ea28793e738$export$2d6ec8fc375ceafa as getFocusableTreeWalker, $9bf71ea28793e738$export$c5251b9e124bf29 as createFocusManager, $907718708eab68af$export$1a38b4ad7f578e1d as FocusRing, $e6afbd83fe6ebbd2$export$13f3202a3e5ddd5 as FocusableProvider, $e6afbd83fe6ebbd2$export$4c014de7c8940b4c as useFocusable, $f7dceffc5ad7768b$export$4e328f61c538687f as useFocusRing, $6a99195332edec8b$export$80f3e147d781571c as focusSafely};
738//# sourceMappingURL=module.js.map