@primer/react
Version:
An implementation of GitHub's Primer Design System using React
78 lines (70 loc) • 2.37 kB
JavaScript
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;
;