UNPKG

@rc-component/trigger

Version:

base abstract trigger component for react

144 lines (135 loc) 4.59 kB
import * as React from 'react'; import Portal from '@rc-component/portal'; import TriggerContext, { UniqueContext } from "../context"; import useDelay from "../hooks/useDelay"; import useAlign from "../hooks/useAlign"; import Popup from "../Popup"; import { useEvent } from '@rc-component/util'; import useTargetState from "./useTargetState"; import { isDOM } from "@rc-component/util/es/Dom/findDOMNode"; import FloatBg from "./FloatBg"; import classNames from 'classnames'; import MotionContent from "./MotionContent"; const UniqueProvider = ({ children }) => { const [trigger, open, options, onTargetVisibleChanged] = useTargetState(); // =========================== Popup ============================ const [popupEle, setPopupEle] = React.useState(null); const [popupSize, setPopupSize] = React.useState(null); // Used for forwardRef popup. Not use internal const externalPopupRef = React.useRef(null); const setPopupRef = useEvent(node => { externalPopupRef.current = node; if (isDOM(node) && popupEle !== node) { setPopupEle(node); } }); // ========================== Register ========================== const [popupId, setPopupId] = React.useState(0); const delayInvoke = useDelay(); const show = useEvent(showOptions => { delayInvoke(() => { if (showOptions.id !== options?.id) { setPopupId(i => i + 1); } trigger(showOptions); }, showOptions.delay); }); const hide = delay => { delayInvoke(() => { trigger(false); // Don't clear target, currentNode, options immediately, wait until animation completes }, delay); }; // Callback after animation completes const onVisibleChanged = useEvent(visible => { // Call useTargetState callback to handle animation state onTargetVisibleChanged(visible); }); // =========================== Align ============================ const [ready, offsetX, offsetY, offsetR, offsetB, arrowX, arrowY, // scaleX - not used in UniqueProvider ,, // scaleY - not used in UniqueProvider alignInfo, onAlign] = useAlign(open, popupEle, options?.target, options?.popupPlacement, options?.builtinPlacements || {}, options?.popupAlign, undefined, // onPopupAlign false // isMobile ); const contextValue = React.useMemo(() => ({ show, hide }), []); // =========================== Motion =========================== const onPrepare = useEvent(() => { onAlign(); return Promise.resolve(); }); // ======================== Trigger Context ===================== const subPopupElements = React.useRef({}); const parentContext = React.useContext(TriggerContext); const triggerContextValue = React.useMemo(() => ({ registerSubPopup: (id, subPopupEle) => { subPopupElements.current[id] = subPopupEle; parentContext?.registerSubPopup(id, subPopupEle); } }), [parentContext]); // =========================== Render =========================== const prefixCls = options?.prefixCls; return /*#__PURE__*/React.createElement(UniqueContext.Provider, { value: contextValue }, children, options && /*#__PURE__*/React.createElement(TriggerContext.Provider, { value: triggerContextValue }, /*#__PURE__*/React.createElement(Popup, { ref: setPopupRef, portal: Portal, prefixCls: prefixCls, popup: /*#__PURE__*/React.createElement(MotionContent, { prefixCls: prefixCls, key: popupId }, options.popup), className: classNames(options.popupClassName, `${prefixCls}-unique-controlled`), style: options.popupStyle, target: options.target, open: open, keepDom: true, fresh: true, autoDestroy: false, onVisibleChanged: onVisibleChanged, ready: ready, offsetX: offsetX, offsetY: offsetY, offsetR: offsetR, offsetB: offsetB, onAlign: onAlign, onPrepare: onPrepare, onResize: size => setPopupSize({ width: size.offsetWidth, height: size.offsetHeight }), arrowPos: { x: arrowX, y: arrowY }, align: alignInfo, zIndex: options.zIndex, mask: options.mask, arrow: options.arrow, motion: options.popupMotion, maskMotion: options.maskMotion, getPopupContainer: options.getPopupContainer }, /*#__PURE__*/React.createElement(FloatBg, { prefixCls: prefixCls, isMobile: false, ready: ready, open: open, align: alignInfo, offsetR: offsetR, offsetB: offsetB, offsetX: offsetX, offsetY: offsetY, popupSize: popupSize, motion: options.popupMotion })))); }; export default UniqueProvider;