import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2"; import _slicedToArray from "@babel/runtime/helpers/esm/slicedToArray"; import _objectWithoutProperties from "@babel/runtime/helpers/esm/objectWithoutProperties"; var _excluded = ["prefixCls", "children", "action", "showAction", "hideAction", "popupVisible", "defaultPopupVisible", "onPopupVisibleChange", "afterPopupVisibleChange", "mouseEnterDelay", "mouseLeaveDelay", "focusDelay", "blurDelay", "mask", "maskClosable", "getPopupContainer", "forceRender", "autoDestroy", "destroyPopupOnHide", "popup", "popupClassName", "popupStyle", "popupPlacement", "builtinPlacements", "popupAlign", "zIndex", "stretch", "getPopupClassNameFromAlign", "fresh", "alignPoint", "onPopupClick", "onPopupAlign", "arrow", "popupMotion", "maskMotion", "popupTransitionName", "popupAnimation", "maskTransitionName", "maskAnimation", "className", "getTriggerDOMNode"]; import Portal from '@rc-component/portal'; import classNames from 'classnames'; import ResizeObserver from 'rc-resize-observer'; import { isDOM } from "rc-util/es/Dom/findDOMNode"; import { getShadowRoot } from "rc-util/es/Dom/shadow"; import useEvent from "rc-util/es/hooks/useEvent"; import useId from "rc-util/es/hooks/useId"; import useLayoutEffect from "rc-util/es/hooks/useLayoutEffect"; import isMobile from "rc-util/es/isMobile"; import * as React from 'react'; import { flushSync } from 'react-dom'; import TriggerContext from "./context"; import useAction from "./hooks/useAction"; import useAlign from "./hooks/useAlign"; import useWatch from "./hooks/useWatch"; import useWinClick from "./hooks/useWinClick"; import Popup from "./Popup"; import TriggerWrapper from "./TriggerWrapper"; import { getAlignPopupClassName, getMotion } from "./util"; // Removed Props List // Seems this can be auto // getDocument?: (element?: HTMLElement) => Document; // New version will not wrap popup with `rc-trigger-popup-content` when multiple children export function generateTrigger() { var PortalComponent = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : Portal; var Trigger = /*#__PURE__*/React.forwardRef(function (props, ref) { var _props$prefixCls = props.prefixCls, prefixCls = _props$prefixCls === void 0 ? 'rc-trigger-popup' : _props$prefixCls, children = props.children, _props$action = props.action, action = _props$action === void 0 ? 'hover' : _props$action, showAction = props.showAction, hideAction = props.hideAction, popupVisible = props.popupVisible, defaultPopupVisible = props.defaultPopupVisible, onPopupVisibleChange = props.onPopupVisibleChange, afterPopupVisibleChange = props.afterPopupVisibleChange, mouseEnterDelay = props.mouseEnterDelay, _props$mouseLeaveDela = props.mouseLeaveDelay, mouseLeaveDelay = _props$mouseLeaveDela === void 0 ? 0.1 : _props$mouseLeaveDela, focusDelay = props.focusDelay, blurDelay = props.blurDelay, mask = props.mask, _props$maskClosable = props.maskClosable, maskClosable = _props$maskClosable === void 0 ? true : _props$maskClosable, getPopupContainer = props.getPopupContainer, forceRender = props.forceRender, autoDestroy = props.autoDestroy, destroyPopupOnHide = props.destroyPopupOnHide, popup = props.popup, popupClassName = props.popupClassName, popupStyle = props.popupStyle, popupPlacement = props.popupPlacement, _props$builtinPlaceme = props.builtinPlacements, builtinPlacements = _props$builtinPlaceme === void 0 ? {} : _props$builtinPlaceme, popupAlign = props.popupAlign, zIndex = props.zIndex, stretch = props.stretch, getPopupClassNameFromAlign = props.getPopupClassNameFromAlign, fresh = props.fresh, alignPoint = props.alignPoint, onPopupClick = props.onPopupClick, onPopupAlign = props.onPopupAlign, arrow = props.arrow, popupMotion = props.popupMotion, maskMotion = props.maskMotion, popupTransitionName = props.popupTransitionName, popupAnimation = props.popupAnimation, maskTransitionName = props.maskTransitionName, maskAnimation = props.maskAnimation, className = props.className, getTriggerDOMNode = props.getTriggerDOMNode, restProps = _objectWithoutProperties(props, _excluded); var mergedAutoDestroy = autoDestroy || destroyPopupOnHide || false; // =========================== Mobile =========================== var _React$useState = React.useState(false), _React$useState2 = _slicedToArray(_React$useState, 2), mobile = _React$useState2[0], setMobile = _React$useState2[1]; useLayoutEffect(function () { setMobile(isMobile()); }, []); // ========================== Context =========================== var subPopupElements = React.useRef({}); var parentContext = React.useContext(TriggerContext); var context = React.useMemo(function () { return { registerSubPopup: function registerSubPopup(id, subPopupEle) { subPopupElements.current[id] = subPopupEle; parentContext === null || parentContext === void 0 ? void 0 : parentContext.registerSubPopup(id, subPopupEle); } }; }, [parentContext]); // =========================== Popup ============================ var id = useId(); var _React$useState3 = React.useState(null), _React$useState4 = _slicedToArray(_React$useState3, 2), popupEle = _React$useState4[0], setPopupEle = _React$useState4[1]; var setPopupRef = useEvent(function (node) { if (isDOM(node) && popupEle !== node) { setPopupEle(node); } parentContext === null || parentContext === void 0 ? void 0 : parentContext.registerSubPopup(id, node); }); // =========================== Target =========================== // Use state to control here since `useRef` update not trigger render var _React$useState5 = React.useState(null), _React$useState6 = _slicedToArray(_React$useState5, 2), targetEle = _React$useState6[0], setTargetEle = _React$useState6[1]; var setTargetRef = useEvent(function (node) { if (isDOM(node) && targetEle !== node) { setTargetEle(node); } }); // ========================== Children ========================== var child = React.Children.only(children); var originChildProps = (child === null || child === void 0 ? void 0 : child.props) || {}; var cloneProps = {}; var inPopupOrChild = useEvent(function (ele) { var _getShadowRoot, _getShadowRoot2; var childDOM = targetEle; return (childDOM === null || childDOM === void 0 ? void 0 : childDOM.contains(ele)) || ((_getShadowRoot = getShadowRoot(childDOM)) === null || _getShadowRoot === void 0 ? void 0 : _getShadowRoot.host) === ele || ele === childDOM || (popupEle === null || popupEle === void 0 ? void 0 : popupEle.contains(ele)) || ((_getShadowRoot2 = getShadowRoot(popupEle)) === null || _getShadowRoot2 === void 0 ? void 0 : _getShadowRoot2.host) === ele || ele === popupEle || Object.values(subPopupElements.current).some(function (subPopupEle) { return (subPopupEle === null || subPopupEle === void 0 ? void 0 : subPopupEle.contains(ele)) || ele === subPopupEle; }); }); // =========================== Motion =========================== var mergePopupMotion = getMotion(prefixCls, popupMotion, popupAnimation, popupTransitionName); var mergeMaskMotion = getMotion(prefixCls, maskMotion, maskAnimation, maskTransitionName); // ============================ Open ============================ var _React$useState7 = React.useState(defaultPopupVisible || false), _React$useState8 = _slicedToArray(_React$useState7, 2), internalOpen = _React$useState8[0], setInternalOpen = _React$useState8[1]; // Render still use props as first priority var mergedOpen = popupVisible !== null && popupVisible !== void 0 ? popupVisible : internalOpen; // We use effect sync here in case `popupVisible` back to `undefined` var setMergedOpen = useEvent(function (nextOpen) { if (popupVisible === undefined) { setInternalOpen(nextOpen); } }); useLayoutEffect(function () { setInternalOpen(popupVisible || false); }, [popupVisible]); var openRef = React.useRef(mergedOpen); openRef.current = mergedOpen; var internalTriggerOpen = useEvent(function (nextOpen) { // Enter or Pointer will both trigger open state change // We only need take one to avoid duplicated change event trigger flushSync(function () { if (mergedOpen !== nextOpen) { setMergedOpen(nextOpen); onPopupVisibleChange === null || onPopupVisibleChange === void 0 ? void 0 : onPopupVisibleChange(nextOpen); } }); }); // Trigger for delay var delayRef = React.useRef(); var clearDelay = function clearDelay() { clearTimeout(delayRef.current); }; var triggerOpen = function triggerOpen(nextOpen) { var delay = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; clearDelay(); if (delay === 0) { internalTriggerOpen(nextOpen); } else { delayRef.current = setTimeout(function () { internalTriggerOpen(nextOpen); }, delay * 1000); } }; React.useEffect(function () { return clearDelay; }, []); // ========================== Motion ============================ var _React$useState9 = React.useState(false), _React$useState10 = _slicedToArray(_React$useState9, 2), inMotion = _React$useState10[0], setInMotion = _React$useState10[1]; useLayoutEffect(function (firstMount) { if (!firstMount || mergedOpen) { setInMotion(true); } }, [mergedOpen]); var _React$useState11 = React.useState(null), _React$useState12 = _slicedToArray(_React$useState11, 2), motionPrepareResolve = _React$useState12[0], setMotionPrepareResolve = _React$useState12[1]; // =========================== Align ============================ var _React$useState13 = React.useState([0, 0]), _React$useState14 = _slicedToArray(_React$useState13, 2), mousePos = _React$useState14[0], setMousePos = _React$useState14[1]; var setMousePosByEvent = function setMousePosByEvent(event) { setMousePos([event.clientX, event.clientY]); }; var _useAlign = useAlign(mergedOpen, popupEle, alignPoint ? mousePos : targetEle, popupPlacement, builtinPlacements, popupAlign, onPopupAlign), _useAlign2 = _slicedToArray(_useAlign, 11), ready = _useAlign2[0], offsetX = _useAlign2[1], offsetY = _useAlign2[2], offsetR = _useAlign2[3], offsetB = _useAlign2[4], arrowX = _useAlign2[5], arrowY = _useAlign2[6], scaleX = _useAlign2[7], scaleY = _useAlign2[8], alignInfo = _useAlign2[9], onAlign = _useAlign2[10]; var _useAction = useAction(mobile, action, showAction, hideAction), _useAction2 = _slicedToArray(_useAction, 2), showActions = _useAction2[0], hideActions = _useAction2[1]; var clickToShow = showActions.has('click'); var clickToHide = hideActions.has('click') || hideActions.has('contextMenu'); var triggerAlign = useEvent(function () { if (!inMotion) { onAlign(); } }); var onScroll = function onScroll() { if (openRef.current && alignPoint && clickToHide) { triggerOpen(false); } }; useWatch(mergedOpen, targetEle, popupEle, triggerAlign, onScroll); useLayoutEffect(function () { triggerAlign(); }, [mousePos, popupPlacement]); // When no builtinPlacements and popupAlign changed useLayoutEffect(function () { if (mergedOpen && !(builtinPlacements !== null && builtinPlacements !== void 0 && builtinPlacements[popupPlacement])) { triggerAlign(); } }, [JSON.stringify(popupAlign)]); var alignedClassName = React.useMemo(function () { var baseClassName = getAlignPopupClassName(builtinPlacements, prefixCls, alignInfo, alignPoint); return classNames(baseClassName, getPopupClassNameFromAlign === null || getPopupClassNameFromAlign === void 0 ? void 0 : getPopupClassNameFromAlign(alignInfo)); }, [alignInfo, getPopupClassNameFromAlign, builtinPlacements, prefixCls, alignPoint]); React.useImperativeHandle(ref, function () { return { forceAlign: triggerAlign }; }); // ========================== Stretch =========================== var _React$useState15 = React.useState(0), _React$useState16 = _slicedToArray(_React$useState15, 2), targetWidth = _React$useState16[0], setTargetWidth = _React$useState16[1]; var _React$useState17 = React.useState(0), _React$useState18 = _slicedToArray(_React$useState17, 2), targetHeight = _React$useState18[0], setTargetHeight = _React$useState18[1]; var syncTargetSize = function syncTargetSize() { if (stretch && targetEle) { var rect = targetEle.getBoundingClientRect(); setTargetWidth(rect.width); setTargetHeight(rect.height); } }; var onTargetResize = function onTargetResize() { syncTargetSize(); triggerAlign(); }; // ========================== Motion ============================ var onVisibleChanged = function onVisibleChanged(visible) { setInMotion(false); onAlign(); afterPopupVisibleChange === null || afterPopupVisibleChange === void 0 ? void 0 : afterPopupVisibleChange(visible); }; // We will trigger align when motion is in prepare var onPrepare = function onPrepare() { return new Promise(function (resolve) { syncTargetSize(); setMotionPrepareResolve(function () { return resolve; }); }); }; useLayoutEffect(function () { if (motionPrepareResolve) { onAlign(); motionPrepareResolve(); setMotionPrepareResolve(null); } }, [motionPrepareResolve]); // =========================== Action =========================== /** * Util wrapper for trigger action */ function wrapperAction(eventName, nextOpen, delay, preEvent) { cloneProps[eventName] = function (event) { var _originChildProps$eve; preEvent === null || preEvent === void 0 ? void 0 : preEvent(event); triggerOpen(nextOpen, delay); // Pass to origin for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { args[_key - 1] = arguments[_key]; } (_originChildProps$eve = originChildProps[eventName]) === null || _originChildProps$eve === void 0 ? void 0 : _originChildProps$eve.call.apply(_originChildProps$eve, [originChildProps, event].concat(args)); }; } // ======================= Action: Click ======================== if (clickToShow || clickToHide) { cloneProps.onClick = function (event) { var _originChildProps$onC; if (openRef.current && clickToHide) { triggerOpen(false); } else if (!openRef.current && clickToShow) { setMousePosByEvent(event); triggerOpen(true); } // Pass to origin for (var _len2 = arguments.length, args = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) { args[_key2 - 1] = arguments[_key2]; } (_originChildProps$onC = originChildProps.onClick) === null || _originChildProps$onC === void 0 ? void 0 : _originChildProps$onC.call.apply(_originChildProps$onC, [originChildProps, event].concat(args)); }; } // Click to hide is special action since click popup element should not hide useWinClick(mergedOpen, clickToHide, targetEle, popupEle, mask, maskClosable, inPopupOrChild, triggerOpen); // ======================= Action: Hover ======================== var hoverToShow = showActions.has('hover'); var hoverToHide = hideActions.has('hover'); var onPopupMouseEnter; var onPopupMouseLeave; if (hoverToShow) { // Compatible with old browser which not support pointer event wrapperAction('onMouseEnter', true, mouseEnterDelay, function (event) { setMousePosByEvent(event); }); wrapperAction('onPointerEnter', true, mouseEnterDelay, function (event) { setMousePosByEvent(event); }); onPopupMouseEnter = function onPopupMouseEnter() { // Only trigger re-open when popup is visible if (mergedOpen || inMotion) { triggerOpen(true, mouseEnterDelay); } }; // Align Point if (alignPoint) { cloneProps.onMouseMove = function (event) { var _originChildProps$onM; // setMousePosByEvent(event); (_originChildProps$onM = originChildProps.onMouseMove) === null || _originChildProps$onM === void 0 ? void 0 : _originChildProps$onM.call(originChildProps, event); }; } } if (hoverToHide) { wrapperAction('onMouseLeave', false, mouseLeaveDelay); wrapperAction('onPointerLeave', false, mouseLeaveDelay); onPopupMouseLeave = function onPopupMouseLeave() { triggerOpen(false, mouseLeaveDelay); }; } // ======================= Action: Focus ======================== if (showActions.has('focus')) { wrapperAction('onFocus', true, focusDelay); } if (hideActions.has('focus')) { wrapperAction('onBlur', false, blurDelay); } // ==================== Action: ContextMenu ===================== if (showActions.has('contextMenu')) { cloneProps.onContextMenu = function (event) { var _originChildProps$onC2; if (openRef.current && hideActions.has('contextMenu')) { triggerOpen(false); } else { setMousePosByEvent(event); triggerOpen(true); } event.preventDefault(); // Pass to origin for (var _len3 = arguments.length, args = new Array(_len3 > 1 ? _len3 - 1 : 0), _key3 = 1; _key3 < _len3; _key3++) { args[_key3 - 1] = arguments[_key3]; } (_originChildProps$onC2 = originChildProps.onContextMenu) === null || _originChildProps$onC2 === void 0 ? void 0 : _originChildProps$onC2.call.apply(_originChildProps$onC2, [originChildProps, event].concat(args)); }; } // ========================= ClassName ========================== if (className) { cloneProps.className = classNames(originChildProps.className, className); } // =========================== Render =========================== var mergedChildrenProps = _objectSpread(_objectSpread({}, originChildProps), cloneProps); // Pass props into cloneProps for nest usage var passedProps = {}; var passedEventList = ['onContextMenu', 'onClick', 'onMouseDown', 'onTouchStart', 'onMouseEnter', 'onMouseLeave', 'onFocus', 'onBlur']; passedEventList.forEach(function (eventName) { if (restProps[eventName]) { passedProps[eventName] = function () { var _mergedChildrenProps$; for (var _len4 = arguments.length, args = new Array(_len4), _key4 = 0; _key4 < _len4; _key4++) { args[_key4] = arguments[_key4]; } (_mergedChildrenProps$ = mergedChildrenProps[eventName]) === null || _mergedChildrenProps$ === void 0 ? void 0 : _mergedChildrenProps$.call.apply(_mergedChildrenProps$, [mergedChildrenProps].concat(args)); restProps[eventName].apply(restProps, args); }; } }); // Child Node var triggerNode = /*#__PURE__*/React.cloneElement(child, _objectSpread(_objectSpread({}, mergedChildrenProps), passedProps)); var arrowPos = { x: arrowX, y: arrowY }; var innerArrow = arrow ? _objectSpread({}, arrow !== true ? arrow : {}) : null; // Render return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(ResizeObserver, { disabled: !mergedOpen, ref: setTargetRef, onResize: onTargetResize }, /*#__PURE__*/React.createElement(TriggerWrapper, { getTriggerDOMNode: getTriggerDOMNode }, triggerNode)), /*#__PURE__*/React.createElement(TriggerContext.Provider, { value: context }, /*#__PURE__*/React.createElement(Popup, { portal: PortalComponent, ref: setPopupRef, prefixCls: prefixCls, popup: popup, className: classNames(popupClassName, alignedClassName), style: popupStyle, target: targetEle, onMouseEnter: onPopupMouseEnter, onMouseLeave: onPopupMouseLeave // https://github.com/ant-design/ant-design/issues/43924 , onPointerEnter: onPopupMouseEnter, zIndex: zIndex // Open , open: mergedOpen, keepDom: inMotion, fresh: fresh // Click , onClick: onPopupClick // Mask , mask: mask // Motion , motion: mergePopupMotion, maskMotion: mergeMaskMotion, onVisibleChanged: onVisibleChanged, onPrepare: onPrepare // Portal , forceRender: forceRender, autoDestroy: mergedAutoDestroy, getPopupContainer: getPopupContainer // Arrow , align: alignInfo, arrow: innerArrow, arrowPos: arrowPos // Align , ready: ready, offsetX: offsetX, offsetY: offsetY, offsetR: offsetR, offsetB: offsetB, onAlign: triggerAlign // Stretch , stretch: stretch, targetWidth: targetWidth / scaleX, targetHeight: targetHeight / scaleY }))); }); if (process.env.NODE_ENV !== 'production') { Trigger.displayName = 'Trigger'; } return Trigger; } export default generateTrigger(Portal);