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