Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rework export to HTML for clipboard to better support Tables and Lists #1610

Merged
merged 2 commits into from
Apr 8, 2022

Conversation

tylerjbainbridge
Copy link
Contributor

This PR tweaks getHtmlContent to use $cloneContents and a new function, $convertLexicalContentToHtml, to build a HTML representation of the Lexical tree that's suitable for the clipboard.

It also renames convertDOM to importDOM and adds a new method, exportDOM, that lets LexicalNodes modify their HTML representation before exporting to the clipboard.

This is useful for tables because most 3rd party editors (Google Docs, Quip) expect style properties such as width and border and extra HTML tags such as colgroup and col.

This PR will also resolve the issue raised in today's sync (by @acywatson) where copying a ListItem won't include the List itself (i.e. <ul> or <ol>) to the clipboard. The same issue occurs with Tables, or any other deeply nested ElementNode. Luckily $cloneContents already handles the hoisting of parents so this was an auto win by reusing existing logic.

@vercel
Copy link

vercel bot commented Apr 5, 2022

This pull request is being automatically deployed with Vercel (learn more).
To see the status of your deployments, click below or on the icon next to each commit.

lexical – ./packages/lexical-website

🔍 Inspect: https://vercel.com/fbopensource/lexical/Eka28v8kQW4ENTsySTkEs9tktHWw
✅ Preview: https://lexical-git-tables-copy-and-paste-from-lexi-16ce04-fbopensource.vercel.app

lexical-playground – ./packages/lexical-playground

🔍 Inspect: https://vercel.com/fbopensource/lexical-playground/5asLxyWUCEhje4Y2wtujjE9aE9rn
✅ Preview: https://lexical-playground-git-tables-copy-and-past-4d1375-fbopensource.vercel.app

lexical-website-new – ./packages/lexical-website-new

🔍 Inspect: https://vercel.com/fbopensource/lexical-website-new/6Dx4BcwPxJZekibbDAKNEmgkej1r
✅ Preview: https://lexical-website-new-git-tables-copy-and-pas-c0e644-fbopensource.vercel.app

CHANGELOG.md Outdated Show resolved Hide resolved
@@ -31,10 +31,15 @@ const IGNORE_TAGS = new Set(['STYLE']);

export function getHtmlContent(editor: LexicalEditor): string | null {
const domSelection = getDOMSelection();
const selection = $getSelection();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure about this - are we basically switching from use native selection to using Lexical selection? Makes sense, but if so, should we just get rid of the domSelection code path(s)?

Copy link
Contributor Author

@tylerjbainbridge tylerjbainbridge Apr 6, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@trueadm or whoever wrote this initially might have more insight, but maybe we can just rely on this new lexicalToHtml and not grab from the DOM.

I decided to keep this around as a back-up for when a lexical selection isn't there, but not sure if that's possible at this stage.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I decided to keep this around as a back-up for when a lexical selection isn't there, but not sure if that's possible at this stage.

Yea, to me it seems that we will always have a Lexical selection. We might want to handle the collapsed case, like we do for the domSelection and just delete the rest? Interested in @trueadm's thoughts.

Copy link
Collaborator

@trueadm trueadm Apr 8, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should avoid using DOM selection, as it might not be right between browsers.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree, so let's just remove the DOM Selection logic before we ship this, I think

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good to me.

node: LexicalNode,
): HTMLElement {
const exportDOM = node.constructor.exportDOM;
const domElement = node.createDOM(editor._config, editor);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if exportDOM just contained all of the logic for creating the DOM node? The base implementation on LexicalNode could just return createDOM()?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's pretty helpful to have the this method called as a final "clean-up" stage. If you look at TableNode's exportDOM it actually moves it's table row children into a table-body wrapper and appends the col/colgroup nodes to it's children.

I do agree though, it'd be a lot cleaner to just expect exportDOM calls its own createDOM function...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh I see, so the use case this enables is traversing and mutating children after the conversion to a DOM tree is finished?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, this allows you to 1. Skip, 2. Modify, or 3. Create a totally new element.

Maybe that's too much power though, where it complicates the overall API.

Also might get tricky for elements without a createDOM method (i.e. a DecoratorNode).

@tylerjbainbridge
Copy link
Contributor Author

Here's a video of a pretty complex document (Lists, Tables, Decorators, Headers) being copy & pasted to Google Docs, as well as partially selected tables.

Screen.Recording.2022-04-06.at.2.56.36.PM.mov

@trueadm trueadm merged commit 5cc3fd9 into main Apr 8, 2022
@trueadm trueadm deleted the tables-copy-and-paste-from-lexical-to-external branch April 8, 2022 21:48
acywatson pushed a commit that referenced this pull request Apr 9, 2022
#1610)

* Rework export to HTML for clipboard to better support Tables and Lists

* Improve Selection Extract Logic
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants