UNPKG

@primer/react

Version:

An implementation of GitHub's Primer Design System using React

78 lines (70 loc) 2.37 kB
'use strict'; var React = require('react'); // Because events are handled at the document level, we provide a mechanism for early return. 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()) { // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition if (handler(event) === stopPropagation || event.defaultPrevented) { break; } } } } const registry = {}; function register(id, handler) { registry[id] = handler; } function deregister(id) { delete registry[id]; } // For auto-incrementing unique identifiers for registered handlers. let handlerId = 0; const useOnOutsideClick = ({ containerRef, ignoreClickRefs, onClickOutside }) => { const id = React.useMemo(() => handlerId++, []); const handler = React.useCallback(event => { var _containerRef$current; // don't call click handler if the mouse event was triggered by an auxiliary button (right click/wheel button/etc) if (event instanceof MouseEvent && event.button > 0) { return stopPropagation; } // don't call handler if the click happened inside of the container if ((_containerRef$current = containerRef.current) !== null && _containerRef$current !== void 0 && _containerRef$current.contains(event.target)) { return stopPropagation; } // don't call handler if click happened on an ignored ref if (ignoreClickRefs && ignoreClickRefs.some(({ current }) => current === null || current === void 0 ? void 0 : current.contains(event.target))) { return stopPropagation; } onClickOutside(event); }, [containerRef, ignoreClickRefs, onClickOutside]); React.useEffect(() => { if (Object.keys(registry).length === 0) { // use capture to ensure we get all events 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]); }; exports.useOnOutsideClick = useOnOutsideClick;