Skip to content

Commit

Permalink
Convert pasted Google Docs Title text into a Heading (#2729)
Browse files Browse the repository at this point in the history
* support GDocs title

* handle it better

* reorg and tests
  • Loading branch information
acywatson authored and thegreatercurve committed Nov 25, 2022
1 parent 3c9dcd7 commit b3b0faf
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 1 deletion.
48 changes: 48 additions & 0 deletions packages/lexical-playground/__tests__/e2e/CopyAndPaste.spec.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
import {
assertHTML,
assertSelection,
clearEditor,
click,
copyToClipboard,
focus,
Expand Down Expand Up @@ -2209,4 +2210,51 @@ test.describe('CopyAndPaste', () => {
`,
);
});

test('HTML Copy + paste a Title from Google Docs', async ({
page,
isPlainText,
}) => {
test.skip(isPlainText);

await focusEditor(page);

const clipboard = {
'text/html': `<meta charset='utf-8'><meta charset="utf-8"><b style="font-weight:normal;" id="docs-internal-guid-whatever"><span style="font-size:26pt;font-family:Arial;color:#000000;background-color:transparent;font-weight:400;font-style:normal;font-variant:normal;text-decoration:none;vertical-align:baseline;white-space:pre;white-space:pre-wrap;">My document</span></b>`,
};

await pasteFromClipboard(page, clipboard);

await assertHTML(
page,
html`
<h1
class="PlaygroundEditorTheme__h1 PlaygroundEditorTheme__ltr"
dir="ltr">
<span data-lexical-text="true">My document</span>
</h1>
`,
);

await clearEditor(page);
await focusEditor(page);

// These can sometimes be put onto the clipboard wrapped in a paragraph element
clipboard[
'text/html'
] = `<meta charset='utf-8'><meta charset="utf-8"><b style="font-weight:normal;" id="docs-internal-guid-wjatever"><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:3pt;"><span style="font-size:26pt;font-family:Arial;color:#000000;background-color:transparent;font-weight:400;font-style:normal;font-variant:normal;text-decoration:none;vertical-align:baseline;white-space:pre;white-space:pre-wrap;">My document</span></p></b>`;

await pasteFromClipboard(page, clipboard);

await assertHTML(
page,
html`
<h1
class="PlaygroundEditorTheme__h1 PlaygroundEditorTheme__ltr"
dir="ltr">
<span data-lexical-text="true">My document</span>
</h1>
`,
);
});
});
32 changes: 32 additions & 0 deletions packages/lexical-rich-text/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,31 @@ export class HeadingNode extends ElementNode {
conversion: convertHeadingElement,
priority: 0,
}),
p: (node: Node) => {
// domNode is a <p> since we matched it by nodeName
const paragraph = node as HTMLParagraphElement;
const firstChild = paragraph.firstChild;
if (firstChild !== null && isGoogleDocsTitle(firstChild)) {
return {
conversion: () => ({node: null}),
priority: 3,
};
}
return null;
},
span: (node: Node) => {
if (isGoogleDocsTitle(node)) {
return {
conversion: (domNode: Node) => {
return {
node: $createHeadingNode('h1'),
};
},
priority: 3,
};
}
return null;
},
};
}

Expand Down Expand Up @@ -296,6 +321,13 @@ export class HeadingNode extends ElementNode {
}
}

function isGoogleDocsTitle(domNode: Node): boolean {
if (domNode.nodeName.toLowerCase() === 'span') {
return (domNode as HTMLSpanElement).style.fontSize === '26pt';
}
return false;
}

function convertHeadingElement(domNode: Node): DOMConversionOutput {
const nodeName = domNode.nodeName.toLowerCase();
let node = null;
Expand Down
1 change: 0 additions & 1 deletion packages/lexical/src/LexicalEvents.ts
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,6 @@ function onSelectionChange(
focusNode: focusDOM,
focusOffset,
} = domSelection;

if (isSelectionChangeFromDOMUpdate) {
isSelectionChangeFromDOMUpdate = false;

Expand Down

0 comments on commit b3b0faf

Please sign in to comment.