feat: make thread text selectable, keeping line breaks on copy - #43
Merged
Conversation
Flutter joins the selected text of separate paragraphs with nothing between them, so each paragraph, code body and turn is a selection container that ends its copied text in a line break when the selection runs past it, and the thread's area trims the trailing ones. The selection colours derive from `primary` (the highlight at 30%) behind an explicit host `textSelectionTheme`; the palette gains no token.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit df6d381. Configure here.
A code block hosts its own selection area whenever no registrar scope sits above it, which made an opted-out thread with no host area indistinguishable from a standalone block: every fence and code part stayed selectable and took long-press. The thread now becomes a disabled scope in that case, and only in that case, so its content still joins a host's area when one exists above.
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.

Summary
Text in a
FlowThreadis selectable, the way a chat in a browser is: drag across turns with a mouse, long-press on touch, copy with the platform's shortcut or menu.FlowThreadhosts oneSelectionAreaacross every turn, on by default.selectable: falseleaves selection to a host that installs its own area around a larger surface. The area and the per-block containers live inlib/src/utils/flow_selection.dart(internal, not exported).SelectionContainerwhose copied text ends in a line break when the selection runs past it. Paragraphs copy on their own lines and turns a blank line apart; the area trims trailing newlines, so a selection drawn to the end never copies a blank line.FlowCodeBlockrenders its code as one paragraph that joins a thread's selection, and hosts its own selection area on its own, so a standalone block stays selectable with the platform's handles and menu.primary(the highlight at 30%), and the composer's caret and highlight now match. An explicitThemeData.textSelectionThemewins field by field.Reviewer notes:
SelectableRegionwrites the clipboard itself on copy, as the code block'sSelectableTextalready did.Screenshots
Selection is state rather than a component, so the before column is the same thread with nothing selected.
How this was verified
?embed=thread&variant=defaultand?embed=code-block&variant=dartin Chrome, light and dark: drags from a user bubble through prose into code, drags starting inside the code text and in the empty space beside it, double-click word selection in prose and code, and the highlight surviving a scroll. The code header and copy button never highlight.SelectionContainer.disabledor withselectable: false, and the thinking label excluded from select-all.flutter analyzeclean for the package andplayground/;example/reports only its pre-existing missingenv.g.dart.dart format .applied.Checklist
flutter analyze libandflutter analyzeinexample/andplayground/are clean (example/only lacks its generatedenv.g.dart, unrelated)dart format .applieddependencies:inpubspec.yaml(Flutter SDK and flutter.dev packages only)lib/flow_ui.dartand documented indocs/and the README tableCHANGELOG.mdupdated for user-facing changes, with breaking changes called outfeat:,fix:,refactor:,docs:,chore:)Note
Medium Risk
Touches selection and clipboard semantics across the thread, markdown, code blocks, and composer; regressions could affect copy formatting or interaction with host-wrapped
SelectionAreas, but there is no auth or data-handling change.Overview
FlowThreadnow hosts built-in text selection (defaultselectable: true): oneFlowSelectionAreaspans turns so users can drag or long-press across prose, code, and tables, with highlight/handles/toolbar using themeprimary(hosttextSelectionThemestill wins per field).selectable: falsedefers to a parentSelectionAreaor disables thread selection entirely viaSelectionContainer.disabled.New internal
flow_selection.dartwiresFlowSelectionBlockdelegates so copied text keeps paragraph line breaks and blank lines between turns, while the area trims trailing newlines from the clipboard.FlowCodeBlockdrops standaloneSelectableTextin favor of joining the thread selection or hosting its own area when used alone; header labels and other chrome (buttons, list markers, thinking/shimmer lines, attachment pills) are wrapped inSelectionContainer.disabled.FlowComposerapplies the sameflowTextSelectionThemefor caret and highlight. Docs, README, changelog, and the thread demo snippet document the behavior.Reviewed by Cursor Bugbot for commit b6f6199. Bugbot is set up for automated code reviews on this repo. Configure here.