1import type { CodeViewScrollTarget } from "@pierre/diffs";
2import { useCallback, useEffect, useRef, useState } from "react";
3
4interface FileRevealHandle {
5 getInstance(): object | undefined;
6 scrollTo(target: CodeViewScrollTarget): void;
7}
8
9// Wait for a mounted viewer and expanded rows, then apply each tree click once.
10// Keep scope stable until the diff or external file selection changes.
11export function useCodeViewFileReveal<TScope>(
12 viewer: FileRevealHandle | null,
13 scope: TScope,
14 readyFileKeys?: ReadonlyArray<string>,
15) {
16 const [request, setRequest] = useState<{ fileKey: string; scope: TScope } | null>(null);
17 const handledRequest = useRef<typeof request>(null);
18
19 useEffect(() => {
20 if (request === null || handledRequest.current === request) return;
21 if (request.scope !== scope) {
22 handledRequest.current = request;
23 return;
24 }
25 if (!viewer?.getInstance() || (readyFileKeys && !readyFileKeys.includes(request.fileKey)))
26 return;
27
28 viewer.scrollTo({ type: "item", id: request.fileKey, align: "start" });
29 handledRequest.current = request;
30 }, [request, scope, viewer, readyFileKeys]);
31
32 return useCallback((fileKey: string) => setRequest({ fileKey, scope }), [scope]);
33}