diff --git a/packages/block-editor/src/components/copy-handler/index.js b/packages/block-editor/src/components/copy-handler/index.js index 3e5a50a8fe49ea..3881ff06f2bf30 100644 --- a/packages/block-editor/src/components/copy-handler/index.js +++ b/packages/block-editor/src/components/copy-handler/index.js @@ -7,6 +7,8 @@ import { pasteHandler, store as blocksStore, createBlock, + findTransform, + getBlockTransforms, } from '@wordpress/blocks'; import { documentHasSelection, @@ -84,6 +86,7 @@ export function useClipboardHandler() { __unstableIsSelectionCollapsed, __unstableIsSelectionMergeable, __unstableGetSelectedBlocksWithPartialSelection, + canInsertBlockType, } = useSelect( blockEditorStore ); const { flashBlock, @@ -91,6 +94,7 @@ export function useClipboardHandler() { replaceBlocks, __unstableDeleteSelection, __unstableExpandSelection, + insertBlocks, } = useDispatch( blockEditorStore ); const notifyCopy = useNotifyCopy(); @@ -201,13 +205,55 @@ export function useClipboardHandler() { __experimentalCanUserUseUnfilteredHTML: canUserUseUnfilteredHTML, } = getSettings(); - const { plainText, html } = getPasteEventData( event ); - const blocks = pasteHandler( { - HTML: html, - plainText, - mode: 'BLOCKS', - canUserUseUnfilteredHTML, - } ); + const { plainText, html, files } = getPasteEventData( event ); + let blocks = []; + + if ( files.length ) { + const fromTransforms = getBlockTransforms( 'from' ); + blocks = files + .reduce( ( accumulator, file ) => { + const transformation = findTransform( + fromTransforms, + ( transform ) => + transform.type === 'files' && + transform.isMatch( [ file ] ) + ); + if ( transformation ) { + accumulator.push( + transformation.transform( [ file ] ) + ); + } + return accumulator; + }, [] ) + .flat(); + } else { + blocks = pasteHandler( { + HTML: html, + plainText, + mode: 'BLOCKS', + canUserUseUnfilteredHTML, + } ); + } + + if ( selectedBlockClientIds.length === 1 ) { + const [ selectedBlockClientId ] = selectedBlockClientIds; + + if ( + blocks.every( ( block ) => + canInsertBlockType( + block.name, + selectedBlockClientId + ) + ) + ) { + insertBlocks( + blocks, + undefined, + selectedBlockClientId + ); + return; + } + } replaceBlocks( selectedBlockClientIds, diff --git a/packages/block-editor/src/components/rich-text/file-paste-handler.js b/packages/block-editor/src/components/rich-text/file-paste-handler.js deleted file mode 100644 index 2aae5984389e68..00000000000000 --- a/packages/block-editor/src/components/rich-text/file-paste-handler.js +++ /dev/null @@ -1,13 +0,0 @@ -/** - * WordPress dependencies - */ -import { createBlobURL } from '@wordpress/blob'; - -export function filePasteHandler( files ) { - return files - .filter( ( { type } ) => - /^image\/(?:jpe?g|png|gif|webp)$/.test( type ) - ) - .map( ( file ) => `` ) - .join( '' ); -} diff --git a/packages/block-editor/src/components/rich-text/use-paste-handler.js b/packages/block-editor/src/components/rich-text/use-paste-handler.js index 5e4f4260f5001f..67c932aceddcc1 100644 --- a/packages/block-editor/src/components/rich-text/use-paste-handler.js +++ b/packages/block-editor/src/components/rich-text/use-paste-handler.js @@ -4,7 +4,11 @@ import { useRef } from '@wordpress/element'; import { useRefEffect } from '@wordpress/compose'; import { getFilesFromDataTransfer } from '@wordpress/dom'; -import { pasteHandler } from '@wordpress/blocks'; +import { + pasteHandler, + findTransform, + getBlockTransforms, +} from '@wordpress/blocks'; import { isEmpty, insert, @@ -17,7 +21,6 @@ import { isURL } from '@wordpress/url'; /** * Internal dependencies */ -import { filePasteHandler } from './file-paste-handler'; import { addActiveFormats, isShortcode } from './utils'; import { splitValue } from './split-value'; import { shouldDismissPastedFiles } from '../../utils/pasting'; @@ -155,6 +158,12 @@ export function usePasteHandler( props ) { return; } + if ( files?.length ) { + // Allows us to ask for this information when we get a report. + // eslint-disable-next-line no-console + window.console.log( 'Received items:\n\n', files ); + } + // Process any attached files, unless we infer that the files in // question are redundant "screenshots" of the actual HTML payload, // as created by certain office-type programs. @@ -164,23 +173,33 @@ export function usePasteHandler( props ) { files?.length && ! shouldDismissPastedFiles( files, html, plainText ) ) { - const content = pasteHandler( { - HTML: filePasteHandler( files ), - mode: 'BLOCKS', - tagName, - preserveWhiteSpace, - } ); - - // Allows us to ask for this information when we get a report. - // eslint-disable-next-line no-console - window.console.log( 'Received items:\n\n', files ); + const fromTransforms = getBlockTransforms( 'from' ); + const blocks = files + .reduce( ( accumulator, file ) => { + const transformation = findTransform( + fromTransforms, + ( transform ) => + transform.type === 'files' && + transform.isMatch( [ file ] ) + ); + if ( transformation ) { + accumulator.push( + transformation.transform( [ file ] ) + ); + } + return accumulator; + }, [] ) + .flat(); + if ( ! blocks.length ) { + return; + } if ( onReplace && isEmpty( value ) ) { - onReplace( content ); + onReplace( blocks ); } else { splitValue( { value, - pastedBlocks: content, + pastedBlocks: blocks, onReplace, onSplit, onSplitMiddle, diff --git a/packages/block-editor/src/utils/pasting.js b/packages/block-editor/src/utils/pasting.js index 366b79a3294229..e962e11050a1d9 100644 --- a/packages/block-editor/src/utils/pasting.js +++ b/packages/block-editor/src/utils/pasting.js @@ -1,7 +1,6 @@ /** * WordPress dependencies */ -import { createBlobURL } from '@wordpress/blob'; import { getFilesFromDataTransfer } from '@wordpress/dom'; export function getPasteEventData( { clipboardData } ) { @@ -25,21 +24,16 @@ export function getPasteEventData( { clipboardData } ) { } } - const files = getFilesFromDataTransfer( clipboardData ).filter( - ( { type } ) => /^image\/(?:jpe?g|png|gif|webp)$/.test( type ) - ); + const files = getFilesFromDataTransfer( clipboardData ); if ( files.length && ! shouldDismissPastedFiles( files, html, plainText ) ) { - html = files - .map( ( file ) => `` ) - .join( '' ); - plainText = ''; + return { files }; } - return { html, plainText }; + return { html, plainText, files: [] }; } /** diff --git a/packages/block-library/src/gallery/edit.js b/packages/block-library/src/gallery/edit.js index 036f0c2133a5d3..24cb0ba0c2f9bb 100644 --- a/packages/block-library/src/gallery/edit.js +++ b/packages/block-library/src/gallery/edit.js @@ -21,6 +21,7 @@ import { MediaPlaceholder, InspectorControls, useBlockProps, + useInnerBlocksProps, BlockControls, MediaReplaceFlow, } from '@wordpress/block-editor'; @@ -64,6 +65,7 @@ const linkOptions = [ }, ]; const ALLOWED_MEDIA_TYPES = [ 'image' ]; +const allowedBlocks = [ 'core/image' ]; const PLACEHOLDER_TEXT = Platform.isNative ? __( 'ADD MEDIA' ) @@ -484,8 +486,20 @@ function GalleryEdit( props ) { className: classnames( className, 'has-nested-images' ), } ); + const innerBlocksProps = useInnerBlocksProps( blockProps, { + allowedBlocks, + orientation: 'horizontal', + renderAppender: false, + __experimentalLayout: { type: 'default', alignments: [] }, + } ); + if ( ! hasImages ) { - return { mediaPlaceholder }; + return ( + + { innerBlocksProps.children } + { mediaPlaceholder } + + ); } const hasLinkTo = linkTo && linkTo !== 'none'; @@ -580,7 +594,7 @@ function GalleryEdit( props ) { ? mediaPlaceholder : undefined } - blockProps={ blockProps } + blockProps={ innerBlocksProps } insertBlocksAfter={ insertBlocksAfter } /> diff --git a/packages/block-library/src/gallery/gallery.js b/packages/block-library/src/gallery/gallery.js index e6176cc8a7256c..957a141d51c6b7 100644 --- a/packages/block-library/src/gallery/gallery.js +++ b/packages/block-library/src/gallery/gallery.js @@ -8,7 +8,6 @@ import classnames from 'classnames'; */ import { RichText, - useInnerBlocksProps, __experimentalGetElementClassName, } from '@wordpress/block-editor'; import { VisuallyHidden } from '@wordpress/components'; @@ -16,8 +15,6 @@ import { __ } from '@wordpress/i18n'; import { createBlock, getDefaultBlockName } from '@wordpress/blocks'; import { View } from '@wordpress/primitives'; -const allowedBlocks = [ 'core/image' ]; - export const Gallery = ( props ) => { const { attributes, @@ -31,16 +28,9 @@ export const Gallery = ( props ) => { const { align, columns, caption, imageCrop } = attributes; - const { children, ...innerBlocksProps } = useInnerBlocksProps( blockProps, { - allowedBlocks, - orientation: 'horizontal', - renderAppender: false, - __experimentalLayout: { type: 'default', alignments: [] }, - } ); - return (
{ } ) } > - { children } - { isSelected && ! children && ( + { blockProps.children } + { isSelected && ! blockProps.children && ( { mediaPlaceholder }