Fix composer height reset after send

This commit is contained in:
murashit 2026-06-16 10:41:55 +09:00
parent b1fc211bb7
commit 71a888fe4d
2 changed files with 100 additions and 0 deletions

View file

@ -93,6 +93,8 @@ export function ComposerShell({
const suggestionsRef = useRef<HTMLDivElement | null>(null);
const selectedSuggestionRef = useRef<HTMLDivElement | null>(null);
const previousDraftRef = useRef(draft);
const onHeightChangeRef = useRef(callbacks.onHeightChange);
onHeightChangeRef.current = callbacks.onHeightChange;
const preservedSelection = preserveComposerSelection(composerRef.current, previousDraftRef.current, draft);
useLayoutEffect(() => {
const composer = composerRef.current;
@ -103,6 +105,10 @@ export function ComposerShell({
onComposer(null);
};
}, [onComposer]);
useLayoutEffect(() => {
const composer = composerRef.current;
if (syncComposerHeight(composer)) onHeightChangeRef.current();
}, [draft]);
useLayoutEffect(() => {
const container = suggestionsRef.current;
const selected = selectedSuggestionRef.current;

View file

@ -423,6 +423,100 @@ describe("ComposerShell decisions", () => {
}
});
it("shrinks composer autogrow when the controlled draft clears after send", () => {
const parent = document.createElement("div");
const callbacks = composerCallbacks();
const onComposer = vi.fn();
let scrollHeight = 120;
const descriptor = Object.getOwnPropertyDescriptor(HTMLTextAreaElement.prototype, "scrollHeight");
Object.defineProperty(HTMLTextAreaElement.prototype, "scrollHeight", {
get: () => scrollHeight,
configurable: true,
});
try {
renderUiRoot(
parent,
h(ComposerShell, {
viewId: "view",
draft: "line one\nline two",
busy: false,
canInterrupt: false,
normalPlaceholder: "Ask Codex to work on this task...",
suggestions: [],
selectedSuggestionIndex: 0,
callbacks,
meta: {
fatal: null,
context: {
cells: [
{ text: "⣀", placeholder: true },
{ text: "⣀", placeholder: true },
{ text: "⣀", placeholder: true },
{ text: "⣀", placeholder: true },
],
percent: "--%",
},
statusSummary: "Context unavailable, plan off, auto-review off, fast off, model default, reasoning effort default",
model: "default",
effort: null,
planActive: false,
autoReviewActive: false,
fastActive: false,
},
onComposer,
}),
);
const composer = parent.querySelector<HTMLTextAreaElement>(".codex-panel__composer-input");
if (!composer) throw new Error("Expected composer shell elements to mount.");
expect(composer.style.height).toBe("120px");
scrollHeight = 56;
renderUiRoot(
parent,
h(ComposerShell, {
viewId: "view",
draft: "",
busy: false,
canInterrupt: false,
normalPlaceholder: "Ask Codex to work on this task...",
suggestions: [],
selectedSuggestionIndex: 0,
callbacks,
meta: {
fatal: null,
context: {
cells: [
{ text: "⣀", placeholder: true },
{ text: "⣀", placeholder: true },
{ text: "⣀", placeholder: true },
{ text: "⣀", placeholder: true },
],
percent: "--%",
},
statusSummary: "Context unavailable, plan off, auto-review off, fast off, model default, reasoning effort default",
model: "default",
effort: null,
planActive: false,
autoReviewActive: false,
fastActive: false,
},
onComposer,
}),
);
expect(parent.querySelector<HTMLTextAreaElement>(".codex-panel__composer-input")).toBe(composer);
expect(composer.style.height).toBe("56px");
expect(callbacks.onHeightChange).toHaveBeenCalled();
} finally {
if (descriptor) {
Object.defineProperty(HTMLTextAreaElement.prototype, "scrollHeight", descriptor);
} else {
Reflect.deleteProperty(HTMLTextAreaElement.prototype, "scrollHeight");
}
}
});
it("scrolls the selected composer suggestion fully into view below the viewport", () => {
const { container, option } = composerSuggestionScrollFixture({
clientHeight: 100,