From 3b632b703f003d35653cc71279b760a2f83636b0 Mon Sep 17 00:00:00 2001 From: Andrew Serong <14988353+andrewserong@users.noreply.github.com> Date: Fri, 31 Mar 2023 16:44:22 +1100 Subject: [PATCH 1/2] List View: Try allowing users to drag to one level up the hierarchy --- .../list-view/use-list-view-drop-zone.js | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/packages/block-editor/src/components/list-view/use-list-view-drop-zone.js b/packages/block-editor/src/components/list-view/use-list-view-drop-zone.js index e49a224e44efbe..1c1641b232b9c3 100644 --- a/packages/block-editor/src/components/list-view/use-list-view-drop-zone.js +++ b/packages/block-editor/src/components/list-view/use-list-view-drop-zone.js @@ -67,6 +67,21 @@ function isNestingGesture( point, rect ) { return point.x > blockCenterX; } +/** + * Determines whether the user is positioning the dragged block so as to move + * up one level in the block hierarchy. + * + * Presently this is determined by whether the cursor is within the left 1/4 side + * of the block. + * + * @param {WPPoint} point The point representing the cursor position when dragging. + * @param {DOMRect} rect The rectangle. + */ +function isUpGesture( point, rect ) { + const blockQuarterX = rect.left + rect.width / 4; + return point.x < blockQuarterX; +} + // Block navigation is always a vertical list, so only allow dropping // to the above or below a block. const ALLOWED_DROP_EDGES = [ 'top', 'bottom' ]; @@ -145,6 +160,24 @@ export function getListViewDropTarget( blocksData, position ) { const isDraggingBelow = candidateEdge === 'bottom'; + // If the user is dragging towards the bottom of the block check whether + // they might be trying to move the block up one level. + // For this to be true, the block must be the last child of its parent, + // and the block must be able to be inserted as a sibling of the block's parent. + if ( + isDraggingBelow && + candidateBlockData.isLastChildOfRoot && + candidateBlockData.canInsertDraggedBlocksIntoParent && + isUpGesture( position, candidateRect ) + ) { + return { + rootClientId: candidateBlockData.parentOfRootClientId, + clientId: candidateBlockData.clientId, // This is used as the target for the drop indicator. + blockIndex: candidateBlockData.parentBlockIndex + 1, + dropPosition: candidateEdge, + }; + } + // If the user is dragging towards the bottom of the block check whether // they might be trying to nest the block as a child. // If the block already has inner blocks, and is expanded, this should be treated @@ -190,6 +223,7 @@ export default function useListViewDropZone() { getBlockRootClientId, getBlockIndex, getBlockCount, + getBlocks, getDraggedBlockClientIds, canInsertBlocks, } = useSelect( blockEditorStore ); @@ -214,12 +248,23 @@ export default function useListViewDropZone() { const clientId = blockElement.dataset.block; const isExpanded = blockElement.dataset.expanded === 'true'; const rootClientId = getBlockRootClientId( clientId ); + const parentOfRootClientId = + getBlockRootClientId( rootClientId ); + const childrenOfRootClientId = getBlocks( rootClientId ); + const isLastChildOfRoot = + childrenOfRootClientId.length > 0 && + childrenOfRootClientId[ + childrenOfRootClientId.length - 1 + ]?.clientId === clientId; return { clientId, isExpanded, + isLastChildOfRoot, + parentOfRootClientId, rootClientId, blockIndex: getBlockIndex( clientId ), + parentBlockIndex: getBlockIndex( rootClientId ), element: blockElement, isDraggedBlock: isBlockDrag ? draggedBlockClientIds.includes( clientId ) @@ -231,6 +276,13 @@ export default function useListViewDropZone() { rootClientId ) : true, + canInsertDraggedBlocksIntoParent: + isBlockDrag && parentOfRootClientId + ? canInsertBlocks( + draggedBlockClientIds, + parentOfRootClientId + ) + : false, canInsertDraggedBlocksAsChild: isBlockDrag ? canInsertBlocks( draggedBlockClientIds, clientId ) : true, From aa4123bd701ab99219af71ceb4492b46143ed37d Mon Sep 17 00:00:00 2001 From: Andrew Serong <14988353+andrewserong@users.noreply.github.com> Date: Tue, 4 Apr 2023 16:38:50 +1000 Subject: [PATCH 2/2] Try allowing drag to the first level --- .../components/list-view/use-list-view-drop-zone.js | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/packages/block-editor/src/components/list-view/use-list-view-drop-zone.js b/packages/block-editor/src/components/list-view/use-list-view-drop-zone.js index 1c1641b232b9c3..1ac253bf7b3921 100644 --- a/packages/block-editor/src/components/list-view/use-list-view-drop-zone.js +++ b/packages/block-editor/src/components/list-view/use-list-view-drop-zone.js @@ -168,10 +168,13 @@ export function getListViewDropTarget( blocksData, position ) { isDraggingBelow && candidateBlockData.isLastChildOfRoot && candidateBlockData.canInsertDraggedBlocksIntoParent && + candidateBlockData.rootClientId && isUpGesture( position, candidateRect ) ) { return { - rootClientId: candidateBlockData.parentOfRootClientId, + rootClientId: + candidateBlockData.parentOfRootClientId ?? + candidateBlockData.rootClientId, clientId: candidateBlockData.clientId, // This is used as the target for the drop indicator. blockIndex: candidateBlockData.parentBlockIndex + 1, dropPosition: candidateEdge, @@ -256,6 +259,7 @@ export default function useListViewDropZone() { childrenOfRootClientId[ childrenOfRootClientId.length - 1 ]?.clientId === clientId; + const blockIndex = getBlockIndex( clientId ); return { clientId, @@ -263,8 +267,9 @@ export default function useListViewDropZone() { isLastChildOfRoot, parentOfRootClientId, rootClientId, - blockIndex: getBlockIndex( clientId ), - parentBlockIndex: getBlockIndex( rootClientId ), + blockIndex, + parentBlockIndex: + getBlockIndex( rootClientId ) || blockIndex, element: blockElement, isDraggedBlock: isBlockDrag ? draggedBlockClientIds.includes( clientId ) @@ -282,7 +287,7 @@ export default function useListViewDropZone() { draggedBlockClientIds, parentOfRootClientId ) - : false, + : true, canInsertDraggedBlocksAsChild: isBlockDrag ? canInsertBlocks( draggedBlockClientIds, clientId ) : true,