From 1b45d6811b6aed70cd4a2776fb81bc21d6547b99 Mon Sep 17 00:00:00 2001 From: Andrew Serong <14988353+andrewserong@users.noreply.github.com> Date: Fri, 2 Feb 2024 15:00:22 +1100 Subject: [PATCH 1/4] Drag and drop: Allow dragging from inserter or desktop to template parts --- .../src/components/block-list/block.js | 4 ++-- .../src/components/inner-blocks/index.js | 4 ++-- .../inserter-draggable-blocks/index.js | 13 ++++++++++- .../components/use-block-drop-zone/index.js | 18 ++++++++++++--- .../block-editor/src/store/private-actions.js | 22 +++++++++++++++++++ .../src/store/private-selectors.js | 11 ++++++++++ packages/block-editor/src/store/reducer.js | 22 +++++++++++++++++++ 7 files changed, 86 insertions(+), 8 deletions(-) diff --git a/packages/block-editor/src/components/block-list/block.js b/packages/block-editor/src/components/block-list/block.js index fa814630b00bb8..69fe3161126185 100644 --- a/packages/block-editor/src/components/block-list/block.js +++ b/packages/block-editor/src/components/block-list/block.js @@ -524,7 +524,7 @@ function BlockListBlockProvider( props ) { __unstableIsFullySelected, __unstableSelectionHasUnmergeableBlock, isBlockBeingDragged, - isDraggingBlocks, + isDragging, hasBlockMovingClientId, canInsertBlockType, __unstableHasActiveBlockOverlayActive, @@ -602,7 +602,7 @@ function BlockListBlockProvider( props ) { isOutlineEnabled: outlineMode, hasOverlay: __unstableHasActiveBlockOverlayActive( clientId ) && - ! isDraggingBlocks(), + ! isDragging(), initialPosition: _isSelected && __unstableGetEditorMode() === 'edit' ? getSelectedBlocksInitialCaretPosition() diff --git a/packages/block-editor/src/components/inner-blocks/index.js b/packages/block-editor/src/components/inner-blocks/index.js index 5233c063ba2094..579e1a152a12be 100644 --- a/packages/block-editor/src/components/inner-blocks/index.js +++ b/packages/block-editor/src/components/inner-blocks/index.js @@ -199,7 +199,7 @@ export function useInnerBlocksProps( props = {}, options = {} ) { getBlockRootClientId, getBlockEditingMode, getBlockSettings, - isDraggingBlocks, + isDragging, } = unlock( select( blockEditorStore ) ); const { hasBlockSupport, getBlockType } = select( blocksStore ); const blockName = getBlockName( clientId ); @@ -219,7 +219,7 @@ export function useInnerBlocksProps( props = {}, options = {} ) { ! isBlockSelected( clientId ) && ! hasSelectedInnerBlock( clientId, true ) && enableClickThrough && - ! isDraggingBlocks(), + ! isDragging(), name: blockName, blockType: getBlockType( blockName ), parentLock: getTemplateLock( parentClientId ), diff --git a/packages/block-editor/src/components/inserter-draggable-blocks/index.js b/packages/block-editor/src/components/inserter-draggable-blocks/index.js index cdaadcb0f36eb5..7d20b5e53650bf 100644 --- a/packages/block-editor/src/components/inserter-draggable-blocks/index.js +++ b/packages/block-editor/src/components/inserter-draggable-blocks/index.js @@ -7,12 +7,15 @@ import { serialize, store as blocksStore, } from '@wordpress/blocks'; -import { useSelect } from '@wordpress/data'; +import { useDispatch, useSelect } from '@wordpress/data'; + /** * Internal dependencies */ import BlockDraggableChip from '../block-draggable/draggable-chip'; import { INSERTER_PATTERN_TYPES } from '../inserter/block-patterns-tab/utils'; +import { store as blockEditorStore } from '../../store'; +import { unlock } from '../../lock-unlock'; const InserterDraggableBlocks = ( { isEnabled, @@ -36,11 +39,16 @@ const InserterDraggableBlocks = ( { [ blocks ] ); + const { startDragging, stopDragging } = unlock( + useDispatch( blockEditorStore ) + ); + return ( { + startDragging(); const parsedBlocks = pattern?.type === INSERTER_PATTERN_TYPES.user && pattern?.syncStatus !== 'unsynced' @@ -51,6 +59,9 @@ const InserterDraggableBlocks = ( { serialize( parsedBlocks ) ); } } + onDragEnd={ () => { + stopDragging(); + } } __experimentalDragComponent={ { + if ( ! isDragging() ) { + startDragging(); + } const allowedBlocks = getAllowedBlocks( targetRootClientId ); const targetBlockName = getBlockNamesByClientId( [ targetRootClientId, @@ -423,6 +432,8 @@ export default function useBlockDropZone( { getBlockIndex, registry, showInsertionPoint, + isDragging, + startDragging, ] ), 200 @@ -444,6 +455,7 @@ export default function useBlockDropZone( { }, onDragEnd() { throttled.cancel(); + stopDragging(); hideInsertionPoint(); }, } ); diff --git a/packages/block-editor/src/store/private-actions.js b/packages/block-editor/src/store/private-actions.js index aea3613884bb69..1d0d41197bc1ee 100644 --- a/packages/block-editor/src/store/private-actions.js +++ b/packages/block-editor/src/store/private-actions.js @@ -370,3 +370,25 @@ export function registerBlockBindingsSource( source ) { lockAttributesEditing: source.lockAttributesEditing, }; } + +/** + * Returns an action object used in signalling that the user has begun to drag. + * + * @return {Object} Action object. + */ +export function startDragging() { + return { + type: 'START_DRAGGING', + }; +} + +/** + * Returns an action object used in signalling that the user has stopped dragging. + * + * @return {Object} Action object. + */ +export function stopDragging() { + return { + type: 'STOP_DRAGGING', + }; +} diff --git a/packages/block-editor/src/store/private-selectors.js b/packages/block-editor/src/store/private-selectors.js index 429e55d99001c2..f373c85dab67db 100644 --- a/packages/block-editor/src/store/private-selectors.js +++ b/packages/block-editor/src/store/private-selectors.js @@ -344,3 +344,14 @@ export function getAllBlockBindingsSources( state ) { export function getBlockBindingsSource( state, sourceName ) { return state.blockBindingsSources[ sourceName ]; } + +/** + * Returns true if the user is dragging, or false otherwise. + * + * @param {Object} state Global application state. + * + * @return {boolean} Whether user is dragging. + */ +export function isDragging( state ) { + return !! state.isDragging; +} diff --git a/packages/block-editor/src/store/reducer.js b/packages/block-editor/src/store/reducer.js index dc69a4da609a4d..c465e390213036 100644 --- a/packages/block-editor/src/store/reducer.js +++ b/packages/block-editor/src/store/reducer.js @@ -1246,6 +1246,27 @@ export function isTyping( state = false, action ) { return state; } +/** + * Reducer returning dragging state. It is possible for a user to be dragging + * data from outside of the editor, so this state is separate from `draggedBlocks`. + * + * @param {boolean} state Current state. + * @param {Object} action Dispatched action. + * + * @return {boolean} Updated state. + */ +export function isDragging( state = false, action ) { + switch ( action.type ) { + case 'START_DRAGGING': + return true; + + case 'STOP_DRAGGING': + return false; + } + + return state; +} + /** * Reducer returning dragged block client id. * @@ -2048,6 +2069,7 @@ function blockPatterns( state = [], action ) { const combinedReducers = combineReducers( { blocks, + isDragging, isTyping, isBlockInterfaceHidden, draggedBlocks, From 8fd632b208c44234aa14ab1d526e1380a63b5c8b Mon Sep 17 00:00:00 2001 From: Andrew Serong <14988353+andrewserong@users.noreply.github.com> Date: Fri, 2 Feb 2024 15:18:32 +1100 Subject: [PATCH 2/4] Add comment --- .../block-editor/src/components/use-block-drop-zone/index.js | 2 ++ 1 file changed, 2 insertions(+) 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 ff5fd7ce03ed47..857a132f1f9fa4 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 @@ -332,6 +332,8 @@ export default function useBlockDropZone( { useCallback( ( event, ownerDocument ) => { if ( ! isDragging() ) { + // When dragging from the desktop, no drag start event is fired. + // So, ensure that the drag state is set when the user drags over a drop zone. startDragging(); } const allowedBlocks = getAllowedBlocks( targetRootClientId ); From d8a3894c8c063485a951f6b576c8d2da1135f170 Mon Sep 17 00:00:00 2001 From: Andrew Serong <14988353+andrewserong@users.noreply.github.com> Date: Mon, 5 Feb 2024 10:50:41 +1100 Subject: [PATCH 3/4] Simplify return statement because we know it'll always be a boolean Co-authored-by: Robert Anderson --- packages/block-editor/src/store/private-selectors.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/block-editor/src/store/private-selectors.js b/packages/block-editor/src/store/private-selectors.js index f373c85dab67db..c7cf390bb68b93 100644 --- a/packages/block-editor/src/store/private-selectors.js +++ b/packages/block-editor/src/store/private-selectors.js @@ -353,5 +353,5 @@ export function getBlockBindingsSource( state, sourceName ) { * @return {boolean} Whether user is dragging. */ export function isDragging( state ) { - return !! state.isDragging; + return state.isDragging; } From a77cb225d836ac4b608aefc50b9cbcf3bda703ca Mon Sep 17 00:00:00 2001 From: Andrew Serong <14988353+andrewserong@users.noreply.github.com> Date: Mon, 5 Feb 2024 11:11:40 +1100 Subject: [PATCH 4/4] Add tests, clarify selector --- .../src/store/private-selectors.js | 4 +++- .../src/store/test/private-actions.js | 18 ++++++++++++++++++ .../src/store/test/private-selectors.js | 19 +++++++++++++++++++ .../block-editor/src/store/test/reducer.js | 19 +++++++++++++++++++ 4 files changed, 59 insertions(+), 1 deletion(-) diff --git a/packages/block-editor/src/store/private-selectors.js b/packages/block-editor/src/store/private-selectors.js index c7cf390bb68b93..ea360daf63f9bd 100644 --- a/packages/block-editor/src/store/private-selectors.js +++ b/packages/block-editor/src/store/private-selectors.js @@ -346,7 +346,9 @@ export function getBlockBindingsSource( state, sourceName ) { } /** - * Returns true if the user is dragging, or false otherwise. + * Returns true if the user is dragging anything, or false otherwise. It is possible for a + * user to be dragging data from outside of the editor, so this selector is separate from + * the `isDraggingBlocks` selector which only returns true if the user is dragging blocks. * * @param {Object} state Global application state. * diff --git a/packages/block-editor/src/store/test/private-actions.js b/packages/block-editor/src/store/test/private-actions.js index 5763cb382937b2..08370f731902d2 100644 --- a/packages/block-editor/src/store/test/private-actions.js +++ b/packages/block-editor/src/store/test/private-actions.js @@ -6,6 +6,8 @@ import { showBlockInterface, __experimentalUpdateSettings, setOpenedBlockSettingsMenu, + startDragging, + stopDragging, } from '../private-actions'; describe( 'private actions', () => { @@ -95,4 +97,20 @@ describe( 'private actions', () => { } ); } ); } ); + + describe( 'startDragging', () => { + it( 'should return the START_DRAGGING action', () => { + expect( startDragging() ).toEqual( { + type: 'START_DRAGGING', + } ); + } ); + } ); + + describe( 'stopDragging', () => { + it( 'should return the STOP_DRAGGING action', () => { + expect( stopDragging() ).toEqual( { + type: 'STOP_DRAGGING', + } ); + } ); + } ); } ); diff --git a/packages/block-editor/src/store/test/private-selectors.js b/packages/block-editor/src/store/test/private-selectors.js index 746a51b6031101..f661271b570b4b 100644 --- a/packages/block-editor/src/store/test/private-selectors.js +++ b/packages/block-editor/src/store/test/private-selectors.js @@ -7,6 +7,7 @@ import { isBlockSubtreeDisabled, getEnabledClientIdsTree, getEnabledBlockParents, + isDragging, } from '../private-selectors'; import { getBlockEditingMode } from '../selectors'; @@ -477,4 +478,22 @@ describe( 'private selectors', () => { ] ); } ); } ); + + describe( 'isDragging', () => { + it( 'should return true if the dragging state is true', () => { + const state = { + isDragging: true, + }; + + expect( isDragging( state ) ).toBe( true ); + } ); + + it( 'should return false if the dragging state is false', () => { + const state = { + isDragging: false, + }; + + expect( isDragging( state ) ).toBe( false ); + } ); + } ); } ); diff --git a/packages/block-editor/src/store/test/reducer.js b/packages/block-editor/src/store/test/reducer.js index 8c82d1c3092b16..c99d914ba21755 100644 --- a/packages/block-editor/src/store/test/reducer.js +++ b/packages/block-editor/src/store/test/reducer.js @@ -21,6 +21,7 @@ import { blocks, isBlockInterfaceHidden, isTyping, + isDragging, draggedBlocks, selection, initialPosition, @@ -2445,6 +2446,24 @@ describe( 'state', () => { } ); } ); + describe( 'isDragging', () => { + it( 'should set the dragging flag to true', () => { + const state = isDragging( false, { + type: 'START_DRAGGING', + } ); + + expect( state ).toBe( true ); + } ); + + it( 'should set the dragging flag to false', () => { + const state = isDragging( true, { + type: 'STOP_DRAGGING', + } ); + + expect( state ).toBe( false ); + } ); + } ); + describe( 'draggedBlocks', () => { it( 'should store the dragged client ids when a user starts dragging blocks', () => { const clientIds = [ 'block-1', 'block-2', 'block-3' ];