fix: preserve desktop composer focus across sends and navigation - #413
Merged
Conversation
Model: gpt-6
Consolidate submission lifetime and focus ownership after independent ablation and negative-control validation. Remove repeated PR 143 fixtures while preserving session-switch coverage. Model: gpt-6
Carry a one-shot navigation focus request to the mounted session composer. Exclude narrow mobile layouts and native shells from entry and completion auto-focus, including rejected submissions. Model: gpt-6
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Related issue
Refs #131
Follow-up to #143.
Problem / pressure
Desktop message submission still lost focus because clearing the real mention composer remounted its textarea, invalidating the previous DOM equality guard. Starting a conversation from chat landing also had no focus handoff to the newly mounted session composer. Mobile rejection recovery could reopen the keyboard, and the landing mount guard missed wide native tablets.
Summary
Keep the textarea mounted on empty transitions and reset mention data/menu/hydration separately. One scoped submission token owns lifetime identity and synchronous submission exclusion; explicit completion state restores desktop focus after React commits. Outside focus/pointer interaction and window blur relinquish ownership. Session changes/unmount retire submissions; late acceptance clears only an unchanged captured draft.
Desktop session creation carries a one-shot focus request in navigation state. Session detail passes the claim to its visible target composer, which consumes it when the input actually mounts, including delayed preparation. Consumption clears the history-state request so remounts and Back do not replay it; entry identity rejects stale claims.
Narrow mobile layouts and native shells, including wide iPads, never auto-focus on landing entry, session creation, or submission completion, whether accepted or rejected. Mobile submission dismisses the keyboard without installing desktop focus listeners. Explicit user focus actions remain available.
Ablation evidence
Individual deletions identified redundant active/finished flags, native focus eligibility checks, the keyboard/button source argument, imperative DOM clearing, and the counter that mirrored draft identity. Remove #143's parallel focus refs/effect and consolidate its repeated session-switch fixture into real-composer parameterized coverage.
The active-element fallback required a stronger replacement: removing it alone failed a stopped-propagation case; capture-phase focus observation covered that behavior and allowed the fallback's removal. Negative controls independently removed the post-commit handoff, lifetime identity, focus/pointer/window listeners, hydration reset, menu ownership, and submission lock; each caused observable regression failures and was reverted.
Test plan
pnpm checkand formatting passed; unrelated formatter changes were excluded.VITE_PREVIEW_PUBLIC_BASE_DOMAIN=preview.example.test pnpm --dir packages/components exec playwright test tests/e2e/composer-submission-focus.spec.ts --workers=1.Context handoff
Instructions for reviewing agents
Authoring context