Skip to content

Commit

Permalink
[RNMobile] Allow dragging from block toolbar (#40886)
Browse files Browse the repository at this point in the history
* Enable dragging from block toolbar

* Ensure root block is dragged for nested blocks

* Add draggingClientId prop to BlockDraggable

With this change the `BlockDraggable` component might receive two different client ids, one is the client id of the block where the component is rendered, and the other (which is optional) is used for identifying the block to be dragged.

* Set dragging always enabled for block toolbar

The block toolbar is only visible when the block is selected so it's safe to allow dragging in all cases, as it won't affect other UI elements.

* Update dragging enabled calculation

In order to prevent issues related to disabling the long-press gesture in elements within the block UI, the logic for enabling the dragging has been updated. Now it will enabled in the following cases:
- The block doesn't have inner blocks. This applies to root blocks and nested blocks without further nested blocks.
- Blocks with nested blocks if the block is selected.
- Blocks with nested blocks if none of the nested blocks is selected.
  • Loading branch information
fluiddot authored May 9, 2022
1 parent 1d87dc6 commit 27f2ba7
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -254,14 +254,20 @@ const BlockDraggableWrapper = ( { children } ) => {
* This component serves for animating the block when it is being dragged.
* Hence, it should be wrapped around the rendering of a block.
*
* @param {Object} props Component props.
* @param {JSX.Element} props.children Children to be rendered.
* @param {string[]} props.clientId Client id of the block.
* @param {boolean} [props.enabled] Enables the draggable trigger.
* @param {Object} props Component props.
* @param {JSX.Element} props.children Children to be rendered.
* @param {string} props.clientId Client id of the block.
* @param {string} [props.draggingClientId] Client id to use for dragging. If not defined, the value from `clientId` will be used.
* @param {boolean} [props.enabled] Enables the draggable trigger.
*
* @return {Function} Render function which includes the parameter `isDraggable` to determine if the block can be dragged.
*/
const BlockDraggable = ( { clientId, children, enabled = true } ) => {
const BlockDraggable = ( {
clientId,
children,
draggingClientId,
enabled = true,
} ) => {
const wasBeingDragged = useRef( false );
const [ isEditingText, setIsEditingText ] = useState( false );
const [ isScreenReaderEnabled, setIsScreenReaderEnabled ] = useState(
Expand Down Expand Up @@ -293,7 +299,6 @@ const BlockDraggable = ( { clientId, children, enabled = true } ) => {
getTemplateLock,
isBlockBeingDragged,
getSelectedBlockClientId,
hasSelectedInnerBlock,
} = _select( blockEditorStore );
const rootClientId = getBlockRootClientId( clientId );
const templateLock = rootClientId
Expand All @@ -305,9 +310,7 @@ const BlockDraggable = ( { clientId, children, enabled = true } ) => {
isBeingDragged: isBlockBeingDragged( clientId ),
isDraggable: 'all' !== templateLock,
isBlockSelected:
selectedBlockClientId &&
( selectedBlockClientId === clientId ||
hasSelectedInnerBlock( clientId, true ) ),
selectedBlockClientId && selectedBlockClientId === clientId,
};
},
[ clientId ]
Expand Down Expand Up @@ -387,7 +390,7 @@ const BlockDraggable = ( { clientId, children, enabled = true } ) => {

return (
<DraggableTrigger
id={ clientId }
id={ draggingClientId || clientId }
enabled={ enabled && canDragBlock }
minDuration={ Platform.select( {
// On iOS, using a lower min duration than the default
Expand Down
24 changes: 21 additions & 3 deletions packages/block-editor/src/components/block-list/block.native.js
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,8 @@ class BlockListBlock extends Component {
marginHorizontal,
isInnerBlockSelected,
name,
rootClientId,
draggingEnabled,
draggingClientId,
} = this.props;

if ( ! attributes || ! blockType ) {
Expand All @@ -209,7 +210,6 @@ class BlockListBlock extends Component {
const isScreenWidthEqual = blockWidth === screenWidth;
const isScreenWidthWider = blockWidth < screenWidth;
const isFullWidthToolbar = isFullWidth( align ) || isScreenWidthEqual;
const hasParent = !! rootClientId;

return (
<TouchableWithoutFeedback
Expand Down Expand Up @@ -260,8 +260,9 @@ class BlockListBlock extends Component {
/>
) }
<BlockDraggable
enabled={ ! hasParent }
clientId={ clientId }
draggingClientId={ draggingClientId }
enabled={ draggingEnabled }
>
{ () =>
isValid ? (
Expand All @@ -288,6 +289,7 @@ class BlockListBlock extends Component {
blockWidth={ blockWidth }
anchorNodeRef={ this.anchorNodeRef.current }
isFullWidth={ isFullWidthToolbar }
draggingClientId={ draggingClientId }
/>
) }
</View>
Expand Down Expand Up @@ -318,13 +320,15 @@ export default compose( [
withSelect( ( select, { clientId } ) => {
const {
getBlockIndex,
getBlockCount,
getSettings,
isBlockSelected,
getBlock,
getSelectedBlockClientId,
getLowestCommonAncestorWithSelectedBlock,
getBlockParents,
hasSelectedInnerBlock,
getBlockHierarchyRootClientId,
} = select( blockEditorStore );

const order = getBlockIndex( clientId );
Expand Down Expand Up @@ -369,13 +373,27 @@ export default compose( [
const baseGlobalStyles = getSettings()
?.__experimentalGlobalStylesBaseStyles;

const hasInnerBlocks = getBlockCount( clientId ) > 0;
// For blocks with inner blocks, we only enable the dragging in the nested
// blocks if any of them are selected. This way we prevent the long-press
// gesture from being disabled for elements within the block UI.
const draggingEnabled =
! hasInnerBlocks ||
isSelected ||
! hasSelectedInnerBlock( clientId, true );
// Dragging nested blocks is not supported yet. For this reason, the block to be dragged
// will be the top in the hierarchy.
const draggingClientId = getBlockHierarchyRootClientId( clientId );

return {
icon,
name: name || 'core/missing',
order,
title,
attributes,
blockType,
draggingClientId,
draggingEnabled,
isSelected,
isInnerBlockSelected,
isValid,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { useState, useEffect } from '@wordpress/element';
*/
import styles from './style.scss';
import BlockMover from '../block-mover';
import BlockDraggable from '../block-draggable';
import BlockActionsMenu from './block-actions-menu';
import { BlockSettingsButton } from '../block-settings';
import { store as blockEditorStore } from '../../store';
Expand All @@ -33,6 +34,7 @@ const BlockMobileToolbar = ( {
blockWidth,
anchorNodeRef,
isFullWidth,
draggingClientId,
} ) => {
const [ fillsLength, setFillsLength ] = useState( null );
const [ appenderWidth, setAppenderWidth ] = useState( 0 );
Expand Down Expand Up @@ -73,7 +75,12 @@ const BlockMobileToolbar = ( {
/>
) }

<View style={ styles.spacer } />
<BlockDraggable
clientId={ clientId }
draggingClientId={ draggingClientId }
>
{ () => <View style={ styles.spacer } /> }
</BlockDraggable>

<BlockSettingsButton.Slot>
{ /* Render only one settings icon even if we have more than one fill - need for hooks with controls. */ }
Expand Down

0 comments on commit 27f2ba7

Please sign in to comment.