File tree Expand file tree Collapse file tree 5 files changed +138
-8
lines changed
packages/react-interactions/accessibility Expand file tree Collapse file tree 5 files changed +138
-8
lines changed Original file line number Diff line number Diff line change 1+ # FocusControl
2+
3+ ` FocusControl ` is a module that exports a selection of helpful utility functions to be used
4+ in conjunction with the ` ref ` from a React Scope, such as ` TabbableScope ` .
5+ A ref from ` FocusManager ` can also be used instead.
6+
7+ ## Example
8+
9+ ``` jsx
10+ const {
11+ focusFirst ,
12+ focusNext ,
13+ focusPrevious ,
14+ getNextScope ,
15+ getPreviousScope ,
16+ } = FocusControl;
17+
18+ function KeyboardFocusMover (props ) {
19+ const scopeRef = useRef (null );
20+
21+ useEffect (() => {
22+ const scope = scopeRef .current ;
23+
24+ if (scope) {
25+ // Focus the first tabbable DOM node in my children
26+ focusFirst (scope);
27+ // Then focus the next chilkd
28+ focusNext (scope);
29+ }
30+ });
31+
32+ return (
33+ < TabbableScope ref= {scopeRef}>
34+ {props .children }
35+ < / TabbableScope>
36+ );
37+ }
38+ ```
39+
40+ ## FocusControl API
41+
42+ ### ` focusFirst `
43+
44+ Focus the first node that matches the given scope.
45+
46+ ### ` focusNext `
47+
48+ Focus the next sequential node that matchs the given scope.
49+
50+ ### ` focusPrevious `
51+
52+ Focus the previous sequential node that matchs the given scope.
53+
54+ ### ` getNextScope `
55+
56+ Focus the first node that matches the next sibling scope from the given scope.
57+
58+ ### ` getPreviousScope `
59+
60+ Focus the first node that matches the previous sibling scope from the given scope.
Original file line number Diff line number Diff line change 1+ # FocusManager
2+
3+ ` FocusManager ` is a component that is designed to provide basic focus management
4+ control. These are the various props that ` FocusManager ` accepts:
5+
6+ ## Usage
7+
8+ ``` jsx
9+ function MyDialog (props ) {
10+ return (
11+ < FocusManager containFocus= {true } autoFocus= {true }>
12+ < div>
13+ < h2> {props .title }< h2>
14+ < p> {props .text }< / p>
15+ < Button onPress= {... }> Accept< / Button>
16+ < Button onPress= {... }> Close< / Button>
17+ < / div>
18+ < / FocusManager>
19+ )
20+ }
21+ ```
22+
23+ ### ` scope `
24+ ` FocusManager ` accepts a custom ` ReactScope ` . If a custom one is not supplied, ` FocusManager `
25+ will default to using ` TabbableScope ` .
26+
27+ ### ` autoFocus `
28+ When enabled, the first host node that matches the ` FocusManager ` scope will be focused
29+ upon the ` FocusManager ` mounting.
30+
31+ ### ` restoreFocus `
32+ When enabled, the previous host node that was focused as ` FocusManager ` is mounted,
33+ has its focus restored upon ` FocusManager ` unmounting.
34+
35+ ### ` containFocus `
36+ This contains the user focus to only that of ` FocusManager ` s sub-tree. Tabbing or
37+ interacting with nodes outside the sub-tree will restore focus back into the ` FocusManager ` .
38+ This is useful for modals, dialogs, dropdowns and other UI elements that require
39+ a form of user-focus control that is similar to the ` inert ` property on the web.
Original file line number Diff line number Diff line change 1+ # TabbableScope
2+
3+ ` TabbableScope ` is a custom scope implementation that can be used with
4+ ` FocusManager ` , ` FocusList ` , ` FocusTable ` and ` FocusControl ` modules.
5+
6+ ## Usage
7+
8+ ``` jsx
9+ function FocusableNodeCollector (props ) {
10+ const scopeRef = useRef (null );
11+
12+ useEffect (() => {
13+ const scope = scopeRef .current ;
14+
15+ if (scope) {
16+ const tabFocusableNodes = scope .getScopedNodes ();
17+ if (tabFocusableNodes && props .onFocusableNodes ) {
18+ props .onFocusableNodes (tabFocusableNodes);
19+ }
20+ }
21+ });
22+
23+ return (
24+ < TabbableScope ref= {scopeRef}>
25+ {props .children }
26+ < / TabbableScope>
27+ );
28+ }
29+ ```
30+
31+ ## Implementation
32+
33+ ` TabbableScope ` uses the experimental ` React.unstable_createScope ` API. The query
34+ function used for the scope is designed to collect DOM nodes that are tab focusable
35+ to the browser. See the [ implementation] ( ../src/TabbableScope.js#L12-L33 ) here.
Original file line number Diff line number Diff line change @@ -110,7 +110,7 @@ export function focusPrevious(
110110 }
111111}
112112
113- export function getNextController (
113+ export function getNextScope (
114114 scope : ReactScopeMethods ,
115115) : null | ReactScopeMethods {
116116 const allScopes = scope . getChildrenFromRoot ( ) ;
@@ -124,7 +124,7 @@ export function getNextController(
124124 return allScopes [ currentScopeIndex + 1 ] ;
125125}
126126
127- export function getPreviousController (
127+ export function getPreviousScope (
128128 scope : ReactScopeMethods ,
129129) : null | ReactScopeMethods {
130130 const allScopes = scope . getChildrenFromRoot ( ) ;
Original file line number Diff line number Diff line change @@ -301,16 +301,12 @@ describe('FocusManager', () => {
301301 FocusControl . focusPrevious ( firstFocusController ) ;
302302 expect ( document . activeElement ) . toBe ( buttonRef . current ) ;
303303
304- const nextController = FocusControl . getNextController (
305- firstFocusController ,
306- ) ;
304+ const nextController = FocusControl . getNextScope ( firstFocusController ) ;
307305 expect ( nextController ) . toBe ( secondFocusController ) ;
308306 FocusControl . focusFirst ( nextController ) ;
309307 expect ( document . activeElement ) . toBe ( divRef . current ) ;
310308
311- const previousController = FocusControl . getPreviousController (
312- nextController ,
313- ) ;
309+ const previousController = FocusControl . getPreviousScope ( nextController ) ;
314310 expect ( previousController ) . toBe ( firstFocusController ) ;
315311 FocusControl . focusFirst ( previousController ) ;
316312 expect ( document . activeElement ) . toBe ( buttonRef . current ) ;
You can’t perform that action at this time.
0 commit comments