@uiw/react-overlay-trigger
Version:
OverlayTrigger component
287 lines (285 loc) • 11.6 kB
JavaScript
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;
;