I put the full code here on CodesandBox. Click to check the real behavior now
expected behavior: after users right-click a new position on the area, the Transition effect will remount at the new position until the old Transition unmount fully.
real behavior now: unmount immediately when users right-click, though behavior still make sense as for UX, but I'm still curious how to achieve the effect like Mac OS behave.
// Main code snippet
import React, { FC, ReactNode, useRef, useState } from "react";
import { SwitchTransition, CSSTransition } from "react-transition-group";
import "./styles.css";
type Props = {
children: ReactNode;
};
export const ContextMenuContainer = ({ children }: Props) => {
const [popperMenuOpen, setPopperMenuOpen] = useState(false);
const [anchor, setAnchor] = useState<{ x?: number; y?: number } | null>();
const [key, setKey] = useState(0); // added state key to force remount of CSSTransition
const nodeRef = useRef(null);
const handlePopperMenuShow = () => {
setPopperMenuOpen(true);
};
const handlePopperMenuClose = () => {
setPopperMenuOpen(false);
};
const countAnchorRef = (event: any) => {
const localX = event.pageX - event?.currentTarget?.offsetLeft;
const localY = event.pageY - event?.currentTarget?.offsetTop;
setAnchor({ x: localX, y: localY });
};
const handleContextMenu = (
e: React.MouseEvent<HTMLDivElement, MouseEvent>
) => {
handlePopperMenuClose();
e.preventDefault();
countAnchorRef(e);
handlePopperMenuClose(); // close previous popper menu
setKey((prevKey) => prevKey + 1); // update key to force remount of CSSTransition
setTimeout(() => {
handlePopperMenuShow(); // show new popper menu after previous menu is closed
}, 100); // wait for previous menu to close before showing new menu
};
return (
<div
style={{
position: "relative",
height: "100px",
border: "1px dashed black"
}}
onContextMenu={handleContextMenu}
onMouseDown={(e) => {
if (e.button === 0) {
handlePopperMenuClose();
// setAnchor(null);
}
}}
>
<CSSTransition
// nodeRef={nodeRef}
key={key}
timeout={600}
in={popperMenuOpen}
mountOnEnter
unmountOnExit
classNames="message"
>
<div
ref={nodeRef}
onTransitionEnd={(e: React.TransitionEvent<HTMLDivElement>) => {
handlePopperMenuClose();
// setAnchor(null);
}}
style={{
position: "absolute",
top: anchor?.y ?? 0,
left: anchor?.x ?? 0,
zIndex: 10,
backgroundColor: "rgba(25,25,25, 0.3)"
}}
>
test
</div>
</CSSTransition>
<div
style={{
width: "30px",
height: "30px",
backgroundColor: "rgba(100,100,100,0.12"
}}
></div>
{children}
</div>
);
};