UNPKG

@material-ui/lab

Version:
244 lines (205 loc) 8.92 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends")); var React = _interopRequireWildcard(require("react")); var _Grow = _interopRequireDefault(require("@material-ui/core/Grow")); var _Paper = _interopRequireDefault(require("@material-ui/core/Paper")); var _Popper = _interopRequireDefault(require("@material-ui/core/Popper")); var _Unstable_TrapFocus = _interopRequireDefault(require("@material-ui/core/Unstable_TrapFocus")); var _utils = require("@material-ui/core/utils"); var _styles = require("@material-ui/core/styles"); var _jsxRuntime = require("react/jsx-runtime"); function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); } function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; } const PickersPopperRoot = (0, _styles.styled)(_Popper.default, { skipSx: true })(({ theme }) => ({ zIndex: theme.zIndex.modal })); const PickersPopperPaper = (0, _styles.styled)(_Paper.default, { skipSx: true })(({ styleProps }) => (0, _extends2.default)({ transformOrigin: 'top center', outline: 0 }, styleProps.placement === 'top' && { transformOrigin: 'bottom center' })); function clickedRootScrollbar(event, doc) { return doc.documentElement.clientWidth < event.clientX || doc.documentElement.clientHeight < event.clientY; } /** * Based on @material-ui/core/ClickAwayListener without the customization. * We can probably strip away even more since children won't be portaled. * @param onClickAway * @param onClick * @param onTouchStart */ function useClickAwayListener(active, onClickAway) { const movedRef = React.useRef(false); const syntheticEventRef = React.useRef(false); const nodeRef = React.useRef(null); const activatedRef = React.useRef(false); React.useEffect(() => { if (!active) { return undefined; } // Ensure that this hook is not "activated" synchronously. // https://github.com/facebook/react/issues/20074 function armClickAwayListener() { activatedRef.current = true; } document.addEventListener('mousedown', armClickAwayListener, true); document.addEventListener('touchstart', armClickAwayListener, true); return () => { document.removeEventListener('mousedown', armClickAwayListener, true); document.removeEventListener('touchstart', armClickAwayListener, true); activatedRef.current = false; }; }, [active]); // The handler doesn't take event.defaultPrevented into account: // // event.preventDefault() is meant to stop default behaviors like // clicking a checkbox to check it, hitting a button to submit a form, // and hitting left arrow to move the cursor in a text input etc. // Only special HTML elements have these default behaviors. const handleClickAway = (0, _utils.useEventCallback)(event => { if (!activatedRef.current) { return; } // Given developers can stop the propagation of the synthetic event, // we can only be confident with a positive value. const insideReactTree = syntheticEventRef.current; syntheticEventRef.current = false; const doc = (0, _utils.ownerDocument)(nodeRef.current); // 1. IE11 support, which trigger the handleClickAway even after the unbind // 2. The child might render null. // 3. Behave like a blur listener. if (!nodeRef.current || 'clientX' in event && clickedRootScrollbar(event, doc)) { return; } // Do not act if user performed touchmove if (movedRef.current) { movedRef.current = false; return; } let insideDOM; // If not enough, can use https://github.com/DieterHolvoet/event-propagation-path/blob/master/propagationPath.js if (event.composedPath) { insideDOM = event.composedPath().indexOf(nodeRef.current) > -1; } else { insideDOM = !doc.documentElement.contains(event.target) || nodeRef.current.contains(event.target); } if (!insideDOM && !insideReactTree) { onClickAway(event); } }); // Keep track of mouse/touch events that bubbled up through the portal. const handleSynthetic = () => { syntheticEventRef.current = true; }; React.useEffect(() => { if (active) { const doc = (0, _utils.ownerDocument)(nodeRef.current); const handleTouchMove = () => { movedRef.current = true; }; doc.addEventListener('touchstart', handleClickAway); doc.addEventListener('touchmove', handleTouchMove); return () => { doc.removeEventListener('touchstart', handleClickAway); doc.removeEventListener('touchmove', handleTouchMove); }; } return undefined; }, [active, handleClickAway]); React.useEffect(() => { // TODO This behavior is not tested automatically // It's unclear whether this is due to different update semantics in test (batched in act() vs discrete on click). // Or if this is a timing related issues due to different Transition components // Once we get rid of all the manual scheduling (e.g. setTimeout(update, 0)) we can revisit this code+test. if (active) { const doc = (0, _utils.ownerDocument)(nodeRef.current); doc.addEventListener('click', handleClickAway); return () => { doc.removeEventListener('click', handleClickAway); }; } return undefined; }, [active, handleClickAway]); return [nodeRef, handleSynthetic, handleSynthetic]; } const PickersPopper = props => { const { anchorEl, children, containerRef = null, onClose, open, PopperProps, role, TransitionComponent = _Grow.default, TrapFocusProps } = props; React.useEffect(() => { function handleKeyDown(nativeEvent) { // IE11, Edge (prior to using Bink?) use 'Esc' if (nativeEvent.key === 'Escape' || nativeEvent.key === 'Esc') { onClose(); } } document.addEventListener('keydown', handleKeyDown); return () => { document.removeEventListener('keydown', handleKeyDown); }; }, [onClose]); const lastFocusedElementRef = React.useRef(null); React.useEffect(() => { if (role === 'tooltip') { return; } if (open) { lastFocusedElementRef.current = document.activeElement; } else if (lastFocusedElementRef.current && lastFocusedElementRef.current instanceof HTMLElement) { lastFocusedElementRef.current.focus(); } }, [open, role]); const [clickAwayRef, onPaperClick, onPaperTouchStart] = useClickAwayListener(open, onClose); const paperRef = React.useRef(null); const handleRef = (0, _utils.useForkRef)(paperRef, containerRef); const handlePaperRef = (0, _utils.useForkRef)(handleRef, clickAwayRef); const styleProps = props; return /*#__PURE__*/(0, _jsxRuntime.jsx)(PickersPopperRoot, (0, _extends2.default)({ transition: true, role: role, open: open, anchorEl: anchorEl, styleProps: styleProps }, PopperProps, { children: ({ TransitionProps, placement }) => /*#__PURE__*/(0, _jsxRuntime.jsx)(_Unstable_TrapFocus.default, (0, _extends2.default)({ open: open, disableAutoFocus: true, disableEnforceFocus: role === 'tooltip', isEnabled: () => true }, TrapFocusProps, { children: /*#__PURE__*/(0, _jsxRuntime.jsx)(TransitionComponent, (0, _extends2.default)({}, TransitionProps, { children: /*#__PURE__*/(0, _jsxRuntime.jsx)(PickersPopperPaper, { tabIndex: -1, elevation: 8, ref: handlePaperRef, onClick: onPaperClick, onTouchStart: onPaperTouchStart, styleProps: (0, _extends2.default)({}, styleProps, { placement }), children: children }) })) })) })); }; var _default = PickersPopper; exports.default = _default;