@@ -11,7 +11,7 @@ import {
1111 MoreHorizontalIcon ,
1212 PlusIcon ,
1313} from "lucide-react" ;
14- import { useCallback , useMemo } from "react" ;
14+ import { useCallback , useMemo , useState } from "react" ;
1515
1616import { writeTextToClipboard } from "~/hooks/useCopyToClipboard" ;
1717import { useOpenPrLink } from "~/lib/openPullRequestLink" ;
@@ -84,13 +84,28 @@ function LinkRow({
8484 onSetWatching : ( ( link : ThreadPullRequestLink , watching : boolean ) => void ) | null ;
8585} ) {
8686 const openPrLink = useOpenPrLink ( threadRef ) ;
87+ const [ menuOpen , setMenuOpen ] = useState ( false ) ;
88+ const [ menuPosition , setMenuPosition ] = useState < { x : number ; y : number } | null > ( null ) ;
89+ const menuAnchor = useMemo (
90+ ( ) =>
91+ menuPosition
92+ ? { getBoundingClientRect : ( ) => new DOMRect ( menuPosition . x , menuPosition . y , 0 , 0 ) }
93+ : undefined ,
94+ [ menuPosition ] ,
95+ ) ;
8796 const { link, depth, stack } = line ;
8897 const snapshot = link . snapshot ;
8998 const open = snapshot === null || snapshot . state === "open" ;
9099 const watching = link . watch !== undefined ;
91100 return (
92101 < div
93102 className = { cn ( PULL_REQUEST_ROW_CLASS , "relative hover:bg-accent/60" ) }
103+ onContextMenu = { ( event ) => {
104+ event . preventDefault ( ) ;
105+ event . stopPropagation ( ) ;
106+ setMenuPosition ( { x : event . clientX , y : event . clientY } ) ;
107+ setMenuOpen ( true ) ;
108+ } }
94109 // Each layer steps in under the one it targets. The step is capped: beyond a few layers
95110 // the indent only says "still in the stack", which the connector line already does, and
96111 // a sixteen-layer stack would otherwise stair-step off the right edge.
@@ -221,7 +236,13 @@ function LinkRow({
221236 ) }
222237 >
223238 < span aria-hidden className = "absolute inset-0 bg-accent/60" />
224- < Menu >
239+ < Menu
240+ open = { menuOpen }
241+ onOpenChange = { ( open ) => {
242+ setMenuOpen ( open ) ;
243+ if ( ! open ) setMenuPosition ( null ) ;
244+ } }
245+ >
225246 < MenuTrigger
226247 render = {
227248 < Button
@@ -234,7 +255,12 @@ function LinkRow({
234255 </ Button >
235256 }
236257 />
237- < MenuPopup align = "end" side = "bottom" >
258+ < MenuPopup
259+ anchor = { menuAnchor }
260+ align = { menuPosition ? "start" : "end" }
261+ side = "bottom"
262+ sideOffset = { menuPosition ? 0 : 4 }
263+ >
238264 < MenuItem onClick = { ( ) => void writeTextToClipboard ( link . url , "link" ) } >
239265 < LinkIcon className = "size-3.5" />
240266 Copy link
0 commit comments