MCPcopy Index your code
hub / github.com/claude-code-best/claude-code / DiffDialog

Function DiffDialog

src/components/diff/DiffDialog.tsx:55–264  ·  view source on GitHub ↗
({ messages, onDone }: Props)

Source from the content-addressed store, hash-verified

53}
54
55export function DiffDialog({ messages, onDone }: Props): React.ReactNode {
56 const gitDiffData = useDiffData();
57 const turnDiffs = useTurnDiffs(messages);
58
59 const [viewMode, setViewMode] = useState<ViewMode>('list');
60 const [selectedIndex, setSelectedIndex] = useState<number>(0);
61 const [sourceIndex, setSourceIndex] = useState<number>(0);
62
63 const sources: DiffSource[] = useMemo(
64 () => [{ type: 'current' }, ...turnDiffs.map((turn): DiffSource => ({ type: 'turn', turn }))],
65 [turnDiffs],
66 );
67
68 const currentSource = sources[sourceIndex];
69 const currentTurn = currentSource?.type === 'turn' ? currentSource.turn : null;
70
71 const diffData = useMemo((): DiffData => {
72 return currentTurn ? turnDiffToDiffData(currentTurn) : gitDiffData;
73 }, [currentTurn, gitDiffData]);
74
75 const selectedFile = diffData.files[selectedIndex];
76 const selectedHunks = useMemo(() => {
77 return selectedFile ? diffData.hunks.get(selectedFile.path) || [] : [];
78 }, [selectedFile, diffData.hunks]);
79
80 // Clamp sourceIndex when sources shrink (e.g., conversation rewind)
81 useEffect(() => {
82 if (sourceIndex >= sources.length) {
83 setSourceIndex(Math.max(0, sources.length - 1));
84 }
85 }, [sources.length, sourceIndex]);
86
87 // Reset file selection when source changes
88 const prevSourceIndex = useRef(sourceIndex);
89 useEffect(() => {
90 if (prevSourceIndex.current !== sourceIndex) {
91 setSelectedIndex(0);
92 prevSourceIndex.current = sourceIndex;
93 }
94 }, [sourceIndex]);
95
96 // Register as modal overlay so Chat keybindings and CancelRequestHandler
97 // are disabled while DiffDialog is showing
98 useRegisterOverlay('diff-dialog');
99
100 // Diff dialog navigation keybindings
101 // View-mode dependent: left/right arrows have different behavior based on mode
102 // (source tab switching vs back navigation), and up/down/enter are
103 // context-sensitive to viewMode
104 //
105 // Note: Escape handling (diff:dismiss) is NOT registered here because Dialog's
106 // built-in useKeybinding('confirm:no', handleCancel) already handles it.
107 // Having both would be dead code since Dialog's child effect registers first
108 // and calls stopImmediatePropagation(). The diff:dismiss binding in
109 // defaultBindings.ts is kept for useShortcutDisplay to show the "esc close" hint.
110 useKeybindings(
111 {
112 // Left arrow: in detail mode goes back, in list mode switches source

Callers

nothing calls this directly

Calls 9

useDiffDataFunction · 0.85
useTurnDiffsFunction · 0.85
turnDiffToDiffDataFunction · 0.85
useRegisterOverlayFunction · 0.85
useKeybindingsFunction · 0.85
pluralFunction · 0.85
useShortcutDisplayFunction · 0.85
maxMethod · 0.80
getMethod · 0.65

Tested by

no test coverage detected