@wordpress/block-editor
Version:
194 lines (177 loc) • 4.91 kB
JavaScript
/**
* External dependencies
*/
import { Platform } from 'react-native';
/**
* WordPress dependencies
*/
import { __ } from '@wordpress/i18n';
import { Picker, ToolbarButton, ToolbarGroup } from '@wordpress/components';
import { withInstanceId, compose } from '@wordpress/compose';
import { withSelect, withDispatch } from '@wordpress/data';
import { useCallback, useEffect, useRef, useState } from '@wordpress/element';
/**
* Internal dependencies
*/
import { getMoversSetup } from './mover-description';
import { store as blockEditorStore } from '../../store';
export const BLOCK_MOVER_DIRECTION_TOP = 'blockPageMoverOptions-moveToTop';
export const BLOCK_MOVER_DIRECTION_BOTTOM =
'blockPageMoverOptions-moveToBottom';
export const BlockMover = ( {
isFirst,
isLast,
canMove,
onMoveDown,
onMoveUp,
onLongMove,
firstIndex,
numberOfBlocks,
rootClientId,
isStackedHorizontally,
} ) => {
const pickerRef = useRef();
const [ shouldPresentPicker, setShouldPresentPicker ] = useState( false );
const [ blockPageMoverState, setBlockPageMoverState ] =
useState( undefined );
const showBlockPageMover = ( direction ) => () => {
if ( ! pickerRef.current ) {
setBlockPageMoverState( undefined );
return;
}
setBlockPageMoverState( direction );
setShouldPresentPicker( true );
};
// Ensure that the picker is only presented after state updates.
useEffect( () => {
if ( shouldPresentPicker ) {
pickerRef.current?.presentPicker();
setShouldPresentPicker( false );
}
}, [ shouldPresentPicker ] );
const {
description: {
backwardButtonHint,
forwardButtonHint,
firstBlockTitle,
lastBlockTitle,
},
icon: { backward: backwardButtonIcon, forward: forwardButtonIcon },
title: { backward: backwardButtonTitle, forward: forwardButtonTitle },
} = getMoversSetup( isStackedHorizontally, { firstIndex } );
const blockPageMoverOptions = [
{
icon: backwardButtonIcon,
label: __( 'Move to top' ),
value: BLOCK_MOVER_DIRECTION_TOP,
onSelect: () => {
onLongMove()( 0 );
},
},
{
icon: forwardButtonIcon,
label: __( 'Move to bottom' ),
value: BLOCK_MOVER_DIRECTION_BOTTOM,
onSelect: () => {
onLongMove()( numberOfBlocks );
},
},
].filter( ( el ) => el.value === blockPageMoverState );
const onPickerSelect = ( value ) => {
const option = blockPageMoverOptions.find(
( el ) => el.value === value
);
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;
}
return (
<ToolbarGroup>
<ToolbarButton
title={ ! isFirst ? backwardButtonTitle : firstBlockTitle }
isDisabled={ isFirst }
onClick={ onMoveUp }
onLongPress={ onLongPressMoveUp }
icon={ backwardButtonIcon }
extraProps={ { hint: backwardButtonHint } }
/>
<ToolbarButton
title={ ! isLast ? forwardButtonTitle : lastBlockTitle }
isDisabled={ isLast }
onClick={ onMoveDown }
onLongPress={ onLongPressMoveDown }
icon={ forwardButtonIcon }
extraProps={ {
hint: forwardButtonHint,
} }
/>
<Picker
ref={ pickerRef }
options={ blockPageMoverOptions }
onChange={ onPickerSelect }
title={ __( 'Change block position' ) }
leftAlign
hideCancelButton={ Platform.OS !== 'ios' }
/>
</ToolbarGroup>
);
};
export default compose(
withSelect( ( select, { clientIds } ) => {
const {
getBlockIndex,
canMoveBlocks,
getBlockRootClientId,
getBlockOrder,
} = select( blockEditorStore );
const normalizedClientIds = Array.isArray( clientIds )
? clientIds
: [ clientIds ];
const firstClientId = normalizedClientIds[ 0 ];
const rootClientId = getBlockRootClientId( firstClientId );
const blockOrder = getBlockOrder( rootClientId );
const firstIndex = getBlockIndex( firstClientId );
const lastIndex = getBlockIndex(
normalizedClientIds[ normalizedClientIds.length - 1 ]
);
return {
firstIndex,
numberOfBlocks: blockOrder.length - 1,
isFirst: firstIndex === 0,
isLast: lastIndex === blockOrder.length - 1,
canMove: canMoveBlocks( clientIds ),
rootClientId,
};
} ),
withDispatch( ( dispatch, { clientIds, rootClientId } ) => {
const { moveBlocksDown, moveBlocksUp, moveBlocksToPosition } =
dispatch( blockEditorStore );
return {
onMoveDown: ( ...args ) =>
moveBlocksDown( clientIds, rootClientId, ...args ),
onMoveUp: ( ...args ) =>
moveBlocksUp( clientIds, rootClientId, ...args ),
onLongMove:
( targetIndex ) =>
( ...args ) =>
moveBlocksToPosition(
clientIds,
rootClientId,
targetIndex,
...args
),
};
} ),
withInstanceId
)( BlockMover );