@@ -5,6 +5,7 @@ import { useSelect, useDispatch } from '@wordpress/data';
55import { useRefEffect } from '@wordpress/compose' ;
66import { store as blockEditorStore } from '../../../store' ;
77import { unlock } from '../../../lock-unlock' ;
8+ import { getLayoutType } from '../../../layouts' ;
89
910// The distance of the dragged blocks from the pointer.
1011const PILE_OFFSET = 8 ;
@@ -333,6 +334,31 @@ export function useEventHandlers( {
333334 }
334335 return ;
335336 }
337+
338+ // A layout can take over the drag of its blocks, such as a
339+ // manual placement grid, which shows the cells the block will
340+ // land in. A multi-selection drag follows the pointer in every
341+ // layout.
342+ const rootClientId = getBlockRootClientId ( clientId ) ;
343+ const rootLayout = getBlockAttributes ( rootClientId ) ?. layout ;
344+ if (
345+ ! isMultiSelectionDrag &&
346+ getLayoutType ( rootLayout ?. type ) ?. startChildDrag ?.(
347+ event ,
348+ {
349+ layout : rootLayout ,
350+ clientId,
351+ // A block that can be dragged is in a block list.
352+ rootClientId : rootClientId ! ,
353+ blockElement : node ,
354+ startDraggingBlocks,
355+ stopDraggingBlocks,
356+ }
357+ )
358+ ) {
359+ return ;
360+ }
361+
336362 const clientIds = isMultiSelectionDrag
337363 ? getSelectedBlockClientIds ( )
338364 : [ clientId ] ;
@@ -367,83 +393,6 @@ export function useEventHandlers( {
367393 ownerDocument . body . appendChild ( dragElement ) ;
368394 dataTransfer . setDragImage ( dragElement , 0 , 0 ) ;
369395
370- // In a manual placement grid, the grid shows the cells the
371- // block will land in, so the block stays in place, dimmed,
372- // instead of following the pointer. A multi-selection drag
373- // can't be placed in cells, so it follows the pointer.
374- const rootLayout = getBlockAttributes (
375- getBlockRootClientId ( clientId )
376- ) ?. layout ;
377- if (
378- ! isMultiSelectionDrag &&
379- rootLayout ?. type === 'grid' &&
380- rootLayout . isManualPlacement &&
381- window . __experimentalEnableGridInteractivity
382- ) {
383- const originalOpacity = node . style . opacity ;
384- node . style . opacity = '0.5' ;
385-
386- // The grid's drop layer is in the editor's document,
387- // outside the canvas, and a drop there can re-render the
388- // block, after which its `dragend` no longer reaches the
389- // canvas. The drag ends on whichever comes first.
390- const endTargets = new Set ( [
391- ownerDocument ,
392- document ,
393- node ,
394- ] ) ;
395-
396- // The grid's drop layer covers the block once dragging
397- // starts. Chrome cancels a drag when that happens during
398- // `dragstart`, so it waits for the first `dragover`.
399- function startGridDrag ( ) {
400- ownerDocument . removeEventListener (
401- 'dragover' ,
402- startGridDrag
403- ) ;
404- startDraggingBlocks ( [ clientId ] ) ;
405- document . body . classList . add (
406- 'is-dragging-components-draggable'
407- ) ;
408- ownerDocument . documentElement . classList . add (
409- 'is-dragging'
410- ) ;
411- }
412-
413- function endGridDrag ( ) {
414- ownerDocument . removeEventListener (
415- 'dragover' ,
416- startGridDrag
417- ) ;
418- for ( const endTarget of endTargets ) {
419- endTarget . removeEventListener (
420- 'dragend' ,
421- endGridDrag
422- ) ;
423- endTarget . removeEventListener (
424- 'drop' ,
425- endGridDrag
426- ) ;
427- }
428- node . style . opacity = originalOpacity ;
429- dragElement . remove ( ) ;
430- stopDraggingBlocks ( ) ;
431- document . body . classList . remove (
432- 'is-dragging-components-draggable'
433- ) ;
434- ownerDocument . documentElement . classList . remove (
435- 'is-dragging'
436- ) ;
437- }
438-
439- for ( const endTarget of endTargets ) {
440- endTarget . addEventListener ( 'dragend' , endGridDrag ) ;
441- endTarget . addEventListener ( 'drop' , endGridDrag ) ;
442- }
443- ownerDocument . addEventListener ( 'dragover' , startGridDrag ) ;
444- return ;
445- }
446-
447396 const rect = node . getBoundingClientRect ( ) ;
448397
449398 // Remove the id and leave it on a shallow clone so that drop
0 commit comments