Repository navigation
fix(studio): keep the reader put when a disclosure expands, and copy clean selections - #2319
Conversation
peppescg
left a comment
There was a problem hiding this comment.
Thanks Daniel. The selection clean-up is neat, and keeping the toggle in place matches the prototype.
Before merge
- Follow stays off after a small expansion (
apps/web/src/features/chat/chat-workspace.tsx:3308). The click capture on a collapsed element setsatTranscriptBottomto false, and only a scroll event sets it back. When the expansion is small (a reasoning toggle, or Activity with a few rows during a stream) or the click grows nothing (a menu trigger), the reader is still within 80px of the bottom, but nothing re-checks, so the streamed reply runs off-screen until they scroll by hand. Suspend follow for that one resize only, then re-checkisNearTranscriptBottomonce (in the observer callback or a rAF after it), so a small expansion keeps following and the 80px rule stays the single source of truth. Please add a test: expand at the bottom, grow by less than 80px, then grow again as if streaming; it should follow.
Nits:
apps/web/src/features/chat/selected-transcript-text.ts:13,17: thefinallyresetshiddentofalserather than to its earlier value. Save and restore it (const was = el.hidden), so a.sr-onlynode hidden for its own reason isn't revealed.apps/web/src/features/chat/chat-workspace.tsx:2722:captureTranscriptSelectionruns on every pointerup in the transcript and toggles.sr-onlynodes, forcing two layouts even for a plain click. Return early onselection.isCollapsed || selection.rangeCount === 0.- The disclosure unit test injects a bare button. One case with a real Activity or reasoning toggle would catch a later change that drops
aria-expandedfrom them.
ca20997 to
395c619
Compare
|
Thanks Giuseppe. Addressed in 8236dcd.
Checked on top of the current head: Biome, typecheck, the full Studio test suite and Fully or partially written by an AI agent. |
|
Added 1d3ede2 (test only): the Fully or partially written by an AI agent. |
1d3ede2 to
ce7a616
Compare
ce7a616 to
bada93e
Compare
…clean selections Expanding a disclosure no longer lets the content observer pull the reader to the bottom. A transcript selection excludes screen-reader-only spans. Adds the e2e for the transient authorization header cue. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…k the bottom - Expanding a disclosure suspends follow only for the resize it causes; two frames later the 80 px rule decides again, so a small expansion (or a click that grows nothing) keeps following and a tall one stays put. - selectedTranscriptText restores each .sr-only node's earlier hidden value instead of forcing false. - captureTranscriptSelection returns early on a collapsed selection, so a plain click no longer forces two layouts. - Tests cover the real Activity and reasoning toggles, not just a bare button. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
… reading it once The spec read the composer with `inputValue()` right after clicking "Add to chat", which does not retry. The draft lands after a state update, so on a slow CI run (seen on the mobile project) the read returned an empty string. Wait for the value with `toHaveValue` first. Under load (4 workers, 10 repeats on desktop and mobile) the old spec failed once in 20 runs and the fixed one passed 20 of 20. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
bada93e to
d20ca6f
Compare
Summary
Expanding Activity, a reasoning disclosure, "Show all N lines" or "Show more" in the last message let the content ResizeObserver pull the reader to the bottom, sometimes leaving the toggle above the viewport. Transcript selections also carried screen-reader-only text.
Part of #2303 ("Tiny follow-up fixes"); it does not close it. This is PR 9 of 14 in a stack of draft PRs, reviewed and merged in order.
What changed
<section>:onClickCaptureon an[aria-expanded="false"]target stops following. The ref is cleared synchronously because the observer fires before the next render, andsetAtTranscriptBottom(false)keeps it false. Following resumes through the existing paths (scroll back within 80px, or the scroll-to-bottom button). The prototype has no observer and follows only when messages change, so expansion never scrolls there.selectedTranscriptText: hides the.sr-onlyspans the selection crosses for one synchronous read and restores them infinally; used by Add to chat, Copy and Add to canvas.Behavior changes
Expansion never scrolls; collapsing and plain growth still follow. Copied selections omit hidden status text. Note:
[aria-expanded="false"]also matches a collapsed Radix menu trigger inside the transcript, so opening a message action menu at the bottom also stops following until the reader scrolls back within 80px.Screenshots
Before is the parent branch (#2318), after is this PR, with the same scenario code and offline mock data.
The view jumped to the end of the list (
scrollTop1337 to 2057); the Activity toggle is above the viewport.The toggle stays in place with the rows below it (
scrollTopstays 1337). The scroll-to-bottom arrow shows because the reader is no longer following the bottom.Draft:
completed,Tool: Bash,Bash,command: ls,report.txt(hidden status text included).Draft:
Bash,command: ls,report.txt(visible text only).The expansion has to be taller than the viewport for the toggle to leave the screen, so the data uses 30 tools (with 10 tools the toggle moved but stayed visible). The selection highlight is not visible in either image because clicking "Add to chat" clears it.
Verification
Biome, typecheck, the full Studio test suite and
pnpm generated:checkpass on this branch, run on the assembled stack. The full Playwright suite passes on the stack tip (122 passed, 30 skipped, 0 failed, includingchat-approvalagainst a realmecatedbuild). The expand test fails with the click-capture condition neutralised, and the selection e2e fails with the oldselection.toString(). The helper's unit tests are new with the helper. The disclosure unit test uses an injected button rather than a real Activity row.Not included
Native Ctrl+C is unchanged.
Fully or partially written by an AI agent.
🤖 Generated with Claude Code