UNPKG

3.88 kBJavaScriptView Raw
1"use strict";
2
3var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
5exports.__esModule = true;
6exports["default"] = void 0;
7
8var _contains = _interopRequireDefault(require("dom-helpers/contains"));
9
10var _listen = _interopRequireDefault(require("dom-helpers/listen"));
11
12var _react = require("react");
13
14var _useEventCallback = _interopRequireDefault(require("@restart/hooks/useEventCallback"));
15
16var _warning = _interopRequireDefault(require("warning"));
17
18var _ownerDocument = _interopRequireDefault(require("./ownerDocument"));
19
20var escapeKeyCode = 27;
21
22var noop = function noop() {};
23
24function isLeftClickEvent(event) {
25 return event.button === 0;
26}
27
28function isModifiedEvent(event) {
29 return !!(event.metaKey || event.altKey || event.ctrlKey || event.shiftKey);
30}
31
32var getRefTarget = function getRefTarget(ref) {
33 return ref && ('current' in ref ? ref.current : ref);
34};
35
36/**
37 * The `useRootClose` hook registers your callback on the document
38 * when rendered. Powers the `<Overlay/>` component. This is used achieve modal
39 * style behavior where your callback is triggered when the user tries to
40 * interact with the rest of the document or hits the `esc` key.
41 *
42 * @param {Ref<HTMLElement>| HTMLElement} ref The element boundary
43 * @param {function} onRootClose
44 * @param {object=} options
45 * @param {boolean=} options.disabled
46 * @param {string=} options.clickTrigger The DOM event name (click, mousedown, etc) to attach listeners on
47 */
48function useRootClose(ref, onRootClose, _temp) {
49 var _ref = _temp === void 0 ? {} : _temp,
50 disabled = _ref.disabled,
51 _ref$clickTrigger = _ref.clickTrigger,
52 clickTrigger = _ref$clickTrigger === void 0 ? 'click' : _ref$clickTrigger;
53
54 var preventMouseRootCloseRef = (0, _react.useRef)(false);
55 var onClose = onRootClose || noop;
56 var handleMouseCapture = (0, _react.useCallback)(function (e) {
57 var currentTarget = getRefTarget(ref);
58 (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');
59 preventMouseRootCloseRef.current = !currentTarget || isModifiedEvent(e) || !isLeftClickEvent(e) || !!(0, _contains["default"])(currentTarget, e.target);
60 }, [ref]);
61 var handleMouse = (0, _useEventCallback["default"])(function (e) {
62 if (!preventMouseRootCloseRef.current) {
63 onClose(e);
64 }
65 });
66 var handleKeyUp = (0, _useEventCallback["default"])(function (e) {
67 if (e.keyCode === escapeKeyCode) {
68 onClose(e);
69 }
70 });
71 (0, _react.useEffect)(function () {
72 if (disabled || ref == null) return undefined;
73 var doc = (0, _ownerDocument["default"])(getRefTarget(ref)); // Use capture for this listener so it fires before React's listener, to
74 // avoid false positives in the contains() check below if the target DOM
75 // element is removed in the React mouse callback.
76
77 var removeMouseCaptureListener = (0, _listen["default"])(doc, clickTrigger, handleMouseCapture, true);
78 var removeMouseListener = (0, _listen["default"])(doc, clickTrigger, handleMouse);
79 var removeKeyupListener = (0, _listen["default"])(doc, 'keyup', handleKeyUp);
80 var mobileSafariHackListeners = [];
81
82 if ('ontouchstart' in doc.documentElement) {
83 mobileSafariHackListeners = [].slice.call(doc.body.children).map(function (el) {
84 return (0, _listen["default"])(el, 'mousemove', noop);
85 });
86 }
87
88 return function () {
89 removeMouseCaptureListener();
90 removeMouseListener();
91 removeKeyupListener();
92 mobileSafariHackListeners.forEach(function (remove) {
93 return remove();
94 });
95 };
96 }, [ref, disabled, clickTrigger, handleMouseCapture, handleMouse, handleKeyUp]);
97}
98
99var _default = useRootClose;
100exports["default"] = _default;
101module.exports = exports.default;
\No newline at end of file