diff --git a/apps/web/src/components/diffs/DiffCommentAnnotation.tsx b/apps/web/src/components/diffs/DiffCommentAnnotation.tsx index d210732b6b60..bce9f7e55f58 100644 --- a/apps/web/src/components/diffs/DiffCommentAnnotation.tsx +++ b/apps/web/src/components/diffs/DiffCommentAnnotation.tsx @@ -1,5 +1,5 @@ import { MessageCircle, Trash2 } from "lucide-react"; -import { useState, type ReactNode } from "react"; +import { useLayoutEffect, useRef, useState, type ReactNode } from "react"; import { Button } from "~/components/ui/button"; import { Textarea } from "~/components/ui/textarea"; @@ -25,6 +25,7 @@ interface DiffCommentAnnotationProps { submitLabel?: string; pending?: boolean; secondaryAction?: DiffCommentSecondaryAction; + focusOnMount?: boolean; } /** The shared inline comment treatment for file previews, thread diffs, and pull-request diffs. */ @@ -40,10 +41,20 @@ export function DiffCommentAnnotation({ submitLabel = "Comment", pending = false, secondaryAction, + focusOnMount = true, }: DiffCommentAnnotationProps) { const [localDraftText, setLocalDraftText] = useState(""); const displayedText = kind === "draft" && !onTextChange ? localDraftText : text; const trimmedText = displayedText.trim(); + const textareaRef = useRef(null); + + useLayoutEffect(() => { + if (kind !== "draft" || !focusOnMount) return; + const frame = window.requestAnimationFrame(() => { + textareaRef.current?.focus({ preventScroll: true }); + }); + return () => window.cancelAnimationFrame(frame); + }, [focusOnMount, kind]); if (kind === "comment") { return ( @@ -78,9 +89,10 @@ export function DiffCommentAnnotation({ onPointerDown={(event) => event.stopPropagation()} >