Skip to content

Commit 85f35be

Browse files
committed
🤖 fix: remove review line tooltip
Stop rendering the floating review comment helper from the shared review diff renderer so hovering the gutter action no longer obscures nearby code. The shared renderer also powers both review panes, so the follow-up comment now calls out that scope directly while preserving the inline review action and range selection behavior. --- _Generated with `mux` • Model: `openai:gpt-5.4` • Thinking: `xhigh` • Cost: `$1.93`_ <!-- mux-attribution: model=openai:gpt-5.4 thinking=xhigh costs=1.93 -->
1 parent 3cec659 commit 85f35be

File tree

2 files changed

+10
-120
lines changed

2 files changed

+10
-120
lines changed

src/browser/features/Shared/DiffRenderer.tsx

Lines changed: 6 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,16 @@
11
/**
22
* DiffRenderer - Shared diff rendering component
33
* Used by FileEditToolCall for read-only diff display.
4-
* ReviewPanel uses SelectableDiffRenderer for interactive line selection.
4+
* ReviewPanel and ImmersiveReviewView both use SelectableDiffRenderer for
5+
* interactive line selection.
56
*/
67

78
import React, { useEffect, useMemo, useState } from "react";
8-
import { createPortal } from "react-dom";
99
import { stopKeyboardPropagation } from "@/browser/utils/events";
1010
import { cn } from "@/common/lib/utils";
1111
import { getLanguageFromPath } from "@/common/utils/git/languageDetector";
1212
import { useOverflowDetection } from "@/browser/hooks/useOverflowDetection";
1313
import { MessageSquare } from "lucide-react";
14-
import { TOOLTIP_SURFACE_CLASSNAME } from "@/browser/components/Tooltip/Tooltip";
1514
import { InlineReviewNote, type ReviewActionCallbacks } from "./InlineReviewNote";
1615
import { groupDiffLines } from "@/browser/utils/highlighting/diffChunking";
1716
import { useTheme, type ThemeMode } from "@/browser/contexts/ThemeContext";
@@ -672,15 +671,6 @@ interface LineSelection {
672671
endIndex: number;
673672
}
674673

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-
684674
// CSS class for diff line wrapper - used by arbitrary selector in CommentButton
685675
const SELECTABLE_DIFF_LINE_CLASS = "selectable-diff-line";
686676

@@ -1029,49 +1019,6 @@ export const SelectableDiffRenderer = React.memo<SelectableDiffRendererProps>(
10291019
const [selection, setSelection] = React.useState<LineSelection | null>(null);
10301020
const [selectionInitialNoteText, setSelectionInitialNoteText] = React.useState("");
10311021

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-
10751022
const flushPendingDragSelection = React.useCallback(() => {
10761023
const anchorIndex = dragAnchorRef.current;
10771024
const pendingLineIndex = pendingDragLineIndexRef.current;
@@ -1139,34 +1086,6 @@ export const SelectableDiffRenderer = React.memo<SelectableDiffRendererProps>(
11391086
};
11401087
}, []);
11411088

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-
11701089
const { theme } = useTheme();
11711090

11721091
const lastExternalSelectionRequestIdRef = React.useRef<number | null>(null);
@@ -1368,8 +1287,6 @@ export const SelectableDiffRenderer = React.memo<SelectableDiffRendererProps>(
13681287
return;
13691288
}
13701289

1371-
hideReviewTooltip();
1372-
13731290
// Notify parent that this hunk should become active.
13741291
onLineClick?.();
13751292
onLineIndexSelect?.(lineIndex, shiftKey);
@@ -1396,7 +1313,7 @@ export const SelectableDiffRenderer = React.memo<SelectableDiffRendererProps>(
13961313
return { startIndex: anchor, endIndex: lineIndex };
13971314
});
13981315
},
1399-
[hideReviewTooltip, onLineClick, onLineIndexSelect, onReviewNote, renderSelectionStartIndex]
1316+
[onLineClick, onLineIndexSelect, onReviewNote, renderSelectionStartIndex]
14001317
);
14011318

14021319
const updateDragSelection = React.useCallback(
@@ -1413,8 +1330,6 @@ export const SelectableDiffRenderer = React.memo<SelectableDiffRendererProps>(
14131330
);
14141331

14151332
const handleCommentButtonClick = (lineIndex: number, shiftKey: boolean) => {
1416-
hideReviewTooltip();
1417-
14181333
// Keep immersive cursor/hunk selection in sync with inline comment actions.
14191334
onLineClick?.();
14201335
onLineIndexSelect?.(lineIndex, shiftKey);
@@ -1573,17 +1488,13 @@ export const SelectableDiffRenderer = React.memo<SelectableDiffRendererProps>(
15731488
reviewButton={
15741489
onReviewNote && (
15751490
<>
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. */}
1491+
{/* Both review panes share SelectableDiffRenderer, so keep the
1492+
review action inline without an extra floating tooltip
1493+
covering nearby lines. */}
15791494
<button
15801495
type="button"
15811496
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"
15821497
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)}
15871498
onClick={(e) => {
15881499
e.stopPropagation();
15891500
handleCommentButtonClick(displayIndex, e.shiftKey);
@@ -1645,25 +1556,6 @@ export const SelectableDiffRenderer = React.memo<SelectableDiffRendererProps>(
16451556
);
16461557
})}
16471558
</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-
)}
16671559
</>
16681560
);
16691561
}

src/browser/features/Shared/SelectableDiffRenderer.dragSelect.test.tsx

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ describe("SelectableDiffRenderer drag selection", () => {
103103
}
104104
});
105105

106-
test("hovering the review button uses the full custom range-selection tooltip", async () => {
106+
test("hovering the review button does not show a tooltip", async () => {
107107
const content = "+const a = 1;\n+const b = 2;";
108108

109109
const { container } = render(
@@ -128,11 +128,9 @@ describe("SelectableDiffRenderer drag selection", () => {
128128

129129
fireEvent.mouseEnter(commentButton!);
130130

131-
await waitFor(() => {
132-
expect(document.body.textContent).toContain(
133-
"Add review comment (Shift-click or drag to select range)"
134-
);
135-
});
131+
expect(document.body.textContent).not.toContain(
132+
"Add review comment (Shift-click or drag to select range)"
133+
);
136134
});
137135

138136
test("dragging on the indicator column selects a line range", async () => {

0 commit comments

Comments
 (0)