@uifabric/utilities
Version:
Fluent UI React utilities for building components.
86 lines • 3.24 kB
JavaScript
import * as React from 'react';
import { getWindow } from './dom/getWindow';
import { isDirectionalKeyCode } from './keyboard';
import { setFocusVisibility } from './setFocusVisibility';
/**
* Counter for mounted component that uses focus rectangle.
* We want to cleanup the listners before last component that uses focus rectangle unmounts.
*/
var mountCounters = new WeakMap();
function setMountCounters(key, delta) {
var newValue;
var currValue = mountCounters.get(key);
if (currValue) {
newValue = currValue + delta;
}
else {
newValue = 1;
}
mountCounters.set(key, newValue);
return newValue;
}
/**
* Initializes the logic which:
*
* 1. Subscribes keydown and mousedown events. (It will only do it once per window,
* so it's safe to call this method multiple times.)
* 2. When the user presses directional keyboard keys, adds the 'ms-Fabric--isFocusVisible' classname
* to the document body, removes the 'ms-Fabric-isFocusHidden' classname.
* 3. When the user clicks a mouse button, adds the 'ms-Fabric-isFocusHidden' classname to the
* document body, removes the 'ms-Fabric--isFocusVisible' classname.
*
* This logic allows components on the page to conditionally render focus treatments based on
* the existence of global classnames, which simplifies logic overall.
*
* @param rootRef - A Ref object. Focus rectangle can be applied on itself and all its children.
*/
export function useFocusRects(rootRef) {
React.useEffect(function () {
var _a, _b;
var win = getWindow((_a = rootRef) === null || _a === void 0 ? void 0 : _a.current);
if (!win || ((_b = win.FabricConfig) === null || _b === void 0 ? void 0 : _b.disableFocusRects) === true) {
return undefined;
}
var count = setMountCounters(win, 1);
if (count <= 1) {
win.addEventListener('mousedown', _onMouseDown, true);
win.addEventListener('pointerdown', _onPointerDown, true);
win.addEventListener('keydown', _onKeyDown, true);
}
return function () {
var _a;
if (!win || ((_a = win.FabricConfig) === null || _a === void 0 ? void 0 : _a.disableFocusRects) === true) {
return;
}
count = setMountCounters(win, -1);
if (count === 0) {
win.removeEventListener('mousedown', _onMouseDown, true);
win.removeEventListener('pointerdown', _onPointerDown, true);
win.removeEventListener('keydown', _onKeyDown, true);
}
};
}, [rootRef]);
}
/**
* Function Component wrapper which enables calling `useFocusRects` hook.
* Renders nothing.
*/
export var FocusRects = function (props) {
useFocusRects(props.rootRef);
return null;
};
function _onMouseDown(ev) {
setFocusVisibility(false, ev.target);
}
function _onPointerDown(ev) {
if (ev.pointerType !== 'mouse') {
setFocusVisibility(false, ev.target);
}
}
function _onKeyDown(ev) {
// eslint-disable-next-line deprecation/deprecation
if (isDirectionalKeyCode(ev.which)) {
setFocusVisibility(true, ev.target);
}
}
//# sourceMappingURL=useFocusRects.js.map