55 */
66
77import React , { useEffect , useMemo , useState } from "react" ;
8- import { createPortal } from "react-dom" ;
98import { stopKeyboardPropagation } from "@/browser/utils/events" ;
109import { cn } from "@/common/lib/utils" ;
1110import { getLanguageFromPath } from "@/common/utils/git/languageDetector" ;
1211import { useOverflowDetection } from "@/browser/hooks/useOverflowDetection" ;
1312import { MessageSquare } from "lucide-react" ;
14- import { TOOLTIP_SURFACE_CLASSNAME } from "@/browser/components/Tooltip/Tooltip" ;
1513import { InlineReviewNote , type ReviewActionCallbacks } from "./InlineReviewNote" ;
1614import { groupDiffLines } from "@/browser/utils/highlighting/diffChunking" ;
1715import { useTheme , type ThemeMode } from "@/browser/contexts/ThemeContext" ;
@@ -672,15 +670,6 @@ interface LineSelection {
672670 endIndex : number ;
673671}
674672
675- interface TooltipAnchorRect {
676- left : number ;
677- top : number ;
678- width : number ;
679- height : number ;
680- }
681-
682- const REVIEW_COMMENT_TOOLTIP = "Add review comment (Shift-click or drag to select range)" ;
683-
684673// CSS class for diff line wrapper - used by arbitrary selector in CommentButton
685674const SELECTABLE_DIFF_LINE_CLASS = "selectable-diff-line" ;
686675
@@ -1029,49 +1018,6 @@ export const SelectableDiffRenderer = React.memo<SelectableDiffRendererProps>(
10291018 const [ selection , setSelection ] = React . useState < LineSelection | null > ( null ) ;
10301019 const [ selectionInitialNoteText , setSelectionInitialNoteText ] = React . useState ( "" ) ;
10311020
1032- const reviewTooltipTriggerRef = React . useRef < HTMLButtonElement | null > ( null ) ;
1033- const [ reviewTooltipAnchorRect , setReviewTooltipAnchorRect ] =
1034- React . useState < TooltipAnchorRect | null > ( null ) ;
1035-
1036- const hideReviewTooltip = React . useCallback ( ( trigger ?: HTMLButtonElement | null ) => {
1037- if ( trigger && reviewTooltipTriggerRef . current !== trigger ) {
1038- return ;
1039- }
1040-
1041- reviewTooltipTriggerRef . current = null ;
1042- setReviewTooltipAnchorRect ( null ) ;
1043- } , [ ] ) ;
1044-
1045- const syncReviewTooltipAnchor = React . useCallback ( ( ) => {
1046- const trigger = reviewTooltipTriggerRef . current ;
1047- if ( ! trigger ?. isConnected ) {
1048- hideReviewTooltip ( ) ;
1049- return ;
1050- }
1051-
1052- const { left, top, width, height } = trigger . getBoundingClientRect ( ) ;
1053- setReviewTooltipAnchorRect ( ( previousRect ) => {
1054- if (
1055- previousRect ?. left === left &&
1056- previousRect ?. top === top &&
1057- previousRect ?. width === width &&
1058- previousRect ?. height === height
1059- ) {
1060- return previousRect ;
1061- }
1062-
1063- return { left, top, width, height } ;
1064- } ) ;
1065- } , [ hideReviewTooltip ] ) ;
1066-
1067- const showReviewTooltip = React . useCallback (
1068- ( trigger : HTMLButtonElement ) => {
1069- reviewTooltipTriggerRef . current = trigger ;
1070- syncReviewTooltipAnchor ( ) ;
1071- } ,
1072- [ syncReviewTooltipAnchor ]
1073- ) ;
1074-
10751021 const flushPendingDragSelection = React . useCallback ( ( ) => {
10761022 const anchorIndex = dragAnchorRef . current ;
10771023 const pendingLineIndex = pendingDragLineIndexRef . current ;
@@ -1139,34 +1085,6 @@ export const SelectableDiffRenderer = React.memo<SelectableDiffRendererProps>(
11391085 } ;
11401086 } , [ ] ) ;
11411087
1142- React . useEffect ( ( ) => {
1143- if ( ! reviewTooltipAnchorRect ) {
1144- return ;
1145- }
1146-
1147- const handleViewportChange = ( ) => {
1148- syncReviewTooltipAnchor ( ) ;
1149- } ;
1150-
1151- window . addEventListener ( "resize" , handleViewportChange ) ;
1152- window . addEventListener ( "scroll" , handleViewportChange , true ) ;
1153-
1154- return ( ) => {
1155- window . removeEventListener ( "resize" , handleViewportChange ) ;
1156- window . removeEventListener ( "scroll" , handleViewportChange , true ) ;
1157- } ;
1158- } , [ reviewTooltipAnchorRect , syncReviewTooltipAnchor ] ) ;
1159-
1160- React . useEffect ( ( ) => {
1161- if ( ! reviewTooltipTriggerRef . current ) {
1162- return ;
1163- }
1164-
1165- // File/hunk switches can remove the hovered trigger during a normal React render without any
1166- // scroll/resize event, so resync here too to avoid leaving a stale floating tooltip behind.
1167- syncReviewTooltipAnchor ( ) ;
1168- } ) ;
1169-
11701088 const { theme } = useTheme ( ) ;
11711089
11721090 const lastExternalSelectionRequestIdRef = React . useRef < number | null > ( null ) ;
@@ -1368,8 +1286,6 @@ export const SelectableDiffRenderer = React.memo<SelectableDiffRendererProps>(
13681286 return ;
13691287 }
13701288
1371- hideReviewTooltip ( ) ;
1372-
13731289 // Notify parent that this hunk should become active.
13741290 onLineClick ?.( ) ;
13751291 onLineIndexSelect ?.( lineIndex , shiftKey ) ;
@@ -1396,7 +1312,7 @@ export const SelectableDiffRenderer = React.memo<SelectableDiffRendererProps>(
13961312 return { startIndex : anchor , endIndex : lineIndex } ;
13971313 } ) ;
13981314 } ,
1399- [ hideReviewTooltip , onLineClick , onLineIndexSelect , onReviewNote , renderSelectionStartIndex ]
1315+ [ onLineClick , onLineIndexSelect , onReviewNote , renderSelectionStartIndex ]
14001316 ) ;
14011317
14021318 const updateDragSelection = React . useCallback (
@@ -1413,8 +1329,6 @@ export const SelectableDiffRenderer = React.memo<SelectableDiffRendererProps>(
14131329 ) ;
14141330
14151331 const handleCommentButtonClick = ( lineIndex : number , shiftKey : boolean ) => {
1416- hideReviewTooltip ( ) ;
1417-
14181332 // Keep immersive cursor/hunk selection in sync with inline comment actions.
14191333 onLineClick ?.( ) ;
14201334 onLineIndexSelect ?.( lineIndex , shiftKey ) ;
@@ -1573,17 +1487,12 @@ export const SelectableDiffRenderer = React.memo<SelectableDiffRendererProps>(
15731487 reviewButton = {
15741488 onReviewNote && (
15751489 < >
1576- { /* Regular review can mount thousands of diff lines at once, so keep
1577- one shared tooltip anchored to the active button instead of mounting
1578- a full Radix tooltip tree for every individual line. */ }
1490+ { /* Review mode already turns the gutter into a hover target, so keep the
1491+ action inline without an extra floating tooltip covering nearby lines. */ }
15791492 < button
15801493 type = "button"
15811494 className = "pointer-events-none absolute inset-0 flex items-center justify-center rounded-sm text-[var(--color-review-accent)]/60 opacity-0 transition-opacity group-hover:pointer-events-auto group-hover:opacity-100 hover:text-[var(--color-review-accent)] active:scale-90"
15821495 style = { { position : "absolute" , inset : 0 } }
1583- onMouseEnter = { ( event ) => showReviewTooltip ( event . currentTarget ) }
1584- onMouseLeave = { ( event ) => hideReviewTooltip ( event . currentTarget ) }
1585- onFocus = { ( event ) => showReviewTooltip ( event . currentTarget ) }
1586- onBlur = { ( event ) => hideReviewTooltip ( event . currentTarget ) }
15871496 onClick = { ( e ) => {
15881497 e . stopPropagation ( ) ;
15891498 handleCommentButtonClick ( displayIndex , e . shiftKey ) ;
@@ -1645,25 +1554,6 @@ export const SelectableDiffRenderer = React.memo<SelectableDiffRendererProps>(
16451554 ) ;
16461555 } ) }
16471556 </ DiffContainer >
1648- { reviewTooltipAnchorRect &&
1649- createPortal (
1650- < div
1651- className = { cn (
1652- TOOLTIP_SURFACE_CLASSNAME ,
1653- "pointer-events-none fixed z-[10001] border-separator-light"
1654- ) }
1655- style = { {
1656- left : reviewTooltipAnchorRect . left + reviewTooltipAnchorRect . width + 8 ,
1657- top : reviewTooltipAnchorRect . top + reviewTooltipAnchorRect . height / 2 ,
1658- maxWidth : "min(20rem, calc(100vw - 24px))" ,
1659- transform : "translateY(-50%)" ,
1660- } }
1661- >
1662- < span className = "border-border-medium bg-modal-bg absolute top-1/2 left-0 h-2 w-2 -translate-x-1/2 -translate-y-1/2 rotate-45 border-b border-l" />
1663- { REVIEW_COMMENT_TOOLTIP }
1664- </ div > ,
1665- document . body
1666- ) }
16671557 </ >
16681558 ) ;
16691559 }
0 commit comments