"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); exports.__esModule = true; exports["default"] = void 0; var _contains = _interopRequireDefault(require("dom-helpers/contains")); var _listen = _interopRequireDefault(require("dom-helpers/listen")); var _react = require("react"); var _useEventCallback = _interopRequireDefault(require("@restart/hooks/useEventCallback")); var _warning = _interopRequireDefault(require("warning")); var _ownerDocument = _interopRequireDefault(require("./ownerDocument")); var escapeKeyCode = 27; var noop = function noop() {}; function isLeftClickEvent(event) { return event.button === 0; } function isModifiedEvent(event) { return !!(event.metaKey || event.altKey || event.ctrlKey || event.shiftKey); } var getRefTarget = function getRefTarget(ref) { return ref && ('current' in ref ? ref.current : ref); }; /** * The `useRootClose` hook registers your callback on the document * when rendered. Powers the `` component. This is used achieve modal * style behavior where your callback is triggered when the user tries to * interact with the rest of the document or hits the `esc` key. * * @param {Ref| HTMLElement} ref The element boundary * @param {function} onRootClose * @param {object=} options * @param {boolean=} options.disabled * @param {string=} options.clickTrigger The DOM event name (click, mousedown, etc) to attach listeners on */ function useRootClose(ref, onRootClose, _temp) { var _ref = _temp === void 0 ? {} : _temp, disabled = _ref.disabled, _ref$clickTrigger = _ref.clickTrigger, clickTrigger = _ref$clickTrigger === void 0 ? 'click' : _ref$clickTrigger; var preventMouseRootCloseRef = (0, _react.useRef)(false); var onClose = onRootClose || noop; var handleMouseCapture = (0, _react.useCallback)(function (e) { var currentTarget = getRefTarget(ref); (0, _warning["default"])(!!currentTarget, 'RootClose captured a close event but does not have a ref to compare it to. ' + 'useRootClose(), should be passed a ref that resolves to a DOM node'); preventMouseRootCloseRef.current = !currentTarget || isModifiedEvent(e) || !isLeftClickEvent(e) || !!(0, _contains["default"])(currentTarget, e.target); }, [ref]); var handleMouse = (0, _useEventCallback["default"])(function (e) { if (!preventMouseRootCloseRef.current) { onClose(e); } }); var handleKeyUp = (0, _useEventCallback["default"])(function (e) { if (e.keyCode === escapeKeyCode) { onClose(e); } }); (0, _react.useEffect)(function () { if (disabled || ref == null) return undefined; // Store the current event to avoid triggering handlers immediately // https://github.com/facebook/react/issues/20074 var currentEvent = window.event; var doc = (0, _ownerDocument["default"])(getRefTarget(ref)); // Use capture for this listener so it fires before React's listener, to // avoid false positives in the contains() check below if the target DOM // element is removed in the React mouse callback. var removeMouseCaptureListener = (0, _listen["default"])(doc, clickTrigger, handleMouseCapture, true); var removeMouseListener = (0, _listen["default"])(doc, clickTrigger, function (e) { // skip if this event is the same as the one running when we added the handlers if (e === currentEvent) { currentEvent = undefined; return; } handleMouse(e); }); var removeKeyupListener = (0, _listen["default"])(doc, 'keyup', function (e) { // skip if this event is the same as the one running when we added the handlers if (e === currentEvent) { currentEvent = undefined; return; } handleKeyUp(e); }); var mobileSafariHackListeners = []; if ('ontouchstart' in doc.documentElement) { mobileSafariHackListeners = [].slice.call(doc.body.children).map(function (el) { return (0, _listen["default"])(el, 'mousemove', noop); }); } return function () { removeMouseCaptureListener(); removeMouseListener(); removeKeyupListener(); mobileSafariHackListeners.forEach(function (remove) { return remove(); }); }; }, [ref, disabled, clickTrigger, handleMouseCapture, handleMouse, handleKeyUp]); } var _default = useRootClose; exports["default"] = _default; module.exports = exports.default;