Inserter: Replace the selected block if empty#4917
Conversation
|
So I managed to avoid the
There's a small difference here compared to the original isEmpty implementation because this means if you trigger drop cap or change a color without inserting any text, this block won't be replaced but I guess it makes sense. cc @jasmussen |
228466a to
73c4975
Compare
|
@jasmussen What about now? |
|
Sorry there's an error on the last commit fixing |
73c4975 to
5581715
Compare
|
So there are still some issues where sometimes the Not sure how to fix this, maybe we should rollback to the |
|
This is solid work for me. I love it. It definitely works for me. Though CC: @mtias regarding isEmpty. We might need it. |
@youknowriad Maybe we can change this in TinyMCE to trigger a change with |
aduth
left a comment
There was a problem hiding this comment.
I appreciate the effort to avoid expanding the block API 😄
blocks/api/helpers.js
Outdated
| * | ||
| * @return {boolean} Whether the block is an untouched default block | ||
| */ | ||
| export function isUntouchedDefaultBlock( block ) { |
There was a problem hiding this comment.
Minor: What do you think of "Unmodified" instead of "Untouched" ? Not sure "touch" is the best way for describing modifications to a bock.
blocks/api/helpers.js
Outdated
| }; | ||
|
|
||
| return ( | ||
| block.name === newDefaultBlock.name && |
There was a problem hiding this comment.
Minor (performance): This could be an early return to avoid Object.assign cloning of keys into attributeKeys:
const newDefaultBlock = createBlock( getDefaultBlockName() );
if ( block.name !== newDefaultBlock.name ) {
return false;
}
const attributeKeys = {
...keys( newDefaultBlock.attributes ),
...keys( block.attributes ),
};
return every( attributeKeys, ( key ) => (
isEqual( newDefaultBlock.attributes[ key ], block.attributes[ key ] )
) );
blocks/api/helpers.js
Outdated
| */ | ||
| export function isUntouchedDefaultBlock( block ) { | ||
| const newDefaultBlock = createBlock( getDefaultBlockName() ); | ||
| const attributeKeys = { |
There was a problem hiding this comment.
Any reason this ought to be an object, rather than an array?
There was a problem hiding this comment.
No just my brain making fun of me
blocks/api/helpers.js
Outdated
|
|
||
| return ( | ||
| block.name === newDefaultBlock.name && | ||
| every( attributeKeys, ( key ) => isEqual( newDefaultBlock.attributes[ key ], block.attributes[ key ] ) ) |
There was a problem hiding this comment.
Do we want the deep equality check of isEqual, or is shallow sufficient? (via is-equal-shallow)
(Might complicate @iseulde's suggestion of onChange( [] ), but maybe the empty value should be represented as undefined ? or null?)
There was a problem hiding this comment.
I think for this function to work properly across several block types (the default block could change and we don't control the attributes shape), this should be a deep equality to avoid bugs.
Performance wise, this is only called when inserting a block (not repeatedly), so probably acceptable.
| ) ); | ||
| const insertedBlock = createBlock( name, { ...initialAttributes, layout } ); | ||
| if ( selectedBlock && isUntouchedDefaultBlock( selectedBlock ) ) { | ||
| dispatchProps.replaceBlocks( selectedBlock.uid, insertedBlock ); |
There was a problem hiding this comment.
Random thought: Would this be any less complex if we just allowed the block to be inserted as normal, but had a side-effect to remove the previous untouched default block?
There was a problem hiding this comment.
Oh sorry about that.
Are you saying I should call another action removeBlock + insertBlocks instead of replaceBlocks: We'd still need the selectedBlock prop to check if it's unmodified or not, so we'd still need mergeProps. I'm thinking this doesn't change anything in terms of complexity
Or maybe you're saying we should use effects? Maybe it just adds unnecessary indirection don't you think? It will have the advantage of being more generic (though I'm not sure we want this to be generic: inserting at a given position, no matter how we triggered this insert will trigger the behavior)
There was a problem hiding this comment.
Or maybe you're saying we should use
effects?
This is more what I had in mind, that upon inserting a new block, if the block preceding it (a) was previously the last block, (b) is of the default block type, and (c) is empty, then it should be removed.
I guess it could be perceived as indirection. I'd framed it in my mind more as a side effect obviously 😄
blocks/api/helpers.js
Outdated
| @@ -0,0 +1,32 @@ | |||
| /** | |||
There was a problem hiding this comment.
Function dumping grounds 😩
As to not be purely cynical: Elsewhere we use "utils" naming? Ought we use that here?
Also, some small tweaks to the isUnmodifiedDefaultBlock function
815a5ef to
fba8389
Compare
|
Update this per @iseulde proposition and it seems to work consistently now. Let me know if you find another edge case. |
|
Feedback addressed, merging |

closes #3627
this PR update the inserter to replace the selected block if it's an empty block.
Testing instructions