-
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
Block Settings Menu: Adding a duplicate block button #5098
Conversation
editor/store/selectors.js
Outdated
@@ -486,6 +486,16 @@ export const getBlocks = createSelector( | |||
] | |||
); | |||
|
|||
export const getBlocksByUid = createSelector( |
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.
More accurately: getBlocksByUids
Also need consensus on capitalization pattern getBlocksByUids
vs. getBlocksByUIDs
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's your preference on the capitalization, let's make it a guideline ;)?
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 agree a guideline would be good. I don't know which I prefer. I think capitalized abbreviations is more the norm, but there's exceptions. It also makes it difficult when a name has two adjacent abbreviations (imagine an XMLHTTPRequest
).
🤷♂️
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 guess I'd slightly lean toward capitalized abbreviations.
index: getBlockIndex( state, last( ownProps.uids ), ownProps.rootUID ), | ||
} ), | ||
{ insertBlocks }, | ||
( { blocks, index }, dispatchProps, { rootUID } ) => ( { |
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 see why it's used here, but I've becoming increasingly cautious of mergeProps
upon discovery in #5090 about excessive renders it can incur.
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.
Another option would be to do this inside the component. Do you think it's better?
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.
Better in performance. Worse in having it become less purely presentational.
🤷♂️
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.
Is this blocking, I think we should keep it as is and revisit once we update the data module.
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.
Should be possible to simplify now with #5137
import { insertBlocks } from '../../store/actions'; | ||
|
||
export function BlockDuplicateButton( { onDuplicate, onClick = noop, isLocked, small = false } ) { | ||
if ( isLocked ) { |
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.
Should also check for useOnce
here :)
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.
👍 Good catch
This is VERY nice. I think this is going to be a very popular feature. The block ellipsis menu is getting a little crowded, but that's due to the transformations rather than this addition. If we feel it's getting out of hand we can revisit having the transformations in this menu. Not for this PR. One enhancement to consider for this, is selecting the new block after it's been duplicated. Especially if you multi select three blocks and duplicate, it'd be nice if the three duplicate blocks were simply still selected so you could move them around or whatever. But no blocker. 👍 👍 nice work! |
It works for a single block, but I'll take a look to see if we can keep the multi-selection as well. |
It's not a requirement, just a nicety. |
I think we should do the flyout menu for transforms :) |
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.
Most of my comments are minor. Seems to work well in my testing.
} ), | ||
{ insertBlocks }, | ||
( { blocks, index }, dispatchProps, { rootUID } ) => ( { | ||
blockNames: blocks.map( block => block.name ), |
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.
Honestly, it would probably be more efficient to pass in the blocks
array in its entirety from getBlocksByUid
, since at least that's memoized, not returning a new instance each time.
const type = getBlockType( name ); | ||
return ! type.useOnce; | ||
} ) ); | ||
if ( isLocked || ! canDuplicate ) { |
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.
Minor (since it's not a common scenario): if isLocked
is true
here, we've wasted effort calculating canDuplicate
, when we could have done an early return before the every
.
editor/store/selectors.js
Outdated
@@ -486,6 +486,16 @@ export const getBlocks = createSelector( | |||
] | |||
); | |||
|
|||
export const getBlocksByUid = createSelector( |
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 guess I'd slightly lean toward capitalized abbreviations.
editor/store/selectors.js
Outdated
return map( uids, ( uid ) => getBlock( state, uid ) ); | ||
}, | ||
( state ) => [ | ||
state.editor.present.blockOrder, |
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 does this depend on blockOrder
?
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.
Also, since this depends on getBlock
, it should define all of the dependants of getBlock
.
Aside: [email protected]
adds a helper utility for this via getBlock.getDependants
(changelog).
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 avoided using getDependants
because of two things:
- I have to map over the uids, to call the
getDependants
of thegetBlock
- I thought it's simpler to just add the global block state as dependants instead of using specific uids since a selector returning multiple blocks.
- blockOrder is necessary because getBlock depends on blockOrder see
getBlockDependantsCacheBust
3067e8c
to
968580d
Compare
I feel like I addressed everything here. Merging. |
closes #2231
Testing instructions
It should also work for multiselection