UNPKG

4.46 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; // Store the current event to avoid triggering handlers immediately
73 // https://github.com/facebook/react/issues/20074
74
75 var currentEvent = window.event;
76 var doc = (0, _ownerDocument["default"])(getRefTarget(ref)); // Use capture for this listener so it fires before React's listener, to
77 // avoid false positives in the contains() check below if the target DOM
78 // element is removed in the React mouse callback.
79
80 var removeMouseCaptureListener = (0, _listen["default"])(doc, clickTrigger, handleMouseCapture, true);
81 var removeMouseListener = (0, _listen["default"])(doc, clickTrigger, function (e) {
82 // skip if this event is the same as the one running when we added the handlers
83 if (e === currentEvent) {
84 currentEvent = undefined;
85 return;
86 }
87
88 handleMouse(e);
89 });
90 var removeKeyupListener = (0, _listen["default"])(doc, 'keyup', function (e) {
91 // skip if this event is the same as the one running when we added the handlers
92 if (e === currentEvent) {
93 currentEvent = undefined;
94 return;
95 }
96
97 handleKeyUp(e);
98 });
99 var mobileSafariHackListeners = [];
100
101 if ('ontouchstart' in doc.documentElement) {
102 mobileSafariHackListeners = [].slice.call(doc.body.children).map(function (el) {
103 return (0, _listen["default"])(el, 'mousemove', noop);
104 });
105 }
106
107 return function () {
108 removeMouseCaptureListener();
109 removeMouseListener();
110 removeKeyupListener();
111 mobileSafariHackListeners.forEach(function (remove) {
112 return remove();
113 });
114 };
115 }, [ref, disabled, clickTrigger, handleMouseCapture, handleMouse, handleKeyUp]);
116}
117
118var _default = useRootClose;
119exports["default"] = _default;
120module.exports = exports.default;
\No newline at end of file