144 lines
7.7 KiB
JavaScript
144 lines
7.7 KiB
JavaScript
define(["require", "exports", "react", "./dom/getWindow", "./keyboard", "./setFocusVisibility"], function (require, exports, React, getWindow_1, keyboard_1, setFocusVisibility_1) {
|
|
"use strict";
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
exports.FocusRects = exports.useFocusRects = exports.FocusRectsContext = void 0;
|
|
var mountCounters = new WeakMap();
|
|
var callbackMap = 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;
|
|
}
|
|
function setCallbackMap(context) {
|
|
var callbacks = callbackMap.get(context);
|
|
if (callbacks) {
|
|
return callbacks;
|
|
}
|
|
var onMouseDown = function (ev) { return _onMouseDown(ev, context.registeredProviders); };
|
|
var onPointerDown = function (ev) { return _onPointerDown(ev, context.registeredProviders); };
|
|
var onKeyDown = function (ev) { return _onKeyDown(ev, context.registeredProviders); };
|
|
var onKeyUp = function (ev) { return _onKeyUp(ev, context.registeredProviders); };
|
|
callbacks = { onMouseDown: onMouseDown, onPointerDown: onPointerDown, onKeyDown: onKeyDown, onKeyUp: onKeyUp };
|
|
callbackMap.set(context, callbacks);
|
|
return callbacks;
|
|
}
|
|
exports.FocusRectsContext = React.createContext(undefined);
|
|
/**
|
|
* Initializes the logic which:
|
|
*
|
|
* 1. Subscribes keydown, keyup, mousedown and pointerdown events. (It will only do it once for the current element of
|
|
* the FocusRectsContext providerRef or once per window if no such element is provided via context, so it's safe to
|
|
* call this method multiple times.)
|
|
* 2. When the user presses triggers a keydown or keyup event via directional keyboard keys, adds the
|
|
* 'ms-Fabric--isFocusVisible' classname to the current element of the FocusRectsContext providerRef or the document
|
|
* body if no such element is provided via context, and removes the 'ms-Fabric-isFocusHidden' classname.
|
|
* 3. When the user triggers a mousedown or pointerdown event, adds the 'ms-Fabric-isFocusHidden' classname to the
|
|
* current element of the FocusRectsContext providerRef or the document body if no such element is provided via
|
|
* context, and 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.
|
|
*/
|
|
function useFocusRects(rootRef) {
|
|
var context = React.useContext(exports.FocusRectsContext);
|
|
React.useEffect(function () {
|
|
var _a, _b, _c, _d;
|
|
var win = (0, getWindow_1.getWindow)(rootRef === null || rootRef === void 0 ? void 0 : rootRef.current);
|
|
if (!win || ((_a = win.FabricConfig) === null || _a === void 0 ? void 0 : _a.disableFocusRects) === true) {
|
|
return undefined;
|
|
}
|
|
var el = win;
|
|
var onMouseDown;
|
|
var onPointerDown;
|
|
var onKeyDown;
|
|
var onKeyUp;
|
|
if (((_b = context === null || context === void 0 ? void 0 : context.providerRef) === null || _b === void 0 ? void 0 : _b.current) &&
|
|
((_d = (_c = context === null || context === void 0 ? void 0 : context.providerRef) === null || _c === void 0 ? void 0 : _c.current) === null || _d === void 0 ? void 0 : _d.addEventListener)) {
|
|
el = context.providerRef.current;
|
|
// The NOINLINE directive tells terser not to move the setCallbackMap implementation into the call site during
|
|
// minification.
|
|
// This prevents the function from capturing additional variables in the closure, which can cause memory leaks.
|
|
var callbacks = /*@__NOINLINE__*/ setCallbackMap(context);
|
|
onMouseDown = callbacks.onMouseDown;
|
|
onPointerDown = callbacks.onPointerDown;
|
|
onKeyDown = callbacks.onKeyDown;
|
|
onKeyUp = callbacks.onKeyUp;
|
|
}
|
|
else {
|
|
onMouseDown = _onMouseDown;
|
|
onPointerDown = _onPointerDown;
|
|
onKeyDown = _onKeyDown;
|
|
onKeyUp = _onKeyUp;
|
|
}
|
|
var count = setMountCounters(el, 1);
|
|
if (count <= 1) {
|
|
el.addEventListener('mousedown', onMouseDown, true);
|
|
el.addEventListener('pointerdown', onPointerDown, true);
|
|
el.addEventListener('keydown', onKeyDown, true);
|
|
el.addEventListener('keyup', onKeyUp, true);
|
|
}
|
|
return function () {
|
|
var _a;
|
|
if (!win || ((_a = win.FabricConfig) === null || _a === void 0 ? void 0 : _a.disableFocusRects) === true) {
|
|
return;
|
|
}
|
|
count = setMountCounters(el, -1);
|
|
if (count === 0) {
|
|
el.removeEventListener('mousedown', onMouseDown, true);
|
|
el.removeEventListener('pointerdown', onPointerDown, true);
|
|
el.removeEventListener('keydown', onKeyDown, true);
|
|
el.removeEventListener('keyup', onKeyUp, true);
|
|
}
|
|
};
|
|
}, [context, rootRef]);
|
|
}
|
|
exports.useFocusRects = useFocusRects;
|
|
/**
|
|
* Function Component wrapper which enables calling `useFocusRects` hook.
|
|
* Renders nothing.
|
|
*/
|
|
var FocusRects = function (props) {
|
|
useFocusRects(props.rootRef);
|
|
return null;
|
|
};
|
|
exports.FocusRects = FocusRects;
|
|
function _onMouseDown(ev, registeredProviders) {
|
|
(0, setFocusVisibility_1.setFocusVisibility)(false, ev.target, registeredProviders);
|
|
}
|
|
function _onPointerDown(ev, registeredProviders) {
|
|
if (ev.pointerType !== 'mouse') {
|
|
(0, setFocusVisibility_1.setFocusVisibility)(false, ev.target, registeredProviders);
|
|
}
|
|
}
|
|
// You need both a keydown and a keyup listener that sets focus visibility to true to handle two distinct scenarios when
|
|
// attaching the listeners and classnames to the provider instead of the document body.
|
|
// If you only have a keydown listener, then the focus rectangles will not show when moving from outside of the provider
|
|
// to inside it. That is why a keyup listener is needed, since it will always trigger after the focus event is fired.
|
|
// If you only have a keyup listener, then the focus rectangles will not show moving between different tabbable elements
|
|
// if the tab key is pressed without being released. That's is why we need a keydown listener, since it will trigger for
|
|
// every element that is being tabbed into.
|
|
// This works because `classList.add` is smart and will not duplicate a classname that already exists on the classList
|
|
// when focus visibility is turned on.
|
|
function _onKeyDown(ev, registeredProviders) {
|
|
// eslint-disable-next-line deprecation/deprecation
|
|
if ((0, keyboard_1.isDirectionalKeyCode)(ev.which)) {
|
|
(0, setFocusVisibility_1.setFocusVisibility)(true, ev.target, registeredProviders);
|
|
}
|
|
}
|
|
function _onKeyUp(ev, registeredProviders) {
|
|
// eslint-disable-next-line deprecation/deprecation
|
|
if ((0, keyboard_1.isDirectionalKeyCode)(ev.which)) {
|
|
(0, setFocusVisibility_1.setFocusVisibility)(true, ev.target, registeredProviders);
|
|
}
|
|
}
|
|
});
|
|
//# sourceMappingURL=useFocusRects.js.map
|