diff --git a/example/src/SimpleStack.tsx b/example/src/SimpleStack.tsx
index e1148ae8..e48029ff 100644
--- a/example/src/SimpleStack.tsx
+++ b/example/src/SimpleStack.tsx
@@ -64,7 +64,7 @@ class ListScreen extends React.Component {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
- backgroundColor: '#fff',
+ // backgroundColor: '#fff',
}}
>
List Screen
@@ -96,7 +96,7 @@ class DetailsScreen extends React.Component {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
- backgroundColor: '#fff',
+ // backgroundColor: '#fff',
}}
>
Details Screen
@@ -119,7 +119,7 @@ class HeaderlessScreen extends React.Component {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
- backgroundColor: '#fff',
+ // backgroundColor: '#fff',
}}
>
Headerless Screen
diff --git a/packages/stack/package.json b/packages/stack/package.json
index 52f7c5ec..76eafeae 100644
--- a/packages/stack/package.json
+++ b/packages/stack/package.json
@@ -45,7 +45,7 @@
"devDependencies": {
"@react-native-community/bob": "^0.10.0",
"@react-native-community/masked-view": "^0.1.7",
- "@react-navigation/stack": "^5.4.2",
+ "@react-navigation/stack": "^5.5.1",
"@types/color": "^3.0.1",
"@types/react": "^16.9.23",
"@types/react-native": "^0.61.22",
diff --git a/packages/stack/scripts/stack.patch b/packages/stack/scripts/stack.patch
index 797a0472..b1911814 100644
--- a/packages/stack/scripts/stack.patch
+++ b/packages/stack/scripts/stack.patch
@@ -1,6 +1,6 @@
diff -Naur ../../node_modules/@react-navigation/stack/src/index.tsx src/vendor/index.tsx
---- ../../node_modules/@react-navigation/stack/src/index.tsx 2020-06-06 02:18:25.000000000 +0200
-+++ src/vendor/index.tsx 2020-06-06 02:22:30.000000000 +0200
+--- ../../node_modules/@react-navigation/stack/src/index.tsx 2020-06-08 11:22:56.000000000 +0200
++++ src/vendor/index.tsx 2020-06-08 11:23:27.000000000 +0200
@@ -3,11 +3,6 @@
import * as TransitionSpecs from './TransitionConfigs/TransitionSpecs';
import * as TransitionPresets from './TransitionConfigs/TransitionPresets';
@@ -28,7 +28,7 @@ diff -Naur ../../node_modules/@react-navigation/stack/src/index.tsx src/vendor/i
StackHeaderLeftButtonProps,
StackHeaderTitleProps,
diff -Naur ../../node_modules/@react-navigation/stack/src/navigators/createStackNavigator.tsx src/vendor/navigators/createStackNavigator.tsx
---- ../../node_modules/@react-navigation/stack/src/navigators/createStackNavigator.tsx 2020-06-06 02:18:25.000000000 +0200
+--- ../../node_modules/@react-navigation/stack/src/navigators/createStackNavigator.tsx 2020-06-08 11:22:56.000000000 +0200
+++ src/vendor/navigators/createStackNavigator.tsx 1970-01-01 01:00:00.000000000 +0100
@@ -1,96 +0,0 @@
-import * as React from 'react';
@@ -128,8 +128,8 @@ diff -Naur ../../node_modules/@react-navigation/stack/src/navigators/createStack
- typeof StackNavigator
->(StackNavigator);
diff -Naur ../../node_modules/@react-navigation/stack/src/types.tsx src/vendor/types.tsx
---- ../../node_modules/@react-navigation/stack/src/types.tsx 2020-06-06 02:18:25.000000000 +0200
-+++ src/vendor/types.tsx 2020-06-06 02:22:30.000000000 +0200
+--- ../../node_modules/@react-navigation/stack/src/types.tsx 2020-06-08 11:22:56.000000000 +0200
++++ src/vendor/types.tsx 2020-06-08 11:23:27.000000000 +0200
@@ -8,15 +8,28 @@
} from 'react-native';
import { EdgeInsets } from 'react-native-safe-area-context';
@@ -218,7 +218,7 @@ diff -Naur ../../node_modules/@react-navigation/stack/src/types.tsx src/vendor/t
};
export type Layout = { width: number; height: number };
-@@ -227,24 +239,27 @@
+@@ -228,24 +240,27 @@
/**
* Navigation prop for the header.
*/
@@ -252,7 +252,7 @@ diff -Naur ../../node_modules/@react-navigation/stack/src/types.tsx src/vendor/t
export type StackNavigationOptions = StackHeaderOptions &
Partial & {
/**
-@@ -329,6 +344,8 @@
+@@ -330,6 +345,8 @@
bottom?: number;
left?: number;
};
@@ -262,8 +262,8 @@ diff -Naur ../../node_modules/@react-navigation/stack/src/types.tsx src/vendor/t
export type StackNavigationConfig = {
diff -Naur ../../node_modules/@react-navigation/stack/src/views/Header/Header.tsx src/vendor/views/Header/Header.tsx
---- ../../node_modules/@react-navigation/stack/src/views/Header/Header.tsx 2020-06-06 02:18:25.000000000 +0200
-+++ src/vendor/views/Header/Header.tsx 2020-06-06 02:22:30.000000000 +0200
+--- ../../node_modules/@react-navigation/stack/src/views/Header/Header.tsx 2020-06-08 11:22:56.000000000 +0200
++++ src/vendor/views/Header/Header.tsx 2020-06-08 11:23:27.000000000 +0200
@@ -1,12 +1,14 @@
import * as React from 'react';
-import { StackActions } from '@react-navigation/native';
@@ -344,8 +344,8 @@ diff -Naur ../../node_modules/@react-navigation/stack/src/views/Header/Header.ts
+
+export default Header;
diff -Naur ../../node_modules/@react-navigation/stack/src/views/Header/HeaderBackButton.tsx src/vendor/views/Header/HeaderBackButton.tsx
---- ../../node_modules/@react-navigation/stack/src/views/Header/HeaderBackButton.tsx 2020-06-06 02:18:25.000000000 +0200
-+++ src/vendor/views/Header/HeaderBackButton.tsx 2020-06-06 02:22:30.000000000 +0200
+--- ../../node_modules/@react-navigation/stack/src/views/Header/HeaderBackButton.tsx 2020-06-08 11:22:56.000000000 +0200
++++ src/vendor/views/Header/HeaderBackButton.tsx 2020-06-08 11:23:27.000000000 +0200
@@ -8,9 +8,9 @@
StyleSheet,
LayoutChangeEvent,
@@ -358,8 +358,8 @@ diff -Naur ../../node_modules/@react-navigation/stack/src/views/Header/HeaderBac
type Props = StackHeaderLeftButtonProps;
diff -Naur ../../node_modules/@react-navigation/stack/src/views/Header/HeaderBackground.tsx src/vendor/views/Header/HeaderBackground.tsx
---- ../../node_modules/@react-navigation/stack/src/views/Header/HeaderBackground.tsx 2020-06-06 02:18:25.000000000 +0200
-+++ src/vendor/views/Header/HeaderBackground.tsx 2020-06-06 02:23:41.000000000 +0200
+--- ../../node_modules/@react-navigation/stack/src/views/Header/HeaderBackground.tsx 2020-06-08 11:22:56.000000000 +0200
++++ src/vendor/views/Header/HeaderBackground.tsx 2020-06-08 11:23:27.000000000 +0200
@@ -7,7 +7,7 @@
StyleProp,
ViewStyle,
@@ -370,8 +370,8 @@ diff -Naur ../../node_modules/@react-navigation/stack/src/views/Header/HeaderBac
type Props = ViewProps & {
style?: Animated.WithAnimatedValue>;
diff -Naur ../../node_modules/@react-navigation/stack/src/views/Header/HeaderContainer.tsx src/vendor/views/Header/HeaderContainer.tsx
---- ../../node_modules/@react-navigation/stack/src/views/Header/HeaderContainer.tsx 2020-06-06 02:18:25.000000000 +0200
-+++ src/vendor/views/Header/HeaderContainer.tsx 2020-06-06 02:22:30.000000000 +0200
+--- ../../node_modules/@react-navigation/stack/src/views/Header/HeaderContainer.tsx 2020-06-08 11:22:56.000000000 +0200
++++ src/vendor/views/Header/HeaderContainer.tsx 2020-06-08 11:23:27.000000000 +0200
@@ -1,11 +1,6 @@
import * as React from 'react';
import { View, StyleSheet, StyleProp, ViewStyle } from 'react-native';
@@ -385,15 +385,15 @@ diff -Naur ../../node_modules/@react-navigation/stack/src/views/Header/HeaderCon
import { EdgeInsets } from 'react-native-safe-area-context';
import Header from './Header';
-@@ -16,6 +11,7 @@
- forSlideRight,
+@@ -17,6 +12,7 @@
} from '../../TransitionConfigs/HeaderStyleInterpolators';
+ import HeaderShownContext from '../../utils/HeaderShownContext';
import {
+ Route,
Layout,
Scene,
StackHeaderStyleInterpolator,
-@@ -99,9 +95,7 @@
+@@ -117,9 +113,7 @@
insets,
scene,
previous,
@@ -404,7 +404,7 @@ diff -Naur ../../node_modules/@react-navigation/stack/src/views/Header/HeaderCon
styleInterpolator:
mode === 'float'
? isHeaderStatic
-@@ -120,7 +114,7 @@
+@@ -138,7 +132,7 @@
key={scene.route.key}
value={scene.descriptor.navigation}
>
@@ -413,9 +413,9 @@ diff -Naur ../../node_modules/@react-navigation/stack/src/views/Header/HeaderCon
+ {header !== undefined ? header(props) : }
-
+ >
@@ -423,8 +423,8 @@ diff -Naur ../../node_modules/@react-navigation/stack/src/views/Header/HeaderCon
);
})}
diff -Naur ../../node_modules/@react-navigation/stack/src/views/Header/HeaderSegment.tsx src/vendor/views/Header/HeaderSegment.tsx
---- ../../node_modules/@react-navigation/stack/src/views/Header/HeaderSegment.tsx 2020-06-06 02:18:25.000000000 +0200
-+++ src/vendor/views/Header/HeaderSegment.tsx 2020-06-06 02:22:30.000000000 +0200
+--- ../../node_modules/@react-navigation/stack/src/views/Header/HeaderSegment.tsx 2020-06-08 11:22:56.000000000 +0200
++++ src/vendor/views/Header/HeaderSegment.tsx 2020-06-08 11:23:27.000000000 +0200
@@ -8,7 +8,7 @@
ViewStyle,
} from 'react-native';
@@ -444,8 +444,8 @@ diff -Naur ../../node_modules/@react-navigation/stack/src/views/Header/HeaderSeg
};
diff -Naur ../../node_modules/@react-navigation/stack/src/views/Header/HeaderTitle.tsx src/vendor/views/Header/HeaderTitle.tsx
---- ../../node_modules/@react-navigation/stack/src/views/Header/HeaderTitle.tsx 2020-06-06 02:18:25.000000000 +0200
-+++ src/vendor/views/Header/HeaderTitle.tsx 2020-06-06 02:22:30.000000000 +0200
+--- ../../node_modules/@react-navigation/stack/src/views/Header/HeaderTitle.tsx 2020-06-08 11:22:56.000000000 +0200
++++ src/vendor/views/Header/HeaderTitle.tsx 2020-06-08 11:23:27.000000000 +0200
@@ -1,6 +1,6 @@
import * as React from 'react';
import { Animated, StyleSheet, Platform } from 'react-native';
@@ -455,8 +455,8 @@ diff -Naur ../../node_modules/@react-navigation/stack/src/views/Header/HeaderTit
type Props = Omit, 'key'> & {
tintColor?: string;
diff -Naur ../../node_modules/@react-navigation/stack/src/views/Stack/Card.tsx src/vendor/views/Stack/Card.tsx
---- ../../node_modules/@react-navigation/stack/src/views/Stack/Card.tsx 2020-06-06 02:18:25.000000000 +0200
-+++ src/vendor/views/Stack/Card.tsx 2020-06-06 02:22:30.000000000 +0200
+--- ../../node_modules/@react-navigation/stack/src/views/Stack/Card.tsx 2020-06-08 11:22:56.000000000 +0200
++++ src/vendor/views/Stack/Card.tsx 2020-06-08 11:23:27.000000000 +0200
@@ -146,7 +146,7 @@
private interactionHandle: number | undefined;
@@ -467,15 +467,16 @@ diff -Naur ../../node_modules/@react-navigation/stack/src/views/Stack/Card.tsx s
private animate = ({
closing,
diff -Naur ../../node_modules/@react-navigation/stack/src/views/Stack/CardContainer.tsx src/vendor/views/Stack/CardContainer.tsx
---- ../../node_modules/@react-navigation/stack/src/views/Stack/CardContainer.tsx 2020-06-06 02:18:25.000000000 +0200
-+++ src/vendor/views/Stack/CardContainer.tsx 2020-06-06 02:22:30.000000000 +0200
-@@ -1,10 +1,11 @@
+--- ../../node_modules/@react-navigation/stack/src/views/Stack/CardContainer.tsx 2020-06-08 11:22:56.000000000 +0200
++++ src/vendor/views/Stack/CardContainer.tsx 2020-06-08 11:23:27.000000000 +0200
+@@ -1,11 +1,12 @@
import * as React from 'react';
import { Animated, View, StyleSheet, StyleProp, ViewStyle } from 'react-native';
-import { Route, useTheme } from '@react-navigation/native';
import { Props as HeaderContainerProps } from '../Header/HeaderContainer';
import Card from './Card';
import HeaderHeightContext from '../../utils/HeaderHeightContext';
+ import HeaderShownContext from '../../utils/HeaderShownContext';
+import useTheme from '../../../utils/useTheme';
import {
+ Route,
@@ -483,8 +484,8 @@ diff -Naur ../../node_modules/@react-navigation/stack/src/views/Stack/CardContai
Layout,
StackHeaderMode,
diff -Naur ../../node_modules/@react-navigation/stack/src/views/Stack/CardStack.tsx src/vendor/views/Stack/CardStack.tsx
---- ../../node_modules/@react-navigation/stack/src/views/Stack/CardStack.tsx 2020-06-06 02:18:25.000000000 +0200
-+++ src/vendor/views/Stack/CardStack.tsx 2020-06-06 02:22:30.000000000 +0200
+--- ../../node_modules/@react-navigation/stack/src/views/Stack/CardStack.tsx 2020-06-08 11:22:56.000000000 +0200
++++ src/vendor/views/Stack/CardStack.tsx 2020-06-08 11:23:27.000000000 +0200
@@ -7,7 +7,7 @@
Platform,
} from 'react-native';
@@ -494,8 +495,8 @@ diff -Naur ../../node_modules/@react-navigation/stack/src/views/Stack/CardStack.
import { MaybeScreenContainer, MaybeScreen } from '../Screens';
import { getDefaultHeaderHeight } from '../Header/HeaderSegment';
-@@ -21,6 +21,7 @@
- import { forNoAnimation as forNoAnimationCard } from '../../TransitionConfigs/CardStyleInterpolators';
+@@ -22,6 +22,7 @@
+ import HeaderShownContext from '../../utils/HeaderShownContext';
import getDistanceForDirection from '../../utils/getDistanceForDirection';
import {
+ Route,
@@ -503,8 +504,8 @@ diff -Naur ../../node_modules/@react-navigation/stack/src/views/Stack/CardStack.
StackHeaderMode,
StackCardMode,
diff -Naur ../../node_modules/@react-navigation/stack/src/views/Stack/StackView.tsx src/vendor/views/Stack/StackView.tsx
---- ../../node_modules/@react-navigation/stack/src/views/Stack/StackView.tsx 2020-06-06 02:18:25.000000000 +0200
-+++ src/vendor/views/Stack/StackView.tsx 2020-06-06 02:22:30.000000000 +0200
+--- ../../node_modules/@react-navigation/stack/src/views/Stack/StackView.tsx 2020-06-08 11:22:56.000000000 +0200
++++ src/vendor/views/Stack/StackView.tsx 2020-06-08 11:23:40.000000000 +0200
@@ -2,11 +2,11 @@
import { View, Platform, StyleSheet } from 'react-native';
import { SafeAreaConsumer, EdgeInsets } from 'react-native-safe-area-context';
@@ -548,7 +549,7 @@ diff -Naur ../../node_modules/@react-navigation/stack/src/views/Stack/StackView.
}
return false;
-@@ -321,24 +325,47 @@
+@@ -321,26 +325,49 @@
return null;
}
@@ -584,22 +585,24 @@ diff -Naur ../../node_modules/@react-navigation/stack/src/views/Stack/StackView.
+
private handleOpenRoute = ({ route }: { route: Route }) => {
const { state, navigation } = this.props;
+ const { closingRouteKeys, replacingRouteKeys } = this.state;
+ this.handleTransitionComplete();
+
if (
- this.state.replacingRouteKeys.every((key) => key !== route.key) &&
+ closingRouteKeys.some((key) => key === route.key) &&
+ replacingRouteKeys.every((key) => key !== route.key) &&
- state.routeNames.includes(route.name) &&
!state.routes.some((r) => r.key === route.key)
) {
- // If route isn't present in current state, assume that a close animation was cancelled
+ // If route isn't present in current state, but was closing, assume that a close animation was cancelled
// So we need to add this route back to the state
- navigation.navigate(route);
+ navigation.dispatch(NavigationActions.navigate(route));
} else {
this.setState((state) => ({
routes: state.replacingRouteKeys.length
-@@ -364,12 +391,11 @@
+@@ -366,12 +393,11 @@
// If a route exists in state, trigger a pop
// This will happen in when the route was closed from the card component
// e.g. When the close animation triggered from a gesture ends
@@ -616,7 +619,7 @@ diff -Naur ../../node_modules/@react-navigation/stack/src/views/Stack/StackView.
// We need to clean up any state tracking the route and pop it immediately
this.setState((state) => ({
routes: state.routes.filter((r) => r.key !== route.key),
-@@ -386,26 +412,29 @@
+@@ -388,26 +414,29 @@
private handleTransitionStart = (
{ route }: { route: Route },
closing: boolean
@@ -658,8 +661,8 @@ diff -Naur ../../node_modules/@react-navigation/stack/src/views/Stack/StackView.
navigation,
keyboardHandlingEnabled,
mode = 'card',
-@@ -423,7 +452,7 @@
- mode === 'card' && Platform.OS === 'ios' ? 'float' : 'screen';
+@@ -425,7 +454,7 @@
+ } = this.state;
return (
-
@@ -667,7 +670,7 @@ diff -Naur ../../node_modules/@react-navigation/stack/src/views/Stack/StackView.
-@@ -456,7 +485,7 @@
+@@ -458,7 +487,7 @@
diff --git a/packages/stack/src/navigators/__tests__/__snapshots__/NestedNavigator.test.tsx.snap b/packages/stack/src/navigators/__tests__/__snapshots__/NestedNavigator.test.tsx.snap
index 91d288f1..a9cad75d 100644
--- a/packages/stack/src/navigators/__tests__/__snapshots__/NestedNavigator.test.tsx.snap
+++ b/packages/stack/src/navigators/__tests__/__snapshots__/NestedNavigator.test.tsx.snap
@@ -10,6 +10,14 @@ exports[`Nested navigators renders succesfully as direct child 1`] = `
>
@@ -267,106 +276,6 @@ exports[`Nested navigators renders succesfully as direct child 1`] = `
}
}
>
-
-
-
-
-
-
-
-
-
-
- Home
-
-
-
-
-
-
@@ -527,6 +438,22 @@ exports[`Nested navigators renders succesfully as direct child 1`] = `
+
diff --git a/packages/stack/src/navigators/__tests__/__snapshots__/StackNavigator.test.tsx.snap b/packages/stack/src/navigators/__tests__/__snapshots__/StackNavigator.test.tsx.snap
index 3848fde8..7b888f59 100644
--- a/packages/stack/src/navigators/__tests__/__snapshots__/StackNavigator.test.tsx.snap
+++ b/packages/stack/src/navigators/__tests__/__snapshots__/StackNavigator.test.tsx.snap
@@ -10,6 +10,14 @@ exports[`StackNavigator applies correct values when headerRight is present 1`] =
>
@@ -298,6 +307,14 @@ exports[`StackNavigator renders successfully 1`] = `
>
diff --git a/packages/stack/src/vendor/types.tsx b/packages/stack/src/vendor/types.tsx
index 0d187d27..5c2e4311 100644
--- a/packages/stack/src/vendor/types.tsx
+++ b/packages/stack/src/vendor/types.tsx
@@ -145,7 +145,8 @@ export type StackHeaderOptions = {
*/
headerBackAllowFontScaling?: boolean;
/**
- * Title string used by the back button on iOS, or `null` to disable label. Defaults to the previous scene's `headerTitle`.
+ * Title string used by the back button on iOS. Defaults to the previous scene's `headerTitle`.
+ * Use `headerBackTitleVisible: false` to hide it.
*/
headerBackTitle?: string;
/**
diff --git a/packages/stack/src/vendor/utils/HeaderShownContext.tsx b/packages/stack/src/vendor/utils/HeaderShownContext.tsx
new file mode 100644
index 00000000..be5b7a57
--- /dev/null
+++ b/packages/stack/src/vendor/utils/HeaderShownContext.tsx
@@ -0,0 +1,5 @@
+import * as React from 'react';
+
+const HeaderShownContext = React.createContext(false);
+
+export default HeaderShownContext;
diff --git a/packages/stack/src/vendor/views/GestureHandler.native.tsx b/packages/stack/src/vendor/views/GestureHandler.native.tsx
index e2c91f99..c00d675e 100644
--- a/packages/stack/src/vendor/views/GestureHandler.native.tsx
+++ b/packages/stack/src/vendor/views/GestureHandler.native.tsx
@@ -10,7 +10,7 @@ export function PanGestureHandler(props: PanGestureHandlerProperties) {
return (
-
+
);
}
diff --git a/packages/stack/src/vendor/views/Header/HeaderContainer.tsx b/packages/stack/src/vendor/views/Header/HeaderContainer.tsx
index 0fb02097..6303fea8 100644
--- a/packages/stack/src/vendor/views/Header/HeaderContainer.tsx
+++ b/packages/stack/src/vendor/views/Header/HeaderContainer.tsx
@@ -10,6 +10,7 @@ import {
forNoAnimation,
forSlideRight,
} from '../../TransitionConfigs/HeaderStyleInterpolators';
+import HeaderShownContext from '../../utils/HeaderShownContext';
import {
Route,
Layout,
@@ -50,6 +51,7 @@ export default function HeaderContainer({
style,
}: Props) {
const focusedRoute = getFocusedRoute();
+ const isParentHeaderShown = React.useContext(HeaderShownContext);
return (
@@ -58,7 +60,16 @@ export default function HeaderContainer({
return null;
}
- const { options } = scene.descriptor;
+ const {
+ header,
+ headerShown = isParentHeaderShown === false,
+ headerTransparent,
+ } = scene.descriptor.options || {};
+
+ if (!headerShown) {
+ return null;
+ }
+
const isFocused = focusedRoute.key === scene.route.key;
const previousRoute = getPreviousRoute({ route: scene.route });
@@ -81,13 +92,20 @@ export default function HeaderContainer({
// This makes the header look like it's moving with the screen
const previousScene = self[i - 1];
const nextScene = self[i + 1];
+
+ const {
+ headerShown: previousHeaderShown = isParentHeaderShown === false,
+ } = previousScene?.descriptor.options || {};
+
+ const { headerShown: nextHeaderShown = isParentHeaderShown === false } =
+ nextScene?.descriptor.options || {};
+
const isHeaderStatic =
- (previousScene &&
- previousScene.descriptor.options.headerShown === false &&
+ (previousHeaderShown === false &&
// We still need to animate when coming back from next scene
// A hacky way to check this is if the next scene exists
!nextScene) ||
- (nextScene && nextScene.descriptor.options.headerShown === false);
+ nextHeaderShown === false;
const props = {
mode,
@@ -133,18 +151,12 @@ export default function HeaderContainer({
style={
// Avoid positioning the focused header absolutely
// Otherwise accessibility tools don't seem to be able to find it
- (mode === 'float' && !isFocused) || options.headerTransparent
+ (mode === 'float' && !isFocused) || headerTransparent
? styles.header
: null
}
>
- {options.headerShown !== false ? (
- options.header !== undefined ? (
- options.header(props)
- ) : (
-
- )
- ) : null}
+ {header !== undefined ? header(props) : }
>
diff --git a/packages/stack/src/vendor/views/Stack/Card.tsx b/packages/stack/src/vendor/views/Stack/Card.tsx
index 2ae6f151..790a1c84 100755
--- a/packages/stack/src/vendor/views/Stack/Card.tsx
+++ b/packages/stack/src/vendor/views/Stack/Card.tsx
@@ -493,6 +493,12 @@ export default class Card extends React.Component {
? Color(backgroundColor).alpha() === 0
: false;
+ // This is a dummy style that doesn't actually change anything visually.
+ // Animated needs the animated value to be used somewhere, otherwise things don't update properly.
+ // If we disable animations and hide header, it could end up making the value unused.
+ // So we have this dummy style that will always be used regardless of what else changed.
+ const dummyStyle = { opacity: Animated.diffClamp(current, 1, 1) };
+
return (
@@ -502,7 +508,12 @@ export default class Card extends React.Component {
) : null}
-
- {renderScene({ route: scene.route })}
-
+
+
+ {renderScene({ route: scene.route })}
+
+
{headerMode === 'screen'
? renderHeader({
diff --git a/packages/stack/src/vendor/views/Stack/CardStack.tsx b/packages/stack/src/vendor/views/Stack/CardStack.tsx
index 79004a44..9c91f142 100755
--- a/packages/stack/src/vendor/views/Stack/CardStack.tsx
+++ b/packages/stack/src/vendor/views/Stack/CardStack.tsx
@@ -19,6 +19,7 @@ import {
} from '../../TransitionConfigs/TransitionPresets';
import { forNoAnimation as forNoAnimationHeader } from '../../TransitionConfigs/HeaderStyleInterpolators';
import { forNoAnimation as forNoAnimationCard } from '../../TransitionConfigs/CardStyleInterpolators';
+import HeaderShownContext from '../../utils/HeaderShownContext';
import getDistanceForDirection from '../../utils/getDistanceForDirection';
import {
Route,
@@ -336,24 +337,6 @@ export default class CardStack extends React.Component {
return state.routes[state.index];
};
- private doesFloatHeaderNeedAbsolutePositioning = () => {
- if (this.props.headerMode !== 'float') {
- return false;
- }
-
- return this.state.scenes.slice(-2).some((scene) => {
- const { descriptor } = scene;
- const options = descriptor ? descriptor.options : {};
- const { headerTransparent, headerShown } = options;
-
- if (headerTransparent || headerShown === false) {
- return true;
- }
-
- return false;
- });
- };
-
render() {
const {
mode,
@@ -382,8 +365,6 @@ export default class CardStack extends React.Component {
const focusedDescriptor = descriptors[focusedRoute.key];
const focusedOptions = focusedDescriptor ? focusedDescriptor.options : {};
- const isFloatHeaderAbsolute = this.doesFloatHeaderNeedAbsolutePositioning();
-
let defaultTransitionPreset =
mode === 'modal' ? ModalTransition : DefaultTransition;
@@ -405,193 +386,225 @@ export default class CardStack extends React.Component {
// For modals, usually we want the screen underneath to be visible, so also disable it there
const isScreensEnabled = Platform.OS !== 'ios' && mode !== 'modal';
- let floatingHeader;
-
- if (headerMode === 'float') {
- floatingHeader = (
-
- {renderHeader({
- mode: 'float',
- layout,
- insets: { top, right, bottom, left },
- scenes,
- getPreviousRoute,
- getFocusedRoute: this.getFocusedRoute,
- onContentHeightChange: this.handleHeaderLayout,
- gestureDirection:
- focusedOptions.gestureDirection !== undefined
- ? focusedOptions.gestureDirection
- : defaultTransitionPreset.gestureDirection,
- styleInterpolator:
- focusedOptions.headerStyleInterpolator !== undefined
- ? focusedOptions.headerStyleInterpolator
- : defaultTransitionPreset.headerStyleInterpolator,
- style: isFloatHeaderAbsolute ? styles.floating : undefined,
- })}
-
- );
- }
-
return (
-
- {isFloatHeaderAbsolute ? null : floatingHeader}
-
- {routes.map((route, index, self) => {
- const focused = focusedRoute.key === route.key;
- const gesture = gestures[route.key];
- const scene = scenes[index];
+
+ {(isParentHeaderShown) => {
+ const isFloatHeaderAbsolute =
+ headerMode === 'float'
+ ? this.state.scenes.slice(-2).some((scene) => {
+ const { descriptor } = scene;
+ const options = descriptor ? descriptor.options : {};
+ const {
+ headerTransparent,
+ headerShown = isParentHeaderShown === false,
+ } = options;
- const isScreenActive = scene.progress.next
- ? scene.progress.next.interpolate({
- inputRange: [0, 1 - EPSILON, 1],
- outputRange: [1, 1, 0],
- extrapolate: 'clamp',
- })
- : 1;
-
- const {
- safeAreaInsets,
- headerShown,
- headerTransparent,
- cardShadowEnabled,
- cardOverlayEnabled,
- cardOverlay,
- cardStyle,
- animationEnabled,
- gestureResponseDistance,
- gestureVelocityImpact,
- gestureDirection = defaultTransitionPreset.gestureDirection,
- transitionSpec = defaultTransitionPreset.transitionSpec,
- cardStyleInterpolator = animationEnabled === false
- ? forNoAnimationCard
- : defaultTransitionPreset.cardStyleInterpolator,
- headerStyleInterpolator = defaultTransitionPreset.headerStyleInterpolator,
- } = scene.descriptor
- ? scene.descriptor.options
- : ({} as StackNavigationOptions);
-
- let transitionConfig = {
- gestureDirection,
- transitionSpec,
- cardStyleInterpolator,
- headerStyleInterpolator,
- };
-
- // When a screen is not the last, it should use next screen's transition config
- // Many transitions also animate the previous screen, so using 2 different transitions doesn't look right
- // For example combining a slide and a modal transition would look wrong otherwise
- // With this approach, combining different transition styles in the same navigator mostly looks right
- // This will still be broken when 2 transitions have different idle state (e.g. modal presentation),
- // but majority of the transitions look alright
- if (index !== self.length - 1) {
- const nextScene = scenes[index + 1];
-
- if (nextScene) {
- const {
- animationEnabled,
- gestureDirection = defaultTransitionPreset.gestureDirection,
- transitionSpec = defaultTransitionPreset.transitionSpec,
- cardStyleInterpolator = animationEnabled === false
- ? forNoAnimationCard
- : defaultTransitionPreset.cardStyleInterpolator,
- headerStyleInterpolator = defaultTransitionPreset.headerStyleInterpolator,
- } = nextScene.descriptor
- ? nextScene.descriptor.options
- : ({} as StackNavigationOptions);
-
- transitionConfig = {
- gestureDirection,
- transitionSpec,
- cardStyleInterpolator,
- headerStyleInterpolator,
- };
- }
- }
-
- const {
- top: safeAreaInsetTop = insets.top,
- right: safeAreaInsetRight = insets.right,
- bottom: safeAreaInsetBottom = insets.bottom,
- left: safeAreaInsetLeft = insets.left,
- } = safeAreaInsets || {};
-
- const previousRoute = getPreviousRoute({ route: scene.route });
-
- let previousScene = scenes[index - 1];
-
- if (previousRoute) {
- // The previous scene will be shortly before the current scene in the array
- // So loop back from current index to avoid looping over the full array
- for (let j = index - 1; j >= 0; j--) {
- const s = scenes[j];
-
- if (s && s.route.key === previousRoute.key) {
- previousScene = s;
- break;
- }
- }
- }
-
- return (
-
-
-
- );
- })}
-
- {isFloatHeaderAbsolute ? floatingHeader : null}
-
+
+ return false;
+ })
+ : false;
+
+ const floatingHeader =
+ headerMode === 'float' ? (
+
+ {renderHeader({
+ mode: 'float',
+ layout,
+ insets: { top, right, bottom, left },
+ scenes,
+ getPreviousRoute,
+ getFocusedRoute: this.getFocusedRoute,
+ onContentHeightChange: this.handleHeaderLayout,
+ gestureDirection:
+ focusedOptions.gestureDirection !== undefined
+ ? focusedOptions.gestureDirection
+ : defaultTransitionPreset.gestureDirection,
+ styleInterpolator:
+ focusedOptions.headerStyleInterpolator !== undefined
+ ? focusedOptions.headerStyleInterpolator
+ : defaultTransitionPreset.headerStyleInterpolator,
+ style: [
+ styles.floating,
+ isFloatHeaderAbsolute && styles.absolute,
+ ],
+ })}
+
+ ) : null;
+
+ return (
+
+ {isFloatHeaderAbsolute ? null : floatingHeader}
+
+ {routes.map((route, index, self) => {
+ const focused = focusedRoute.key === route.key;
+ const gesture = gestures[route.key];
+ const scene = scenes[index];
+
+ const isScreenActive = scene.progress.next
+ ? scene.progress.next.interpolate({
+ inputRange: [0, 1 - EPSILON, 1],
+ outputRange: [1, 1, 0],
+ extrapolate: 'clamp',
+ })
+ : 1;
+
+ const {
+ safeAreaInsets,
+ headerShown = isParentHeaderShown === false,
+ headerTransparent,
+ cardShadowEnabled,
+ cardOverlayEnabled,
+ cardOverlay,
+ cardStyle,
+ animationEnabled,
+ gestureResponseDistance,
+ gestureVelocityImpact,
+ gestureDirection = defaultTransitionPreset.gestureDirection,
+ transitionSpec = defaultTransitionPreset.transitionSpec,
+ cardStyleInterpolator = animationEnabled === false
+ ? forNoAnimationCard
+ : defaultTransitionPreset.cardStyleInterpolator,
+ headerStyleInterpolator = defaultTransitionPreset.headerStyleInterpolator,
+ } = scene.descriptor
+ ? scene.descriptor.options
+ : ({} as StackNavigationOptions);
+
+ let transitionConfig = {
+ gestureDirection,
+ transitionSpec,
+ cardStyleInterpolator,
+ headerStyleInterpolator,
+ };
+
+ // When a screen is not the last, it should use next screen's transition config
+ // Many transitions also animate the previous screen, so using 2 different transitions doesn't look right
+ // For example combining a slide and a modal transition would look wrong otherwise
+ // With this approach, combining different transition styles in the same navigator mostly looks right
+ // This will still be broken when 2 transitions have different idle state (e.g. modal presentation),
+ // but majority of the transitions look alright
+ if (index !== self.length - 1) {
+ const nextScene = scenes[index + 1];
+
+ if (nextScene) {
+ const {
+ animationEnabled,
+ gestureDirection = defaultTransitionPreset.gestureDirection,
+ transitionSpec = defaultTransitionPreset.transitionSpec,
+ cardStyleInterpolator = animationEnabled === false
+ ? forNoAnimationCard
+ : defaultTransitionPreset.cardStyleInterpolator,
+ headerStyleInterpolator = defaultTransitionPreset.headerStyleInterpolator,
+ } = nextScene.descriptor
+ ? nextScene.descriptor.options
+ : ({} as StackNavigationOptions);
+
+ transitionConfig = {
+ gestureDirection,
+ transitionSpec,
+ cardStyleInterpolator,
+ headerStyleInterpolator,
+ };
+ }
+ }
+
+ const {
+ top: safeAreaInsetTop = insets.top,
+ right: safeAreaInsetRight = insets.right,
+ bottom: safeAreaInsetBottom = insets.bottom,
+ left: safeAreaInsetLeft = insets.left,
+ } = safeAreaInsets || {};
+
+ const previousRoute = getPreviousRoute({
+ route: scene.route,
+ });
+
+ let previousScene = scenes[index - 1];
+
+ if (previousRoute) {
+ // The previous scene will be shortly before the current scene in the array
+ // So loop back from current index to avoid looping over the full array
+ for (let j = index - 1; j >= 0; j--) {
+ const s = scenes[j];
+
+ if (s && s.route.key === previousRoute.key) {
+ previousScene = s;
+ break;
+ }
+ }
+ }
+
+ const headerHeight =
+ headerMode !== 'none' && headerShown !== false
+ ? headerHeights[route.key]
+ : 0;
+
+ return (
+
+
+
+ );
+ })}
+
+ {isFloatHeaderAbsolute ? floatingHeader : null}
+
+ );
+ }}
+
);
}
}
@@ -600,10 +613,13 @@ const styles = StyleSheet.create({
container: {
flex: 1,
},
- floating: {
+ absolute: {
position: 'absolute',
top: 0,
left: 0,
right: 0,
},
+ floating: {
+ zIndex: 1,
+ },
});
diff --git a/packages/stack/src/vendor/views/Stack/StackView.tsx b/packages/stack/src/vendor/views/Stack/StackView.tsx
index dcb21773..9474e771 100644
--- a/packages/stack/src/vendor/views/Stack/StackView.tsx
+++ b/packages/stack/src/vendor/views/Stack/StackView.tsx
@@ -356,14 +356,16 @@ export default class StackView extends React.Component {
private handleOpenRoute = ({ route }: { route: Route }) => {
const { state, navigation } = this.props;
+ const { closingRouteKeys, replacingRouteKeys } = this.state;
this.handleTransitionComplete();
if (
- this.state.replacingRouteKeys.every((key) => key !== route.key) &&
+ closingRouteKeys.some((key) => key === route.key) &&
+ replacingRouteKeys.every((key) => key !== route.key) &&
!state.routes.some((r) => r.key === route.key)
) {
- // If route isn't present in current state, assume that a close animation was cancelled
+ // If route isn't present in current state, but was closing, assume that a close animation was cancelled
// So we need to add this route back to the state
navigation.dispatch(NavigationActions.navigate(route));
} else {
@@ -438,6 +440,9 @@ export default class StackView extends React.Component {
navigation,
keyboardHandlingEnabled,
mode = 'card',
+ headerMode = mode === 'card' && Platform.OS === 'ios'
+ ? 'float'
+ : 'screen',
...rest
} = this.props;
@@ -448,9 +453,6 @@ export default class StackView extends React.Component {
closingRouteKeys,
} = this.state;
- const headerMode =
- mode === 'card' && Platform.OS === 'ios' ? 'float' : 'screen';
-
return (
<>
diff --git a/yarn.lock b/yarn.lock
index c4e37b24..ed1c53a8 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -3202,10 +3202,10 @@
resolved "https://registry.yarnpkg.com/@react-native-community/masked-view/-/masked-view-0.1.7.tgz#a65ce0702f55cb67fd777995de6fc7b3e5781903"
integrity sha512-9KbP7LTLFz9dx1heURJbO6nuVMdSjDez8znlrUzaB1nUwKVsTTwlKRuHxGUYIIkReLWrJQeCv9tidy+84z2eCw==
-"@react-navigation/stack@^5.4.2":
- version "5.4.2"
- resolved "https://registry.yarnpkg.com/@react-navigation/stack/-/stack-5.4.2.tgz#ca4e77e8ab55b446e44f656068702825ec3b29d3"
- integrity sha512-EG8DqHsfg257XeNaO6MIeAnPClekmr8po3PYikezyXon02rJUmHU4px25/PWOvh1hTFiH40W4WYBKzrzMBFaOQ==
+"@react-navigation/stack@^5.5.1":
+ version "5.5.1"
+ resolved "https://registry.yarnpkg.com/@react-navigation/stack/-/stack-5.5.1.tgz#95efa28edbfd1323e5ad9f01f539d43ffad8decc"
+ integrity sha512-oU2FEm+Ba6jMd5VA2WnuNfCO2HlZmGhrEX9yjBCyFj7fFCG1SB7WJdKLhZShtx3KxG/qWKphICeTLlYvkHdSpQ==
dependencies:
color "^3.1.2"
react-native-iphone-x-helper "^1.2.1"