diff --git a/apps/web/src/components/pullRequest/ThreadPullRequestsPanel.tsx b/apps/web/src/components/pullRequest/ThreadPullRequestsPanel.tsx index 643c17d4b775..42b09f4387e7 100644 --- a/apps/web/src/components/pullRequest/ThreadPullRequestsPanel.tsx +++ b/apps/web/src/components/pullRequest/ThreadPullRequestsPanel.tsx @@ -11,7 +11,7 @@ import { MoreHorizontalIcon, PlusIcon, } from "lucide-react"; -import { useCallback, useMemo } from "react"; +import { useCallback, useMemo, useState } from "react"; import { writeTextToClipboard } from "~/hooks/useCopyToClipboard"; import { useOpenPrLink } from "~/lib/openPullRequestLink"; @@ -84,6 +84,15 @@ function LinkRow({ onSetWatching: ((link: ThreadPullRequestLink, watching: boolean) => void) | null; }) { const openPrLink = useOpenPrLink(threadRef); + const [menuOpen, setMenuOpen] = useState(false); + const [menuPosition, setMenuPosition] = useState<{ x: number; y: number } | null>(null); + const menuAnchor = useMemo( + () => + menuPosition + ? { getBoundingClientRect: () => new DOMRect(menuPosition.x, menuPosition.y, 0, 0) } + : undefined, + [menuPosition], + ); const { link, depth, stack } = line; const snapshot = link.snapshot; const open = snapshot === null || snapshot.state === "open"; @@ -91,6 +100,12 @@ function LinkRow({ return (
{ + event.preventDefault(); + event.stopPropagation(); + setMenuPosition({ x: event.clientX, y: event.clientY }); + setMenuOpen(true); + }} // Each layer steps in under the one it targets. The step is capped: beyond a few layers // the indent only says "still in the stack", which the connector line already does, and // a sixteen-layer stack would otherwise stair-step off the right edge. @@ -221,7 +236,13 @@ function LinkRow({ )} > - + { + setMenuOpen(open); + if (!open) setMenuPosition(null); + }} + > } /> - + void writeTextToClipboard(link.url, "link")}> Copy link