diff --git a/packages/block-editor/src/components/block-popover/inbetween.js b/packages/block-editor/src/components/block-popover/inbetween.js index f82b4a56ce74ee..a08df1600e03c5 100644 --- a/packages/block-editor/src/components/block-popover/inbetween.js +++ b/packages/block-editor/src/components/block-popover/inbetween.js @@ -34,6 +34,7 @@ function BlockPopoverInbetween( { __unstablePopoverSlot, __unstableContentRef, operation = 'insert', + nearestSide = 'right', ...props } ) { // This is a temporary hack to get the inbetween inserter to recompute properly. @@ -82,7 +83,10 @@ function BlockPopoverInbetween( { return undefined; } - const contextElement = previousElement || nextElement; + const contextElement = + operation === 'group' + ? nextElement || previousElement + : previousElement || nextElement; return { contextElement, @@ -100,12 +104,16 @@ function BlockPopoverInbetween( { let height = 0; if ( operation === 'group' ) { - // If the operation is group, nextRect is the target to be grouped. - // Not sure if previousRect is needed here. - top = nextRect ? nextRect.top : previousRect.top; - width = nextRect ? nextRect.width : previousRect.width; - height = nextRect ? nextRect.bottom - nextRect.top : 0; - left = nextRect ? nextRect.left : previousRect.left; + const targetRect = nextRect || previousRect; + top = targetRect.top; + width = targetRect.width; + height = targetRect.bottom - targetRect.top; + // Popover calculates its distance from mid-block so some + // adjustments are needed to make it appear in the right place. + left = + nearestSide === 'left' + ? -targetRect.width / 2 + targetRect.left + : targetRect.width / 2 + targetRect.left; } else if ( isVertical ) { // vertical top = previousRect ? previousRect.bottom : nextRect.top; @@ -149,6 +157,8 @@ function BlockPopoverInbetween( { popoverRecomputeCounter, isVertical, isVisible, + operation, + nearestSide, ] ); const popoverScrollRef = usePopoverScroll( __unstableContentRef ); diff --git a/packages/block-editor/src/components/block-tools/insertion-point.js b/packages/block-editor/src/components/block-tools/insertion-point.js index 0a6a19ea126ac5..19ad39caca336a 100644 --- a/packages/block-editor/src/components/block-tools/insertion-point.js +++ b/packages/block-editor/src/components/block-tools/insertion-point.js @@ -25,6 +25,7 @@ function InbetweenInsertionPointPopover( { __unstablePopoverSlot, __unstableContentRef, operation = 'insert', + nearestSide = 'right', } ) { const { selectBlock, hideInsertionPoint } = useDispatch( blockEditorStore ); const openRef = useContext( InsertionPointOpenRef ); @@ -156,6 +157,7 @@ function InbetweenInsertionPointPopover( { __unstablePopoverSlot={ __unstablePopoverSlot } __unstableContentRef={ __unstableContentRef } operation={ operation } + nearestSide={ nearestSide } > ); diff --git a/packages/block-editor/src/components/use-block-drop-zone/index.js b/packages/block-editor/src/components/use-block-drop-zone/index.js index 97a219a2317eda..8b611811dcec31 100644 --- a/packages/block-editor/src/components/use-block-drop-zone/index.js +++ b/packages/block-editor/src/components/use-block-drop-zone/index.js @@ -66,6 +66,7 @@ export function getDropTargetPosition( let insertPosition = 'before'; let minDistance = Infinity; let targetBlockIndex = null; + let nearestSide = 'right'; blocksData.forEach( ( { isUnmodifiedDefaultBlock, getBoundingClientRect, blockIndex } ) => { @@ -86,6 +87,13 @@ export function getDropTargetPosition( // Set target block index if the point is inside of the block // and the block is modified. targetBlockIndex = blockIndex; + // If the point is inside of the block, find nearest side. + const [ , sideEdge ] = getDistanceToNearestEdge( + position, + rect, + [ 'left', 'right' ] + ); + nearestSide = sideEdge; } if ( distance < minDistance ) { @@ -113,7 +121,7 @@ export function getDropTargetPosition( // If the target index is set then group with the block at that index. if ( targetBlockIndex !== null ) { - return [ targetBlockIndex, 'group' ]; + return [ targetBlockIndex, 'group', nearestSide ]; } // If both blocks are not unmodified default blocks then just insert between them. if ( @@ -181,6 +189,7 @@ export default function useBlockDropZone( { const onBlockDrop = useOnBlockDrop( targetRootClientId, dropTarget.index, { operation: dropTarget.operation, + nearestSide: dropTarget.nearestSide, } ); const throttled = useThrottle( useCallback( @@ -215,19 +224,22 @@ export default function useBlockDropZone( { }; } ); - const [ targetIndex, operation ] = getDropTargetPosition( - blocksData, - { x: event.clientX, y: event.clientY }, - getBlockListSettings( targetRootClientId )?.orientation - ); + const [ targetIndex, operation, nearestSide ] = + getDropTargetPosition( + blocksData, + { x: event.clientX, y: event.clientY }, + getBlockListSettings( targetRootClientId )?.orientation + ); registry.batch( () => { setDropTarget( { index: targetIndex, operation, + nearestSide, } ); showInsertionPoint( targetRootClientId, targetIndex, { operation, + nearestSide, } ); } ); }, diff --git a/packages/block-editor/src/components/use-on-block-drop/index.js b/packages/block-editor/src/components/use-on-block-drop/index.js index 7c074ad72dd8c5..cef83fe5a8a299 100644 --- a/packages/block-editor/src/components/use-on-block-drop/index.js +++ b/packages/block-editor/src/components/use-on-block-drop/index.js @@ -230,7 +230,7 @@ export default function useOnBlockDrop( targetBlockIndex, options = {} ) { - const { operation = 'insert' } = options; + const { operation = 'insert', nearestSide = 'right' } = options; const hasUploadPermissions = useSelect( ( select ) => select( blockEditorStore ).getSettings().mediaUpload, [] @@ -266,7 +266,11 @@ export default function useOnBlockDrop( replaceBlocks( clientId, blocks, undefined, initialPosition ); } else if ( operation === 'group' ) { const targetBlock = getBlock( clientId ); - blocks.unshift( targetBlock ); + if ( nearestSide === 'left' ) { + blocks.push( targetBlock ); + } else { + blocks.unshift( targetBlock ); + } const groupInnerBlocks = blocks.map( ( block ) => { return createBlock( @@ -279,7 +283,7 @@ export default function useOnBlockDrop( const wrappedBlocks = createBlock( 'core/group', { - layout: { type: 'flex' }, + layout: { type: 'flex', flexWrap: 'nowrap' }, }, groupInnerBlocks ); diff --git a/packages/block-editor/src/store/actions.js b/packages/block-editor/src/store/actions.js index b21436161cb8c3..d59a0aea71941d 100644 --- a/packages/block-editor/src/store/actions.js +++ b/packages/block-editor/src/store/actions.js @@ -640,13 +640,15 @@ export function showInsertionPoint( index, __unstableOptions = {} ) { - const { __unstableWithInserter, operation } = __unstableOptions; + const { __unstableWithInserter, operation, nearestSide } = + __unstableOptions; return { type: 'SHOW_INSERTION_POINT', rootClientId, index, __unstableWithInserter, operation, + nearestSide, }; } /** diff --git a/packages/block-editor/src/store/reducer.js b/packages/block-editor/src/store/reducer.js index d5ff85e9e4257b..6856e53b13bf07 100644 --- a/packages/block-editor/src/store/reducer.js +++ b/packages/block-editor/src/store/reducer.js @@ -1580,13 +1580,19 @@ export function blocksMode( state = {}, action ) { export function insertionPoint( state = null, action ) { switch ( action.type ) { case 'SHOW_INSERTION_POINT': { - const { rootClientId, index, __unstableWithInserter, operation } = - action; + const { + rootClientId, + index, + __unstableWithInserter, + operation, + nearestSide, + } = action; const nextState = { rootClientId, index, __unstableWithInserter, operation, + nearestSide, }; // Bail out updates if the states are the same.