fix(web): keep the composer open while selecting timeline text#9499

merged1
fix/composer-paste-expands
fix/composer-hold-for-selection
openedSep 3, 2026byJJulius Marminge
View on GitHubTwo-way sync enabledPR last imported 3d ago

Raised on #7855 with a video: drag-selecting an assistant response while the composer is expanded makes the Cite button flash and vanish. The selection blurs the composer, the composer rests, the timeline reflows under it, and the selection toolbar dismisses on that scroll.

The blur check now holds while a non-collapsed selection lives inside the timeline, and a selectionchange listener re-runs it once the selection clears (click elsewhere, Escape, or using Cite). The rest still happens; it just waits until the user is done with the text. Desktop only; the phone collapse is focus-driven and unaffected.

Stacked on #9498 (paste-to-focus); this layer's diff is independent of it.

Before

Drag-select with the composer expanded: composer rests (84px), no Cite button.

before

https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/4239771dd51fcfde/before-select.mp4

After

Composer stays expanded through the selection, Cite is usable, and the citation lands in the draft. Once the selection clears the composer rests as before.

Selection heldCite used
after selectafter cite

https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/4a53b1968522ead9/after-select.mp4

Verification

  • vp test run on the new composerSelectionHold.test.ts (4 passing).
  • tsgo --noEmit in web, lint clean on the touched files.
  • Manual pass in the web app: held at 178px with Cite visible โ†’ clear selection โ†’ rests at 84px.

Claude Fable 5 via Claude Code.

๐Ÿค– Generated with Claude Code

Note

Keep ChatComposer open while selecting timeline text on desktop

  • Adds selectionHoldsComposerOpen predicate that returns true only for a non-collapsed selection whose range ancestor is inside the timeline node
  • Updates the desktop blur/collapse check in ChatComposer.tsx to skip clearing focus while a timeline selection is active, and adds a selectionchange listener that schedules a collapse check when the selection ends
  • Adds unit tests in composerSelectionHold.test.ts covering active, collapsed, external, empty, and missing-node cases
  • Behavioral Change: mobile is excluded from both new paths; desktop composer will no longer auto-collapse during an active timeline selection

Macroscope summarized 4557997.

Added 1 commit

  • fix(web): keep the composer open while selecting timeline text4557997
Synced from GitHub

Thread transfer impact

โœ… Thread transfer remains within every enforced ceiling.

โ„น๏ธ No successful main baseline artifact is available yet. This run establishes the initial measurement.

ProviderMetricMain baselineThis PRImpactPR ceiling
CodexTotal thread wireโ€”13.7 KiBโ€”15.1 KiBโœ…
CodexThread snapshot wireโ€”7.0 KiBโ€”7.3 KiBโœ…
CodexLive turn WebSocket wireโ€”6.7 KiBโ€”7.8 KiBโœ…
CodexLive turn WebSocket decodedโ€”58.5 KiBโ€”66.4 KiBโœ…
CodexLive turn messagesโ€”10โ€”21โœ…
ClaudeTotal thread wireโ€”13.6 KiBโ€”15.1 KiBโœ…
ClaudeThread snapshot wireโ€”7.0 KiBโ€”7.3 KiBโœ…
ClaudeLive turn WebSocket wireโ€”6.6 KiBโ€”7.8 KiBโœ…
ClaudeLive turn WebSocket decodedโ€”57.9 KiBโ€”66.4 KiBโœ…
ClaudeLive turn messagesโ€”10โ€”21โœ…

Baseline: unavailable ยท PR result: 4557997 ยท Source CI: success

Scenario and decoded snapshot size

10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.

  • Codex decoded thread snapshot: 113.8 KiB
  • Claude decoded thread snapshot: 114.5 KiB

Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed.

CcursorBotreviewed ยท 1 inline threadSep 3, 2026
Synced from GitHub

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Fix All in Cursor

Bugbot Autofix is ON, but a cloud agent failed to start.

Reviewed by Cursor Bugbot for commit 4557997a01c6af375598d8b97c293045a1f8b5fb. Configure here.

โ€ฆโ€ฆ@@ -4293,9 +4294,42 @@ export const ChatComposer = memo(function ChatComposer(props: ChatComposerProps)
4329+ isComposerFocused,
4330+ isMobileViewport,
4331+ scheduleComposerCollapseCheck,
4332+ ]);
CcursorBoton line 4332Sep 3, 2026

Focus-in bypasses selection hold

Medium Severity

The new timeline-selection hold only gates scheduleComposerCollapseCheck. Desktop focusin still calls setIsComposerFocused(false) as soon as focus leaves the composer. Tabbing to the portaled Cite control therefore rests the composer, reflows the timeline, and can dismiss the toolbar this change is meant to keep usable.

Additional Locations (1)

Reviewed by Cursor Bugbot for commit 4557997a01c6af375598d8b97c293045a1f8b5fb. Configure here.

Synced from GitHub

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable โ€” This focused desktop UI fix changes composer collapse behavior during timeline text selection, but the focus-management path still has a plausible route that can dismiss the composer while the selection toolbar is in use. Human validation is warranted for the complete selection and focus interaction.

You can add or adjust custom eligibility rules. Learn more.