MCPcopy Index your code
hub / github.com/adobe/react-spectrum / FocusScope

Function FocusScope

packages/react-aria/src/focus/FocusScope.tsx:88–209  ·  view source on GitHub ↗
(props: FocusScopeProps)

Source from the content-addressed store, hash-verified

86 * to user events.
87 */
88export function FocusScope(props: FocusScopeProps): JSX.Element {
89 let {children, contain, restoreFocus, autoFocus} = props;
90 let startRef = useRef<HTMLSpanElement>(null);
91 let endRef = useRef<HTMLSpanElement>(null);
92 let scopeRef = useRef<Element[]>([]);
93 let {parentNode} = useContext(FocusContext) || {};
94
95 // Create a tree node here so we can add children to it even before it is added to the tree.
96 let node = useMemo(() => new TreeNode({scopeRef}), [scopeRef]);
97
98 useLayoutEffect(() => {
99 // If a new scope mounts outside the active scope, (e.g. DialogContainer launched from a menu),
100 // use the active scope as the parent instead of the parent from context. Layout effects run bottom
101 // up, so if the parent is not yet added to the tree, don't do this. Only the outer-most FocusScope
102 // that is being added should get the activeScope as its parent.
103 let parent = parentNode || focusScopeTree.root;
104 if (
105 focusScopeTree.getTreeNode(parent.scopeRef) &&
106 activeScope &&
107 !isAncestorScope(activeScope, parent.scopeRef)
108 ) {
109 let activeNode = focusScopeTree.getTreeNode(activeScope);
110 if (activeNode) {
111 parent = activeNode;
112 }
113 }
114
115 // Add the node to the parent, and to the tree.
116 parent.addChild(node);
117 focusScopeTree.addNode(node);
118 }, [node, parentNode]);
119
120 useLayoutEffect(() => {
121 let node = focusScopeTree.getTreeNode(scopeRef);
122 if (node) {
123 node.contain = !!contain;
124 }
125 }, [contain]);
126
127 useLayoutEffect(() => {
128 // Find all rendered nodes between the sentinels and add them to the scope.
129 let node = startRef.current?.nextSibling!;
130 let nodes: Element[] = [];
131 let stopPropagation = e => e.stopPropagation();
132 while (node && node !== endRef.current) {
133 nodes.push(node as Element);
134 // Stop custom restore focus event from propagating to parent focus scopes.
135 node.addEventListener(RESTORE_FOCUS_EVENT, stopPropagation);
136 node = node.nextSibling as Element;
137 }
138
139 scopeRef.current = nodes;
140
141 return () => {
142 for (let node of nodes) {
143 node.removeEventListener(RESTORE_FOCUS_EVENT, stopPropagation);
144 }
145 };

Callers

nothing calls this directly

Calls 15

getActiveElementFunction · 0.90
getOwnerDocumentFunction · 0.90
isAncestorScopeFunction · 0.85
useActiveScopeTrackerFunction · 0.85
useFocusContainmentFunction · 0.85
useRestoreFocusFunction · 0.85
useAutoFocusFunction · 0.85
isElementInScopeFunction · 0.85
getTreeNodeMethod · 0.80
addChildMethod · 0.80
pushMethod · 0.80

Tested by

no test coverage detected