-
Notifications
You must be signed in to change notification settings - Fork 4.3k
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
Maintain Editable focus synchronously when splitting blocks #635
Conversation
6287a61
to
7096b93
Compare
The issues I was seeing previously with infinite loops was a result of React trying to reconcile changes applied to the element tree, but doing so after TinyMCE had initialized and made its own modifications. To account for this, I've moved This should be ready for review now. |
blocks/components/editable/index.js
Outdated
@@ -12,6 +12,7 @@ import 'element-closest'; | |||
*/ | |||
import './style.scss'; | |||
import FormatToolbar from './format-toolbar'; | |||
import TinyMce from './tinymce'; |
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.
TinyMCE? :)
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.
TinyMCE? :)
This is another convention I think we'll want to settle: handling abbreviations and acronyms in variable naming. JavaScript / DOM APIs set a pretty inconsistent precedent, with examples like getElementById
(camel-cased ID), encodeURIComponent
(capitalized URI), and my favorite: XMLHttpRequest
(¯\_(ツ)_/¯).
While elsewhere I've settled on forced camel-case, I do find that capitalized abbreviations tend to be more the more common convention, both in the language and in the ecosystem.
I'll plan to change.
return wp.element.createElement( tagName, { | ||
ref: ( node ) => this.editorNode = node, | ||
contentEditable: true, | ||
suppressContentEditableWarning: true, |
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.
Any reason to add, then suppress?
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.
Any reason to add, then suppress?
The suppress is needed because otherwise React will complain about rendering into a contentEditable
since similar to the reason for creating this separate component, it will lead to a bad time if reconciliation is attempted.
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.
Seems like switching the heading size is broken too, because we're switching the tagname
.
blocks/components/editable/index.js
Outdated
@@ -263,11 +233,11 @@ export default class Editable extends wp.element.Component { | |||
} | |||
|
|||
content = wp.element.renderToString( content ); | |||
this.editor.setContent( content ); | |||
this.editor.setContent( content, { format: 'raw' } ); |
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.
This breaks merging a paragraph into a heading, because this ignore the content sanitization (due to the custom parent node).
The behaviour of this branch appends a p
element at the end of the Heading and thus transforms the heading into a multi-paragraph block. We could solve this by dropping the p
container in the merge function, but I feel this validation is important to ensure each block contain only what we want it to contain.
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.
We could solve this by dropping the
p
container in the merge function, but I feel this validation is important to ensure each block contain only what we want it to contain.
I find it weird that we'd rely on TinyMCE to validate this though. Seems like we shouldn't be returning an invalid structure from the Text -> Heading transform (like <h2>foo<p>text</p></h2>
).
Did you try the "batched subscribe" approach to maintain the focus on merge? Do you think, this is something we could consider? |
Can you link to the specific project you were considering? I know I'd looked at one at the time which relied on some unstable React APIs, but there seem to be a handful of different options now that I'm searching again. For this specific need though, I don't see how batching is necessarily relevant to providing merit on its own, aside from again treating the symptoms of the issues we're experiencing. Whether batching could provide performance benefits, I think would be fair to consider separately. |
@youknowriad Since @iseulde has mentioned she wants to make additional refactoring to these same components, I'm going to simply drop c1636d7ea06e684f1216b79bb245aaf1caafe5c0 from the changes for now with plans to address separately, then merge this. |
7096b93
to
9dc2741
Compare
@aduth Hm, this still breaks heading level switching |
😞 Thanks for noting. I'll plan to take a look shortly. |
I think this may also have broken changing to Text mode. |
Hah, I was wondering where that broke. Will have a look too then. |
Actually, I don't think the styling regressions are the fault of the changes here since I can recreate them checked out to a commit prior to this merge, but there is a new warning about React keys since this was introduced (perhaps due to how we're rendering children in the |
Yeah, checked the same |
We seem to have array of an array in the quote footer. |
If I change the attribute to |
Is this cause of Should |
Hm, we are giving it a nodeList, not sure why it shouldn't give us back an array. |
If we want to disallow an array of |
Hm and I see { value && wp.element.Children.map( value, ( paragraph, i ) => (
<p key={ i }>{ paragraph }</p>
) ) } for the paragraph, but just So either it also needs add keys there, or it just needs to make one |
Related: #480 (comment)
This pull request seeks to try to refactor Editable with an aim toward managing changes synchronously, and assuming more control of value contents as a known React element (
setContent
as raw, avoidsetContent
after initialization).Doing so, it improves behavior slightly by (a) avoiding focus flickering to the previous block when splitting a text block, and (b) potentially better performance by avoiding unnecessary content setting with TinyMCE's default content validation.
Testing instructions:
Ensure that no regressions occur in content splitting and merging to and from separate text blocks, and that in doing so, focus transfers seamlessly respectively to the beginning and end of the split and merged blocks.