@wordpress/block-editor
Version:
142 lines (123 loc) • 3.64 kB
JavaScript
/**
* External dependencies
*/
import { Animated, Easing, View, Platform } from 'react-native';
/**
* WordPress dependencies
*/
import { ToolbarButton, ToolbarGroup } from '@wordpress/components';
import { useEffect, useState, useRef } from '@wordpress/element';
import { withSelect, withDispatch } from '@wordpress/data';
import { compose } from '@wordpress/compose';
import { __ } from '@wordpress/i18n';
/**
* Internal dependencies
*/
import styles from './styles.scss';
import NavigateUpSVG from './nav-up-icon';
import BlockSelectionButton from '../block-list/block-selection-button.native';
import { store as blockEditorStore } from '../../store';
const EASE_IN_DURATION = 250;
const EASE_OUT_DURATION = 80;
const TRANSLATION_RANGE = 8;
const FloatingToolbar = ( {
selectedClientId,
parentId,
showFloatingToolbar,
onNavigateUp,
isRTL,
} ) => {
const opacity = useRef( new Animated.Value( 0 ) ).current;
// Sustain old selection for proper block selection button rendering when exit animation is ongoing.
const [ previousSelection, setPreviousSelection ] = useState( {} );
useEffect( () => {
Animated.timing( opacity, {
toValue: showFloatingToolbar ? 1 : 0,
duration: showFloatingToolbar
? EASE_IN_DURATION
: EASE_OUT_DURATION,
easing: Easing.ease,
useNativeDriver: true,
} ).start();
}, [ showFloatingToolbar ] );
useEffect( () => {
if ( showFloatingToolbar ) {
setPreviousSelection( { clientId: selectedClientId, parentId } );
}
}, [ selectedClientId ] );
const translationRange =
( Platform.OS === 'android' ? -1 : 1 ) * TRANSLATION_RANGE;
const translation = opacity.interpolate( {
inputRange: [ 0, 1 ],
outputRange: [ translationRange, 0 ],
} );
const animationStyle = {
opacity,
transform: [ { translateY: translation } ],
};
const {
clientId: previousSelectedClientId,
parentId: previousSelectedParentId,
} = previousSelection;
const showPrevious = previousSelectedClientId && ! showFloatingToolbar;
const blockSelectionButtonClientId = showPrevious
? previousSelectedClientId
: selectedClientId;
const showNavUpButton =
!! parentId || ( showPrevious && !! previousSelectedParentId );
return (
!! opacity && (
<Animated.View
style={ [ styles.floatingToolbar, animationStyle ] }
pointerEvents={ showFloatingToolbar ? 'auto' : 'none' }
>
{ showNavUpButton && (
<ToolbarGroup passedStyle={ styles.toolbar }>
<ToolbarButton
title={ __( 'Navigate Up' ) }
onClick={
! showPrevious &&
( () => onNavigateUp( parentId ) )
}
icon={ <NavigateUpSVG isRTL={ isRTL } /> }
/>
<View style={ styles.pipe } />
</ToolbarGroup>
) }
<BlockSelectionButton
clientId={ blockSelectionButtonClientId }
/>
</Animated.View>
)
);
};
export default compose( [
withSelect( ( select ) => {
const {
getSelectedBlockClientId,
getBlockHierarchyRootClientId,
getBlockRootClientId,
getBlockCount,
getSettings,
} = select( blockEditorStore );
const selectedClientId = getSelectedBlockClientId();
if ( ! selectedClientId ) {
return;
}
const rootBlockId = getBlockHierarchyRootClientId( selectedClientId );
return {
selectedClientId,
showFloatingToolbar: !! getBlockCount( rootBlockId ),
parentId: getBlockRootClientId( selectedClientId ),
isRTL: getSettings().isRTL,
};
} ),
withDispatch( ( dispatch ) => {
const { selectBlock } = dispatch( blockEditorStore );
return {
onNavigateUp( clientId, initialPosition ) {
selectBlock( clientId, initialPosition );
},
};
} ),
] )( FloatingToolbar );