shelley/ui: fix focus loss after pasting image

Philip Zeyliger and Shelley created

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 <shelley@exe.dev>

Change summary

ui/e2e/file-upload.spec.ts         |  2 +-
ui/src/components/MessageInput.tsx | 10 ++--------
2 files changed, 3 insertions(+), 9 deletions(-)

Detailed changes

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:');
   });
+});

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 !)