diff --git a/packages/block-editor/src/components/block-list/block.js b/packages/block-editor/src/components/block-list/block.js index 01196254ed682c..c0f2de4077d32c 100644 --- a/packages/block-editor/src/components/block-list/block.js +++ b/packages/block-editor/src/components/block-list/block.js @@ -464,7 +464,23 @@ const applyWithDispatch = withDispatch( ( dispatch, ownProps, registry ) => { return; } - if ( getBlockOrder( nextBlockClientId ).length ) { + // Forward deleting an unmodified default block should + // remove it and move into the next block, not pull the + // next block's first item out of it. + if ( isUnmodifiedDefaultBlock( getBlock( clientId ) ) ) { + // Select the first leaf block, so the caret starts at + // the beginning of the block's content rather than on + // a container's shell. + let firstLeafClientId = nextBlockClientId; + while ( getBlockOrder( firstLeafClientId ).length ) { + firstLeafClientId = + getBlockOrder( firstLeafClientId )[ 0 ]; + } + registry.batch( () => { + removeBlock( clientId ); + selectBlock( firstLeafClientId ); + } ); + } else if ( getBlockOrder( nextBlockClientId ).length ) { moveFirstItemUp( nextBlockClientId, false ); } else { mergeBlocks( clientId, nextBlockClientId ); diff --git a/test/e2e/specs/editor/various/splitting-merging.spec.js b/test/e2e/specs/editor/various/splitting-merging.spec.js index d2b8191a95e4a2..4f3097b877ae1f 100644 --- a/test/e2e/specs/editor/various/splitting-merging.spec.js +++ b/test/e2e/specs/editor/various/splitting-merging.spec.js @@ -277,6 +277,62 @@ test.describe( 'splitting and merging blocks (@firefox, @webkit)', () => { ] ); } ); + test( 'should forward delete an empty paragraph without breaking apart the next block', async ( { + editor, + page, + } ) => { + await editor.insertBlock( { name: 'core/paragraph' } ); + await editor.insertBlock( { + name: 'core/list', + innerBlocks: [ + { name: 'core/list-item', attributes: { content: 'one' } }, + { name: 'core/list-item', attributes: { content: 'two' } }, + ], + } ); + + await editor.canvas + .getByRole( 'document', { name: 'Empty block' } ) + .click(); + + await expect.poll( editor.getBlocks ).toMatchObject( [ + { name: 'core/paragraph', attributes: { content: '' } }, + { + name: 'core/list', + innerBlocks: [ + { + name: 'core/list-item', + attributes: { content: 'one' }, + }, + { + name: 'core/list-item', + attributes: { content: 'two' }, + }, + ], + }, + ] ); + + await page.keyboard.press( 'Delete' ); + await page.keyboard.type( '|' ); + + // The empty paragraph is removed and the list is left intact, with + // the caret at the start of its first item. + await expect.poll( editor.getBlocks ).toMatchObject( [ + { + name: 'core/list', + innerBlocks: [ + { + name: 'core/list-item', + attributes: { content: '|one' }, + }, + { + name: 'core/list-item', + attributes: { content: 'two' }, + }, + ], + }, + ] ); + } ); + test( 'should remove empty paragraph block on backspace', async ( { editor, page,