feat(text): markdown formatting with floating format bar - #175
devin-ai-integration[bot] wants to merge 8 commits into
Conversation
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
|
I'll fix CI failures and address comments from users with write access. I'll skip comments containing "(aside)".
|
|
Important Review skippedBot user detected. To trigger a single review, invoke the ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Advanced Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
|
| final below = childRect.bottom + 8; | ||
| final top = below + TextFormatBar.height + 8 <= overlaySize.height | ||
| ? below | ||
| : childRect.top - TextFormatBar.height - 8; |
There was a problem hiding this comment.
When the bar cannot fit below a tall text widget near the top of the overlay, the fallback puts it above the widget without bounding the result. A frame at top = 10 calculates 10 - 36 - 8 = -34, leaving nearly all of the 36px toolbar outside the viewport and its formatting controls inaccessible. Clamp the fallback to a visible overlay inset, or use a bounded placement when neither preferred side has enough room.
There was a problem hiding this comment.
Fixed in 1842972: top is now clamped to [8, overlayHeight - barHeight - 8], same as left.
Comments Outside DiffThese findings sit on lines the diff does not cover, so they could not be posted inline. Each one leaves this list once its file changes.
|
…heck Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
… for active Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Summary
Text widgets now understand a small Markdown subset and get a floating format bar while editing, so people who don't know the syntax can still bold, bullet, number, and head their notes. Always on, no setting.
PlacedText.textstays a plainString(the source with markers), so nothing changes for Hive, migrations, or.icaround-trips; old strategies render exactly as before unless they happen to contain markers.Supported:
**bold**,*italic*/_italic_,-/*/•bullets,1./1)numbered,#–###headings. Unclosed markers stay literal. No Markdown dependency; the parser is ~200 lines intext_markup.dart.How it fits together
FormattedTextView. Tap →TextField(decoration: null)withMarkupTextEditingController, both inside the same 12px vertical padding, so the card is the same height in either state (hint is drawn by hand for the empty case); focus loss commits the draft and returns to the formatted view. Same swap for drag feedback, screenshots, and page transitions, so every non-editing path renders formatted.OverlayPortal(not scaled by map zoom), centred under the widget's transformed bounds, flips above when there's no room below, clamped to the viewport. Its taps share aTapRegiongroup with the field so clicking a button doesn't end editing.ListContinuationFormatter), Enter on an empty item exits the list. Ctrl/Cmd+B and +I toggle inline marks; with a collapsed caret they wrap the word under the caret, or insert****and park the caret inside._TextBoxFrame), and the overlay is outside it, so resize, drag, and defense-side mirroring behave as before.EditorToolbarButtongained anactiveflag: the glyph turns violet (DESIGN.md: violet on an icon means checked), no fill.One test removed:
canonical_coordinates_testasserted the live card height equalsPlacedMediaGeometry.legacyTextFootprintInWorld. That formula only feeds the one-time canonical-coordinates migration and models the oldTextFieldcard; the runtime mirrors from live measurement, and the new card (text + 12px padding, no Material chrome) is a different height at the same font, so the two can't stay equal by design. Shout if you'd rather I pin the card to the old footprint instead.Screenshots (Linux run)
Editing, bar below the widget, markers dimmed, active kind in violet:
Same widget not editing (same card height):
Rendered after focus loss, after a resize:
Heading + numbered list + inline bold rendered:
Defense side (mirrored), formatting intact:
Exported screenshot (camera button) crop:
Video walkthrough is in the first comment.
Tests
test/text_markup_test.dart,test/formatted_text_view_test.dartnew;test/text_widget_resilience_test.dartextended (enter editing, draft, commit on blur).fvm flutter analyzeclean for touched files; targeted suite+42 passed.Link to Devin session: https://app.devin.ai/sessions/dc7ec45e6e12464494017e5ba546e542
Open in Devin Desktop: https://app.devin.ai/desktop/session/dc7ec45e6e12464494017e5ba546e542?variant=devin
Requested by: @SunkenInTime