@wordpress/block-editor
Version:
153 lines (134 loc) • 3.51 kB
JavaScript
/**
* External dependencies
*/
import { Animated, View } from 'react-native';
/**
* WordPress dependencies
*/
import {
useCallback,
useEffect,
useMemo,
useRef,
useState,
} from '@wordpress/element';
import { __ } from '@wordpress/i18n';
import { SegmentedControl } from '@wordpress/components';
/**
* Internal dependencies
*/
import BlockTypesTab from './block-types-tab';
import ReusableBlocksTab from './reusable-blocks-tab';
import styles from './style.scss';
const TAB_ANIMATION_DURATION = 250;
function InserterTabs( {
listProps,
onSelect,
rootClientId,
showReusableBlocks,
tabIndex,
} ) {
const tabAnimation = useRef( new Animated.Value( 0 ) ).current;
const lastScrollEvents = useRef( [] ).current;
const [ wrapperWidth, setWrapperWidth ] = useState( 0 );
function onScroll( event ) {
lastScrollEvents[ tabIndex ] = event.nativeEvent;
listProps.onScroll( event );
}
const onWrapperLayout = useCallback(
( { nativeEvent } ) => {
setWrapperWidth( nativeEvent.layout.width );
},
[ setWrapperWidth ]
);
useEffect( () => {
Animated.timing( tabAnimation, {
duration: TAB_ANIMATION_DURATION,
toValue: tabIndex,
useNativeDriver: true,
} ).start();
// Notify upstream with the last scroll event of the current tab.
const lastScrollEvent = lastScrollEvents[ tabIndex ];
if ( lastScrollEvent ) {
listProps.onScroll( { nativeEvent: lastScrollEvent } );
}
}, [ tabIndex ] );
const { tabs, tabKeys } = useMemo( () => {
const filteredTabs = InserterTabs.getTabs().filter(
( { name } ) => showReusableBlocks || name !== 'reusable'
);
return {
tabs: filteredTabs,
tabKeys: [ ...filteredTabs.keys() ],
};
}, [ showReusableBlocks ] );
const translateX = useMemo(
() =>
tabKeys.length > 1
? tabAnimation.interpolate( {
inputRange: tabKeys,
outputRange: tabKeys.map(
( key ) => key * -wrapperWidth
),
} )
: tabAnimation,
[ tabAnimation, tabKeys, wrapperWidth ]
);
const containerStyle = [
styles[ 'inserter-tabs__container' ],
{
width: wrapperWidth * tabKeys.length,
transform: [ { translateX } ],
},
];
return (
<View
style={ styles[ 'inserter-tabs__wrapper' ] }
onLayout={ onWrapperLayout }
>
<Animated.View style={ containerStyle }>
{ tabs.map( ( { component: TabComponent }, index ) => (
<View key={ `tab-${ index }` }>
<TabComponent
rootClientId={ rootClientId }
onSelect={ onSelect }
listProps={ { ...listProps, onScroll } }
/>
</View>
) ) }
</Animated.View>
</View>
);
}
function TabsControl( { onChangeTab, showReusableBlocks } ) {
const tabs = InserterTabs.getTabs();
const segments = useMemo( () => {
const filteredTabs = tabs.filter(
( { name } ) => showReusableBlocks || name !== 'reusable'
);
return filteredTabs.map( ( { title } ) => title );
}, [ showReusableBlocks ] );
const segmentHandler = useCallback(
( selectedTab ) => {
const tabTitles = tabs.map( ( { title } ) => title );
onChangeTab( tabTitles.indexOf( selectedTab ) );
},
[ onChangeTab ]
);
return segments.length > 1 ? (
<SegmentedControl
segments={ segments }
segmentHandler={ segmentHandler }
/>
) : null;
}
InserterTabs.Control = TabsControl;
InserterTabs.getTabs = () => [
{ name: 'blocks', title: __( 'Blocks' ), component: BlockTypesTab },
{
name: 'reusable',
title: __( 'Synced patterns' ),
component: ReusableBlocksTab,
},
];
export default InserterTabs;