diff --git a/packages/stack/example/App.js b/packages/stack/example/App.js
index 259a2205..018cb1c9 100644
--- a/packages/stack/example/App.js
+++ b/packages/stack/example/App.js
@@ -23,6 +23,7 @@ import LifecycleInteraction from './src/LifecycleInteraction';
import GestureInteraction from './src/GestureInteraction';
import SwitchWithStacks from './src/SwitchWithStacks';
import StackWithDrawer from './src/StackWithDrawer';
+import StackWithInput from './src/StackWithInput';
import HeaderPreset from './src/HeaderPreset';
import {
HeaderBackgroundDefault,
@@ -75,6 +76,11 @@ const data = [
title: 'Stack with drawer inside',
routeName: 'StackWithDrawer',
},
+ {
+ component: StackWithInput,
+ title: 'Stack with text input',
+ routeName: 'StackWithInput',
+ },
{
component: HeaderBackgroundDefault,
title: 'Header background (UIKit transition)',
diff --git a/packages/stack/example/src/StackWithInput.js b/packages/stack/example/src/StackWithInput.js
new file mode 100644
index 00000000..344ecf26
--- /dev/null
+++ b/packages/stack/example/src/StackWithInput.js
@@ -0,0 +1,58 @@
+import * as React from 'react';
+import { Button, TextInput, View } from 'react-native';
+import {
+ createStackNavigator,
+ TransitionPresets,
+} from 'react-navigation-stack';
+
+class Input extends React.Component {
+ static navigationOptions = {
+ title: 'Input screen',
+ };
+
+ render() {
+ return (
+
+ );
+ }
+}
+
+class Home extends React.Component {
+ static navigationOptions = {
+ title: 'Home',
+ };
+
+ render() {
+ return (
+
+
+ );
+ }
+}
+
+const App = createStackNavigator(
+ {
+ Home: { screen: Home },
+ Input: { screen: Input },
+ },
+ {
+ defaultNavigationOptions: {
+ ...TransitionPresets.SlideFromRightIOS,
+ gesturesEnabled: true,
+ },
+ }
+);
+
+export default App;
diff --git a/packages/stack/package.json b/packages/stack/package.json
index b511b0d8..8c5dc7b9 100644
--- a/packages/stack/package.json
+++ b/packages/stack/package.json
@@ -76,7 +76,6 @@
},
"peerDependencies": {
"@react-navigation/core": "^3.0.0",
- "@react-navigation/native": "^3.0.0",
"react": "*",
"react-native": "*",
"react-native-gesture-handler": "^1.0.0",
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 d726fd93..b934e417 100644
--- a/packages/stack/src/navigators/__tests__/__snapshots__/NestedNavigator.test.tsx.snap
+++ b/packages/stack/src/navigators/__tests__/__snapshots__/NestedNavigator.test.tsx.snap
@@ -30,7 +30,6 @@ Array [
onClose={[Function]}
onGestureBegin={[Function]}
onGestureCanceled={[Function]}
- onGestureEnd={[Function]}
onOpen={[Function]}
onTransitionStart={[Function]}
pointerEvents="box-none"
@@ -182,7 +181,6 @@ Array [
onClose={[Function]}
onGestureBegin={[Function]}
onGestureCanceled={[Function]}
- onGestureEnd={[Function]}
onOpen={[Function]}
onTransitionStart={[Function]}
pointerEvents="box-none"
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 4d7eec24..c2939601 100644
--- a/packages/stack/src/navigators/__tests__/__snapshots__/StackNavigator.test.tsx.snap
+++ b/packages/stack/src/navigators/__tests__/__snapshots__/StackNavigator.test.tsx.snap
@@ -30,7 +30,6 @@ Array [
onClose={[Function]}
onGestureBegin={[Function]}
onGestureCanceled={[Function]}
- onGestureEnd={[Function]}
onOpen={[Function]}
onTransitionStart={[Function]}
pointerEvents="box-none"
@@ -344,7 +343,6 @@ Array [
onClose={[Function]}
onGestureBegin={[Function]}
onGestureCanceled={[Function]}
- onGestureEnd={[Function]}
onOpen={[Function]}
onTransitionStart={[Function]}
pointerEvents="box-none"
diff --git a/packages/stack/src/navigators/createStackNavigator.tsx b/packages/stack/src/navigators/createStackNavigator.tsx
index 6676ce86..6b3579bd 100644
--- a/packages/stack/src/navigators/createStackNavigator.tsx
+++ b/packages/stack/src/navigators/createStackNavigator.tsx
@@ -1,5 +1,5 @@
+import * as React from 'react';
import { StackRouter, createNavigator } from '@react-navigation/core';
-import { createKeyboardAwareNavigator } from '@react-navigation/native';
import { Platform } from 'react-native';
import StackView from '../views/Stack/StackView';
import {
@@ -8,6 +8,7 @@ import {
NavigationProp,
Screen,
} from '../types';
+import KeyboardManager from '../views/KeyboardManager';
function createStackNavigator(
routeConfigMap: {
@@ -26,13 +27,19 @@ function createStackNavigator(
) {
const router = StackRouter(routeConfigMap, stackConfig);
- // Create a navigator with StackView as the view
- let Navigator = createNavigator(StackView, router, stackConfig);
- if (!stackConfig.disableKeyboardHandling && Platform.OS !== 'web') {
- Navigator = createKeyboardAwareNavigator(Navigator, stackConfig);
+ if (stackConfig.disableKeyboardHandling || Platform.OS === 'web') {
+ return createNavigator(StackView, router, stackConfig);
}
- return Navigator;
+ return createNavigator(
+ navigatorProps => (
+
+ {props => }
+
+ ),
+ router,
+ stackConfig
+ );
}
export default createStackNavigator;
diff --git a/packages/stack/src/views/KeyboardManager.tsx b/packages/stack/src/views/KeyboardManager.tsx
new file mode 100644
index 00000000..01721bb4
--- /dev/null
+++ b/packages/stack/src/views/KeyboardManager.tsx
@@ -0,0 +1,52 @@
+import * as React from 'react';
+import { TextInput, Keyboard } from 'react-native';
+
+type Props = {
+ children: (props: {
+ onPageChangeStart: () => void;
+ onPageChangeConfirm: () => void;
+ onPageChangeCancel: () => void;
+ }) => React.ReactNode;
+};
+
+export default class KeyboardManager extends React.Component {
+ // Numeric id of the previously focused text input
+ // When a gesture didn't change the tab, we can restore the focused input with this
+ private previouslyFocusedTextInput: number | null = null;
+
+ private handlePageChangeStart = () => {
+ const input = TextInput.State.currentlyFocusedField();
+
+ // When a page change begins, blur the currently focused input
+ TextInput.State.blurTextInput(input);
+
+ // Store the id of this input so we can refocus it if change was cancelled
+ this.previouslyFocusedTextInput = input;
+ };
+
+ private handlePageChangeConfirm = () => {
+ Keyboard.dismiss();
+
+ // Cleanup the ID on successful page change
+ this.previouslyFocusedTextInput = null;
+ };
+
+ private handlePageChangeCancel = () => {
+ // The page didn't change, we should restore the focus of text input
+ const input = this.previouslyFocusedTextInput;
+
+ if (input) {
+ TextInput.State.focusTextInput(input);
+ }
+
+ this.previouslyFocusedTextInput = null;
+ };
+
+ render() {
+ return this.props.children({
+ onPageChangeStart: this.handlePageChangeStart,
+ onPageChangeConfirm: this.handlePageChangeConfirm,
+ onPageChangeCancel: this.handlePageChangeCancel,
+ });
+ }
+}
diff --git a/packages/stack/src/views/Stack/Stack.tsx b/packages/stack/src/views/Stack/Stack.tsx
index ddafc88f..3e520a31 100755
--- a/packages/stack/src/views/Stack/Stack.tsx
+++ b/packages/stack/src/views/Stack/Stack.tsx
@@ -46,13 +46,9 @@ type Props = {
renderHeader: (props: HeaderContainerProps) => React.ReactNode;
renderScene: (props: { route: Route }) => React.ReactNode;
headerMode: HeaderMode;
- onTransitionStart?: (
- current: { index: number },
- previous: { index: number }
- ) => void;
- onGestureBegin?: () => void;
- onGestureCanceled?: () => void;
- onGestureEnd?: () => void;
+ onPageChangeStart?: () => void;
+ onPageChangeConfirm?: () => void;
+ onPageChangeCancel?: () => void;
};
type State = {
@@ -258,20 +254,10 @@ export default class Stack extends React.Component {
}));
};
- private handleTransitionStart = ({
- route,
- current,
- previous,
- }: {
- route: Route;
- current: { index: number };
- previous: { index: number };
- }) => {
- const { onTransitionStart, descriptors } = this.props;
+ private handleTransitionStart = ({ route }: { route: Route }) => {
+ const { descriptors } = this.props;
const descriptor = descriptors[route.key];
- onTransitionStart && onTransitionStart(current, previous);
-
descriptor &&
descriptor.options.onTransitionStart &&
descriptor.options.onTransitionStart();
@@ -300,9 +286,9 @@ export default class Stack extends React.Component {
renderHeader,
renderScene,
headerMode,
- onGestureBegin,
- onGestureCanceled,
- onGestureEnd,
+ onPageChangeStart,
+ onPageChangeConfirm,
+ onPageChangeCancel,
} = this.props;
const { scenes, layout, progress, floatingHeaderHeights } = this.state;
@@ -386,9 +372,9 @@ export default class Stack extends React.Component {
cardShadowEnabled={cardShadowEnabled}
cardStyle={cardStyle}
gesturesEnabled={index !== 0 && getGesturesEnabled({ route })}
- onGestureBegin={onGestureBegin}
- onGestureCanceled={onGestureCanceled}
- onGestureEnd={onGestureEnd}
+ onPageChangeStart={onPageChangeStart}
+ onPageChangeConfirm={onPageChangeConfirm}
+ onPageChangeCancel={onPageChangeCancel}
gestureResponseDistance={gestureResponseDistance}
floatingHeaderHeight={floatingHeaderHeights[route.key]}
hasCustomHeader={header === null}
diff --git a/packages/stack/src/views/Stack/StackItem.tsx b/packages/stack/src/views/Stack/StackItem.tsx
index 69904b6f..7a2cec83 100644
--- a/packages/stack/src/views/Stack/StackItem.tsx
+++ b/packages/stack/src/views/Stack/StackItem.tsx
@@ -33,15 +33,11 @@ type Props = TransitionPreset & {
onOpenRoute: (props: { route: Route }) => void;
onCloseRoute: (props: { route: Route }) => void;
onGoBack: (props: { route: Route }) => void;
- onTransitionStart?: (props: {
- route: Route;
- current: { index: number };
- previous: { index: number };
- }) => void;
+ onTransitionStart?: (props: { route: Route }) => void;
onTransitionEnd?: (props: { route: Route }) => void;
- onGestureBegin?: () => void;
- onGestureCanceled?: () => void;
- onGestureEnd?: () => void;
+ onPageChangeStart?: () => void;
+ onPageChangeConfirm?: () => void;
+ onPageChangeCancel?: () => void;
gestureResponseDistance?: {
vertical?: number;
horizontal?: number;
@@ -68,15 +64,21 @@ export default class StackItem extends React.PureComponent {
};
private handleTransitionStart = ({ closing }: { closing: boolean }) => {
- const { index, scene, onTransitionStart, onGoBack } = this.props;
+ const {
+ scene,
+ onTransitionStart,
+ onPageChangeConfirm,
+ onPageChangeCancel,
+ onGoBack,
+ } = this.props;
- onTransitionStart &&
- onTransitionStart({
- route: scene.route,
- previous: { index: closing ? index - 1 : index },
- current: { index },
- });
+ if (closing) {
+ onPageChangeConfirm && onPageChangeConfirm();
+ } else {
+ onPageChangeCancel && onPageChangeCancel();
+ }
+ onTransitionStart && onTransitionStart({ route: scene.route });
closing && onGoBack({ route: scene.route });
};
@@ -96,9 +98,8 @@ export default class StackItem extends React.PureComponent {
cardShadowEnabled,
cardStyle,
gesturesEnabled,
- onGestureBegin,
- onGestureCanceled,
- onGestureEnd,
+ onPageChangeStart,
+ onPageChangeCancel,
gestureResponseDistance,
floatingHeaderHeight,
hasCustomHeader,
@@ -129,9 +130,8 @@ export default class StackItem extends React.PureComponent {
shadowEnabled={cardShadowEnabled}
gesturesEnabled={gesturesEnabled}
onTransitionStart={this.handleTransitionStart}
- onGestureBegin={onGestureBegin}
- onGestureCanceled={onGestureCanceled}
- onGestureEnd={onGestureEnd}
+ onGestureBegin={onPageChangeStart}
+ onGestureCanceled={onPageChangeCancel}
gestureResponseDistance={gestureResponseDistance}
transitionSpec={transitionSpec}
styleInterpolator={cardStyleInterpolator}
diff --git a/packages/stack/src/views/Stack/StackView.tsx b/packages/stack/src/views/Stack/StackView.tsx
index 8888fb98..393e85c6 100644
--- a/packages/stack/src/views/Stack/StackView.tsx
+++ b/packages/stack/src/views/Stack/StackView.tsx
@@ -16,13 +16,9 @@ type Props = {
navigation: NavigationProp;
descriptors: SceneDescriptorMap;
navigationConfig: NavigationStackConfig;
- onTransitionStart?: (
- current: { index: number },
- previous: { index: number }
- ) => void;
- onGestureBegin?: () => void;
- onGestureCanceled?: () => void;
- onGestureEnd?: () => void;
+ onPageChangeStart?: () => void;
+ onPageChangeConfirm?: () => void;
+ onPageChangeCancel?: () => void;
screenProps?: unknown;
};
@@ -275,10 +271,9 @@ class StackView extends React.Component {
const {
navigation,
navigationConfig,
- onTransitionStart,
- onGestureBegin,
- onGestureCanceled,
- onGestureEnd,
+ onPageChangeStart,
+ onPageChangeConfirm,
+ onPageChangeCancel,
} = this.props;
const { mode = 'card', ...config } = navigationConfig;
@@ -298,10 +293,9 @@ class StackView extends React.Component {
onGoBack={this.handleGoBack}
onOpenRoute={this.handleOpenRoute}
onCloseRoute={this.handleCloseRoute}
- onTransitionStart={onTransitionStart}
- onGestureBegin={onGestureBegin}
- onGestureCanceled={onGestureCanceled}
- onGestureEnd={onGestureEnd}
+ onPageChangeStart={onPageChangeStart}
+ onPageChangeConfirm={onPageChangeConfirm}
+ onPageChangeCancel={onPageChangeCancel}
renderHeader={this.renderHeader}
renderScene={this.renderScene}
headerMode={headerMode}