-
Notifications
You must be signed in to change notification settings - Fork 4.2k
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
Block: split out toolbar rendering #19564
Conversation
e592896
to
aa9195a
Compare
d9b41e1
to
43227f6
Compare
9d5ac15
to
8f7eb28
Compare
@@ -307,7 +274,6 @@ function BlockListBlock( { | |||
'is-focused': isFocusMode && ( isSelected || isAncestorOfSelectedBlock ), | |||
'is-focus-mode': isFocusMode, | |||
'has-child-selected': isAncestorOfSelectedBlock, | |||
'has-toolbar-captured': hasAncestorCapturingToolbars, |
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.
Removing this class since it was used only for one broken CSS rule. Additionally it's a lot of selectors running for each block.
|
||
// Toolbar is captured | ||
&.has-toolbar-captured::before { | ||
left: 0; // place "selected" indicator closer to block due to no toolbar |
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 rule is targeting .block-editor-block-list__layout
, but .has-toolbar-captured
is only added to blocks, so it's broken. I don't see any issues with the block border without this rule. Everything is looking good. Additionally there are plans to get rid of the border altogether anyway.
Performance test:
|
In general we avoid using complex objects (DOM elements) in state. Any particular reason to avoid block DOM utils. |
@@ -564,16 +420,13 @@ const applyWithSelect = withSelect( | |||
isValid, | |||
isSelected, | |||
isAncestorOfSelectedBlock, | |||
isCapturingDescendantToolbars, | |||
hasAncestorCapturingToolbars, |
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 don't expect the removed props from this component to have been used by plugins (blockedit filter), that said, we need to communicate this with a dev note.
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 was added recently, so it won't be in any WP release. #18440
Yes, we need the component to rerender when the block DOM node is mounted, but I can simplify it by only saving the client ID and then getting the element by ID. I'll adjust it. |
881b5d3
to
35745da
Compare
35745da
to
dcd76e2
Compare
Let's merge and iterate as this is a good separation to have and it has clear performance benefits. |
* | ||
* @return {boolean} Updated state. | ||
*/ | ||
export function selectedMountedBlock( state, action ) { |
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.
How is this different from the block selection state?
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 only set when the block node is mounted. This is useful when you have to render a popover at the position of this node. We can't render the popover before the node is mounted.
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 honestly feel this is entirely useless. If the selected block is in the store, it's already mounted right? at worst it's mounted after a useEffect
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 don't think it's useless, but we can try alternative ways for sure. Being a selected block in the store doesn't mean that the block is mounted. React first has to render the block. This is similar to the block node not being available at the time of rendering. You have to use useEffect
.
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'm open to alternatives though.
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 feel having a state just to say "something is mounted" is not great. ideally, something in the state should make the block mount, in the case of blocks, blocks are mounted as soon as they are in the state, which for me suggests that it should be treated at the component level.
I guess the main issue here is that the rendering of the block and the rendering of the toolbar arae separate in two separate React trees so for the first render of the blocks, we're not certain which one will render first.
I'm not sure what's the perfect solution here other than just using an interval/useEffect or something like that.
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.
Right, the only dependency on BlockListBlock
is the position of the DOM node. I totally agree with you that it's not ideal and that's why I marked it unstable. I'll explore an alternative idea in a separate PR.
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 try to provide Popover
with a selector for the anchor. Popover
already repositions at an interval, so this could work. Additionally, we also already use a selector for multi selected block (to enable sticking the toolbar).
Description
Offers a 7% performance gain.
This PR moves the toolbar popover out of the block tree. Eventually, the goal is to be able to remove the special popover slot and maybe unify it with the fixed toolbar and/or mobile toolbar. I suspect it may improve performance a bit too.
This step is very important in simplifying the React tree of the block and further performance improvements.
Worth noting is that I rewrote the way toolbar capturing works. Since toolbars are in popovers, toolbar capturing is a matter of attaching the popover to the right parent block node. There's no need to use slots.
Also worth noting is that block nodes are added to the block-editor state. This is very useful for any components that need to render based on wether or not a block node in actually mounted in the DOM. I marked this API unstable for now.
How has this been tested?
Everything should work as before. Test toolbar rendering.
Screenshots
Types of changes
Refactoring.
Checklist: