fix: inherit run formatting when inserting inline structured content (SD-1421)#2501
Conversation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 7747620487
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| // When the user has a ranged selection, cut the right half from | ||
| // the end of the selection so the selected text is removed. | ||
| const $to = state.doc.resolve(to); | ||
| const endOffset = $to.parent === parentRun ? $to.parentOffset : startOffset; |
There was a problem hiding this comment.
Replace the entire selection when it crosses run boundaries
If the selection starts inside a run but ends in a different sibling run or paragraph, $to.parent !== parentRun makes endOffset fall back to startOffset, and this branch still replaces only runStart..runEnd. In that case insertStructuredContentInline inserts the new SDT next to the original text but leaves the rest of the selected content untouched, so a cross-run selection is no longer actually replaced. The old replaceWith(from, to, node) path handled that case correctly.
Useful? React with 👍 / 👎.
| // from wrapping the SDT itself. | ||
| const runType = schema.nodes.run; | ||
| if (runType && !options.json && content.isText) { | ||
| const formattingState = getFormattingStateAtPos(state, from, editor); |
There was a problem hiding this comment.
Pass stored marks into formatting resolution
This now copies formatting with getFormattingStateAtPos(state, from, editor), but on a collapsed selection that helper ignores state.storedMarks unless they are passed explicitly. If a user toggles bold/font size on an empty cursor and then inserts an inline field, the new structuredContent will inherit the surrounding run instead of the pending toolbar formatting, which is inconsistent with normal text insertion.
Useful? React with 👍 / 👎.
Summary
insertStructuredContentInlineproducedrun > structuredContent > run > textnesting — the SDT is now placed at paragraph level between split sibling runsProblem
insertStructuredContentInlineused a baretr.replaceWith(from, to, sdtNode)to insert the SDT. When the cursor was inside a run, ProseMirror placed the SDT as a child of the run (sincerunhascontent: 'inline*'). ThenwrapTextInRunsPluginnormalized this intorun{null} > SDT > run > text, creating unwanted nesting with an empty outer run.Additionally, the SDT's text content was created without any marks or run wrapping, so it appeared unformatted regardless of the surrounding text style.
Solution
Two changes to
insertStructuredContentInline:runPropertiesfrom the cursor position viagetFormattingStateAtPosand wraps the text in a properly formatted run inside the SDT[leftRun, sdtNode, rightRun]at the paragraph level, producing the correct flat structure