eleven / messenger Public

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>
Paul Campbell 5c527edd95a9808b0b93f7b60b422cd404d38950 parent d596c42
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