[react-interactions] Add more documentation for a11y components (#16894)
Dominic Gannaway committed
Sep 25, 2019 at 19:01 UTC
7c3bd08b3767ed69ddf398176de58214561194a0
5 files changed
+138
-8
packages/react-interactions/accessibility/docs/FocusControl.md
new
+60
@@ -0,0 +1,60 @@
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.
\ No newline at end of file
packages/react-interactions/accessibility/docs/FocusManager.md
new
+39
@@ -0,0 +1,39 @@
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.
\ No newline at end of file
packages/react-interactions/accessibility/docs/TabbableScope.md
new
+35
@@ -0,0 +1,35 @@
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.
packages/react-interactions/accessibility/src/FocusControl.js
+2
-2
@@ -110,7 +110,7 @@ export function focusPrevious(
110
}
111
}
112
113
-export function getNextController(
113
+export function getNextScope(
114
scope: ReactScopeMethods,
115
): null | ReactScopeMethods {
116
const allScopes = scope.getChildrenFromRoot();
@@ -124,7 +124,7 @@ export function getNextController(
124
return allScopes[currentScopeIndex + 1];
125
}
126
127
-export function getPreviousController(
127
+export function getPreviousScope(
128
scope: ReactScopeMethods,
129
): null | ReactScopeMethods {
130
const allScopes = scope.getChildrenFromRoot();
packages/react-interactions/accessibility/src/__tests__/FocusManager-test.internal.js
+2
-6
@@ -301,16 +301,12 @@ describe('FocusManager', () => {
301
FocusControl.focusPrevious(firstFocusController);
302
expect(document.activeElement).toBe(buttonRef.current);
303
304
- const nextController = FocusControl.getNextController(
305
- firstFocusController,
306
- );
304
+ const nextController = FocusControl.getNextScope(firstFocusController);
305
expect(nextController).toBe(secondFocusController);
306
FocusControl.focusFirst(nextController);
307
expect(document.activeElement).toBe(divRef.current);
308
311
- const previousController = FocusControl.getPreviousController(
312
- nextController,
313
- );
309
+ const previousController = FocusControl.getPreviousScope(nextController);
310
expect(previousController).toBe(firstFocusController);
311
FocusControl.focusFirst(previousController);
312
expect(document.activeElement).toBe(buttonRef.current);