fix(rich-markdown-editor): reliable image selection + serialization/paste polish#5590
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
PR SummaryMedium Risk Overview Images: plain clicks now always node-select via a Save noise: Paste: pasting a single URL/ Reviewed by Cursor Bugbot for commit b281258. Configure here. |
Greptile SummaryThis PR improves the rich markdown editor's image handling, paste behavior, and markdown serialization.
Confidence Score: 5/5This looks safe to merge.
Important Files Changed
Reviews (2): Last reviewed commit: "chore(rich-markdown-editor): drop useles..." | Re-trigger Greptile |
…en-image polish - Reactive editability. The editor runs with shouldRerenderOnTransaction:false, so a node view that read editor.isEditable once at render kept a stale value after setEditable() toggled (e.g. an agent stream settling into the doc), leaving a pasted image showing read-only affordances and code blocks stuck on their read-only label until a full refresh. A shared useEditorEditable hook subscribes to the editor's update/transaction events so both node views track editability reactively. - Deterministic click-to-select. A handleClickOn plugin sets the image's NodeSelection on a plain click so selecting never depends on ProseMirror's click-vs-drag arbitration; grab-anywhere drag-reorder is kept, and modified clicks (Cmd/Ctrl to follow a linked badge) fall through. - Resize commits once. The width previews in local state during the drag and commits to the node once on pointer-up (or pointer-cancel), so a resize is a single undo step and an interrupted drag isn't lost. - Broken-image placeholder. A src that fails to load renders as a visible box with its alt text and stays selectable, instead of collapsing to a bare broken-icon.
…lize The normalizing serializer rewrote a bare URL or <url>/<email> autolink to [url](url) / [a@b.com](mailto:a@b.com) on every save, churning every README's links. postProcessSerializedMarkdown now collapses a link back to its bare form when the visible text already equals the destination (a plain http(s) URL, or an email behind mailto:) — GFM re-autolinks it, so the round-trip is identical with a far quieter diff. Titled links, explicit links, and any link inside a fenced/inline code region are left untouched. Idempotent.
…over it Pasting a single URL (or a bare www. host / email) over a non-empty text selection within one block now wraps the selection in a link, keeping the visible text. www. gets https://, an email gets mailto:, and the href is scheme-sanitized (javascript:/data: rejected; mailto: requires a real user@host address). Collapsed carets, cross-block selections, multi-word pastes, node selections, and code contexts fall through to normal paste.
biome 2.0's noUselessStringRaw flags HIGHLIGHT_BODY — its pattern has no escape sequences, so String.raw is equivalent to a plain template literal (byte-identical value; interpolated into the other String.raw regexes unchanged). Pre-existing on staging; the repo-wide lint gate blocks CI on it.
a66e02a to
b281258
Compare
|
@cursor review |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit b281258. Configure here.
Summary
A pass over the rich-markdown editor to fix a reported image bug and close the highest-value gaps toward SOTA parity. Every change was reproduced-then-fixed and re-verified; 409 editor tests pass with no regressions.
Image selection — the reported bug (reliable now)
shouldRerenderOnTransaction:false, so a node view that readeditor.isEditableonce at render kept a stale value aftersetEditable()toggled (e.g. an agent stream settling into the doc) — leaving a pasted image showing read-only affordances (no drag/grab/resize) and code blocks stuck on their read-only label until a full refresh. A shareduseEditorEditablehook subscribes to the editor'supdate/transactionevents so both node views stay reactive.handleClickOnplugin sets the image'sNodeSelectionon click, so selecting never depends on ProseMirror's click-vs-drag arbitration. Grab-anywhere drag-reorder is kept (validated against how Notion/BlockNote/Lexical/Obsidian/TipTap handle this).Image polish
Serialization + paste
<url>/<email>autolinks to[url](url)on every save, churning every README's links. They now round-trip in their bare form (GFM re-autolinks them) with a far quieter diff — titled/explicit links and links inside code are untouched, and it's idempotent.www./email) over a non-empty text selection wraps it in a link (keeping the text) —www.→https://, email→mailto:, href scheme-sanitized. Carets, multi-word pastes, node selections, and code contexts fall through.Testing
draggable=falseafter settle) → fixed; click selects the node; resize is a single undo step.Not included (documented follow-ups)
Ordered-list nested-indent and table-cell-code pipe escaping need serializer-internals surgery (the serializer uses a fixed indent with no per-marker option); plain-paste, image-upload placeholder, and alt-text editing touch the editor component that can't currently build in the harness for empirical verification. Left as deliberate, scoped follow-ups rather than unverified edits.