UNPKG

@material-ui/core

Version:

React components that implement Google's Material Design.

159 lines (119 loc) 4.79 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _react = _interopRequireDefault(require("react")); var _reactDom = _interopRequireDefault(require("react-dom")); var _propTypes = _interopRequireDefault(require("prop-types")); var _ownerDocument = _interopRequireDefault(require("../utils/ownerDocument")); var _reactHelpers = require("../utils/reactHelpers"); var _useEventCallback = _interopRequireDefault(require("../utils/useEventCallback")); var _utils = require("@material-ui/utils"); function useMountedRef() { var mountedRef = _react.default.useRef(false); _react.default.useEffect(function () { mountedRef.current = true; return function () { mountedRef.current = false; }; }, []); return mountedRef; } function mapEventPropToEvent(eventProp) { return eventProp.substring(2).toLowerCase(); } /** * Listen for click events that occur somewhere in the document, outside of the element itself. * For instance, if you need to hide a menu when people click anywhere else on your page. */ function ClickAwayListener(props) { var children = props.children, _props$mouseEvent = props.mouseEvent, mouseEvent = _props$mouseEvent === void 0 ? 'onClick' : _props$mouseEvent, _props$touchEvent = props.touchEvent, touchEvent = _props$touchEvent === void 0 ? 'onTouchEnd' : _props$touchEvent, onClickAway = props.onClickAway; var mountedRef = useMountedRef(); var movedRef = _react.default.useRef(false); var nodeRef = _react.default.useRef(null); // can be removed once we drop support for non ref forwarding class components var handleOwnRef = _react.default.useCallback(function (instance) { // #StrictMode ready nodeRef.current = _reactDom.default.findDOMNode(instance); }, []); var handleRef = (0, _reactHelpers.useForkRef)(children.ref, handleOwnRef); var handleClickAway = (0, _useEventCallback.default)(function (event) { // Ignore events that have been `event.preventDefault()` marked. if (event.defaultPrevented) { return; } // IE 11 support, which trigger the handleClickAway even after the unbind if (!mountedRef.current) { return; } // Do not act if user performed touchmove if (movedRef.current) { movedRef.current = false; return; } var node = nodeRef.current; // The child might render null. if (!node) { return; } var doc = (0, _ownerDocument.default)(node); if (doc.documentElement && doc.documentElement.contains(event.target) && !node.contains(event.target)) { onClickAway(event); } }); var handleTouchMove = _react.default.useCallback(function () { movedRef.current = true; }, []); _react.default.useEffect(function () { if (touchEvent !== false) { var mappedTouchEvent = mapEventPropToEvent(touchEvent); document.addEventListener(mappedTouchEvent, handleClickAway); document.addEventListener('touchmove', handleTouchMove); return function () { document.removeEventListener(mappedTouchEvent, handleClickAway); document.removeEventListener('touchmove', handleTouchMove); }; } return undefined; }, [handleClickAway, handleTouchMove, touchEvent]); _react.default.useEffect(function () { if (mouseEvent !== false) { var mappedMouseEvent = mapEventPropToEvent(mouseEvent); document.addEventListener(mappedMouseEvent, handleClickAway); return function () { document.removeEventListener(mappedMouseEvent, handleClickAway); }; } return undefined; }, [handleClickAway, mouseEvent]); return _react.default.createElement(_react.default.Fragment, null, _react.default.cloneElement(children, { ref: handleRef })); } process.env.NODE_ENV !== "production" ? ClickAwayListener.propTypes = { /** * The wrapped element. */ children: _utils.elementAcceptingRef.isRequired, /** * The mouse event to listen to. You can disable the listener by providing `false`. */ mouseEvent: _propTypes.default.oneOf(['onClick', 'onMouseDown', 'onMouseUp', false]), /** * Callback fired when a "click away" event is detected. */ onClickAway: _propTypes.default.func.isRequired, /** * The touch event to listen to. You can disable the listener by providing `false`. */ touchEvent: _propTypes.default.oneOf(['onTouchStart', 'onTouchEnd', false]) } : void 0; if (process.env.NODE_ENV !== 'production') { // eslint-disable-next-line ClickAwayListener['propTypes' + ''] = (0, _utils.exactProp)(ClickAwayListener.propTypes); } var _default = ClickAwayListener; exports.default = _default;