From abd782494ed2c33315a4cbede67aedfce1131539 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A8=8B=E5=BA=8F=E5=91=98=E9=98=BF=E6=B1=9F=28Relakkes?= =?UTF-8?q?=29?= Date: Tue, 19 May 2026 22:26:18 +0800 Subject: [PATCH] fix: keep desktop composer toolbar out of multiline input The active-session composer used an absolute toolbar overlay and textarea bottom padding to reserve space. When the input grew and scrolled, the caret could render inside that reserved overlay area, making it appear to pass through the controls. Move the non-hero toolbar back into normal layout flow and remove the oversized textarea bottom padding so the text area and controls occupy separate boxes. Constraint: Active-session and hero composer variants share the component, so keep the change scoped to the non-hero toolbar path. Rejected: Increase textarea bottom padding | preserves the overlapping layout that caused the caret artifact. Confidence: high Scope-risk: narrow Directive: Do not reintroduce an absolutely positioned toolbar over the active-session textarea without validating multiline caret rendering. Tested: cd desktop && bun run test src/components/chat/ChatInput.test.tsx Tested: cd desktop && bun run lint Tested: bun run check:desktop Tested: Browser DOM check confirmed textarea and toolbar no longer overlap. --- desktop/src/components/chat/ChatInput.test.tsx | 16 ++++++++++++++++ desktop/src/components/chat/ChatInput.tsx | 8 ++++---- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/desktop/src/components/chat/ChatInput.test.tsx b/desktop/src/components/chat/ChatInput.test.tsx index 05c42d26..6b1c3d63 100644 --- a/desktop/src/components/chat/ChatInput.test.tsx +++ b/desktop/src/components/chat/ChatInput.test.tsx @@ -841,6 +841,22 @@ describe('ChatInput file mentions', () => { expect(fileSearchMenu).not.toHaveTextContent('Navigate') }) + it('keeps the active-session toolbar in flow so multiline caret cannot render behind controls', async () => { + render() + + await waitFor(() => { + expect(mocks.getGitInfo).toHaveBeenCalledWith(sessionId) + }) + + const input = screen.getByRole('textbox') + const toolbar = screen.getByTestId('chat-input-toolbar') + + expect(toolbar).not.toHaveClass('absolute') + expect(toolbar).toHaveClass('mt-2') + expect(input).not.toHaveClass('pb-12') + expect(input).not.toHaveClass('pb-14') + }) + it('prioritizes active-session slash commands by command name when filtering', async () => { useChatStore.setState({ sessions: { diff --git a/desktop/src/components/chat/ChatInput.tsx b/desktop/src/components/chat/ChatInput.tsx index 0b1d9f2c..48bc7aae 100644 --- a/desktop/src/components/chat/ChatInput.tsx +++ b/desktop/src/components/chat/ChatInput.tsx @@ -983,15 +983,15 @@ export function ChatInput({ variant = 'default', compact = false }: ChatInputPro disabled={isWorkspaceMissing} rows={1} className={`w-full resize-none bg-transparent text-sm leading-relaxed text-[var(--color-text-primary)] outline-none placeholder:text-[var(--color-text-tertiary)] disabled:opacity-50 ${ - useCompactControls ? 'py-1.5 pb-14' : 'py-2 pb-12' + useCompactControls ? 'py-1.5' : 'py-2' }`} /> )} -
{!isMemberSession && (