-
Notifications
You must be signed in to change notification settings - Fork 4.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* inital attempt to bring block commands and transforms * don't register commands if no blocks are selected * move to top level editor components * cleanup copy pasta from the block editor components * fix rebase artefact * update icons to match the action, remove 'block' suffix for command names, use add instead of insert * remove conflict marker * packages update * fix copy command * Revert "fix copy command" This reverts commit e6d70b2. * remove copy and paste styles actions --------- Co-authored-by: scruffian <[email protected]>
- Loading branch information
1 parent
5a238f9
commit 5a97d8e
Showing
7 changed files
with
308 additions
and
1 deletion.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
284 changes: 284 additions & 0 deletions
284
packages/block-editor/src/components/use-block-commands/index.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,284 @@ | ||
/** | ||
* WordPress dependencies | ||
*/ | ||
import { __, sprintf } from '@wordpress/i18n'; | ||
import { | ||
hasBlockSupport, | ||
store as blocksStore, | ||
switchToBlockType, | ||
isTemplatePart, | ||
} from '@wordpress/blocks'; | ||
import { useSelect, useDispatch } from '@wordpress/data'; | ||
import { useCommandLoader } from '@wordpress/commands'; | ||
import { | ||
copy, | ||
edit as remove, | ||
create as add, | ||
group, | ||
ungroup, | ||
moveTo as move, | ||
} from '@wordpress/icons'; | ||
|
||
/** | ||
* Internal dependencies | ||
*/ | ||
import { store as blockEditorStore } from '../../store'; | ||
|
||
export const useTransformCommands = () => { | ||
const { clientIds } = useSelect( ( select ) => { | ||
const { getSelectedBlockClientIds } = select( blockEditorStore ); | ||
const selectedBlockClientIds = getSelectedBlockClientIds(); | ||
|
||
return { | ||
clientIds: selectedBlockClientIds, | ||
}; | ||
}, [] ); | ||
const blocks = useSelect( | ||
( select ) => | ||
select( blockEditorStore ).getBlocksByClientId( clientIds ), | ||
[ clientIds ] | ||
); | ||
const { replaceBlocks, multiSelect } = useDispatch( blockEditorStore ); | ||
const { possibleBlockTransformations, canRemove } = useSelect( | ||
( select ) => { | ||
const { | ||
getBlockRootClientId, | ||
getBlockTransformItems, | ||
canRemoveBlocks, | ||
} = select( blockEditorStore ); | ||
const rootClientId = getBlockRootClientId( | ||
Array.isArray( clientIds ) ? clientIds[ 0 ] : clientIds | ||
); | ||
return { | ||
possibleBlockTransformations: getBlockTransformItems( | ||
blocks, | ||
rootClientId | ||
), | ||
canRemove: canRemoveBlocks( clientIds, rootClientId ), | ||
}; | ||
}, | ||
[ clientIds, blocks ] | ||
); | ||
|
||
const isTemplate = blocks.length === 1 && isTemplatePart( blocks[ 0 ] ); | ||
|
||
function selectForMultipleBlocks( insertedBlocks ) { | ||
if ( insertedBlocks.length > 1 ) { | ||
multiSelect( | ||
insertedBlocks[ 0 ].clientId, | ||
insertedBlocks[ insertedBlocks.length - 1 ].clientId | ||
); | ||
} | ||
} | ||
|
||
// Simple block tranformation based on the `Block Transforms` API. | ||
function onBlockTransform( name ) { | ||
const newBlocks = switchToBlockType( blocks, name ); | ||
replaceBlocks( clientIds, newBlocks ); | ||
selectForMultipleBlocks( newBlocks ); | ||
} | ||
|
||
/** | ||
* The `isTemplate` check is a stopgap solution here. | ||
* Ideally, the Transforms API should handle this | ||
* by allowing to exclude blocks from wildcard transformations. | ||
*/ | ||
const hasPossibleBlockTransformations = | ||
!! possibleBlockTransformations.length && canRemove && ! isTemplate; | ||
|
||
if ( | ||
! clientIds || | ||
clientIds.length < 1 || | ||
! hasPossibleBlockTransformations | ||
) { | ||
return { isLoading: false, commands: [] }; | ||
} | ||
|
||
const commands = possibleBlockTransformations.map( ( transformation ) => { | ||
const { name, title, icon } = transformation; | ||
return { | ||
name: 'core/block-editor/transform-to-' + name.replace( '/', '-' ), | ||
// translators: %s: block title/name. | ||
label: sprintf( __( 'Transform to %s' ), title ), | ||
icon: icon.src, | ||
callback: ( { close } ) => { | ||
onBlockTransform( name ); | ||
close(); | ||
}, | ||
}; | ||
} ); | ||
|
||
return { isLoading: false, commands }; | ||
}; | ||
|
||
const useActionsCommands = () => { | ||
const { clientIds } = useSelect( ( select ) => { | ||
const { getSelectedBlockClientIds } = select( blockEditorStore ); | ||
const selectedBlockClientIds = getSelectedBlockClientIds(); | ||
|
||
return { | ||
clientIds: selectedBlockClientIds, | ||
}; | ||
}, [] ); | ||
const { | ||
canInsertBlockType, | ||
getBlockRootClientId, | ||
getBlocksByClientId, | ||
canMoveBlocks, | ||
canRemoveBlocks, | ||
} = useSelect( blockEditorStore ); | ||
const { getDefaultBlockName, getGroupingBlockName } = | ||
useSelect( blocksStore ); | ||
|
||
const blocks = getBlocksByClientId( clientIds ); | ||
const rootClientId = getBlockRootClientId( clientIds[ 0 ] ); | ||
|
||
const canDuplicate = blocks.every( ( block ) => { | ||
return ( | ||
!! block && | ||
hasBlockSupport( block.name, 'multiple', true ) && | ||
canInsertBlockType( block.name, rootClientId ) | ||
); | ||
} ); | ||
|
||
const canInsertDefaultBlock = canInsertBlockType( | ||
getDefaultBlockName(), | ||
rootClientId | ||
); | ||
|
||
const canMove = canMoveBlocks( clientIds, rootClientId ); | ||
const canRemove = canRemoveBlocks( clientIds, rootClientId ); | ||
|
||
const { | ||
removeBlocks, | ||
replaceBlocks, | ||
duplicateBlocks, | ||
insertAfterBlock, | ||
insertBeforeBlock, | ||
setBlockMovingClientId, | ||
setNavigationMode, | ||
selectBlock, | ||
} = useDispatch( blockEditorStore ); | ||
|
||
const onDuplicate = () => { | ||
if ( ! canDuplicate ) { | ||
return; | ||
} | ||
return duplicateBlocks( clientIds, true ); | ||
}; | ||
const onRemove = () => { | ||
if ( ! canRemove ) { | ||
return; | ||
} | ||
return removeBlocks( clientIds, true ); | ||
}; | ||
const onAddBefore = () => { | ||
if ( ! canInsertDefaultBlock ) { | ||
return; | ||
} | ||
const clientId = Array.isArray( clientIds ) ? clientIds[ 0 ] : clientId; | ||
insertBeforeBlock( clientId ); | ||
}; | ||
const onAddAfter = () => { | ||
if ( ! canInsertDefaultBlock ) { | ||
return; | ||
} | ||
const clientId = Array.isArray( clientIds ) | ||
? clientIds[ clientIds.length - 1 ] | ||
: clientId; | ||
insertAfterBlock( clientId ); | ||
}; | ||
const onMoveTo = () => { | ||
if ( ! canMove ) { | ||
return; | ||
} | ||
setNavigationMode( true ); | ||
selectBlock( clientIds[ 0 ] ); | ||
setBlockMovingClientId( clientIds[ 0 ] ); | ||
}; | ||
const onGroup = () => { | ||
if ( ! blocks.length ) { | ||
return; | ||
} | ||
|
||
const groupingBlockName = getGroupingBlockName(); | ||
|
||
// Activate the `transform` on `core/group` which does the conversion. | ||
const newBlocks = switchToBlockType( blocks, groupingBlockName ); | ||
|
||
if ( ! newBlocks ) { | ||
return; | ||
} | ||
replaceBlocks( clientIds, newBlocks ); | ||
}; | ||
const onUngroup = () => { | ||
if ( ! blocks.length ) { | ||
return; | ||
} | ||
|
||
const innerBlocks = blocks[ 0 ].innerBlocks; | ||
|
||
if ( ! innerBlocks.length ) { | ||
return; | ||
} | ||
|
||
replaceBlocks( clientIds, innerBlocks ); | ||
}; | ||
|
||
if ( ! clientIds || clientIds.length < 1 ) { | ||
return { isLoading: false, commands: [] }; | ||
} | ||
|
||
const icons = { | ||
ungroup, | ||
group, | ||
move, | ||
add, | ||
remove, | ||
duplicate: copy, | ||
}; | ||
|
||
const commands = [ | ||
onUngroup, | ||
onGroup, | ||
onMoveTo, | ||
onAddAfter, | ||
onAddBefore, | ||
onRemove, | ||
onDuplicate, | ||
].map( ( callback ) => { | ||
const action = callback.name | ||
.replace( 'on', '' ) | ||
.replace( /([a-z])([A-Z])/g, '$1 $2' ); | ||
|
||
return { | ||
name: 'core/block-editor/action-' + callback.name, | ||
// translators: %s: type of the command. | ||
label: action, | ||
icon: icons[ | ||
callback.name | ||
.replace( 'on', '' ) | ||
.match( /[A-Z]{1}[a-z]*/ ) | ||
.toString() | ||
.toLowerCase() | ||
], | ||
callback: ( { close } ) => { | ||
callback(); | ||
close(); | ||
}, | ||
}; | ||
} ); | ||
|
||
return { isLoading: false, commands }; | ||
}; | ||
|
||
export const useBlockCommands = () => { | ||
useCommandLoader( { | ||
name: 'core/block-editor/blockTransforms', | ||
hook: useTransformCommands, | ||
} ); | ||
useCommandLoader( { | ||
name: 'core/block-editor/blockActions', | ||
hook: useActionsCommands, | ||
} ); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
5a97d8e
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.
Flaky tests detected in 5a97d8e.
Some tests passed with failed attempts. The failures may not be related to this commit but are still reported for visibility. See the documentation for more information.
🔍 Workflow run URL: https://github.com/WordPress/gutenberg/actions/runs/5855920381
📝 Reported issues:
/test/e2e/specs/editor/various/multi-block-selection.spec.js