@samitouri / QOS-React-2 / commits / 7c3bd08b37

[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);