Skip to content

Commit fbc19c7

Browse files
committed
fix(paste): prevent false positive headings and list-item corruption
1 parent 167f5aa commit fbc19c7

2 files changed

Lines changed: 36 additions & 5 deletions

File tree

packages/super-editor/src/core/inputRules/google-docs-paste/google-docs-paste.js

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,9 @@ function buildListPath(level, map) {
278278
* @param {HTMLElement} container
279279
*/
280280
function convertStyledHeadings(container) {
281-
const paragraphs = Array.from(container.querySelectorAll('p'));
281+
const paragraphs = Array.from(container.querySelectorAll('p')).filter(
282+
(p) => p.parentElement?.tagName?.toLowerCase() !== 'li',
283+
);
282284

283285
paragraphs.forEach((p) => {
284286
const { fontSize, isBold } = getHeadingStyleProps(p);
@@ -305,10 +307,16 @@ function convertStyledHeadings(container) {
305307
* @returns {{ fontSize: number|null, isBold: boolean }}
306308
*/
307309
function getHeadingStyleProps(el) {
308-
const span = el.querySelector('span');
309-
const fontSize = parsePtValue(el.style.fontSize) ?? parsePtValue(span?.style.fontSize);
310-
const isBold = boldWeightRegex.test(el.style.fontWeight || '') || boldWeightRegex.test(span?.style.fontWeight || '');
311-
return { fontSize, isBold };
310+
const fontSize = parsePtValue(el.style.fontSize);
311+
const isBoldOnEl = boldWeightRegex.test(el.style.fontWeight || '');
312+
313+
const { children } = el;
314+
const singleSpan = children.length === 1 && children[0].tagName?.toLowerCase() === 'span' ? children[0] : null;
315+
316+
return {
317+
fontSize: fontSize ?? parsePtValue(singleSpan?.style.fontSize),
318+
isBold: isBoldOnEl || boldWeightRegex.test(singleSpan?.style.fontWeight || ''),
319+
};
312320
}
313321

314322
/**

packages/super-editor/src/core/inputRules/google-docs-paste/google-docs-paste.test.js

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,29 @@ describe('handleGoogleDocsHtml', () => {
156156
expect(dom.querySelector('h1')?.textContent?.trim()).toBe('Big Heading');
157157
});
158158

159+
it('does not convert a paragraph where only the first of multiple spans is bold', () => {
160+
// Body paragraph with a bold opening word — must not become a heading.
161+
const html = `
162+
<p>
163+
<span style="font-size:11pt;font-weight:700">Bold word</span>
164+
<span style="font-size:11pt;">rest of text</span>
165+
</p>
166+
`;
167+
const dom = parseHeadings(html);
168+
expect(dom.querySelector('h1,h2,h3,h4,h5')).toBeNull();
169+
});
170+
171+
it('does not convert <p> elements inside <li> to avoid corrupting list structure', () => {
172+
const html = `
173+
<ul>
174+
<li><p style="font-size:20pt;font-weight:700">List item</p></li>
175+
</ul>
176+
`;
177+
const dom = parseHeadings(html);
178+
expect(dom.querySelector('h1')).toBeNull();
179+
expect(dom.querySelector('p[data-num-id]')).not.toBeNull();
180+
});
181+
159182
it('converts when font-size is on <p> but font-weight is only on the child <span>', () => {
160183
const html = `
161184
<p style="font-size:20pt"><span style="font-weight:700">Split style heading</span></p>

0 commit comments

Comments
 (0)