@rc-component/trigger
Version:
base abstract trigger component for react
144 lines (135 loc) • 4.59 kB
JavaScript
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;