From 6a594655b0ab981140acc2c060776fb804912108 Mon Sep 17 00:00:00 2001 From: Andrew Serong <14988353+andrewserong@users.noreply.github.com> Date: Thu, 23 Nov 2023 16:54:04 +1100 Subject: [PATCH 1/9] Try: Allow drag between blocks based on a threshold --- .../components/use-block-drop-zone/index.js | 44 ++++++++++++++++--- .../src/components/use-on-block-drop/index.js | 22 +++++++++- 2 files changed, 58 insertions(+), 8 deletions(-) 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 25dc6ee408982..ae90c992eee3b 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 @@ -60,12 +60,34 @@ export function getDropTargetPosition( ? [ 'left', 'right' ] : [ 'top', 'bottom' ]; - const isRightToLeft = isRTL(); - let nearestIndex = 0; let insertPosition = 'before'; let minDistance = Infinity; + // TODO: Figure out a neater way to handle passing in the drop zone element. + const dropZoneElement = blocksData[ 0 ]?.dropZoneElement; + + if ( dropZoneElement ) { + const rect = dropZoneElement.getBoundingClientRect(); + + const [ distance, edge ] = getDistanceToNearestEdge( position, rect, [ + 'top', + 'bottom', + ] ); + + // TODO: Replace `30` with a constant. + if ( distance < 30 ) { + if ( edge === 'top' ) { + return [ 0, 'insert', 'before' ]; + } + if ( edge === 'bottom' ) { + return [ 0, 'insert', 'after' ]; + } + } + } + + const isRightToLeft = isRTL(); + blocksData.forEach( ( { isUnmodifiedDefaultBlock, getBoundingClientRect, blockIndex } ) => { const rect = getBoundingClientRect(); @@ -173,6 +195,7 @@ export default function useBlockDropZone( { useDispatch( blockEditorStore ); const onBlockDrop = useOnBlockDrop( targetRootClientId, dropTarget.index, { + moveBeforeOrAfter: dropTarget.moveBeforeOrAfter, operation: dropTarget.operation, } ); const throttled = useThrottle( @@ -198,6 +221,7 @@ export default function useBlockDropZone( { const clientId = block.clientId; return { + dropZoneElement, isUnmodifiedDefaultBlock: getIsUnmodifiedDefaultBlock( block ), getBoundingClientRect: () => @@ -208,23 +232,29 @@ export default function useBlockDropZone( { }; } ); - const [ targetIndex, operation ] = getDropTargetPosition( - blocksData, - { x: event.clientX, y: event.clientY }, - getBlockListSettings( targetRootClientId )?.orientation - ); + const [ targetIndex, operation, moveBeforeOrAfter ] = + getDropTargetPosition( + blocksData, + { x: event.clientX, y: event.clientY }, + getBlockListSettings( targetRootClientId )?.orientation + ); registry.batch( () => { setDropTarget( { + moveBeforeOrAfter, index: targetIndex, operation, } ); + + // TODO: Fix display of insertion point, so that it matches onBlockDrop logic. showInsertionPoint( targetRootClientId, targetIndex, { + moveBeforeOrAfter, operation, } ); } ); }, [ + dropZoneElement, getBlocks, targetRootClientId, getBlockListSettings, 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 72ea6a698c343..1e9c61c49589b 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 @@ -210,7 +210,7 @@ export default function useOnBlockDrop( targetBlockIndex, options = {} ) { - const { operation = 'insert' } = options; + const { operation = 'insert', moveBeforeOrAfter } = options; const hasUploadPermissions = useSelect( ( select ) => select( blockEditorStore ).getSettings().mediaUpload, [] @@ -220,6 +220,7 @@ export default function useOnBlockDrop( getBlockIndex, getClientIdsOfDescendants, getBlockOrder, + getBlockParents, getBlocksByClientId, } = useSelect( blockEditorStore ); const { @@ -280,6 +281,24 @@ export default function useOnBlockDrop( ); } ); } else { + if ( moveBeforeOrAfter ) { + const parentBlock = + getBlockParents( targetRootClientId )[ 0 ]; + // const targetBlockClientIds = getBlockOrder( parentBlock ); + let blockIndex = getBlockIndex( targetRootClientId ); + if ( moveBeforeOrAfter === 'after' ) { + ++blockIndex; + } + // const targetBlockClientId = + // targetBlockClientIds[ blockIndex ]; + moveBlocksToPosition( + sourceClientIds, + sourceRootClientId, + parentBlock, + blockIndex + ); + return; + } moveBlocksToPosition( sourceClientIds, sourceRootClientId, @@ -293,6 +312,7 @@ export default function useOnBlockDrop( getBlockOrder, getBlocksByClientId, insertBlocks, + moveBeforeOrAfter, moveBlocksToPosition, removeBlocks, targetBlockIndex, From 14a73dd6e29c10b851694771dc9a3a7513110c30 Mon Sep 17 00:00:00 2001 From: Andrew Serong <14988353+andrewserong@users.noreply.github.com> Date: Fri, 24 Nov 2023 15:42:25 +1100 Subject: [PATCH 2/9] Update insertion point to reflect threshold --- .../components/use-block-drop-zone/index.js | 54 +++++++++++++------ .../src/components/use-on-block-drop/index.js | 6 ++- 2 files changed, 41 insertions(+), 19 deletions(-) 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 ae90c992eee3b..8db5107707841 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 @@ -20,6 +20,8 @@ import { } from '../../utils/math'; import { store as blockEditorStore } from '../../store'; +const THRESHOLD_DISTANCE = 30; + /** @typedef {import('../../utils/math').WPPoint} WPPoint */ /** @typedef {import('../use-on-block-drop/types').WPDropOperation} WPDropOperation */ @@ -48,12 +50,14 @@ import { store as blockEditorStore } from '../../store'; * @param {WPBlockData[]} blocksData The block data list. * @param {WPPoint} position The position of the item being dragged. * @param {WPBlockListOrientation} orientation The orientation of the block list. + * @param {Object} options Additional options. * @return {[number, WPDropOperation]} The drop target position. */ export function getDropTargetPosition( blocksData, position, - orientation = 'vertical' + orientation = 'vertical', + options = {} ) { const allowedEdges = orientation === 'horizontal' @@ -64,10 +68,9 @@ export function getDropTargetPosition( let insertPosition = 'before'; let minDistance = Infinity; - // TODO: Figure out a neater way to handle passing in the drop zone element. - const dropZoneElement = blocksData[ 0 ]?.dropZoneElement; + const { dropZoneElement, parentBlock, rootBlockIndex = 0 } = options; - if ( dropZoneElement ) { + if ( dropZoneElement && parentBlock ) { const rect = dropZoneElement.getBoundingClientRect(); const [ distance, edge ] = getDistanceToNearestEdge( position, rect, [ @@ -75,13 +78,13 @@ export function getDropTargetPosition( 'bottom', ] ); - // TODO: Replace `30` with a constant. - if ( distance < 30 ) { + // TODO: Check if the parent block is horizontal / vertical orientation. + if ( distance < THRESHOLD_DISTANCE ) { if ( edge === 'top' ) { - return [ 0, 'insert', 'before' ]; + return [ rootBlockIndex, 'insert', 'before' ]; } if ( edge === 'bottom' ) { - return [ 0, 'insert', 'after' ]; + return [ rootBlockIndex + 1, 'insert', 'after' ]; } } } @@ -172,19 +175,26 @@ export default function useBlockDropZone( { operation: 'insert', } ); - const isDisabled = useSelect( + const { isDisabled, parentBlock, rootBlockIndex } = useSelect( ( select ) => { const { __unstableIsWithinBlockOverlay, __unstableHasActiveBlockOverlayActive, + getBlockIndex, + getBlockParents, getBlockEditingMode, } = select( blockEditorStore ); const blockEditingMode = getBlockEditingMode( targetRootClientId ); - return ( - blockEditingMode !== 'default' || - __unstableHasActiveBlockOverlayActive( targetRootClientId ) || - __unstableIsWithinBlockOverlay( targetRootClientId ) - ); + return { + parentBlock: getBlockParents( targetRootClientId, true )[ 0 ], + rootBlockIndex: getBlockIndex( targetRootClientId ), + isDisabled: + blockEditingMode !== 'default' || + __unstableHasActiveBlockOverlayActive( + targetRootClientId + ) || + __unstableIsWithinBlockOverlay( targetRootClientId ), + }; }, [ targetRootClientId ] ); @@ -221,7 +231,6 @@ export default function useBlockDropZone( { const clientId = block.clientId; return { - dropZoneElement, isUnmodifiedDefaultBlock: getIsUnmodifiedDefaultBlock( block ), getBoundingClientRect: () => @@ -236,7 +245,12 @@ export default function useBlockDropZone( { getDropTargetPosition( blocksData, { x: event.clientX, y: event.clientY }, - getBlockListSettings( targetRootClientId )?.orientation + getBlockListSettings( targetRootClientId )?.orientation, + { + dropZoneElement, + parentBlock, + rootBlockIndex, + } ); registry.batch( () => { @@ -246,8 +260,12 @@ export default function useBlockDropZone( { operation, } ); + const insertionPointClientId = moveBeforeOrAfter + ? parentBlock + : targetRootClientId; + // TODO: Fix display of insertion point, so that it matches onBlockDrop logic. - showInsertionPoint( targetRootClientId, targetIndex, { + showInsertionPoint( insertionPointClientId, targetIndex, { moveBeforeOrAfter, operation, } ); @@ -261,6 +279,8 @@ export default function useBlockDropZone( { registry, showInsertionPoint, getBlockIndex, + parentBlock, + rootBlockIndex, ] ), 200 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 1e9c61c49589b..7688b7ad95434 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 @@ -282,8 +282,10 @@ export default function useOnBlockDrop( } ); } else { if ( moveBeforeOrAfter ) { - const parentBlock = - getBlockParents( targetRootClientId )[ 0 ]; + const parentBlock = getBlockParents( + targetRootClientId, + true + )[ 0 ]; // const targetBlockClientIds = getBlockOrder( parentBlock ); let blockIndex = getBlockIndex( targetRootClientId ); if ( moveBeforeOrAfter === 'after' ) { From 66d414487dd9f5ed067195c956595a51c725c6d9 Mon Sep 17 00:00:00 2001 From: Andrew Serong <14988353+andrewserong@users.noreply.github.com> Date: Tue, 28 Nov 2023 16:44:15 +1100 Subject: [PATCH 3/9] Fix threshold for Group block by passing in dropZoneElement --- packages/block-library/src/group/edit.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/block-library/src/group/edit.js b/packages/block-library/src/group/edit.js index 9c8690c4e0e8e..a763bc95e60d7 100644 --- a/packages/block-library/src/group/edit.js +++ b/packages/block-library/src/group/edit.js @@ -10,6 +10,7 @@ import { store as blockEditorStore, } from '@wordpress/block-editor'; import { SelectControl } from '@wordpress/components'; +import { useRef } from '@wordpress/element'; import { __ } from '@wordpress/i18n'; import { View } from '@wordpress/primitives'; @@ -97,7 +98,8 @@ function GroupEdit( { attributes, name, setAttributes, clientId } ) { themeSupportsLayout || type === 'flex' || type === 'grid'; // Hooks. - const blockProps = useBlockProps(); + const ref = useRef(); + const blockProps = useBlockProps( { ref } ); const [ showPlaceholder, setShowPlaceholder ] = useShouldShowPlaceHolder( { attributes, @@ -124,6 +126,7 @@ function GroupEdit( { attributes, name, setAttributes, clientId } ) { ? blockProps : { className: 'wp-block-group__inner-container' }, { + dropZoneElement: ref.current, templateLock, allowedBlocks, renderAppender, From b949ab0d7acc3a311e1125ffeb3773916350ddcb Mon Sep 17 00:00:00 2001 From: Andrew Serong <14988353+andrewserong@users.noreply.github.com> Date: Wed, 6 Dec 2023 16:31:16 +1100 Subject: [PATCH 4/9] Simplify by reusing operation option --- .../components/use-block-drop-zone/index.js | 34 ++++++------- .../src/components/use-on-block-drop/index.js | 51 ++++++++++--------- 2 files changed, 42 insertions(+), 43 deletions(-) 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 8db5107707841..169f17183315b 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 @@ -81,10 +81,10 @@ export function getDropTargetPosition( // TODO: Check if the parent block is horizontal / vertical orientation. if ( distance < THRESHOLD_DISTANCE ) { if ( edge === 'top' ) { - return [ rootBlockIndex, 'insert', 'before' ]; + return [ rootBlockIndex, 'before' ]; } if ( edge === 'bottom' ) { - return [ rootBlockIndex + 1, 'insert', 'after' ]; + return [ rootBlockIndex + 1, 'after' ]; } } } @@ -205,7 +205,6 @@ export default function useBlockDropZone( { useDispatch( blockEditorStore ); const onBlockDrop = useOnBlockDrop( targetRootClientId, dropTarget.index, { - moveBeforeOrAfter: dropTarget.moveBeforeOrAfter, operation: dropTarget.operation, } ); const throttled = useThrottle( @@ -241,32 +240,31 @@ export default function useBlockDropZone( { }; } ); - const [ targetIndex, operation, moveBeforeOrAfter ] = - getDropTargetPosition( - blocksData, - { x: event.clientX, y: event.clientY }, - getBlockListSettings( targetRootClientId )?.orientation, - { - dropZoneElement, - parentBlock, - rootBlockIndex, - } - ); + const [ targetIndex, operation ] = getDropTargetPosition( + blocksData, + { x: event.clientX, y: event.clientY }, + getBlockListSettings( targetRootClientId )?.orientation, + { + dropZoneElement, + parentBlock, + rootBlockIndex, + } + ); registry.batch( () => { setDropTarget( { - moveBeforeOrAfter, index: targetIndex, operation, } ); - const insertionPointClientId = moveBeforeOrAfter + const insertionPointClientId = [ + 'before', + 'after', + ].includes( operation ) ? parentBlock : targetRootClientId; - // TODO: Fix display of insertion point, so that it matches onBlockDrop logic. showInsertionPoint( insertionPointClientId, targetIndex, { - moveBeforeOrAfter, operation, } ); } ); 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 7688b7ad95434..37a4f042bce99 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 @@ -210,7 +210,7 @@ export default function useOnBlockDrop( targetBlockIndex, options = {} ) { - const { operation = 'insert', moveBeforeOrAfter } = options; + const { operation = 'insert' } = options; const hasUploadPermissions = useSelect( ( select ) => select( blockEditorStore ).getSettings().mediaUpload, [] @@ -280,43 +280,44 @@ export default function useOnBlockDrop( 0 ); } ); - } else { - if ( moveBeforeOrAfter ) { - const parentBlock = getBlockParents( - targetRootClientId, - true - )[ 0 ]; - // const targetBlockClientIds = getBlockOrder( parentBlock ); - let blockIndex = getBlockIndex( targetRootClientId ); - if ( moveBeforeOrAfter === 'after' ) { - ++blockIndex; - } - // const targetBlockClientId = - // targetBlockClientIds[ blockIndex ]; - moveBlocksToPosition( - sourceClientIds, - sourceRootClientId, - parentBlock, - blockIndex - ); - return; + } else if ( [ 'after', 'before' ].includes( operation ) ) { + const parentBlock = getBlockParents( + targetRootClientId, + true + )[ 0 ]; + // const targetBlockClientIds = getBlockOrder( parentBlock ); + let blockIndex = getBlockIndex( targetRootClientId ); + + if ( operation === 'after' ) { + ++blockIndex; } + // const targetBlockClientId = + // targetBlockClientIds[ blockIndex ]; moveBlocksToPosition( sourceClientIds, sourceRootClientId, - targetRootClientId, - insertIndex + parentBlock, + blockIndex ); + return; } + moveBlocksToPosition( + sourceClientIds, + sourceRootClientId, + targetRootClientId, + insertIndex + ); }, [ operation, + getBlockIndex, + getBlockParents, getBlockOrder, getBlocksByClientId, - insertBlocks, - moveBeforeOrAfter, moveBlocksToPosition, + registry, removeBlocks, + replaceBlocks, targetBlockIndex, targetRootClientId, ] From 9e0a9f06b9815ddeb94cb039ad2415920d480344 Mon Sep 17 00:00:00 2001 From: Andrew Serong <14988353+andrewserong@users.noreply.github.com> Date: Wed, 6 Dec 2023 16:50:43 +1100 Subject: [PATCH 5/9] Re-use logic that factors in the dragged blocks if we are ultimately dropping at the same level --- .../src/components/use-on-block-drop/index.js | 53 ++++++++----------- 1 file changed, 23 insertions(+), 30 deletions(-) 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 37a4f042bce99..e4e0c14f0b1b8 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 @@ -198,15 +198,15 @@ export function onHTMLDrop( /** * A React hook for handling block drop events. * - * @param {string} targetRootClientId The root client id where the block(s) will be inserted. - * @param {number} targetBlockIndex The index where the block(s) will be inserted. - * @param {Object} options The optional options. - * @param {WPDropOperation} [options.operation] The type of operation to perform on drop. Could be `insert` or `replace` for now. + * @param {string} originalTargetRootClientId The root client id where the block(s) will be inserted. + * @param {number} targetBlockIndex The index where the block(s) will be inserted. + * @param {Object} options The optional options. + * @param {WPDropOperation} [options.operation] The type of operation to perform on drop. Could be `insert` or `replace` for now. * * @return {Function} A function to be passed to the onDrop handler. */ export default function useOnBlockDrop( - targetRootClientId, + originalTargetRootClientId, targetBlockIndex, options = {} ) { @@ -220,7 +220,6 @@ export default function useOnBlockDrop( getBlockIndex, getClientIdsOfDescendants, getBlockOrder, - getBlockParents, getBlocksByClientId, } = useSelect( blockEditorStore ); const { @@ -233,6 +232,21 @@ export default function useOnBlockDrop( } = useDispatch( blockEditorStore ); const registry = useRegistry(); + const { targetRootClientId } = useSelect( + ( select ) => { + const firstParent = select( blockEditorStore ).getBlockParents( + originalTargetRootClientId, + true + )[ 0 ]; + return { + targetRootClientId: [ 'before', 'after' ].includes( operation ) + ? firstParent + : originalTargetRootClientId, + }; + }, + [ originalTargetRootClientId, operation ] + ); + const insertOrReplaceBlocks = useCallback( ( blocks, updateSelection = true, initialPosition = 0 ) => { if ( operation === 'replace' ) { @@ -280,38 +294,17 @@ export default function useOnBlockDrop( 0 ); } ); - } else if ( [ 'after', 'before' ].includes( operation ) ) { - const parentBlock = getBlockParents( - targetRootClientId, - true - )[ 0 ]; - // const targetBlockClientIds = getBlockOrder( parentBlock ); - let blockIndex = getBlockIndex( targetRootClientId ); - - if ( operation === 'after' ) { - ++blockIndex; - } - // const targetBlockClientId = - // targetBlockClientIds[ blockIndex ]; + } else { moveBlocksToPosition( sourceClientIds, sourceRootClientId, - parentBlock, - blockIndex + targetRootClientId, + insertIndex ); - return; } - moveBlocksToPosition( - sourceClientIds, - sourceRootClientId, - targetRootClientId, - insertIndex - ); }, [ operation, - getBlockIndex, - getBlockParents, getBlockOrder, getBlocksByClientId, moveBlocksToPosition, From f9aadc93b999ed2aed2b2e5eab4edf31f932da6c Mon Sep 17 00:00:00 2001 From: Andrew Serong <14988353+andrewserong@users.noreply.github.com> Date: Thu, 7 Dec 2023 14:26:51 +1100 Subject: [PATCH 6/9] Simplify a little further --- .../components/use-block-drop-zone/index.js | 12 ++++++--- .../src/components/use-on-block-drop/index.js | 25 ++++--------------- 2 files changed, 14 insertions(+), 23 deletions(-) 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 169f17183315b..47c722d2a8322 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 @@ -204,9 +204,15 @@ export default function useBlockDropZone( { const { showInsertionPoint, hideInsertionPoint } = useDispatch( blockEditorStore ); - const onBlockDrop = useOnBlockDrop( targetRootClientId, dropTarget.index, { - operation: dropTarget.operation, - } ); + const onBlockDrop = useOnBlockDrop( + dropTarget.operation === 'before' || dropTarget.operation === 'after' + ? parentBlock + : targetRootClientId, + dropTarget.index, + { + operation: dropTarget.operation, + } + ); const throttled = useThrottle( useCallback( ( event, ownerDocument ) => { 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 e4e0c14f0b1b8..ab0da8ad99e2a 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 @@ -198,15 +198,15 @@ export function onHTMLDrop( /** * A React hook for handling block drop events. * - * @param {string} originalTargetRootClientId The root client id where the block(s) will be inserted. - * @param {number} targetBlockIndex The index where the block(s) will be inserted. - * @param {Object} options The optional options. - * @param {WPDropOperation} [options.operation] The type of operation to perform on drop. Could be `insert` or `replace` for now. + * @param {string} targetRootClientId The root client id where the block(s) will be inserted. + * @param {number} targetBlockIndex The index where the block(s) will be inserted. + * @param {Object} options The optional options. + * @param {WPDropOperation} [options.operation] The type of operation to perform on drop. Could be `insert` or `replace` for now. * * @return {Function} A function to be passed to the onDrop handler. */ export default function useOnBlockDrop( - originalTargetRootClientId, + targetRootClientId, targetBlockIndex, options = {} ) { @@ -232,21 +232,6 @@ export default function useOnBlockDrop( } = useDispatch( blockEditorStore ); const registry = useRegistry(); - const { targetRootClientId } = useSelect( - ( select ) => { - const firstParent = select( blockEditorStore ).getBlockParents( - originalTargetRootClientId, - true - )[ 0 ]; - return { - targetRootClientId: [ 'before', 'after' ].includes( operation ) - ? firstParent - : originalTargetRootClientId, - }; - }, - [ originalTargetRootClientId, operation ] - ); - const insertOrReplaceBlocks = useCallback( ( blocks, updateSelection = true, initialPosition = 0 ) => { if ( operation === 'replace' ) { From bf4ba5e4601da1296d8ffd98c7439e70949dba7b Mon Sep 17 00:00:00 2001 From: Andrew Serong <14988353+andrewserong@users.noreply.github.com> Date: Thu, 7 Dec 2023 14:55:36 +1100 Subject: [PATCH 7/9] Factor in orientation --- .../components/use-block-drop-zone/index.js | 29 +++++++++++++------ 1 file changed, 20 insertions(+), 9 deletions(-) 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 47c722d2a8322..646020d71ad7c 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 @@ -68,9 +68,13 @@ export function getDropTargetPosition( let insertPosition = 'before'; let minDistance = Infinity; - const { dropZoneElement, parentBlock, rootBlockIndex = 0 } = options; + const { + dropZoneElement, + parentBlockOrientation, + rootBlockIndex = 0, + } = options; - if ( dropZoneElement && parentBlock ) { + if ( dropZoneElement && parentBlockOrientation !== 'horizontal' ) { const rect = dropZoneElement.getBoundingClientRect(); const [ distance, edge ] = getDistanceToNearestEdge( position, rect, [ @@ -78,7 +82,9 @@ export function getDropTargetPosition( 'bottom', ] ); - // TODO: Check if the parent block is horizontal / vertical orientation. + // If dragging over the top or bottom of the drop zone, insert the block + // before or after the parent block. This only applies to blocks that use + // a drop zone element, typically container blocks such as Group or Cover. if ( distance < THRESHOLD_DISTANCE ) { if ( edge === 'top' ) { return [ rootBlockIndex, 'before' ]; @@ -175,7 +181,7 @@ export default function useBlockDropZone( { operation: 'insert', } ); - const { isDisabled, parentBlock, rootBlockIndex } = useSelect( + const { isDisabled, parentBlockClientId, rootBlockIndex } = useSelect( ( select ) => { const { __unstableIsWithinBlockOverlay, @@ -186,7 +192,8 @@ export default function useBlockDropZone( { } = select( blockEditorStore ); const blockEditingMode = getBlockEditingMode( targetRootClientId ); return { - parentBlock: getBlockParents( targetRootClientId, true )[ 0 ], + parentBlockClientId: + getBlockParents( targetRootClientId, true )[ 0 ] || '', rootBlockIndex: getBlockIndex( targetRootClientId ), isDisabled: blockEditingMode !== 'default' || @@ -206,7 +213,7 @@ export default function useBlockDropZone( { const onBlockDrop = useOnBlockDrop( dropTarget.operation === 'before' || dropTarget.operation === 'after' - ? parentBlock + ? parentBlockClientId : targetRootClientId, dropTarget.index, { @@ -252,7 +259,11 @@ export default function useBlockDropZone( { getBlockListSettings( targetRootClientId )?.orientation, { dropZoneElement, - parentBlock, + parentBlockClientId, + parentBlockOrientation: parentBlockClientId + ? getBlockListSettings( parentBlockClientId ) + ?.orientation + : undefined, rootBlockIndex, } ); @@ -267,7 +278,7 @@ export default function useBlockDropZone( { 'before', 'after', ].includes( operation ) - ? parentBlock + ? parentBlockClientId : targetRootClientId; showInsertionPoint( insertionPointClientId, targetIndex, { @@ -283,7 +294,7 @@ export default function useBlockDropZone( { registry, showInsertionPoint, getBlockIndex, - parentBlock, + parentBlockClientId, rootBlockIndex, ] ), From 3617b4932a84a8b46565de16738cc98b8174a74f Mon Sep 17 00:00:00 2001 From: Andrew Serong <14988353+andrewserong@users.noreply.github.com> Date: Thu, 7 Dec 2023 16:23:11 +1100 Subject: [PATCH 8/9] Add minimum height for threshold so that short blocks are still usable --- .../src/components/use-block-drop-zone/index.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) 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 646020d71ad7c..11f3fc3ad0ff9 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 @@ -21,6 +21,7 @@ import { import { store as blockEditorStore } from '../../store'; const THRESHOLD_DISTANCE = 30; +const MINIMUM_HEIGHT_FOR_THRESHOLD = 120; /** @typedef {import('../../utils/math').WPPoint} WPPoint */ /** @typedef {import('../use-on-block-drop/types').WPDropOperation} WPDropOperation */ @@ -85,7 +86,10 @@ export function getDropTargetPosition( // If dragging over the top or bottom of the drop zone, insert the block // before or after the parent block. This only applies to blocks that use // a drop zone element, typically container blocks such as Group or Cover. - if ( distance < THRESHOLD_DISTANCE ) { + if ( + rect.height > MINIMUM_HEIGHT_FOR_THRESHOLD && + distance < THRESHOLD_DISTANCE + ) { if ( edge === 'top' ) { return [ rootBlockIndex, 'before' ]; } From b1e0fadbe31e0cce4b2749f6505b2419c0ca89f5 Mon Sep 17 00:00:00 2001 From: Andrew Serong <14988353+andrewserong@users.noreply.github.com> Date: Tue, 12 Dec 2023 16:12:00 +1100 Subject: [PATCH 9/9] Allow threshold when parent block is horizontal, i.e. a Row block --- .../components/use-block-drop-zone/index.js | 33 ++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) 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 11f3fc3ad0ff9..cb3c3ae6a28a3 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 @@ -22,6 +22,7 @@ import { store as blockEditorStore } from '../../store'; const THRESHOLD_DISTANCE = 30; const MINIMUM_HEIGHT_FOR_THRESHOLD = 120; +const MINIMUM_WIDTH_FOR_THRESHOLD = 120; /** @typedef {import('../../utils/math').WPPoint} WPPoint */ /** @typedef {import('../use-on-block-drop/types').WPDropOperation} WPDropOperation */ @@ -75,9 +76,9 @@ export function getDropTargetPosition( rootBlockIndex = 0, } = options; + // Allow before/after when dragging over the top/bottom edges of the drop zone. if ( dropZoneElement && parentBlockOrientation !== 'horizontal' ) { const rect = dropZoneElement.getBoundingClientRect(); - const [ distance, edge ] = getDistanceToNearestEdge( position, rect, [ 'top', 'bottom', @@ -101,6 +102,36 @@ export function getDropTargetPosition( const isRightToLeft = isRTL(); + // Allow before/after when dragging over the left/right edges of the drop zone. + if ( dropZoneElement && parentBlockOrientation === 'horizontal' ) { + const rect = dropZoneElement.getBoundingClientRect(); + const [ distance, edge ] = getDistanceToNearestEdge( position, rect, [ + 'left', + 'right', + ] ); + + // If dragging over the left or right of the drop zone, insert the block + // before or after the parent block. This only applies to blocks that use + // a drop zone element, typically container blocks such as Group. + if ( + rect.width > MINIMUM_WIDTH_FOR_THRESHOLD && + distance < THRESHOLD_DISTANCE + ) { + if ( + ( isRightToLeft && edge === 'right' ) || + ( ! isRightToLeft && edge === 'left' ) + ) { + return [ rootBlockIndex, 'before' ]; + } + if ( + ( isRightToLeft && edge === 'left' ) || + ( ! isRightToLeft && edge === 'right' ) + ) { + return [ rootBlockIndex + 1, 'after' ]; + } + } + } + blocksData.forEach( ( { isUnmodifiedDefaultBlock, getBoundingClientRect, blockIndex } ) => { const rect = getBoundingClientRect();