UNPKG

3.24 kBJavaScriptView Raw
1import * as React from 'react';
2import { getWindow } from './dom/getWindow';
3import { isDirectionalKeyCode } from './keyboard';
4import { setFocusVisibility } from './setFocusVisibility';
5/**
6 * Counter for mounted component that uses focus rectangle.
7 * We want to cleanup the listners before last component that uses focus rectangle unmounts.
8 */
9var mountCounters = new WeakMap();
10function setMountCounters(key, delta) {
11 var newValue;
12 var currValue = mountCounters.get(key);
13 if (currValue) {
14 newValue = currValue + delta;
15 }
16 else {
17 newValue = 1;
18 }
19 mountCounters.set(key, newValue);
20 return newValue;
21}
22/**
23 * Initializes the logic which:
24 *
25 * 1. Subscribes keydown and mousedown events. (It will only do it once per window,
26 * so it's safe to call this method multiple times.)
27 * 2. When the user presses directional keyboard keys, adds the 'ms-Fabric--isFocusVisible' classname
28 * to the document body, removes the 'ms-Fabric-isFocusHidden' classname.
29 * 3. When the user clicks a mouse button, adds the 'ms-Fabric-isFocusHidden' classname to the
30 * document body, removes the 'ms-Fabric--isFocusVisible' classname.
31 *
32 * This logic allows components on the page to conditionally render focus treatments based on
33 * the existence of global classnames, which simplifies logic overall.
34 *
35 * @param rootRef - A Ref object. Focus rectangle can be applied on itself and all its children.
36 */
37export function useFocusRects(rootRef) {
38 React.useEffect(function () {
39 var _a, _b;
40 var win = getWindow((_a = rootRef) === null || _a === void 0 ? void 0 : _a.current);
41 if (!win || ((_b = win.FabricConfig) === null || _b === void 0 ? void 0 : _b.disableFocusRects) === true) {
42 return undefined;
43 }
44 var count = setMountCounters(win, 1);
45 if (count <= 1) {
46 win.addEventListener('mousedown', _onMouseDown, true);
47 win.addEventListener('pointerdown', _onPointerDown, true);
48 win.addEventListener('keydown', _onKeyDown, true);
49 }
50 return function () {
51 var _a;
52 if (!win || ((_a = win.FabricConfig) === null || _a === void 0 ? void 0 : _a.disableFocusRects) === true) {
53 return;
54 }
55 count = setMountCounters(win, -1);
56 if (count === 0) {
57 win.removeEventListener('mousedown', _onMouseDown, true);
58 win.removeEventListener('pointerdown', _onPointerDown, true);
59 win.removeEventListener('keydown', _onKeyDown, true);
60 }
61 };
62 }, [rootRef]);
63}
64/**
65 * Function Component wrapper which enables calling `useFocusRects` hook.
66 * Renders nothing.
67 */
68export var FocusRects = function (props) {
69 useFocusRects(props.rootRef);
70 return null;
71};
72function _onMouseDown(ev) {
73 setFocusVisibility(false, ev.target);
74}
75function _onPointerDown(ev) {
76 if (ev.pointerType !== 'mouse') {
77 setFocusVisibility(false, ev.target);
78 }
79}
80function _onKeyDown(ev) {
81 // eslint-disable-next-line deprecation/deprecation
82 if (isDirectionalKeyCode(ev.which)) {
83 setFocusVisibility(true, ev.target);
84 }
85}
86//# sourceMappingURL=useFocusRects.js.map
\No newline at end of file