-
Notifications
You must be signed in to change notification settings - Fork 1.8k
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
Conversation
This pull request is being automatically deployed with Vercel (learn more). lexical – ./packages/lexical-website🔍 Inspect: https://vercel.com/fbopensource/lexical/Eka28v8kQW4ENTsySTkEs9tktHWw lexical-playground – ./packages/lexical-playground🔍 Inspect: https://vercel.com/fbopensource/lexical-playground/5asLxyWUCEhje4Y2wtujjE9aE9rn lexical-website-new – ./packages/lexical-website-new🔍 Inspect: https://vercel.com/fbopensource/lexical-website-new/6Dx4BcwPxJZekibbDAKNEmgkej1r |
@@ -31,10 +31,15 @@ const IGNORE_TAGS = new Set(['STYLE']); | |||
|
|||
export function getHtmlContent(editor: LexicalEditor): string | null { | |||
const domSelection = getDOMSelection(); | |||
const selection = $getSelection(); |
There was a problem hiding this comment.
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)?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
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()?
There was a problem hiding this comment.
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...
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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).
790465f
to
a2eb840
Compare
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 |
9494341
to
9bc9dc8
Compare
6568b45
to
def9cd4
Compare
#1610) * Rework export to HTML for clipboard to better support Tables and Lists * Improve Selection Extract Logic
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
toimportDOM
and adds a new method,exportDOM
, that letsLexicalNodes
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
andborder
and extra HTML tags such ascolgroup
andcol
.This PR will also resolve the issue raised in today's sync (by @acywatson) where copying a
ListItem
won't include theList
itself (i.e.<ul>
or<ol>
) to the clipboard. The same issue occurs withTables
, or any other deeply nestedElementNode
. Luckily$cloneContents
already handles the hoisting of parents so this was an auto win by reusing existing logic.