@wordpress/components
Version:
UI components for WordPress.
174 lines (156 loc) • 3.88 kB
JavaScript
/**
* External dependencies
*/
import { View, Easing } from 'react-native';
import { NavigationContainer, DefaultTheme } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
/**
* WordPress dependencies
*/
import {
useState,
useContext,
useMemo,
useCallback,
Children,
useRef,
cloneElement,
} from '@wordpress/element';
import { usePreferredColorSchemeStyle } from '@wordpress/compose';
/**
* Internal dependencies
*/
import { performLayoutAnimation } from '../../layout-animation';
import {
BottomSheetNavigationContext,
BottomSheetNavigationProvider,
} from './bottom-sheet-navigation-context';
import styles from './styles.scss';
const AnimationSpec = {
animation: 'timing',
config: {
duration: 200,
easing: Easing.ease,
},
};
const fadeConfig = ( { current } ) => {
return {
cardStyle: {
opacity: current.progress,
},
};
};
const options = {
transitionSpec: {
open: AnimationSpec,
close: AnimationSpec,
},
headerShown: false,
gestureEnabled: false,
cardStyleInterpolator: fadeConfig,
};
const ANIMATION_DURATION = 190;
function BottomSheetNavigationContainer( {
children,
animate,
main,
theme,
style,
} ) {
const Stack = useRef( createStackNavigator() ).current;
const context = useContext( BottomSheetNavigationContext );
const [ currentHeight, setCurrentHeight ] = useState(
context.currentHeight || 1
);
const backgroundStyle = usePreferredColorSchemeStyle(
styles.background,
styles.backgroundDark
);
const _theme = theme || {
...DefaultTheme,
colors: {
...DefaultTheme.colors,
background: backgroundStyle.backgroundColor,
},
};
const setHeight = useCallback(
( height ) => {
// The screen is fullHeight.
if (
typeof height === 'string' &&
typeof height !== typeof currentHeight
) {
performLayoutAnimation( ANIMATION_DURATION );
setCurrentHeight( height );
return;
}
if (
height > 1 &&
Math.round( height ) !== Math.round( currentHeight )
) {
if ( currentHeight === 1 ) {
setCurrentHeight( height );
} else if ( animate ) {
performLayoutAnimation( ANIMATION_DURATION );
setCurrentHeight( height );
} else {
setCurrentHeight( height );
}
}
},
// Disable reason: deferring this refactor to the native team.
// see https://github.com/WordPress/gutenberg/pull/41166
// eslint-disable-next-line react-hooks/exhaustive-deps
[ currentHeight ]
);
const screens = useMemo( () => {
return Children.map( children, ( child ) => {
let screen = child;
const { name, ...otherProps } = child.props;
if ( ! main ) {
screen = cloneElement( child, {
...child.props,
isNested: true,
} );
}
return (
<Stack.Screen
name={ name }
{ ...otherProps }
children={ () => screen }
/>
);
} );
// Disable reason: deferring this refactor to the native team.
// see https://github.com/WordPress/gutenberg/pull/41166
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [ children ] );
return useMemo( () => {
return (
<View style={ [ style, { height: currentHeight } ] }>
<BottomSheetNavigationProvider
value={ {
setHeight,
currentHeight,
} }
>
{ main ? (
<NavigationContainer theme={ _theme }>
<Stack.Navigator screenOptions={ options }>
{ screens }
</Stack.Navigator>
</NavigationContainer>
) : (
<Stack.Navigator screenOptions={ options }>
{ screens }
</Stack.Navigator>
) }
</BottomSheetNavigationProvider>
</View>
);
// Disable reason: deferring this refactor to the native team.
// see https://github.com/WordPress/gutenberg/pull/41166
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [ currentHeight, _theme ] );
}
export default BottomSheetNavigationContainer;