Skip to content

Commit

Permalink
Drag and drop: Allow dragging from inserter or desktop to template pa…
Browse files Browse the repository at this point in the history
…rts (#58589)

* Drag and drop: Allow dragging from inserter or desktop to template parts

* Add comment

* Simplify return statement because we know it'll always be a boolean

Co-authored-by: Robert Anderson <robert@noisysocks.com>

* Add tests, clarify selector

---------

Co-authored-by: Robert Anderson <robert@noisysocks.com>
Co-authored-by: andrewserong <andrewserong@git.wordpress.org>
Co-authored-by: noisysocks <noisysocks@git.wordpress.org>
Co-authored-by: tellthemachines <isabel_brison@git.wordpress.org>
Co-authored-by: talldan <talldanwp@git.wordpress.org>
Co-authored-by: annezazu <annezazu@git.wordpress.org>
  • Loading branch information
7 people authored Feb 5, 2024
1 parent 8d14357 commit 4de62d7
Show file tree
Hide file tree
Showing 10 changed files with 146 additions and 8 deletions.
4 changes: 2 additions & 2 deletions packages/block-editor/src/components/block-list/block.js
Original file line number Diff line number Diff line change
Expand Up @@ -524,7 +524,7 @@ function BlockListBlockProvider( props ) {
__unstableIsFullySelected,
__unstableSelectionHasUnmergeableBlock,
isBlockBeingDragged,
isDraggingBlocks,
isDragging,
hasBlockMovingClientId,
canInsertBlockType,
__unstableHasActiveBlockOverlayActive,
Expand Down Expand Up @@ -602,7 +602,7 @@ function BlockListBlockProvider( props ) {
isOutlineEnabled: outlineMode,
hasOverlay:
__unstableHasActiveBlockOverlayActive( clientId ) &&
! isDraggingBlocks(),
! isDragging(),
initialPosition:
_isSelected && __unstableGetEditorMode() === 'edit'
? getSelectedBlocksInitialCaretPosition()
Expand Down
4 changes: 2 additions & 2 deletions packages/block-editor/src/components/inner-blocks/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ export function useInnerBlocksProps( props = {}, options = {} ) {
getBlockRootClientId,
getBlockEditingMode,
getBlockSettings,
isDraggingBlocks,
isDragging,
} = unlock( select( blockEditorStore ) );
const { hasBlockSupport, getBlockType } = select( blocksStore );
const blockName = getBlockName( clientId );
Expand All @@ -223,7 +223,7 @@ export function useInnerBlocksProps( props = {}, options = {} ) {
! isBlockSelected( clientId ) &&
! hasSelectedInnerBlock( clientId, true ) &&
enableClickThrough &&
! isDraggingBlocks(),
! isDragging(),
name: blockName,
blockType: getBlockType( blockName ),
parentLock: getTemplateLock( parentClientId ),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -36,11 +39,16 @@ const InserterDraggableBlocks = ( {
[ blocks ]
);

const { startDragging, stopDragging } = unlock(
useDispatch( blockEditorStore )
);

return (
<Draggable
__experimentalTransferDataType="wp-blocks"
transferData={ transferData }
onDragStart={ ( event ) => {
startDragging();
const parsedBlocks =
pattern?.type === INSERTER_PATTERN_TYPES.user &&
pattern?.syncStatus !== 'unsynced'
Expand All @@ -51,6 +59,9 @@ const InserterDraggableBlocks = ( {
serialize( parsedBlocks )
);
} }
onDragEnd={ () => {
stopDragging();
} }
__experimentalDragComponent={
<BlockDraggableChip
count={ blocks.length }
Expand Down
20 changes: 17 additions & 3 deletions packages/block-editor/src/components/use-block-drop-zone/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
isPointWithinTopAndBottomBoundariesOfRect,
} from '../../utils/math';
import { store as blockEditorStore } from '../../store';
import { unlock } from '../../lock-unlock';

const THRESHOLD_DISTANCE = 30;
const MINIMUM_HEIGHT_FOR_THRESHOLD = 120;
Expand Down Expand Up @@ -308,9 +309,14 @@ export default function useBlockDropZone( {
getDraggedBlockClientIds,
getBlockNamesByClientId,
getAllowedBlocks,
} = useSelect( blockEditorStore );
const { showInsertionPoint, hideInsertionPoint } =
useDispatch( blockEditorStore );
isDragging,
} = unlock( useSelect( blockEditorStore ) );
const {
showInsertionPoint,
hideInsertionPoint,
startDragging,
stopDragging,
} = unlock( useDispatch( blockEditorStore ) );

const onBlockDrop = useOnBlockDrop(
dropTarget.operation === 'before' || dropTarget.operation === 'after'
Expand All @@ -325,6 +331,11 @@ export default function useBlockDropZone( {
const throttled = useThrottle(
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 );
const targetBlockName = getBlockNamesByClientId( [
targetRootClientId,
Expand Down Expand Up @@ -423,6 +434,8 @@ export default function useBlockDropZone( {
getBlockIndex,
registry,
showInsertionPoint,
isDragging,
startDragging,
]
),
200
Expand All @@ -444,6 +457,7 @@ export default function useBlockDropZone( {
},
onDragEnd() {
throttled.cancel();
stopDragging();
hideInsertionPoint();
},
} );
Expand Down
22 changes: 22 additions & 0 deletions packages/block-editor/src/store/private-actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -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',
};
}
13 changes: 13 additions & 0 deletions packages/block-editor/src/store/private-selectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -351,3 +351,16 @@ export function getAllBlockBindingsSources( state ) {
export function getBlockBindingsSource( state, sourceName ) {
return state.blockBindingsSources[ sourceName ];
}

/**
* 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.
*
* @return {boolean} Whether user is dragging.
*/
export function isDragging( state ) {
return state.isDragging;
}
22 changes: 22 additions & 0 deletions packages/block-editor/src/store/reducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*
Expand Down Expand Up @@ -2048,6 +2069,7 @@ function blockPatterns( state = [], action ) {

const combinedReducers = combineReducers( {
blocks,
isDragging,
isTyping,
isBlockInterfaceHidden,
draggedBlocks,
Expand Down
18 changes: 18 additions & 0 deletions packages/block-editor/src/store/test/private-actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import {
showBlockInterface,
__experimentalUpdateSettings,
setOpenedBlockSettingsMenu,
startDragging,
stopDragging,
} from '../private-actions';

describe( 'private actions', () => {
Expand Down Expand Up @@ -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',
} );
} );
} );
} );
19 changes: 19 additions & 0 deletions packages/block-editor/src/store/test/private-selectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
isBlockSubtreeDisabled,
getEnabledClientIdsTree,
getEnabledBlockParents,
isDragging,
} from '../private-selectors';
import { getBlockEditingMode } from '../selectors';

Expand Down Expand Up @@ -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 );
} );
} );
} );
19 changes: 19 additions & 0 deletions packages/block-editor/src/store/test/reducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {
blocks,
isBlockInterfaceHidden,
isTyping,
isDragging,
draggedBlocks,
selection,
initialPosition,
Expand Down Expand Up @@ -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' ];
Expand Down

0 comments on commit 4de62d7

Please sign in to comment.