feat: use modal presentation style for modals on iOS by default

This commit is contained in:
Satyajit Sahoo
2020-11-12 01:39:42 +01:00
parent 0c55803b32
commit 8a63f193bf
8 changed files with 56 additions and 35 deletions

View File

@@ -116,6 +116,6 @@ export const DefaultTransition = Platform.select({
* Default modal transition for the current platform.
*/
export const ModalTransition = Platform.select({
ios: ModalSlideFromBottomIOS,
ios: ModalPresentationIOS,
default: DefaultTransition,
});

View File

@@ -0,0 +1,5 @@
import * as React from 'react';
const ModalPresentationContext = React.createContext(false);
export default ModalPresentationContext;

View File

@@ -1,20 +1,21 @@
import * as React from 'react';
import { StackActions } from '@react-navigation/native';
import { StackActions, useNavigationState } from '@react-navigation/native';
import HeaderSegment from './HeaderSegment';
import HeaderTitle from './HeaderTitle';
import HeaderShownContext from '../../utils/HeaderShownContext';
import ModalPresentationContext from '../../utils/ModalPresentationContext';
import debounce from '../../utils/debounce';
import type { StackHeaderProps, StackHeaderTitleProps } from '../../types';
export default React.memo(function Header(props: StackHeaderProps) {
const {
scene,
previous,
layout,
insets,
navigation,
styleInterpolator,
} = props;
export default React.memo(function Header({
scene,
previous,
layout,
insets,
navigation,
styleInterpolator,
}: StackHeaderProps) {
const { options } = scene.descriptor;
const title =
typeof options.headerTitle !== 'function' &&
@@ -54,6 +55,15 @@ export default React.memo(function Header(props: StackHeaderProps) {
[navigation, scene.route.key]
);
const isModal = React.useContext(ModalPresentationContext);
const isParentHeaderShown = React.useContext(HeaderShownContext);
const isFirstRouteInParent = useNavigationState(
(state) => state.routes[0].key === scene.route.key
);
const statusBarHeight =
(isModal && !isFirstRouteInParent) || isParentHeaderShown ? 0 : insets.top;
return (
<HeaderSegment
{...options}
@@ -67,6 +77,7 @@ export default React.memo(function Header(props: StackHeaderProps) {
? (props: StackHeaderTitleProps) => <HeaderTitle {...props} />
: options.headerTitle
}
headerStatusBarHeight={statusBarHeight}
onGoBack={previous ? goBack : undefined}
styleInterpolator={styleInterpolator}
/>

View File

@@ -11,7 +11,6 @@ import type { EdgeInsets } from 'react-native-safe-area-context';
import type { Route } from '@react-navigation/native';
import HeaderBackButton from './HeaderBackButton';
import HeaderBackground from './HeaderBackground';
import HeaderShownContext from '../../utils/HeaderShownContext';
import memoize from '../../utils/memoize';
import type {
Layout,
@@ -22,8 +21,12 @@ import type {
Scene,
} from '../../types';
type Props = StackHeaderOptions & {
type Props = Omit<
StackHeaderOptions,
'headerTitle' | 'headerStatusBarHeight'
> & {
headerTitle: (props: StackHeaderTitleProps) => React.ReactNode;
headerStatusBarHeight: number;
layout: Layout;
insets: EdgeInsets;
onGoBack?: () => void;
@@ -81,8 +84,6 @@ export default function HeaderSegment(props: Props) {
undefined
);
const isParentHeaderShown = React.useContext(HeaderShownContext);
const handleTitleLayout = (e: LayoutChangeEvent) => {
const { height, width } = e.nativeEvent.layout;
@@ -171,7 +172,7 @@ export default function HeaderSegment(props: Props) {
headerRightContainerStyle: rightContainerStyle,
headerTitleContainerStyle: titleContainerStyle,
headerStyle: customHeaderStyle,
headerStatusBarHeight = isParentHeaderShown ? 0 : insets.top,
headerStatusBarHeight,
styleInterpolator,
} = props;

View File

@@ -90,7 +90,6 @@ const hasOpacityStyle = (style: any) => {
export default class Card extends React.Component<Props> {
static defaultProps = {
overlayEnabled: Platform.OS !== 'ios',
shadowEnabled: true,
gestureEnabled: true,
gestureVelocityImpact: GESTURE_VELOCITY_IMPACT,

View File

@@ -3,9 +3,11 @@ import { Animated, View, StyleSheet, StyleProp, ViewStyle } from 'react-native';
import { Route, useTheme } from '@react-navigation/native';
import type { Props as HeaderContainerProps } from '../Header/HeaderContainer';
import Card from './Card';
import { forModalPresentationIOS } from '../../TransitionConfigs/CardStyleInterpolators';
import HeaderHeightContext from '../../utils/HeaderHeightContext';
import HeaderShownContext from '../../utils/HeaderShownContext';
import PreviousSceneContext from '../../utils/PreviousSceneContext';
import ModalPresentationContext from '../../utils/ModalPresentationContext';
import type {
Scene,
Layout,
@@ -29,7 +31,7 @@ type Props = TransitionPreset & {
cardOverlay?: (props: {
style: Animated.WithAnimatedValue<StyleProp<ViewStyle>>;
}) => React.ReactNode;
cardOverlayEnabled?: boolean;
cardOverlayEnabled: boolean;
cardShadowEnabled?: boolean;
cardStyle?: StyleProp<ViewStyle>;
getPreviousScene: (props: {
@@ -184,6 +186,7 @@ function CardContainer({
}, [pointerEvents, scene.progress.next]);
const previousScene = getPreviousScene({ route: scene.route });
const isModalPresentation = cardStyleInterpolator === forModalPresentationIOS;
return (
<Card
@@ -236,8 +239,9 @@ function CardContainer({
</HeaderShownContext.Provider>
</PreviousSceneContext.Provider>
</View>
{headerMode !== 'float'
? renderHeader({
{headerMode !== 'float' ? (
<ModalPresentationContext.Provider value={isModalPresentation}>
{renderHeader({
mode: 'screen',
layout,
insets,
@@ -247,8 +251,9 @@ function CardContainer({
gestureDirection,
styleInterpolator: headerStyleInterpolator,
onContentHeightChange: onHeaderHeightChange,
})
: null}
})}
</ModalPresentationContext.Provider>
) : null}
</View>
</Card>
);

View File

@@ -4,6 +4,7 @@ import {
StyleSheet,
LayoutChangeEvent,
Dimensions,
Platform,
} from 'react-native';
import type { EdgeInsets } from 'react-native-safe-area-context';
import type {
@@ -542,7 +543,7 @@ export default class CardStack extends React.Component<Props, State> {
headerShown = true,
headerTransparent,
cardShadowEnabled,
cardOverlayEnabled,
cardOverlayEnabled = Platform.OS !== 'ios' || mode === 'modal',
cardOverlay,
cardStyle,
animationEnabled,