From a460f253c9ad70d0796148a4d86a0497e1888358 Mon Sep 17 00:00:00 2001 From: Philip Zeyliger Date: Sat, 7 Feb 2026 05:41:23 +0000 Subject: [PATCH] shelley/ui: fix focus loss after pasting image Prompt: Fix https://github.com/boldsoftware/shelley/issues/65 again. The textarea was disabled during uploads (isDisabled = disabled || uploadsInProgress > 0). When a paste triggered an upload, uploadsInProgress went to 1, disabling the textarea, which caused the browser to yank focus out of it. Fix: only disable the textarea based on the disabled prop, not uploads. The send button still gates on uploadsInProgress === 0, so users can't send while uploads are in flight, but they can keep typing. Also fix the e2e test that was placed outside its describe block. Fixes boldsoftware/shelley#65 Co-authored-by: Shelley --- ui/e2e/file-upload.spec.ts | 2 +- ui/src/components/MessageInput.tsx | 10 ++-------- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/ui/e2e/file-upload.spec.ts b/ui/e2e/file-upload.spec.ts index 2f72f578a811b4287ba2c3b64dbc14b868a8a8da..4464a35e6a3e7178a66f8e09af7228a01dec4b97 100644 --- a/ui/e2e/file-upload.spec.ts +++ b/ui/e2e/file-upload.spec.ts @@ -195,7 +195,6 @@ test.describe('File Upload via Paste and Drag', () => { // Both are acceptable as we're testing the UI flow expect(inputValue).toBeTruthy(); }); -}); test('focus is retained in input after pasting image', async ({ page }) => { await page.goto('/'); @@ -246,3 +245,4 @@ test.describe('File Upload via Paste and Drag', () => { const inputValue = await messageInput.inputValue(); expect(inputValue).toContain('Testing paste focus:'); }); +}); diff --git a/ui/src/components/MessageInput.tsx b/ui/src/components/MessageInput.tsx index 0fbb97b918fa72461f680d83086b16069973fa59..a414beccd5be8dbf0ddd33586b061a9ae6f272ae 100644 --- a/ui/src/components/MessageInput.tsx +++ b/ui/src/components/MessageInput.tsx @@ -237,12 +237,6 @@ function MessageInput({ event.preventDefault(); // Fire and forget - uploadFile handles state updates internally. uploadFile(file); - // Restore focus after React updates. We use setTimeout(0) to ensure - // the focus happens after React's state update commits to the DOM. - // The timeout must be longer than 0 to reliably work across browsers. - setTimeout(() => { - textareaRef.current?.focus(); - }, 10); return; } } @@ -411,8 +405,8 @@ function MessageInput({ }; }, []); - const isDisabled = disabled || uploadsInProgress > 0; - const canSubmit = message.trim() && !isDisabled && !submitting; + const isDisabled = disabled; + const canSubmit = message.trim() && !isDisabled && !submitting && uploadsInProgress === 0; const isDraggingOver = dragCounter > 0; // Check if user is typing a shell command (starts with !)