From 7e67812ddc159221fc533d461d9286b8127b7221 Mon Sep 17 00:00:00 2001 From: Carlos Garcia Date: Wed, 13 Apr 2022 17:59:05 +0200 Subject: [PATCH 01/10] Present block mover picker only after state updates --- .../components/block-mover/index.native.js | 28 +++++++++++++++---- 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/packages/block-editor/src/components/block-mover/index.native.js b/packages/block-editor/src/components/block-mover/index.native.js index 35a7503cef4a82..a4a3bd60f16ba1 100644 --- a/packages/block-editor/src/components/block-mover/index.native.js +++ b/packages/block-editor/src/components/block-mover/index.native.js @@ -11,7 +11,7 @@ import { __ } from '@wordpress/i18n'; import { Picker, ToolbarButton } from '@wordpress/components'; import { withInstanceId, compose } from '@wordpress/compose'; import { withSelect, withDispatch } from '@wordpress/data'; -import { useRef, useState } from '@wordpress/element'; +import { useCallback, useEffect, useRef, useState } from '@wordpress/element'; /** * Internal dependencies @@ -36,6 +36,7 @@ export const BlockMover = ( { isStackedHorizontally, } ) => { const pickerRef = useRef(); + const [ shouldPresentPicker, setShouldPresentPicker ] = useState( false ); const [ blockPageMoverState, setBlockPageMoverState ] = useState( undefined ); @@ -46,9 +47,17 @@ export const BlockMover = ( { } setBlockPageMoverState( direction ); - pickerRef.current.presentPicker(); + setShouldPresentPicker( true ); }; + // Ensure that the picker is only presented after state updates. + useEffect( () => { + if ( shouldPresentPicker ) { + pickerRef.current?.presentPicker(); + setShouldPresentPicker( false ); + } + }, [ shouldPresentPicker ] ); + const { description: { backwardButtonHint, @@ -86,6 +95,15 @@ export const BlockMover = ( { if ( option && option.onSelect ) option.onSelect(); }; + const onLongPressMoveUp = useCallback( + showBlockPageMover( BLOCK_MOVER_DIRECTION_TOP ), + [] + ); + const onLongPressMoveDown = useCallback( + showBlockPageMover( BLOCK_MOVER_DIRECTION_BOTTOM ), + [] + ); + if ( ! canMove || ( isFirst && isLast && ! rootClientId ) ) { return null; } @@ -96,7 +114,7 @@ export const BlockMover = ( { title={ ! isFirst ? backwardButtonTitle : firstBlockTitle } isDisabled={ isFirst } onClick={ onMoveUp } - onLongPress={ showBlockPageMover( BLOCK_MOVER_DIRECTION_TOP ) } + onLongPress={ onLongPressMoveUp } icon={ backwardButtonIcon } extraProps={ { hint: backwardButtonHint } } /> @@ -105,9 +123,7 @@ export const BlockMover = ( { title={ ! isLast ? forwardButtonTitle : lastBlockTitle } isDisabled={ isLast } onClick={ onMoveDown } - onLongPress={ showBlockPageMover( - BLOCK_MOVER_DIRECTION_BOTTOM - ) } + onLongPress={ onLongPressMoveDown } icon={ forwardButtonIcon } extraProps={ { hint: forwardButtonHint, From 85e2c158f7bd2106ec0384f5a653fc70f8dd245d Mon Sep 17 00:00:00 2001 From: Carlos Garcia Date: Wed, 13 Apr 2022 19:09:52 +0200 Subject: [PATCH 02/10] Refactor draggable component --- .../components/src/draggable/index.native.js | 197 ++++++++++++------ .../src/draggable/style.native.scss | 3 + packages/components/src/index.native.js | 2 +- 3 files changed, 134 insertions(+), 68 deletions(-) create mode 100644 packages/components/src/draggable/style.native.scss diff --git a/packages/components/src/draggable/index.native.js b/packages/components/src/draggable/index.native.js index bc300d7e3a3c29..58545592e96ae3 100644 --- a/packages/components/src/draggable/index.native.js +++ b/packages/components/src/draggable/index.native.js @@ -1,108 +1,171 @@ /** * External dependencies */ -import { Gesture, GestureDetector } from 'react-native-gesture-handler'; +import { + Gesture, + GestureDetector, + LongPressGestureHandler, +} from 'react-native-gesture-handler'; import Animated, { useSharedValue, runOnJS, - runOnUI, + useAnimatedReaction, + useAnimatedGestureHandler, } from 'react-native-reanimated'; -import TextInputState from 'react-native/Libraries/Components/TextInput/TextInputState'; /** * WordPress dependencies */ -import { Platform } from '@wordpress/element'; +import { createContext, useContext, useRef } from '@wordpress/element'; /** - * Draggable component + * Internal dependencies + */ +import styles from './style.scss'; + +const Context = createContext( {} ); +const { Provider } = Context; + +/** + * Draggable component. * - * @param {Object} props Component props. - * @param {JSX.Element} props.children Children to be rendered. - * @param {number} [props.maxDistance] Maximum distance, that defines how far the finger is allowed to travel during a long press gesture. - * @param {number} [props.minDuration] Minimum time, that a finger must remain pressed on the corresponding view. - * @param {Function} [props.onDragEnd] Callback when dragging ends. - * @param {Function} [props.onDragOver] Callback when dragging happens over an element. - * @param {Function} [props.onDragStart] Callback when dragging starts. - * @param {import('react-native-reanimated').StyleProp} [props.wrapperAnimatedStyles] Animated styles for the wrapper component. + * @param {Object} props Component props. + * @param {JSX.Element} props.children Children to be rendered. + * @param {Function} [props.onDragEnd] Callback when dragging ends. + * @param {Function} [props.onDragOver] Callback when dragging happens over an element. + * @param {Function} [props.onDragStart] Callback when dragging starts. * * @return {JSX.Element} The component to be rendered. */ -export default function Draggable( { - children, - maxDistance = 1000, - minDuration = 450, - onDragEnd, - onDragOver, - onDragStart, - wrapperAnimatedStyles, -} ) { +const Draggable = ( { children, onDragEnd, onDragOver, onDragStart } ) => { const isDragging = useSharedValue( false ); - const isAnyTextInputFocused = useSharedValue( false ); + const draggingId = useSharedValue( '' ); + const panGestureRef = useRef(); - const checkTextInputFocus = () => { - const isTextInputFocused = - TextInputState.currentlyFocusedInput() !== null; - isAnyTextInputFocused.value = isTextInputFocused; - return isTextInputFocused; + const initialPosition = { + x: useSharedValue( 0 ), + y: useSharedValue( 0 ), }; - - const dragStart = ( event ) => { - const isTextInputFocused = checkTextInputFocus(); - - if ( ! isTextInputFocused && onDragStart ) { - runOnUI( onDragStart )( event ); - } + const lastPosition = { + x: useSharedValue( 0 ), + y: useSharedValue( 0 ), }; - const dragEnd = () => { - const isTextInputFocused = checkTextInputFocus(); + useAnimatedReaction( + () => isDragging.value, + ( result, previous ) => { + if ( result === previous ) { + return; + } - if ( ! isTextInputFocused && onDragEnd ) { - runOnUI( onDragEnd )(); + if ( result ) { + if ( onDragStart ) { + onDragStart( { + x: initialPosition.x.value, + y: initialPosition.y.value, + id: draggingId.value, + } ); + } + } else if ( onDragEnd ) { + onDragEnd( { + x: lastPosition.x.value, + y: lastPosition.y.value, + id: draggingId.value, + } ); + } } - }; - - const longPressGesture = Gesture.LongPress() - .onStart( ( ev ) => { - 'worklet'; - isDragging.value = true; - runOnJS( dragStart )( ev ); - } ) - .onEnd( () => { - 'worklet'; - isDragging.value = false; - runOnJS( dragEnd )(); - } ) - .maxDistance( maxDistance ) - .minDuration( minDuration ) - .shouldCancelWhenOutside( false ); + ); const panGesture = Gesture.Pan() .manualActivation( true ) + .onTouchesDown( ( event ) => { + const { x = 0, y = 0 } = event.allTouches[ 0 ]; + initialPosition.x.value = x; + initialPosition.y.value = y; + } ) .onTouchesMove( ( _, state ) => { - 'worklet'; if ( isDragging.value ) { state.activate(); - } else if ( Platform.isIOS || isAnyTextInputFocused.value ) { - state.fail(); } } ) - .onUpdate( ( ev ) => { - 'worklet'; + .onUpdate( ( event ) => { + lastPosition.x.value = event.x; + lastPosition.y.value = event.y; + if ( onDragOver ) { - onDragOver( ev ); + onDragOver( event ); } } ) + .withRef( panGestureRef ) .shouldCancelWhenOutside( false ); - const dragHandler = Gesture.Simultaneous( panGesture, longPressGesture ); - return ( - - - { children } + + + + { children } + ); -} +}; + +/** + * Draggable trigger component. + * + * This component acts as the trigger for the dragging functionality. + * + * @param {Object} props Component props. + * @param {JSX.Element} props.children Children to be rendered. + * @param {*} props.id Identifier passed within the event callbacks. + * @param {boolean} [props.enabled] Enables the long-press gesture. + * @param {number} [props.maxDistance] Maximum distance, that defines how far the finger is allowed to travel during a long press gesture. + * @param {number} [props.minDuration] Minimum time, that a finger must remain pressed on the corresponding view. + * @param {Function} [props.onLongPress] Callback when long-press gesture is triggered over an element. + * @param {Function} [props.onLongPressEnd] Callback when long-press gesture ends. + * + * @return {JSX.Element} The component to be rendered. + */ +const DraggableTrigger = ( { + children, + enabled = true, + id, + maxDistance = 1000, + minDuration = 500, + onLongPress, + onLongPressEnd, +} ) => { + const { panGestureRef, isDragging, draggingId } = useContext( Context ); + + const gestureHandler = useAnimatedGestureHandler( { + onActive: () => { + isDragging.value = true; + draggingId.value = id; + if ( onLongPress ) { + runOnJS( onLongPress )( id ); + } + }, + onEnd: () => { + isDragging.value = false; + if ( onLongPressEnd ) { + runOnJS( onLongPressEnd )( id ); + } + }, + } ); + + return ( + + { children } + + ); +}; + +export { DraggableTrigger }; +export default Draggable; diff --git a/packages/components/src/draggable/style.native.scss b/packages/components/src/draggable/style.native.scss new file mode 100644 index 00000000000000..a3165cbe080ca2 --- /dev/null +++ b/packages/components/src/draggable/style.native.scss @@ -0,0 +1,3 @@ +.draggable__container { + flex: 1; +} diff --git a/packages/components/src/index.native.js b/packages/components/src/index.native.js index 108fb95b094be3..140ad940ace6eb 100644 --- a/packages/components/src/index.native.js +++ b/packages/components/src/index.native.js @@ -61,7 +61,7 @@ export { filterUnitsWithSettings as filterUnitsWithSettings, } from './unit-control/utils'; export { default as Disabled } from './disabled'; -export { default as Draggable } from './draggable'; +export { default as Draggable, DraggableTrigger } from './draggable'; // Higher-Order Components. export { default as withConstrainedTabbing } from './higher-order/with-constrained-tabbing'; From 43b684e3ff9c6576a84588d288fa1a774882934f Mon Sep 17 00:00:00 2001 From: Carlos Garcia Date: Wed, 13 Apr 2022 19:22:28 +0200 Subject: [PATCH 03/10] Use DraggableTrigger in BlockDraggable --- .../block-draggable/index.native.js | 100 +++++++++--------- 1 file changed, 51 insertions(+), 49 deletions(-) diff --git a/packages/block-editor/src/components/block-draggable/index.native.js b/packages/block-editor/src/components/block-draggable/index.native.js index 926f102bd562ac..303c9f2622b978 100644 --- a/packages/block-editor/src/components/block-draggable/index.native.js +++ b/packages/block-editor/src/components/block-draggable/index.native.js @@ -10,14 +10,14 @@ import Animated, { withDelay, withTiming, } from 'react-native-reanimated'; +import TextInputState from 'react-native/Libraries/Components/TextInput/TextInputState'; /** * WordPress dependencies */ -import { Draggable } from '@wordpress/components'; +import { Draggable, DraggableTrigger } from '@wordpress/components'; import { useSelect, useDispatch } from '@wordpress/data'; -import { useEffect, useRef } from '@wordpress/element'; -import { usePreferredColorSchemeStyle } from '@wordpress/compose'; +import { useEffect, useRef, useState } from '@wordpress/element'; /** * Internal dependencies @@ -51,22 +51,15 @@ const BLOCK_OPACITY_ANIMATION_DELAY = 250; * @return {Function} Render function that passes `onScroll` event handler. */ const BlockDraggableWrapper = ( { children } ) => { - const currentBlockLayout = useRef(); - - const wrapperStyles = usePreferredColorSchemeStyle( - styles[ 'draggable-wrapper__container' ], - styles[ 'draggable-wrapper__container--dark' ] - ); - - const { startDraggingBlocks, stopDraggingBlocks } = useDispatch( - blockEditorStore - ); + const [ currentClientId, setCurrentClientId ] = useState(); const { - blocksLayouts, - scrollRef, - findBlockLayoutByPosition, - } = useBlockListContext(); + selectBlock, + startDraggingBlocks, + stopDraggingBlocks, + } = useDispatch( blockEditorStore ); + + const { scrollRef } = useBlockListContext(); const animatedScrollRef = useAnimatedRef(); animatedScrollRef( scrollRef ); @@ -113,16 +106,10 @@ const BlockDraggableWrapper = ( { children } ) => { }; }, [] ); - const onStartDragging = ( position ) => { - const blockLayout = findBlockLayoutByPosition( blocksLayouts.current, { - x: position.x, - y: position.y + scroll.offsetY.value, - } ); - - const foundClientId = blockLayout?.clientId; - currentBlockLayout.current = blockLayout; - if ( foundClientId ) { - startDraggingBlocks( [ foundClientId ] ); + const onStartDragging = ( { clientId, position } ) => { + if ( clientId ) { + startDraggingBlocks( [ clientId ] ); + setCurrentClientId( clientId ); runOnUI( startScrolling )( position.y ); } else { // We stop dragging if no block is found. @@ -131,7 +118,6 @@ const BlockDraggableWrapper = ( { children } ) => { }; const onStopDragging = () => { - const currentClientId = currentBlockLayout.current?.clientId; if ( currentClientId ) { onBlockDrop( { // Dropping is only allowed at root level @@ -139,6 +125,8 @@ const BlockDraggableWrapper = ( { children } ) => { srcClientIds: [ currentClientId ], type: 'block', } ); + selectBlock( currentClientId ); + setCurrentClientId( undefined ); } onBlockDragEnd(); stopDraggingBlocks(); @@ -149,7 +137,7 @@ const BlockDraggableWrapper = ( { children } ) => { chip.height.value = layout.height; }; - const startDragging = ( { x, y } ) => { + const startDragging = ( { x, y, id } ) => { 'worklet'; const dragPosition = { x, y }; chip.x.value = dragPosition.x; @@ -158,7 +146,7 @@ const BlockDraggableWrapper = ( { children } ) => { isDragging.value = true; chip.scale.value = withTiming( 1 ); - runOnJS( onStartDragging )( dragPosition ); + runOnJS( onStartDragging )( { clientId: id, position: dragPosition } ); }; const updateDragging = ( { x, y } ) => { @@ -209,12 +197,10 @@ const BlockDraggableWrapper = ( { children } ) => { isDragging={ isDragging } targetBlockIndex={ targetBlockIndex } /> - { children( { onScroll: scrollHandler } ) } @@ -235,14 +221,14 @@ 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 {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. * * @return {Function} Render function which includes the parameter `isDraggable` to determine if the block can be dragged. */ -const BlockDraggable = ( { clientId, children } ) => { - const { selectBlock } = useDispatch( blockEditorStore ); +const BlockDraggable = ( { clientId, children, enabled = true } ) => { const wasBeingDragged = useRef( false ); const draggingAnimation = { @@ -261,53 +247,69 @@ const BlockDraggable = ( { clientId, children } ) => { BLOCK_OPACITY_ANIMATION_DELAY, withTiming( 1, BLOCK_OPACITY_ANIMATION_CONFIG ) ); - runOnJS( selectBlock )( clientId ); }; - const { isDraggable, isBeingDragged } = useSelect( + const { isDraggable, isBeingDragged, canDragBlock } = useSelect( ( select ) => { const { getBlockRootClientId, getTemplateLock, isBlockBeingDragged, + hasSelectedBlock, } = select( blockEditorStore ); const rootClientId = getBlockRootClientId( clientId ); const templateLock = rootClientId ? getTemplateLock( rootClientId ) : null; + const isAnyTextInputFocused = + TextInputState.currentlyFocusedInput() !== null; return { isBeingDragged: isBlockBeingDragged( clientId ), isDraggable: 'all' !== templateLock, + canDragBlock: hasSelectedBlock() + ? ! isAnyTextInputFocused + : true, }; }, [ clientId ] ); useEffect( () => { - if ( isBeingDragged ) { - startDraggingBlock(); - wasBeingDragged.current = true; - } else if ( wasBeingDragged.current ) { - stopDraggingBlock(); - wasBeingDragged.current = false; + if ( isBeingDragged !== wasBeingDragged.current ) { + if ( isBeingDragged ) { + startDraggingBlock(); + } else { + stopDraggingBlock(); + } } + wasBeingDragged.current = isBeingDragged; }, [ isBeingDragged ] ); - const wrapperStyles = useAnimatedStyle( () => { + const animatedWrapperStyles = useAnimatedStyle( () => { return { opacity: draggingAnimation.opacity.value, }; } ); + const wrapperStyles = [ + animatedWrapperStyles, + styles[ 'draggable-wrapper__container' ], + ]; if ( ! isDraggable ) { return children( { isDraggable: false } ); } return ( - - { children( { isDraggable: true } ) } - + + + { children( { isDraggable: true } ) } + + ); }; From 1266379b204a7b447889b5b271c6904a4fc7a01f Mon Sep 17 00:00:00 2001 From: Carlos Garcia Date: Wed, 13 Apr 2022 19:24:03 +0200 Subject: [PATCH 04/10] Move BlockDraggable render to BlockListBlock component --- .../block-list/block-list-item-cell.native.js | 9 +------ .../src/components/block-list/block.native.js | 26 +++++++++++++------ 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/packages/block-editor/src/components/block-list/block-list-item-cell.native.js b/packages/block-editor/src/components/block-list/block-list-item-cell.native.js index 5577b0705d686d..c399643a633996 100644 --- a/packages/block-editor/src/components/block-list/block-list-item-cell.native.js +++ b/packages/block-editor/src/components/block-list/block-list-item-cell.native.js @@ -12,7 +12,6 @@ import { useEffect, useCallback } from '@wordpress/element'; * Internal dependencies */ import { useBlockListContext } from './block-list-context'; -import BlockDraggable from '../block-draggable'; function BlockListItemCell( { children, clientId, rootClientId } ) { const { blocksLayouts, updateBlocksLayouts } = useBlockListContext(); @@ -37,13 +36,7 @@ function BlockListItemCell( { children, clientId, rootClientId } ) { [ clientId, rootClientId, updateBlocksLayouts ] ); - return ( - - - { () => children } - - - ); + return { children }; } export default BlockListItemCell; diff --git a/packages/block-editor/src/components/block-list/block.native.js b/packages/block-editor/src/components/block-list/block.native.js index 33317778e66b22..3f02a045388553 100644 --- a/packages/block-editor/src/components/block-list/block.native.js +++ b/packages/block-editor/src/components/block-list/block.native.js @@ -31,6 +31,7 @@ import BlockEdit from '../block-edit'; import BlockInvalidWarning from './block-invalid-warning'; import BlockMobileToolbar from '../block-mobile-toolbar'; import { store as blockEditorStore } from '../../store'; +import BlockDraggable from '../block-draggable'; const emptyArray = []; function BlockForType( { @@ -189,6 +190,7 @@ class BlockListBlock extends Component { marginHorizontal, isInnerBlockSelected, name, + rootClientId, } = this.props; if ( ! attributes || ! blockType ) { @@ -207,6 +209,7 @@ class BlockListBlock extends Component { const isScreenWidthEqual = blockWidth === screenWidth; const isScreenWidthWider = blockWidth < screenWidth; const isFullWidthToolbar = isFullWidth( align ) || isScreenWidthEqual; + const hasParent = !! rootClientId; return ( ) } - { isValid ? ( - this.getBlockForType() - ) : ( - - ) } + + { () => + isValid ? ( + this.getBlockForType() + ) : ( + + ) + } + Date: Mon, 18 Apr 2022 12:52:27 +0200 Subject: [PATCH 05/10] Fix long-press gesture when editing a text on iOS --- .../src/components/block-draggable/index.native.js | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/packages/block-editor/src/components/block-draggable/index.native.js b/packages/block-editor/src/components/block-draggable/index.native.js index 303c9f2622b978..439ce078865661 100644 --- a/packages/block-editor/src/components/block-draggable/index.native.js +++ b/packages/block-editor/src/components/block-draggable/index.native.js @@ -17,7 +17,7 @@ import TextInputState from 'react-native/Libraries/Components/TextInput/TextInpu */ import { Draggable, DraggableTrigger } from '@wordpress/components'; import { useSelect, useDispatch } from '@wordpress/data'; -import { useEffect, useRef, useState } from '@wordpress/element'; +import { useEffect, useRef, useState, Platform } from '@wordpress/element'; /** * Internal dependencies @@ -33,6 +33,7 @@ import styles from './style.scss'; const CHIP_OFFSET_TO_TOUCH_POSITION = 32; const BLOCK_OPACITY_ANIMATION_CONFIG = { duration: 350 }; const BLOCK_OPACITY_ANIMATION_DELAY = 250; +const DEFAULT_LONG_PRESS_MIN_DURATION = 500; /** * Block draggable wrapper component @@ -304,7 +305,14 @@ const BlockDraggable = ( { clientId, children, enabled = true } ) => { { children( { isDraggable: true } ) } From 909c5f82cfbbb34296d9cbde28f417459539fef7 Mon Sep 17 00:00:00 2001 From: Carlos Garcia Date: Mon, 18 Apr 2022 13:07:44 +0200 Subject: [PATCH 06/10] Memoize draggable provider value to prevent re-renders --- packages/components/src/draggable/index.native.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/packages/components/src/draggable/index.native.js b/packages/components/src/draggable/index.native.js index 58545592e96ae3..42b8a4b387c0c1 100644 --- a/packages/components/src/draggable/index.native.js +++ b/packages/components/src/draggable/index.native.js @@ -16,7 +16,7 @@ import Animated, { /** * WordPress dependencies */ -import { createContext, useContext, useRef } from '@wordpress/element'; +import { createContext, useContext, useRef, useMemo } from '@wordpress/element'; /** * Internal dependencies @@ -99,12 +99,14 @@ const Draggable = ( { children, onDragEnd, onDragOver, onDragStart } ) => { .withRef( panGestureRef ) .shouldCancelWhenOutside( false ); + const providerValue = useMemo( () => { + return { panGestureRef, isDragging, draggingId }; + }, [] ); + return ( - - { children } - + { children } ); From af4c9e5067e1fe6c33da955df24b2895478a4f1e Mon Sep 17 00:00:00 2001 From: Carlos Garcia Date: Tue, 19 Apr 2022 12:50:54 +0200 Subject: [PATCH 07/10] Fix dragging not being disabled after scrolling --- packages/components/src/draggable/index.native.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/components/src/draggable/index.native.js b/packages/components/src/draggable/index.native.js index 42b8a4b387c0c1..99566c4e57b73e 100644 --- a/packages/components/src/draggable/index.native.js +++ b/packages/components/src/draggable/index.native.js @@ -96,6 +96,9 @@ const Draggable = ( { children, onDragEnd, onDragOver, onDragStart } ) => { onDragOver( event ); } } ) + .onEnd( () => { + isDragging.value = false; + } ) .withRef( panGestureRef ) .shouldCancelWhenOutside( false ); From 8ead864fedede55fef1d3d786835477108c61330 Mon Sep 17 00:00:00 2001 From: Carlos Garcia Date: Tue, 19 Apr 2022 13:59:07 +0200 Subject: [PATCH 08/10] Reduce calls to event handlers of pan and long-press gestures --- packages/components/src/draggable/index.native.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/components/src/draggable/index.native.js b/packages/components/src/draggable/index.native.js index 99566c4e57b73e..814c0ea3a7322e 100644 --- a/packages/components/src/draggable/index.native.js +++ b/packages/components/src/draggable/index.native.js @@ -39,6 +39,7 @@ const { Provider } = Context; */ const Draggable = ( { children, onDragEnd, onDragOver, onDragStart } ) => { const isDragging = useSharedValue( false ); + const isPanActive = useSharedValue( false ); const draggingId = useSharedValue( '' ); const panGestureRef = useRef(); @@ -84,7 +85,8 @@ const Draggable = ( { children, onDragEnd, onDragOver, onDragStart } ) => { initialPosition.y.value = y; } ) .onTouchesMove( ( _, state ) => { - if ( isDragging.value ) { + if ( ! isPanActive.value && isDragging.value ) { + isPanActive.value = true; state.activate(); } } ) @@ -97,6 +99,7 @@ const Draggable = ( { children, onDragEnd, onDragOver, onDragStart } ) => { } } ) .onEnd( () => { + isPanActive.value = false; isDragging.value = false; } ) .withRef( panGestureRef ) @@ -144,6 +147,10 @@ const DraggableTrigger = ( { const gestureHandler = useAnimatedGestureHandler( { onActive: () => { + if ( isDragging.value ) { + return; + } + isDragging.value = true; draggingId.value = id; if ( onLongPress ) { From b68268ccbe514fc5f9228d251c42f6cbe3db01ca Mon Sep 17 00:00:00 2001 From: Carlos Garcia Date: Tue, 19 Apr 2022 14:00:13 +0200 Subject: [PATCH 09/10] Prevent onDragEnd event to be called upon mounting --- packages/components/src/draggable/index.native.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/components/src/draggable/index.native.js b/packages/components/src/draggable/index.native.js index 814c0ea3a7322e..1b8ecb05a26ec4 100644 --- a/packages/components/src/draggable/index.native.js +++ b/packages/components/src/draggable/index.native.js @@ -55,7 +55,7 @@ const Draggable = ( { children, onDragEnd, onDragOver, onDragStart } ) => { useAnimatedReaction( () => isDragging.value, ( result, previous ) => { - if ( result === previous ) { + if ( result === previous || previous === null ) { return; } From 0a42d315306a86ba5248c022f34d6e7560ab6e6f Mon Sep 17 00:00:00 2001 From: Carlos Garcia Date: Wed, 20 Apr 2022 10:34:22 +0200 Subject: [PATCH 10/10] Add DEFAULT_IOS_LONG_PRESS_MIN_DURATION constant --- .../src/components/block-draggable/index.native.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/block-editor/src/components/block-draggable/index.native.js b/packages/block-editor/src/components/block-draggable/index.native.js index 439ce078865661..d0d4bbbf49eb90 100644 --- a/packages/block-editor/src/components/block-draggable/index.native.js +++ b/packages/block-editor/src/components/block-draggable/index.native.js @@ -34,6 +34,8 @@ const CHIP_OFFSET_TO_TOUCH_POSITION = 32; const BLOCK_OPACITY_ANIMATION_CONFIG = { duration: 350 }; const BLOCK_OPACITY_ANIMATION_DELAY = 250; const DEFAULT_LONG_PRESS_MIN_DURATION = 500; +const DEFAULT_IOS_LONG_PRESS_MIN_DURATION = + DEFAULT_LONG_PRESS_MIN_DURATION - 50; /** * Block draggable wrapper component @@ -310,7 +312,9 @@ const BlockDraggable = ( { clientId, children, enabled = true } ) => { // value prevents the long-press gesture from being // triggered in underneath elements. This is required to // prevent enabling text editing when dragging is available. - ios: canDragBlock ? 450 : DEFAULT_LONG_PRESS_MIN_DURATION, + ios: canDragBlock + ? DEFAULT_IOS_LONG_PRESS_MIN_DURATION + : DEFAULT_LONG_PRESS_MIN_DURATION, android: DEFAULT_LONG_PRESS_MIN_DURATION, } ) } >