Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions src/browser/hooks/useAutoResizeTextarea.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ function createFakeTextarea(initialScrollHeight: number): {
ref: RefObject<HTMLTextAreaElement>;
assignments: string[];
setScrollHeight: (value: number) => void;
setInlineHeight: (value: string) => void;
} {
let height = "";
let scrollHeight = initialScrollHeight;
Expand Down Expand Up @@ -35,6 +36,9 @@ function createFakeTextarea(initialScrollHeight: number): {
setScrollHeight: (value) => {
scrollHeight = value;
},
setInlineHeight: (value) => {
height = value;
},
};
}

Expand Down Expand Up @@ -90,6 +94,33 @@ describe("useAutoResizeTextarea", () => {
expect(textarea.assignments).toEqual(["auto", "40px"]);
});

it("restores the capped height when a deletion keeps the same measured height", () => {
const textarea = createFakeTextarea(800);
const { rerender } = renderHook(({ value }) => useAutoResizeTextarea(textarea.ref, value, 50), {
initialProps: { value: "line one\nline two\nline three" },
});
expect(textarea.assignments).toEqual(["auto", "500px"]);
textarea.assignments.length = 0;

rerender({ value: "line one\nline two" });

expect(textarea.assignments).toEqual(["auto", "500px"]);
});

it("repairs the inline height after another caller clears it", () => {
const textarea = createFakeTextarea(800);
const { rerender } = renderHook(({ value }) => useAutoResizeTextarea(textarea.ref, value, 50), {
initialProps: { value: "line one\nline two" },
});
expect(textarea.assignments).toEqual(["auto", "500px"]);
textarea.assignments.length = 0;

textarea.setInlineHeight("");
rerender({ value: "line one\nline two!" });

expect(textarea.assignments).toEqual(["500px"]);
});

it("shrinks when a longer replacement does not preserve the previous text", () => {
const textarea = createFakeTextarea(84);
const { rerender } = renderHook(({ value }) => useAutoResizeTextarea(textarea.ref, value, 50), {
Expand Down
9 changes: 8 additions & 1 deletion src/browser/hooks/useAutoResizeTextarea.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,14 @@ export function useAutoResizeTextarea(
nextHeight = Math.min(el.scrollHeight, max);
}

if (appliedHeightRef.current !== nextHeight) {
// The cached height can match even after this effect temporarily set `auto`, or
// after callers cleared the inline style. Verify the DOM still has the px height
// before skipping the write; otherwise large drafts collapse to the CSS min-height.
const currentInlineHeight = Number.parseFloat(el.style.height);
const inlineHeightMatches =
Number.isFinite(currentInlineHeight) && Math.abs(currentInlineHeight - nextHeight) < 0.5;

if (appliedHeightRef.current !== nextHeight || !inlineHeightMatches) {
el.style.height = `${nextHeight}px`;
appliedHeightRef.current = nextHeight;
}
Expand Down
Loading