web: switching chats returns focus to the composer (#921)
The fresh-mount path focuses as chat.js builds ('desktop opens ready to
type'), but instant-restoring a parked pane rebuilds nothing — switching
between already-open chats left focus wherever it was. Call
focusChatComposer() after the pane mounts (it self-guards touch and
never steals from another editable field), and point the re-tap branch
at it too — that branch still focused the legacy #text textarea, a
hidden no-op since the chat app took over.
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
1 file changed,
+7
−1
web/static/shell.js+7 −1
diff --git a/web/static/shell.js b/web/static/shell.js| index fdfa15f..2313063 100644 |
| --- a/web/static/shell.js |
| +++ b/web/static/shell.js |
| @@ -3871,7 +3871,7 @@ async function openThread(id) { |
| // the pane (mobile navigates list → thread). No flash, no wiped draft. |
| if (id === activeId) { |
| document.getElementById("tt").classList.add("show-thread"); |
| - if (!isCoarse) document.getElementById("text").focus(); |
| + focusChatComposer(); // self-guards: no-op on touch / when another field holds focus |
| return; |
| } |
| if (activeId) stashAppPane(activeId); // park the outgoing app-thread's full-pane root |
| @@ -3918,6 +3918,12 @@ async function openThread(id) { |
| } |
| if (renderApp) { |
| await openAppThreadView(id, myOpen, renderApp, threadApp[id] || null); |
| + // Land ready to type. The fresh-mount path focuses in chat.js as it |
| + // builds; the instant-restore path re-attaches a parked root without |
| + // rebuilding, so it needs this nudge. focusChatComposer self-guards |
| + // (touch, another editable focused); embed's focus belongs to the |
| + // native composer. |
| + if (myOpen === openSeq && !embed) focusChatComposer(); |
| return; |
| } |
| // No feed to mount for this thread. Never leave the outgoing thread's feed |