@navikt/ds-react
Version:
React components from the Norwegian Labour and Welfare Administration.
45 lines • 2.27 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.useFocusOutside = useFocusOutside;
const react_1 = require("react");
const hooks_1 = require("../../../util/hooks");
const dispatchCustomEvent_1 = require("./dispatchCustomEvent");
/**
* Tracks focus outside a React subtree. Returns props for the subtree root.
*/
function useFocusOutside(callback, ownerDocument = globalThis === null || globalThis === void 0 ? void 0 : globalThis.document) {
const handleFocusOutside = (0, hooks_1.useCallbackRef)(callback);
const isFocusInsideReactTreeRef = (0, react_1.useRef)(false);
(0, react_1.useEffect)(() => {
const handleFocus = (event) => {
if (event.target && !isFocusInsideReactTreeRef.current) {
const eventDetail = { originalEvent: event };
/**
* The `DismisableLayer`-API is based on the ability to stop events from propagating and in the end calling `onDismiss`
* if `useFocusOutside`-callback runs `event.preventDefault()`.
*
* Because of the `focusin`-event not being cancelable,
* we need to use a custom event to ensure that the event is cancelable.
* https://developer.mozilla.org/en-US/docs/Web/API/Element/focusin_event
* > The focusin event is not cancelable.
*/
(0, dispatchCustomEvent_1.dispatchCustomEvent)(dispatchCustomEvent_1.CUSTOM_EVENTS.FOCUS_OUTSIDE, handleFocusOutside, eventDetail);
}
};
ownerDocument.addEventListener("focusin", handleFocus);
return () => ownerDocument.removeEventListener("focusin", handleFocus);
}, [ownerDocument, handleFocusOutside]);
/**
* By directly setting isFocusInsideReactTreeRef on focus-events at the root of the "dismissable" element,
* we can eliminate the need for DOM traversal to verify if the focused element is within the react tree.
*/
return {
onFocusCapture: () => {
isFocusInsideReactTreeRef.current = true;
},
onBlurCapture: () => {
isFocusInsideReactTreeRef.current = false;
},
};
}
//# sourceMappingURL=useFocusOutside.js.map
;