Skip to content

Commit 02cdbdc

Browse files
committed
fix(rich-markdown-editor): isolate verbatim block nodes from boundary joins
footnoteDef and rawHtmlBlock hold exact source text but were neither isolating nor atom, so a single Backspace/Delete at their boundary let ProseMirror's default join merge their raw markdown into an adjacent paragraph as HTML-escaped prose — silently destroying the node and corrupting saved markdown. Mark the block variants isolating so boundary keys can't cross their edge. Round-trip and in-place editing are unchanged.
1 parent 9acc75c commit 02cdbdc

2 files changed

Lines changed: 33 additions & 0 deletions

File tree

apps/sim/app/workspace/[workspaceId]/files/components/file-viewer/rich-markdown-editor/keymap.test.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,3 +228,32 @@ describe('empty list-item Enter', () => {
228228
editor.destroy()
229229
})
230230
})
231+
232+
describe('verbatim block boundary (isolating)', () => {
233+
beforeEach(() => {
234+
Element.prototype.scrollIntoView = vi.fn()
235+
})
236+
237+
function caretIntoNode(editor: Editor, nodeType: string): void {
238+
editor.state.doc.descendants((node, pos) => {
239+
if (node.type.name === nodeType) editor.commands.setTextSelection(pos + 1)
240+
})
241+
}
242+
243+
it.each([
244+
['footnote definition', 'body text[^x]\n\n[^x]: the note', 'footnoteDef'],
245+
['raw HTML block', 'body\n\n<div>\nhello\n</div>', 'rawHtmlBlock'],
246+
])(
247+
'Backspace at the start of a %s does not merge across its boundary and destroy it',
248+
(_label, markdown, nodeType) => {
249+
const editor = editorWith('')
250+
editor.commands.setContent(markdown, { contentType: 'markdown' })
251+
editor.commands.focus()
252+
expect(blockShape(editor)).toContain(nodeType)
253+
caretIntoNode(editor, nodeType)
254+
pressBackspace(editor)
255+
expect(blockShape(editor)).toContain(nodeType)
256+
editor.destroy()
257+
}
258+
)
259+
})

apps/sim/app/workspace/[workspaceId]/files/components/file-viewer/rich-markdown-editor/raw-markdown-snippet.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,10 @@ function verbatimNodeConfig({ name, inline, badgeLabel }: VerbatimNodeOptions) {
167167
marks: '',
168168
code: true,
169169
defining: !inline,
170+
// Block verbatim nodes hold exact source text; `isolating` stops a boundary Backspace/Delete from
171+
// joining across their edge, which would otherwise merge their raw markdown into an adjacent
172+
// paragraph as HTML-escaped prose and destroy the node (silent data loss on save).
173+
isolating: !inline,
170174
selectable: true,
171175
atom: false,
172176
parseHTML() {

0 commit comments

Comments
 (0)