diff --git a/packages/block-editor/src/components/writing-flow/use-clipboard-handler.js b/packages/block-editor/src/components/writing-flow/use-clipboard-handler.js index 56583447d3f0e9..bed07b183cc0cc 100644 --- a/packages/block-editor/src/components/writing-flow/use-clipboard-handler.js +++ b/packages/block-editor/src/components/writing-flow/use-clipboard-handler.js @@ -6,6 +6,7 @@ import { findTransform, getBlockTransforms, hasBlockSupport, + switchToBlockType, } from '@wordpress/blocks'; import { documentHasSelection, @@ -208,15 +209,36 @@ export default function useClipboardHandler() { firstSelectedClientId ); - if ( - ! blocks.every( ( block ) => - canInsertBlockType( block.name, rootClientId ) - ) - ) { - return; + const newBlocks = []; + + for ( const block of blocks ) { + if ( canInsertBlockType( block.name, rootClientId ) ) { + newBlocks.push( block ); + } else { + // If a block cannot be inserted in a root block, try + // converting it to that root block type and insert the + // inner blocks. + // Example: paragraphs cannot be inserted into a list, + // so convert the paragraphs to a list for list items. + const rootBlockName = getBlockName( rootClientId ); + const switchedBlocks = + block.name !== rootBlockName + ? switchToBlockType( block, rootBlockName ) + : [ block ]; + + if ( ! switchedBlocks ) { + return; + } + + for ( const switchedBlock of switchedBlocks ) { + for ( const innerBlock of switchedBlock.innerBlocks ) { + newBlocks.push( innerBlock ); + } + } + } } - __unstableSplitSelection( blocks ); + __unstableSplitSelection( newBlocks ); event.preventDefault(); } } diff --git a/test/e2e/specs/editor/various/__snapshots__/Copy-cut-paste-should-paste-list-in-list-1-chromium.txt b/test/e2e/specs/editor/various/__snapshots__/Copy-cut-paste-should-paste-list-in-list-1-chromium.txt new file mode 100644 index 00000000000000..7f74d7fd8b3d03 --- /dev/null +++ b/test/e2e/specs/editor/various/__snapshots__/Copy-cut-paste-should-paste-list-in-list-1-chromium.txt @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/test/e2e/specs/editor/various/__snapshots__/Copy-cut-paste-should-paste-paragraphs-in-list-1-chromium.txt b/test/e2e/specs/editor/various/__snapshots__/Copy-cut-paste-should-paste-paragraphs-in-list-1-chromium.txt new file mode 100644 index 00000000000000..7f74d7fd8b3d03 --- /dev/null +++ b/test/e2e/specs/editor/various/__snapshots__/Copy-cut-paste-should-paste-paragraphs-in-list-1-chromium.txt @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/test/e2e/specs/editor/various/copy-cut-paste.spec.js b/test/e2e/specs/editor/various/copy-cut-paste.spec.js index 48392170e66dde..4951f99fb6b5b2 100644 --- a/test/e2e/specs/editor/various/copy-cut-paste.spec.js +++ b/test/e2e/specs/editor/various/copy-cut-paste.spec.js @@ -494,6 +494,32 @@ test.describe( 'Copy/cut/paste', () => { expect( await editor.getEditedPostContent() ).toMatchSnapshot(); } ); + test( 'should paste list in list', async ( { + page, + pageUtils, + editor, + } ) => { + pageUtils.setClipboardData( { html: '' } ); + await editor.insertBlock( { name: 'core/list' } ); + await pageUtils.pressKeys( 'primary+v' ); + // Ensure the selection is correct. + await page.keyboard.type( '‸' ); + expect( await editor.getEditedPostContent() ).toMatchSnapshot(); + } ); + + test( 'should paste paragraphs in list', async ( { + page, + pageUtils, + editor, + } ) => { + pageUtils.setClipboardData( { html: '

x

y

' } ); + await editor.insertBlock( { name: 'core/list' } ); + await pageUtils.pressKeys( 'primary+v' ); + // Ensure the selection is correct. + await page.keyboard.type( '‸' ); + expect( await editor.getEditedPostContent() ).toMatchSnapshot(); + } ); + test( 'should link selection', async ( { pageUtils, editor } ) => { await editor.insertBlock( { name: 'core/paragraph',