@primer/react
Version:
An implementation of GitHub's Primer Design System using React
45 lines (44 loc) • 1.67 kB
JavaScript
import { useCallback, useEffect, useMemo } from "react";
//#region src/hooks/useOnOutsideClick.tsx
const stopPropagation = true;
/**
* Calls all handlers in reverse order
* @param event The MouseEvent generated by the click event.
*/
function handleClick(event) {
if (!event.defaultPrevented) {
for (const handler of Object.values(registry).reverse()) if (handler(event) === stopPropagation || event.defaultPrevented) break;
}
}
const registry = {};
function register(id, handler) {
registry[id] = handler;
}
function deregister(id) {
delete registry[id];
}
let handlerId = 0;
const useOnOutsideClick = ({ containerRef, ignoreClickRefs, onClickOutside }) => {
const id = useMemo(() => handlerId++, []);
const handler = useCallback((event) => {
var _containerRef$current;
if (event instanceof MouseEvent && event.button > 0) return stopPropagation;
if ((_containerRef$current = containerRef.current) !== null && _containerRef$current !== void 0 && _containerRef$current.contains(event.target)) return stopPropagation;
if (ignoreClickRefs && ignoreClickRefs.some(({ current }) => current === null || current === void 0 ? void 0 : current.contains(event.target))) return stopPropagation;
onClickOutside(event);
}, [
containerRef,
ignoreClickRefs,
onClickOutside
]);
useEffect(() => {
if (Object.keys(registry).length === 0) document.addEventListener("mousedown", handleClick, { capture: true });
register(id, handler);
return () => {
deregister(id);
if (Object.keys(registry).length === 0) document.removeEventListener("mousedown", handleClick, { capture: true });
};
}, [id, handler]);
};
//#endregion
export { useOnOutsideClick };