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 (