-
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
InnerBlocks: Support insert before/after block actions when using allowedBlocks #59162
Changes from all commits
f77d553
6aeb454
95d23d4
9010ab0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -20,42 +20,55 @@ export default function BlockActions( { | |
children, | ||
__experimentalUpdateSelection: updateSelection, | ||
} ) { | ||
const { | ||
canInsertBlockType, | ||
getBlockRootClientId, | ||
getBlocksByClientId, | ||
canMoveBlocks, | ||
canRemoveBlocks, | ||
} = useSelect( blockEditorStore ); | ||
const { getDefaultBlockName, getGroupingBlockName } = | ||
useSelect( blocksStore ); | ||
|
||
const blocks = getBlocksByClientId( clientIds ); | ||
const rootClientId = getBlockRootClientId( clientIds[ 0 ] ); | ||
|
||
const canCopyStyles = blocks.every( ( block ) => { | ||
return ( | ||
!! block && | ||
( hasBlockSupport( block.name, 'color' ) || | ||
hasBlockSupport( block.name, 'typography' ) ) | ||
); | ||
} ); | ||
|
||
const canDuplicate = blocks.every( ( block ) => { | ||
return ( | ||
!! block && | ||
hasBlockSupport( block.name, 'multiple', true ) && | ||
canInsertBlockType( block.name, rootClientId ) | ||
); | ||
} ); | ||
|
||
const canInsertDefaultBlock = canInsertBlockType( | ||
getDefaultBlockName(), | ||
rootClientId | ||
const selected = useSelect( | ||
( select ) => { | ||
const { | ||
canInsertBlockType, | ||
getBlockRootClientId, | ||
getBlocksByClientId, | ||
getDirectInsertBlock, | ||
canMoveBlocks, | ||
canRemoveBlocks, | ||
} = select( blockEditorStore ); | ||
|
||
const blocks = getBlocksByClientId( clientIds ); | ||
const rootClientId = getBlockRootClientId( clientIds[ 0 ] ); | ||
const canInsertDefaultBlock = canInsertBlockType( | ||
getDefaultBlockName(), | ||
rootClientId | ||
); | ||
const directInsertBlock = rootClientId | ||
? getDirectInsertBlock( rootClientId ) | ||
: null; | ||
|
||
return { | ||
canMove: canMoveBlocks( clientIds, rootClientId ), | ||
canRemove: canRemoveBlocks( clientIds, rootClientId ), | ||
canInsertBlock: canInsertDefaultBlock || !! directInsertBlock, | ||
canCopyStyles: blocks.every( ( block ) => { | ||
return ( | ||
!! block && | ||
( hasBlockSupport( block.name, 'color' ) || | ||
hasBlockSupport( block.name, 'typography' ) ) | ||
); | ||
} ), | ||
canDuplicate: blocks.every( ( block ) => { | ||
return ( | ||
!! block && | ||
hasBlockSupport( block.name, 'multiple', true ) && | ||
canInsertBlockType( block.name, rootClientId ) | ||
); | ||
} ), | ||
}; | ||
}, | ||
[ clientIds, getDefaultBlockName ] | ||
); | ||
const { getBlocksByClientId, getBlocks } = useSelect( blockEditorStore ); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This approach is much nicer 🙂 |
||
|
||
const canMove = canMoveBlocks( clientIds, rootClientId ); | ||
const canRemove = canRemoveBlocks( clientIds, rootClientId ); | ||
const { canMove, canRemove, canInsertBlock, canCopyStyles, canDuplicate } = | ||
selected; | ||
|
||
const { | ||
removeBlocks, | ||
|
@@ -75,11 +88,9 @@ export default function BlockActions( { | |
return children( { | ||
canCopyStyles, | ||
canDuplicate, | ||
canInsertDefaultBlock, | ||
canInsertBlock, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just confirming that There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Correct. It's not a public API. |
||
canMove, | ||
canRemove, | ||
rootClientId, | ||
blocks, | ||
onDuplicate() { | ||
return duplicateBlocks( clientIds, updateSelection ); | ||
}, | ||
|
@@ -104,44 +115,43 @@ export default function BlockActions( { | |
setBlockMovingClientId( clientIds[ 0 ] ); | ||
}, | ||
onGroup() { | ||
if ( ! blocks.length ) { | ||
if ( ! clientIds.length ) { | ||
return; | ||
} | ||
|
||
const groupingBlockName = getGroupingBlockName(); | ||
|
||
// Activate the `transform` on `core/group` which does the conversion. | ||
const newBlocks = switchToBlockType( blocks, groupingBlockName ); | ||
const newBlocks = switchToBlockType( | ||
getBlocksByClientId( clientIds ), | ||
groupingBlockName | ||
); | ||
|
||
if ( ! newBlocks ) { | ||
return; | ||
} | ||
replaceBlocks( clientIds, newBlocks ); | ||
}, | ||
onUngroup() { | ||
if ( ! blocks.length ) { | ||
if ( ! clientIds.length ) { | ||
return; | ||
} | ||
|
||
const innerBlocks = blocks[ 0 ].innerBlocks; | ||
|
||
const innerBlocks = getBlocks( clientIds[ 0 ] ); | ||
if ( ! innerBlocks.length ) { | ||
return; | ||
} | ||
|
||
replaceBlocks( clientIds, innerBlocks ); | ||
}, | ||
onCopy() { | ||
const selectedBlockClientIds = blocks.map( | ||
( { clientId } ) => clientId | ||
); | ||
if ( blocks.length === 1 ) { | ||
flashBlock( selectedBlockClientIds[ 0 ] ); | ||
if ( clientIds.length === 1 ) { | ||
flashBlock( clientIds[ 0 ] ); | ||
} | ||
notifyCopy( 'copy', selectedBlockClientIds ); | ||
notifyCopy( 'copy', clientIds ); | ||
}, | ||
async onPasteStyles() { | ||
await pasteStyles( blocks ); | ||
await pasteStyles( getBlocksByClientId( clientIds ) ); | ||
}, | ||
} ); | ||
} |
Original file line number | Diff line number | Diff line change | ||||||
---|---|---|---|---|---|---|---|---|
|
@@ -1539,7 +1539,7 @@ export const duplicateBlocks = | |||||||
}; | ||||||||
|
||||||||
/** | ||||||||
* Action that inserts an empty block before a given block. | ||||||||
* Action that inserts a default block before a given block. | ||||||||
* | ||||||||
* @param {string} clientId | ||||||||
*/ | ||||||||
|
@@ -1555,16 +1555,34 @@ export const insertBeforeBlock = | |||||||
return; | ||||||||
} | ||||||||
|
||||||||
const firstSelectedIndex = select.getBlockIndex( clientId ); | ||||||||
return dispatch.insertDefaultBlock( | ||||||||
{}, | ||||||||
rootClientId, | ||||||||
firstSelectedIndex | ||||||||
); | ||||||||
const blockIndex = select.getBlockIndex( clientId ); | ||||||||
const directInsertBlock = rootClientId | ||||||||
? select.getDirectInsertBlock( rootClientId ) | ||||||||
: null; | ||||||||
|
||||||||
if ( ! directInsertBlock ) { | ||||||||
return dispatch.insertDefaultBlock( {}, rootClientId, blockIndex ); | ||||||||
} | ||||||||
|
||||||||
const copiedAttributes = {}; | ||||||||
if ( directInsertBlock.attributesToCopy ) { | ||||||||
const attributes = select.getBlockAttributes( clientId ); | ||||||||
directInsertBlock.attributesToCopy.forEach( ( key ) => { | ||||||||
if ( attributes[ key ] ) { | ||||||||
copiedAttributes[ key ] = attributes[ key ]; | ||||||||
} | ||||||||
} ); | ||||||||
} | ||||||||
|
||||||||
const block = createBlock( directInsertBlock.name, { | ||||||||
...directInsertBlock.attributes, | ||||||||
...copiedAttributes, | ||||||||
} ); | ||||||||
return dispatch.insertBlock( block, blockIndex, rootClientId ); | ||||||||
}; | ||||||||
|
||||||||
/** | ||||||||
* Action that inserts an empty block after a given block. | ||||||||
* Action that inserts a default block after a given block. | ||||||||
* | ||||||||
* @param {string} clientId | ||||||||
*/ | ||||||||
|
@@ -1580,12 +1598,34 @@ export const insertAfterBlock = | |||||||
return; | ||||||||
} | ||||||||
|
||||||||
const firstSelectedIndex = select.getBlockIndex( clientId ); | ||||||||
return dispatch.insertDefaultBlock( | ||||||||
{}, | ||||||||
rootClientId, | ||||||||
firstSelectedIndex + 1 | ||||||||
); | ||||||||
const blockIndex = select.getBlockIndex( clientId ); | ||||||||
const directInsertBlock = rootClientId | ||||||||
? select.getDirectInsertBlock( rootClientId ) | ||||||||
: null; | ||||||||
|
||||||||
if ( ! directInsertBlock ) { | ||||||||
return dispatch.insertDefaultBlock( | ||||||||
{}, | ||||||||
rootClientId, | ||||||||
blockIndex + 1 | ||||||||
); | ||||||||
} | ||||||||
|
||||||||
const copiedAttributes = {}; | ||||||||
if ( directInsertBlock.attributesToCopy ) { | ||||||||
const attributes = select.getBlockAttributes( clientId ); | ||||||||
directInsertBlock.attributesToCopy.forEach( ( key ) => { | ||||||||
if ( attributes[ key ] ) { | ||||||||
copiedAttributes[ key ] = attributes[ key ]; | ||||||||
} | ||||||||
} ); | ||||||||
} | ||||||||
|
||||||||
const block = createBlock( directInsertBlock.name, { | ||||||||
...directInsertBlock.attributes, | ||||||||
...copiedAttributes, | ||||||||
} ); | ||||||||
return dispatch.insertBlock( block, blockIndex + 1, rootClientId ); | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we make There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So, move most of the logic into the The only issue I see here is that gutenberg/packages/editor/src/components/post-title/index.js Lines 77 to 79 in 09dc127
P.S. It's definitely doable, but I am unsure if removing 20+ lines is worth complicating the logic of the existing There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sorry I meant a new selector not Up to you. I think it's worth it now that the logic isn't trivial, but respect your judgement. |
||||||||
}; | ||||||||
|
||||||||
/** | ||||||||
|
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.
Why store in
selected
instead of destructuring right 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.
Learned this "hack" from @ellatrix. It's to avoid the
already declared in the upper scope
ESLint error formapSelect
.It's no longer needed after 6aeb454. But let's keep this pattern for now.
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.
😮 omg that's life changing