Skip to content

Commit

Permalink
Block editor: add a keyboard shortcut to create group from the select…
Browse files Browse the repository at this point in the history
…ed blocks
  • Loading branch information
t-hamano committed Mar 2, 2024
1 parent 63acff0 commit f329fa4
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 3 deletions.
5 changes: 5 additions & 0 deletions docs/getting-started/faq.md
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,11 @@ This is the canonical list of keyboard shortcuts:
<td><kbd>/</kbd></td>
<td><kbd>/</kbd></td>
</tr>
<tr>
<td>Create a group block from the selected block(s).</td>
<td><kbd>Ctrl</kbd>+<kbd>Alt</kbd>+<kbd>G</kbd></td>
<td><kbd>⌥</kbd><kbd>⌘</kbd><kbd>⇧</kbd><kbd>G</kbd></td>
</tr>
<tr>
<td>Remove multiple selected blocks.</td>
<td><kbd>del</kbd><kbd>backspace</kbd></td>
Expand Down
24 changes: 21 additions & 3 deletions packages/block-editor/src/components/block-tools/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { useSelect, useDispatch } from '@wordpress/data';
import { Popover } from '@wordpress/components';
import { __unstableUseShortcutEventMatch as useShortcutEventMatch } from '@wordpress/keyboard-shortcuts';
import { useRef } from '@wordpress/element';
import { switchToBlockType, store as blocksStore } from '@wordpress/blocks';

/**
* Internal dependencies
Expand Down Expand Up @@ -62,9 +63,13 @@ export default function BlockTools( {
[]
);
const isMatch = useShortcutEventMatch();
const { getSelectedBlockClientIds, getBlockRootClientId } =
useSelect( blockEditorStore );

const {
getBlocksByClientId,
getSelectedBlockClientIds,
getBlockRootClientId,
isGroupable,
} = useSelect( blockEditorStore );
const { getGroupingBlockName } = useSelect( blocksStore );
const {
showEmptyBlockSideInserter,
showBreadcrumb,
Expand All @@ -74,6 +79,7 @@ export default function BlockTools( {
const {
duplicateBlocks,
removeBlocks,
replaceBlocks,
insertAfterBlock,
insertBeforeBlock,
selectBlock,
Expand Down Expand Up @@ -140,6 +146,18 @@ export default function BlockTools( {
// In effect, to the user this feels like deselecting the multi-selection.
selectBlock( clientIds[ 0 ] );
}
} else if ( isMatch( 'core/block-editor/group', event ) ) {
const clientIds = getSelectedBlockClientIds();
if ( clientIds.length > 1 && isGroupable( clientIds ) ) {
event.preventDefault();
const blocks = getBlocksByClientId( clientIds );
const groupingBlockName = getGroupingBlockName();
const newBlocks = switchToBlockType(
blocks,
groupingBlockName
);
replaceBlocks( clientIds, newBlocks );
}
}
}

Expand Down
12 changes: 12 additions & 0 deletions packages/block-editor/src/components/keyboard-shortcuts/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,18 @@ function KeyboardShortcutsRegister() {
character: 'y',
},
} );

registerShortcut( {
name: 'core/block-editor/group',
category: 'block',
description: __(
'Create a group block from the selected block(s).'
),
keyCombination: {
modifier: 'primaryAlt',
character: 'g',
},
} );
}, [ registerShortcut ] );

return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -217,4 +217,68 @@ test.describe( 'Block editor keyboard shortcuts', () => {
] );
} );
} );

test.describe( 'create a group block from the selected blocks', () => {
test( 'should propagate properly if multiple blocks are selected.', async ( {
editor,
page,
pageUtils,
} ) => {
await addTestParagraphBlocks( { editor, page } );

// Multiselect via keyboard.
await pageUtils.pressKeys( 'primary+a', { times: 2 } );

await pageUtils.pressKeys( 'primaryAlt+g' ); // Keyboard shortcut for Insert before.
await expect.poll( editor.getBlocks ).toMatchObject( [
{
name: 'core/group',
innerBlocks: [
{
name: 'core/paragraph',
attributes: { content: '1st' },
},
{
name: 'core/paragraph',
attributes: { content: '2nd' },
},
{
name: 'core/paragraph',
attributes: { content: '3rd' },
},
],
},
] );
} );

test( 'should prevent if a single block is selected.', async ( {
editor,
page,
pageUtils,
} ) => {
await addTestParagraphBlocks( { editor, page } );
const firstParagraphBlock = editor.canvas
.getByRole( 'document', {
name: 'Block: Paragraph',
} )
.first();
await editor.selectBlocks( firstParagraphBlock );
await pageUtils.pressKeys( 'primaryAlt+g' );

await expect.poll( editor.getBlocks ).toMatchObject( [
{
name: 'core/paragraph',
attributes: { content: '1st' },
},
{
name: 'core/paragraph',
attributes: { content: '2nd' },
},
{
name: 'core/paragraph',
attributes: { content: '3rd' },
},
] );
} );
} );
} );

0 comments on commit f329fa4

Please sign in to comment.