UNPKG

click-away-listener

Version:

A React component and hook library for detecting clicks outside an element, compatible with React 18 and Next.js

87 lines 4.05 kB
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) { if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { if (ar || !(i in from)) { if (!ar) ar = Array.prototype.slice.call(from, 0, i); ar[i] = from[i]; } } return to.concat(ar || Array.prototype.slice.call(from)); }; import { useEffect, useRef, useCallback } from 'react'; import { isMouseEvent, isTouchEvent, isFocusEvent, isKeyboardEvent, isInExcluded, getEventGroup } from './utils'; export var useClickAway = function (ref, onClickAway, options) { if (options === void 0) { options = {}; } var _a = options.disabled, disabled = _a === void 0 ? false : _a, _b = options.eventConfig, eventConfig = _b === void 0 ? { mouseEvents: ['mousedown'], touchEvents: ['touchstart'] } : _b, _c = options.excludeRefs, excludeRefs = _c === void 0 ? [] : _c, _d = options.debounceTimeout, debounceTimeout = _d === void 0 ? 0 : _d, _e = options.clickTolerance, clickTolerance = _e === void 0 ? 5 : _e, _f = options.testMode, testMode = _f === void 0 ? false : _f; var mountedRef = useRef(false); var timerRef = useRef(); var coordsRef = useRef(null); var handleEvent = useCallback(function (event) { var _a; if (!mountedRef.current || disabled) return; var target = event.target; var eventGroup = getEventGroup(event); if (!target || !document.contains(target)) return; if (((_a = ref.current) === null || _a === void 0 ? void 0 : _a.contains(target)) || isInExcluded(target, excludeRefs)) { return; } if (isMouseEvent(event) && clickTolerance > 0) { var clientX = event.clientX, clientY = event.clientY; if (coordsRef.current) { var distance = Math.sqrt(Math.pow(clientX - coordsRef.current.x, 2) + Math.pow(clientY - coordsRef.current.y, 2)); if (distance > clickTolerance) return; } coordsRef.current = { x: clientX, y: clientY }; } var handler = function () { if (eventGroup === 'mouse' && isMouseEvent(event)) { onClickAway(event); } else if (eventGroup === 'touch' && isTouchEvent(event)) { onClickAway(event); } else if (eventGroup === 'focus' && isFocusEvent(event)) { onClickAway(event); } else if (eventGroup === 'keyboard' && isKeyboardEvent(event)) { onClickAway(event); } }; if (debounceTimeout > 0) { if (timerRef.current) { window.clearTimeout(timerRef.current); } timerRef.current = window.setTimeout(handler, debounceTimeout); } else { handler(); } }, [ref, disabled, excludeRefs, onClickAway, clickTolerance, debounceTimeout]); useEffect(function () { mountedRef.current = true; return function () { mountedRef.current = false; if (timerRef.current) { window.clearTimeout(timerRef.current); } }; }, []); useEffect(function () { if (testMode || disabled) return; var events = __spreadArray(__spreadArray(__spreadArray(__spreadArray([], (eventConfig.mouseEvents || []), true), (eventConfig.touchEvents || []), true), (eventConfig.focusEvents || []), true), (eventConfig.keyboardEvents || []), true); var options = { capture: true }; events.forEach(function (event) { document.addEventListener(event, handleEvent, options); }); return function () { events.forEach(function (event) { document.removeEventListener(event, handleEvent, options); }); }; }, [eventConfig, handleEvent, disabled, testMode]); }; //# sourceMappingURL=useClickAway.js.map