diff --git a/src/renderer/src/components/diff-comments/DiffCommentCard.resize.test.tsx b/src/renderer/src/components/diff-comments/DiffCommentCard.resize.test.tsx index f17dfbb7613..648b33357d4 100644 --- a/src/renderer/src/components/diff-comments/DiffCommentCard.resize.test.tsx +++ b/src/renderer/src/components/diff-comments/DiffCommentCard.resize.test.tsx @@ -1,5 +1,5 @@ // @vitest-environment happy-dom -import { act, cleanup, render } from '@testing-library/react' +import { act, cleanup, fireEvent, render } from '@testing-library/react' import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' import { DiffCommentCard } from './DiffCommentCard' @@ -44,6 +44,7 @@ describe('DiffCommentCard content resize', () => { afterEach(() => { cleanup() + vi.restoreAllMocks() vi.unstubAllGlobals() }) @@ -101,4 +102,52 @@ describe('DiffCommentCard content resize', () => { expect(constructObserver).not.toHaveBeenCalled() expect(onContentResize).not.toHaveBeenCalled() }) + + it('requests rail reflow only when the editing textarea height changes', () => { + const onContentResize = vi.fn() + let scrollHeight = 60 + vi.spyOn(HTMLTextAreaElement.prototype, 'scrollHeight', 'get').mockImplementation( + () => scrollHeight + ) + const view = render( + true} + /> + ) + + fireEvent.click(view.getByRole('button', { name: 'Edit note' })) + expect(onContentResize).toHaveBeenCalledOnce() + + const textarea = view.getByRole('textbox') + expect(textarea.style.height).toBe('60px') + fireEvent.change(textarea, { target: { value: 'A saved note!' } }) + expect(onContentResize).toHaveBeenCalledOnce() + + for (let index = 0; index < 50; index++) { + fireEvent.change(textarea, { target: { value: `A saved note! ${index}` } }) + } + expect(textarea.style.height).toBe('60px') + expect(onContentResize).toHaveBeenCalledOnce() + + scrollHeight = 400 + fireEvent.change(textarea, { target: { value: 'A much taller saved note' } }) + expect(textarea.style.height).toBe('240px') + expect(onContentResize).toHaveBeenCalledTimes(2) + + scrollHeight = 480 + fireEvent.change(textarea, { target: { value: 'A still taller saved note' } }) + expect(textarea.style.height).toBe('240px') + expect(onContentResize).toHaveBeenCalledTimes(2) + + scrollHeight = 80 + fireEvent.change(textarea, { target: { value: 'A shorter saved note' } }) + expect(textarea.style.height).toBe('80px') + expect(onContentResize).toHaveBeenCalledTimes(3) + + fireEvent.click(view.getByRole('button', { name: 'Cancel' })) + expect(onContentResize).toHaveBeenCalledTimes(4) + }) }) diff --git a/src/renderer/src/components/diff-comments/DiffCommentCard.tsx b/src/renderer/src/components/diff-comments/DiffCommentCard.tsx index 9e7ddf229ce..6becfe1fb34 100644 --- a/src/renderer/src/components/diff-comments/DiffCommentCard.tsx +++ b/src/renderer/src/components/diff-comments/DiffCommentCard.tsx @@ -35,6 +35,13 @@ type Props = { headerActions?: ReactNode } +function resizeDiffCommentTextarea(textarea: HTMLTextAreaElement): boolean { + const previousHeight = textarea.style.height + textarea.style.height = 'auto' + textarea.style.height = `${Math.min(textarea.scrollHeight, 240)}px` + return textarea.style.height !== previousHeight +} + export function DiffCommentCard({ lineNumber, startLine, @@ -116,8 +123,7 @@ export function DiffCommentCard({ if (!el) { return } - el.style.height = 'auto' - el.style.height = `${Math.min(el.scrollHeight, 240)}px` + resizeDiffCommentTextarea(el) el.focus() el.setSelectionRange(el.value.length, el.value.length) onContentResizeRef.current?.() @@ -281,10 +287,10 @@ export function DiffCommentCard({ value={draft} onChange={(e) => { setDraft(e.target.value) - const el = e.currentTarget - el.style.height = 'auto' - el.style.height = `${Math.min(el.scrollHeight, 240)}px` - onContentResizeRef.current?.() + // Why: rich-review layout measures every note; skip it when this card stayed put. + if (resizeDiffCommentTextarea(e.currentTarget)) { + onContentResizeRef.current?.() + } }} onKeyDown={(e) => { if (e.key === 'Escape') {