Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Disallow drag from Nav list view into block canvas #47615

Closed
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions docs/reference-guides/data/data-core-block-editor.md
Original file line number Diff line number Diff line change
Expand Up @@ -518,6 +518,18 @@ _Returns_

- `string[]`: Array of dragged block client ids.

### getDraggedBlocksOrigin

Returns the origin of the dragged blocks (if any).

_Parameters_

- _state_ `Object`: Global application state.

_Returns_

- `string`: The origin of the dragged blocks.

### getFirstMultiSelectedBlockClientId

Returns the client ID of the first block in the multi-selection set, or null
Expand Down Expand Up @@ -1573,6 +1585,7 @@ Returns an action object used in signalling that the user has begun to drag bloc
_Parameters_

- _clientIds_ `string[]`: An array of client ids being dragged
- _origin_ `string`: the name of the origin of the drag blocks.

_Returns_

Expand Down
1 change: 1 addition & 0 deletions packages/block-editor/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -830,6 +830,7 @@ _Parameters_

- _props_ `Object`: Optional. Props to pass to the element. Must contain the ref if one is defined.
- _options_ `Object`: Optional. Inner blocks options.
- _options.dropZoneName_ `string`: Optional. The name of the drop zone.

### useSetting

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ const BlockDraggable = ( {
cloneClassname,
onDragStart,
onDragEnd,
dragOrigin,
} ) => {
const { srcRootClientId, isDraggable, icon } = useSelect(
( select ) => {
Expand Down Expand Up @@ -59,6 +60,7 @@ const BlockDraggable = ( {
type: 'block',
srcClientIds: clientIds,
srcRootClientId,
dragOrigin,
};

return (
Expand All @@ -67,7 +69,7 @@ const BlockDraggable = ( {
__experimentalTransferDataType="wp-blocks"
transferData={ transferData }
onDragStart={ ( event ) => {
startDraggingBlocks( clientIds );
startDraggingBlocks( clientIds, dragOrigin );
isDragging.current = true;

startScrolling( event );
Expand Down
15 changes: 10 additions & 5 deletions packages/block-editor/src/components/inner-blocks/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -154,15 +154,19 @@ const ForwardedInnerBlocks = forwardRef( ( props, ref ) => {
* returns. Optionally, you can also pass any other props through this hook, and
* they will be merged and returned.
*
* @param {Object} props Optional. Props to pass to the element. Must contain
* the ref if one is defined.
* @param {Object} options Optional. Inner blocks options.
* @param {Object} props Optional. Props to pass to the element. Must contain
* the ref if one is defined.
* @param {Object} options Optional. Inner blocks options.
*
* @param {string} options.dropZoneName Optional. The name of the drop zone.
* @see https://github.com/WordPress/gutenberg/blob/HEAD/packages/block-editor/src/components/inner-blocks/README.md
*/
export function useInnerBlocksProps( props = {}, options = {} ) {
const { __unstableDisableLayoutClassNames, __unstableDisableDropZone } =
options;
const {
__unstableDisableLayoutClassNames,
__unstableDisableDropZone,
__unstableDropZoneName = 'inner-blocks',
getdave marked this conversation as resolved.
Show resolved Hide resolved
} = options;
const {
clientId,
layout = null,
Expand Down Expand Up @@ -204,6 +208,7 @@ export function useInnerBlocksProps( props = {}, options = {} ) {

const blockDropZoneRef = useBlockDropZone( {
rootClientId: clientId,
dropZoneName: __unstableDropZoneName,
draganescu marked this conversation as resolved.
Show resolved Hide resolved
} );

const ref = useMergeRefs( [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,10 @@ const ListViewBlockContents = forwardRef(
} }
/>
) }
<BlockDraggable clientIds={ draggableClientIds }>
<BlockDraggable
clientIds={ draggableClientIds }
dragOrigin="offcanvas"
draganescu marked this conversation as resolved.
Show resolved Hide resolved
>
{ ( { draggable, onDragStart, onDragEnd } ) => (
<ListViewBlockSelectButton
ref={ ref }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ export default function useBlockDropZone( {
// values returned by the `getRootBlockClientId` selector, which also uses
// an empty string to represent top-level blocks.
rootClientId: targetRootClientId = '',
dropZoneName,
} = {} ) {
const [ dropTarget, setDropTarget ] = useState( {
index: null,
Expand All @@ -166,17 +167,34 @@ export default function useBlockDropZone( {
[ targetRootClientId ]
);

const { getBlockListSettings, getBlocks, getBlockIndex } =
useSelect( blockEditorStore );
const {
getBlockListSettings,
getBlocks,
getBlockIndex,
getDraggedBlocksOrigin,
} = useSelect( blockEditorStore );
getdave marked this conversation as resolved.
Show resolved Hide resolved

const { showInsertionPoint, hideInsertionPoint } =
useDispatch( blockEditorStore );

const onBlockDrop = useOnBlockDrop( targetRootClientId, dropTarget.index, {
operation: dropTarget.operation,
dropZoneName,
} );
const throttled = useThrottle(
useCallback(
( event, ownerDocument ) => {
const draggedBlocksOrigin = getDraggedBlocksOrigin();
draganescu marked this conversation as resolved.
Show resolved Hide resolved

if (
dropZoneName &&
draggedBlocksOrigin &&
dropZoneName !== draggedBlocksOrigin
) {
// If drag and drop names are available and they don't match, don't allow dropping.
return;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Exiting early here means that no drop zone UI affordances are displayed when dragging. For example the blue lines that appear when dragging over a drop zone will not show.

}

const blocks = getBlocks( targetRootClientId );

// The block list is empty, don't show the insertion point but still allow dropping.
Expand Down
14 changes: 11 additions & 3 deletions packages/block-editor/src/components/use-on-block-drop/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ export function parseDropEvent( event ) {
srcIndex: null,
type: null,
blocks: null,
dragOrigin: null,
};

if ( ! event.dataTransfer ) {
Expand Down Expand Up @@ -61,6 +62,7 @@ export function parseDropEvent( event ) {
* @param {Function} moveBlocks A function that moves blocks.
* @param {Function} insertOrReplaceBlocks A function that inserts or replaces blocks.
* @param {Function} clearSelectedBlock A function that clears block selection.
* @param {string} dropZoneName The dropZoneName where the drop event will occur (e.g. 'list-view', 'canvas)
* @return {Function} The event handler for a block drop event.
*/
export function onBlockDrop(
Expand All @@ -70,14 +72,16 @@ export function onBlockDrop(
getClientIdsOfDescendants,
moveBlocks,
insertOrReplaceBlocks,
clearSelectedBlock
clearSelectedBlock,
dropZoneName
) {
return ( event ) => {
const {
srcRootClientId: sourceRootClientId,
srcClientIds: sourceClientIds,
type: dropType,
blocks,
dragOrigin,
} = parseDropEvent( event );

// If the user is inserting a block.
Expand All @@ -91,6 +95,9 @@ export function onBlockDrop(

// If the user is moving a block.
if ( dropType === 'block' ) {
if ( dropZoneName && dragOrigin && dropZoneName !== dragOrigin ) {
return;
}
const sourceBlockIndex = getBlockIndex( sourceClientIds[ 0 ] );

// If the user is dropping to the same position, return early.
Expand Down Expand Up @@ -210,7 +217,7 @@ export default function useOnBlockDrop(
targetBlockIndex,
options = {}
) {
const { operation = 'insert' } = options;
const { operation = 'insert', dropZoneName } = options;
const hasUploadPermissions = useSelect(
( select ) => select( blockEditorStore ).getSettings().mediaUpload,
[]
Expand Down Expand Up @@ -307,7 +314,8 @@ export default function useOnBlockDrop(
getClientIdsOfDescendants,
moveBlocks,
insertOrReplaceBlocks,
clearSelectedBlock
clearSelectedBlock,
dropZoneName
);
const _onFilesDrop = onFilesDrop(
targetRootClientId,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ describe( 'parseDropEvent', () => {
srcClientIds: [ 'abc' ],
srcIndex: 1,
type: 'block',
dragOrigin: 'canvas',
};
const event = {
dataTransfer: {
Expand Down Expand Up @@ -55,6 +56,7 @@ describe( 'parseDropEvent', () => {
srcRootClientId: null,
srcIndex: null,
blocks: null,
dragOrigin: null,
...rawDataTransfer,
} );
} );
Expand All @@ -66,6 +68,7 @@ describe( 'parseDropEvent', () => {
srcClientIds: null,
srcIndex: null,
type: null,
dragOrigin: null,
};
const event = {
dataTransfer: {
Expand All @@ -85,6 +88,7 @@ describe( 'parseDropEvent', () => {
srcClientIds: null,
srcIndex: null,
type: null,
dragOrigin: null,
};
const event = {};

Expand Down Expand Up @@ -298,6 +302,50 @@ describe( 'onBlockDrop', () => {
insertIndex
);
} );

it( 'does nothing if the block is dropped into a drop target that does not match origin of the drag', () => {
const targetRootClientId = '1';
const targetBlockIndex = 0;

const dropZoneName = 'canvas';
const dragOrigin = 'list-view';

const getBlockIndex = jest.fn( () => 1 );
// Dragged block is being dropped as a descendant of itself.
const getClientIdsOfDescendants = jest.fn( () => [
targetRootClientId,
] );
const moveBlocks = jest.fn();
const insertOrReplaceBlocks = jest.fn();
const clearSelectedBlock = jest.fn();

const event = {
dataTransfer: {
getData() {
return JSON.stringify( {
type: 'block',
srcRootClientId: '0',
srcClientIds: [ '5' ],
dragOrigin,
} );
},
},
};

const eventHandler = onBlockDrop(
targetRootClientId,
targetBlockIndex,
getBlockIndex,
getClientIdsOfDescendants,
moveBlocks,
insertOrReplaceBlocks,
clearSelectedBlock,
dropZoneName
);
eventHandler( event );

expect( moveBlocks ).not.toHaveBeenCalled();
} );
} );

describe( 'onFilesDrop', () => {
Expand Down
4 changes: 3 additions & 1 deletion packages/block-editor/src/store/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -1291,12 +1291,14 @@ export function stopTyping() {
*
* @param {string[]} clientIds An array of client ids being dragged
*
* @param {string} origin the name of the origin of the drag blocks.
* @return {Object} Action object.
*/
export function startDraggingBlocks( clientIds = [] ) {
export function startDraggingBlocks( clientIds = [], origin ) {
return {
type: 'START_DRAGGING_BLOCKS',
clientIds,
origin,
};
}

Expand Down
13 changes: 13 additions & 0 deletions packages/block-editor/src/store/reducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -1247,6 +1247,18 @@ export function draggedBlocks( state = [], action ) {
return state;
}

export function draggedBlocksOrigin( state = '', action ) {
switch ( action.type ) {
case 'START_DRAGGING_BLOCKS':
return action.origin;

case 'STOP_DRAGGING_BLOCKS':
return '';
}

return state;
}

/**
* Reducer tracking the visible blocks.
*
Expand Down Expand Up @@ -1886,4 +1898,5 @@ export default combineReducers( {
lastBlockInserted,
temporarilyEditingAsBlocks,
blockVisibility,
draggedBlocksOrigin,
} );
10 changes: 10 additions & 0 deletions packages/block-editor/src/store/selectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -1303,6 +1303,16 @@ export function getDraggedBlockClientIds( state ) {
return state.draggedBlocks;
}

/**
* Returns the origin of the dragged blocks (if any).
*
* @param {Object} state Global application state.
* @return {string} The origin of the dragged blocks.
*/
export function getDraggedBlocksOrigin( state ) {
return state.draggedBlocksOrigin;
}

/**
* Returns whether the block is being dragged.
*
Expand Down
11 changes: 11 additions & 0 deletions packages/block-editor/src/store/test/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -799,6 +799,17 @@ describe( 'actions', () => {
clientIds,
} );
} );

it( 'should optionally return a drag origin with START_DRAGGING_BLOCKS action', () => {
const clientIds = [ 'block-1', 'block-2', 'block-3' ];
expect( startDraggingBlocks( clientIds, 'inner-blocks' ) ).toEqual(
{
type: 'START_DRAGGING_BLOCKS',
clientIds,
origin: 'inner-blocks',
}
);
} );
} );

describe( 'stopDraggingBlocks', () => {
Expand Down
Loading