UNPKG

@uiw/react-overlay-trigger

Version:

OverlayTrigger component

287 lines (285 loc) 11.6 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault")["default"]; var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard")["default"]; Object.defineProperty(exports, "__esModule", { value: true }); exports["default"] = void 0; var _createForOfIteratorHelper2 = _interopRequireDefault(require("@babel/runtime/helpers/createForOfIteratorHelper")); var _objectSpread2 = _interopRequireDefault(require("@babel/runtime/helpers/objectSpread2")); var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray")); var _objectWithoutProperties2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutProperties")); var _typeof2 = _interopRequireDefault(require("@babel/runtime/helpers/typeof")); var _react = _interopRequireWildcard(require("react")); var _utils = require("@uiw/utils"); var _reactOverlay = _interopRequireDefault(require("@uiw/react-overlay")); var _utils2 = _interopRequireDefault(require("./utils")); var _getStyle = require("./getStyle"); var _jsxRuntime = require("react/jsx-runtime"); var _excluded = ["className", "prefixCls", "usePortal", "isOutside", "isClickOutside", "disabled", "isOpen", "trigger", "placement", "autoAdjustOverflow", "transitionName", "children", "overlay", "onVisibleChange", "onEnter"]; var normalizeDelay = function normalizeDelay(delay) { return delay && (0, _typeof2["default"])(delay) === 'object' ? delay : { show: delay, hide: delay }; }; var _default = exports["default"] = /*#__PURE__*/_react["default"].forwardRef(function (props, ref) { var _child$props; var className = props.className, _props$prefixCls = props.prefixCls, prefixCls = _props$prefixCls === void 0 ? 'w-overlay-trigger' : _props$prefixCls, _props$usePortal = props.usePortal, usePortal = _props$usePortal === void 0 ? true : _props$usePortal, _props$isOutside = props.isOutside, isOutside = _props$isOutside === void 0 ? false : _props$isOutside, _props$isClickOutside = props.isClickOutside, isClickOutside = _props$isClickOutside === void 0 ? true : _props$isClickOutside, _props$disabled = props.disabled, disabled = _props$disabled === void 0 ? false : _props$disabled, _props$isOpen = props.isOpen, _ = _props$isOpen === void 0 ? false : _props$isOpen, _props$trigger = props.trigger, trigger = _props$trigger === void 0 ? 'hover' : _props$trigger, _props$placement = props.placement, placement = _props$placement === void 0 ? 'top' : _props$placement, autoAdjustOverflow = props.autoAdjustOverflow, transitionName = props.transitionName, children = props.children, overlay = props.overlay, _props$onVisibleChang = props.onVisibleChange, onVisibleChange = _props$onVisibleChang === void 0 ? _utils.noop : _props$onVisibleChang, _props$onEnter = props.onEnter, onEnter = _props$onEnter === void 0 ? _utils.noop : _props$onEnter, other = (0, _objectWithoutProperties2["default"])(props, _excluded); var zIndex = (0, _react.useRef)(999); var triggerRef = (0, _react.useRef)(); var popupRef = (0, _react.useRef)(); var timeoutRef = (0, _react.useRef)([]); var hoverStateRef = (0, _react.useRef)(null); var _useState = (0, _react.useState)(!!props.isOpen), _useState2 = (0, _slicedToArray2["default"])(_useState, 2), isOpen = _useState2[0], setIsOpen = _useState2[1]; var _useState3 = (0, _react.useState)({ placement: placement, top: 0, bottom: 0, left: 0, right: 0, zIndex: zIndex.current }), _useState4 = (0, _slicedToArray2["default"])(_useState3, 2), overlayStyl = _useState4[0], setOverlayStyl = _useState4[1]; (0, _react.useImperativeHandle)(ref, function () { return { hide: function hide() { return _hide(); }, show: function show() { return _show(); }, overlayDom: popupRef }; }); var child = _react["default"].Children.only(children); var overlayProps = (0, _objectSpread2["default"])((0, _objectSpread2["default"])({}, other), {}, { placement: placement, isOpen: isOpen, dialogProps: {} }); var triggerProps = {}; function getChildProps() { if (child && /*#__PURE__*/_react["default"].isValidElement(child)) { return child.props; } return {}; } (0, _react.useEffect)(function () { if (isClickOutside && isOpen) { document && document.addEventListener('mousedown', handleClickOutside); window.addEventListener('resize', handleResize); } return function () { document && isClickOutside && document.removeEventListener('mousedown', handleClickOutside); window.removeEventListener('resize', handleResize); }; }, [isOpen]); (0, _react.useEffect)(function () { if (props.isOpen !== isOpen) { setIsOpen(!!props.isOpen); } }, [props.isOpen]); (0, _react.useEffect)(function () { var styls = (0, _getStyle.getStyle)({ placement: overlayStyl.placement || placement, trigger: triggerRef.current, popup: popupRef.current, usePortal: usePortal, autoAdjustOverflow: autoAdjustOverflow }); setOverlayStyl((0, _objectSpread2["default"])((0, _objectSpread2["default"])({}, styls), {}, { zIndex: zIndex.current })); onVisibleChange(isOpen); }, [isOpen]); var handleResize = function handleResize() { if (isOpen) { zIndex.current -= 1; setIsOpen(false); onVisibleChange && onVisibleChange(false); } }; var handleClickOutside = function handleClickOutside(e) { var popNode = popupRef.current; var childNode = triggerRef.current; if (popNode && childNode && e.target && !(0, _utils2["default"])(popNode, e.target) && !(0, _utils2["default"])(childNode, e.target)) { zIndex.current -= 1; setIsOpen(false); onVisibleChange && onVisibleChange(false); } }; function clearTimeouts() { if (timeoutRef.current.length > 0) { var _iterator = (0, _createForOfIteratorHelper2["default"])(timeoutRef.current), _step; try { for (_iterator.s(); !(_step = _iterator.n()).done;) { var timeoutId = _step.value; window.clearTimeout(timeoutId); } } catch (err) { _iterator.e(err); } finally { _iterator.f(); } timeoutRef.current = []; } } function handleShow() { var _props$children; clearTimeouts(); hoverStateRef.current = 'show'; var delay = normalizeDelay(props.delay); if (!delay.show && !((_props$children = props.children) !== null && _props$children !== void 0 && _props$children.props.disabled)) { _show(); return; } var handle = window.setTimeout(function () { if (hoverStateRef.current === 'show') _show(); }, delay.show); clearTimeout(handle); timeoutRef.current.push(handle); } function handleHide(isOutside) { clearTimeouts(); if (!isOutside && props.isOutside) return; hoverStateRef.current = 'hide'; var delay = normalizeDelay(props.delay); if (!delay.hide) { _hide(); return; } var handle = window.setTimeout(function () { if (hoverStateRef.current === 'hide') _hide(); }, delay.hide); timeoutRef.current.push(handle); } // Simple implementation of mouseEnter and mouseLeave. // React's built version is broken: https://github.com/facebook/react/issues/4251 // for cases when the trigger is disabled and mouseOut/Over can cause flicker // moving from one child element to another. function handleMouseOverOut(handler, e, relatedNative) { var target = e.currentTarget; var related = e.relatedTarget || e.nativeEvent[relatedNative]; var isOutside = true; if (popupRef.current && (0, _utils2["default"])(popupRef.current, related) || triggerRef.current && (0, _utils2["default"])(triggerRef.current, related)) { isOutside = false; } if ((!related || related !== target) && !(0, _utils2["default"])(target, related)) { handler(isOutside, e); } } function _hide() { if (!isOpen) return; if (zIndex.current <= 999) { zIndex.current = 999; } else { zIndex.current -= 1; } setIsOpen(false); } function _show() { var _triggerRef$current; if (isOpen) return; var nodeIndex = (_triggerRef$current = triggerRef.current) === null || _triggerRef$current === void 0 ? void 0 : _triggerRef$current.style.zIndex; if (nodeIndex) { zIndex.current = Number(nodeIndex) + 1; } else { zIndex.current += 1; } setIsOpen(true); } function handleEnter(node, isAppearing) { onEnter && onEnter(node, isAppearing); var styls = (0, _getStyle.getStyle)({ placement: overlayStyl.placement || placement, trigger: triggerRef.current, popup: popupRef.current, usePortal: usePortal, autoAdjustOverflow: autoAdjustOverflow }); setOverlayStyl((0, _objectSpread2["default"])((0, _objectSpread2["default"])({}, styls), {}, { zIndex: zIndex.current })); } if (trigger === 'click' && !disabled) { triggerProps.onClick = function (e) { var _ref = getChildProps(), onClick = _ref.onClick; isOpen ? _hide() : _show(); if (onClick) onClick(e, !isOpen); }; } if (trigger === 'focus' && !disabled) { triggerProps.onFocus = function () { return handleShow(); }; } if (trigger === 'hover' && !disabled) { triggerProps.onMouseOver = triggerProps.onMouseEnter = function (e) { handleMouseOverOut(handleShow, e, 'fromElement'); }; triggerProps.onMouseOut = triggerProps.onMouseLeave = function (e) { handleMouseOverOut(handleHide, e, 'toElement'); }; if (overlayProps.dialogProps) { overlayProps.dialogProps.onMouseLeave = function (e) { handleMouseOverOut(handleHide, e, 'toElement'); }; } } overlayProps.style = (0, _objectSpread2["default"])((0, _objectSpread2["default"])({}, overlayProps.style), overlayStyl); return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_react["default"].Fragment, { children: [/*#__PURE__*/(0, _react.cloneElement)(child, Object.assign({}, child.props, (0, _objectSpread2["default"])((0, _objectSpread2["default"])({}, triggerProps), {}, { ref: triggerRef, style: (0, _objectSpread2["default"])((0, _objectSpread2["default"])({}, (_child$props = child.props) === null || _child$props === void 0 ? void 0 : _child$props.style), {}, { zIndex: zIndex.current }), className: [child.props.className, disabled ? "".concat(prefixCls, "-disabled") : null].filter(Boolean).join(' ').trim() }))), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactOverlay["default"], (0, _objectSpread2["default"])((0, _objectSpread2["default"])({}, overlayProps), {}, { style: (0, _objectSpread2["default"])((0, _objectSpread2["default"])({}, overlayProps.style), overlayStyl), onEnter: handleEnter, className: [prefixCls, className, overlayStyl.placement].filter(Boolean).join(' ').trim(), usePortal: usePortal, transitionName: transitionName, isOpen: isOpen, hasBackdrop: false, children: /*#__PURE__*/(0, _react.cloneElement)(overlay, Object.assign((0, _objectSpread2["default"])((0, _objectSpread2["default"])({}, overlay.props), {}, { ref: popupRef, className: [overlay.props && overlay.props.className, placement].filter(Boolean).join(' ').trim() }))) }))] }); }); module.exports = exports.default;