From d8d460ff6bf0aaedd5a6c7aa4b799116d8d34983 Mon Sep 17 00:00:00 2001 From: Luccas Correa Date: Wed, 11 Feb 2026 15:58:50 -0300 Subject: [PATCH] fix: ignore sdBlockId when pasting content --- packages/super-editor/src/core/InputRule.js | 5 ++++- packages/super-editor/src/core/InputRule.test.js | 6 +++++- .../src/core/inputRules/docx-paste/docx-paste.js | 1 + .../src/core/inputRules/docx-paste/docx-paste.test.js | 3 ++- 4 files changed, 12 insertions(+), 3 deletions(-) diff --git a/packages/super-editor/src/core/InputRule.js b/packages/super-editor/src/core/InputRule.js index f3294fc8f6..4e27f3163a 100644 --- a/packages/super-editor/src/core/InputRule.js +++ b/packages/super-editor/src/core/InputRule.js @@ -392,10 +392,13 @@ export function sanitizeHtml(html, forbiddenTags = ['meta', 'svg', 'script', 'st continue; } - // Remove linebreaktype here - we don't want it when pasting HTML + // Internal/runtime-only attributes must not be preserved across paste. if (child.hasAttribute('linebreaktype')) { child.removeAttribute('linebreaktype'); } + if (child.hasAttribute('data-sd-block-id')) { + child.removeAttribute('data-sd-block-id'); + } walkAndClean(child); } diff --git a/packages/super-editor/src/core/InputRule.test.js b/packages/super-editor/src/core/InputRule.test.js index 7b839896a3..a874f28111 100644 --- a/packages/super-editor/src/core/InputRule.test.js +++ b/packages/super-editor/src/core/InputRule.test.js @@ -80,11 +80,15 @@ describe('InputRule helpers', () => { }); it('sanitizes forbidden tags and attributes', () => { - const sanitized = sanitizeHtml('
ok
'); + const sanitized = sanitizeHtml( + '

ok

', + ); expect(sanitized.querySelector('script')).toBeNull(); const div = sanitized.querySelector('div'); expect(div?.hasAttribute('linebreaktype')).toBe(false); + const paragraph = sanitized.querySelector('p'); + expect(paragraph?.hasAttribute('data-sd-block-id')).toBe(false); expect(div?.querySelector('span')?.textContent).toBe('ok'); }); diff --git a/packages/super-editor/src/core/inputRules/docx-paste/docx-paste.js b/packages/super-editor/src/core/inputRules/docx-paste/docx-paste.js index 54120bcbfd..c73ab4f933 100644 --- a/packages/super-editor/src/core/inputRules/docx-paste/docx-paste.js +++ b/packages/super-editor/src/core/inputRules/docx-paste/docx-paste.js @@ -31,6 +31,7 @@ export const handleDocxPaste = (html, editor, view) => { const tempDiv = document.createElement('div'); tempDiv.innerHTML = cleanedHtml; + tempDiv.querySelectorAll('[data-sd-block-id]').forEach((node) => node.removeAttribute('data-sd-block-id')); const data = tempDiv.querySelectorAll('p, li, ' + [1, 2, 3, 4, 5, 6, 7, 8, 9].map((n) => `h${n}`).join(', ')); diff --git a/packages/super-editor/src/core/inputRules/docx-paste/docx-paste.test.js b/packages/super-editor/src/core/inputRules/docx-paste/docx-paste.test.js index 7f751f9889..44eb3a14be 100644 --- a/packages/super-editor/src/core/inputRules/docx-paste/docx-paste.test.js +++ b/packages/super-editor/src/core/inputRules/docx-paste/docx-paste.test.js @@ -103,7 +103,7 @@ describe('handleDocxPaste', () => { First item -

+

2. Second item

@@ -133,6 +133,7 @@ describe('handleDocxPaste', () => { const parsedNode = parseSpy.mock.calls[0][0]; const generatedParagraphs = Array.from(parsedNode.querySelectorAll('p[data-list-level]')); expect(generatedParagraphs).toHaveLength(2); + expect(parsedNode.querySelector('[data-sd-block-id]')).toBeNull(); expect(generatedParagraphs[0].getAttribute('data-num-id')).toBe('200'); expect(generatedParagraphs[0].getAttribute('data-list-level')).toBe('[1]'); expect(generatedParagraphs[1].getAttribute('data-list-level')).toBe('[2]');