diff --git a/apps/web/src/components/chat/AssistantCitationChip.browser.test.tsx b/apps/web/src/components/chat/AssistantCitationChip.browser.test.tsx index deee8d7afa69d..d583b69d02569 100644 --- a/apps/web/src/components/chat/AssistantCitationChip.browser.test.tsx +++ b/apps/web/src/components/chat/AssistantCitationChip.browser.test.tsx @@ -1,5 +1,6 @@ import { ASSISTANT_CITATION_MAX_COMMENT_LENGTH, + type AssistantCitation, EnvironmentId, MessageId, ThreadId, @@ -50,12 +51,16 @@ function setup() { return { sourceAnchor, [Symbol.dispose]: () => source.remove() }; } -function mount(sourceAnchor: AssistantCitationSourceAnchor, onSave: () => boolean) { +function mount( + sourceAnchor: AssistantCitationSourceAnchor | undefined, + onSave: () => boolean, + chipCitation: AssistantCitation = citation, +) { function Composer() { const [open, setOpen] = useState(true); return ( @@ -128,6 +133,25 @@ describe("citation comment source disappearance", () => { }); }); +describe("citation comment caret", () => { + it("opens a saved comment with the caret after its end, scrolled into view", async () => { + using _source = setup(); + const comment = `${"line\n".repeat(40)}end`; + await using _screen = await mount( + undefined, + vi.fn(() => true), + { ...citation, comment }, + ); + await vi.waitFor(() => expect(document.activeElement).toBe(textarea())); + const input = textarea()!; + + expect(input.scrollHeight).toBeGreaterThan(input.clientHeight); + expect(input.scrollTop).toBe(input.scrollHeight - input.clientHeight); + await userEvent.keyboard("!"); + expect(input.value).toBe(`${comment}!`); + }); +}); + describe("citation comment popup position", () => { it("stays on screen when the cited text ends in a code block's hidden overflow", async () => { using _source = setup(); diff --git a/apps/web/src/components/chat/AssistantCitationChip.tsx b/apps/web/src/components/chat/AssistantCitationChip.tsx index 2b90b09f68e77..953724c77062e 100644 --- a/apps/web/src/components/chat/AssistantCitationChip.tsx +++ b/apps/web/src/components/chat/AssistantCitationChip.tsx @@ -190,7 +190,13 @@ export function AssistantCitationChip({ align="end" anchor={popupAnchor} initialFocus={() => { - commentInputRef.current?.focus({ preventScroll: true }); + const input = commentInputRef.current; + if (input) { + input.focus({ preventScroll: true }); + input.setSelectionRange(input.value.length, input.value.length); + // Moving the caret doesn't scroll a long comment to it. + input.scrollTop = input.scrollHeight; + } return false; }} finalFocus={