Uh oh!
There was an error while loading. Please reload this page.
feat(rich-md-editor): table row/col toolbar, raw HTML/footnote support, paste fidelity - #5438
Conversation
…t, paste fidelity - Add a table toolbar (add/delete row, add/delete column, toggle header, delete table) wired to stock @tiptap/extension-table commands - Add verbatim snippet nodes for raw HTML blocks, HTML comments, footnotes (def + ref), and inline raw HTML tags — these no longer force the whole document read-only, and the raw source is directly editable in place - Fix an upstream @tiptap/markdown footgun found while building this: a custom tokenizer with no explicit `start` callback corrupts the shared lexer and silently drops unrelated content elsewhere in the document - Prefer the markdown parser over generic HTML→DOM paste mapping when the plaintext clipboard side looks like markdown, even if an HTML sibling is present - Fix a stale select-all selection surviving a stream-settle content replace, which permanently highlighted every divider/image after a file regeneration
The latest updates on your projects. Learn more about Vercel for GitHub. |
PR SummaryMedium Risk Overview Adds a floating table toolbar when the caret is in a table (insert/delete rows and columns, toggle header row, delete table), using stock Introduces verbatim snippet nodes for raw HTML blocks, HTML comments, footnotes (reference + definition), and unsupported inline HTML. These used to trip the round-trip safety gate and lock the whole file read-only; they now store exact source text, serialize byte-for-byte, and are editable in place (with monospace styling and optional “Raw HTML” / “Footnote” badges in the live editor). Custom markdown tokenizers use an explicit Paste behavior now runs the internal markdown parser when On stream settle, collapses a surviving select-all after Editability gate ( Reviewed by Cursor Bugbot for commit 0eb68c2. Configure here. |
Uh oh!
There was an error while loading. Please reload this page.
Greptile SummaryThis PR adds table row/column toolbar commands, verbatim snippet nodes for raw HTML blocks/comments/footnotes/inline HTML (replacing the previous read-only gate on those constructs), a markdown-prefer paste strategy, and a stream-settle selection-collapse fix.
Confidence Score: 5/5Safe to merge — the verbatim snippet nodes, table toolbar, paste fidelity change, and stream-settle selection fix are all well-contained and thoroughly tested. All three issues raised in the prior review round (multi-line footnote truncation, unbalanced close-tag scan, stale toolbar scroll position) were resolved in 86d1cdb and are covered by new round-trip tests. The start: () => -1 lexer-guard is correct and documented. The paste-preference change is an intentional design decision appropriate for a markdown-first editor. No data-loss paths, schema breakage, or auth issues were found across any of the 14 changed files. No files require special attention. Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[Clipboard paste event] --> B{looksLikeMarkdown text/plain?}
B -- No --> C[ProseMirror DOM path]
B -- Yes --> D[parseMarkdownToDoc insertContent]
E[Markdown source] --> F[marked.js lexer]
F --> G{Token type}
G -- html block --> H[RawHtmlBlock verbatim]
G -- footnoteDef --> I[FootnoteDef verbatim]
G -- footnoteRef --> J[FootnoteRef verbatim]
G -- rawInlineHtml --> K[RawInlineHtml verbatim]
G -- other --> L[Standard tiptap nodes]
H & I --> M[ReactNodeViewRenderer RawBlockView]
J & K --> N[renderHTML span/div]
H & I & J & K --> O[renderMarkdown byte-for-byte]
P[Stream settle] --> Q[setContent new doc]
Q --> R[setTextSelection doc.content.size]
R --> S[setEditable]
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
A[Clipboard paste event] --> B{looksLikeMarkdown text/plain?}
B -- No --> C[ProseMirror DOM path]
B -- Yes --> D[parseMarkdownToDoc insertContent]
E[Markdown source] --> F[marked.js lexer]
F --> G{Token type}
G -- html block --> H[RawHtmlBlock verbatim]
G -- footnoteDef --> I[FootnoteDef verbatim]
G -- footnoteRef --> J[FootnoteRef verbatim]
G -- rawInlineHtml --> K[RawInlineHtml verbatim]
G -- other --> L[Standard tiptap nodes]
H & I --> M[ReactNodeViewRenderer RawBlockView]
J & K --> N[renderHTML span/div]
H & I & J & K --> O[renderMarkdown byte-for-byte]
P[Stream settle] --> Q[setContent new doc]
Q --> R[setTextSelection doc.content.size]
R --> S[setEditable]
Reviews (3): Last reviewed commit: "fix(rich-md-editor): fix CI type errors ..." | Re-trigger Greptile |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
- Collapse the stream-settle selection unconditionally, not only when setContent re-runs — the last streaming tick already syncs lastSyncedBodyRef to the final body, so the fix was previously skipped in the common streamed-content case (Cursor Bugbot) - Support GFM footnote definition continuation lines (>=4-space indented, with blank lines between paragraphs) instead of truncating to just the opening line (Greptile P1) - Fix the inline raw-HTML tokenizer to find the balanced closing tag by tracking nesting depth, instead of matching the first same-name closing tag — fixes corruption on nested same-tag elements like <span>outer <span>inner</span></span> (Greptile P1) - Stop caching the table toolbar's anchor rect by selection key — the same cell can move on screen from scrolling alone with no selection change, and the cached rect went stale (Greptile P2)
waleedlatif1
commented
Jul 6, 2026
waleedlatif1
commented
Jul 6, 2026
@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 86d1cdb. Configure here.
- parseMarkdown callbacks returned null on no-match, which @tiptap/core's MarkdownParseResult type doesn't permit — switch to returning [] (empty array), matching the same no-match convention MarkdownCodeBlock already uses, with identical runtime behavior - Pin NodeViewContent's generic to 'span' (NodeViewContent<'span'> as='span'), since it defaults to 'div' and rejects other `as` values without an explicit type argument Verified with a full `tsc --noEmit` (NODE_OPTIONS=--max-old-space-size=8192, matching CI) — 0 errors, where it previously failed the Next.js build's type-check step.
waleedlatif1
commented
Jul 6, 2026
waleedlatif1
commented
Jul 6, 2026
@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 0eb68c2. Configure here.
Summary
@tiptap/extension-tablecommands — no schema/serializer changes@tiptap/markdownbug found while building this: a custom tokenizer with no explicitstartcallback corrupts the shared lexer, silently dropping unrelated content (images, tables, mentions) elsewhere in the same documentType of Change
Testing
223 tests passing in the rich-markdown-editor directory (up from 196), 362 passing across the whole files module. Added integration-level tests exercising the live editor stack (not just headless parse/serialize): table toolbar commands round-tripping through the real serializer, raw snippet node views rendering and being genuinely editable in the DOM, and the stream-settle selection fix locked in at the ProseMirror mechanism level. Biome clean across all 68 files in the directory.
Checklist