Skip to content
This repository was archived by the owner on Feb 25, 2020. It is now read-only.

Commit eeab763

Browse files
committed
refactor: don't use keyboardAwareNavigator
The HOC currently forces us to expose some options in stack config which we don't want to. So we vendor this functionality for now to avoid this.
1 parent 004f53e commit eeab763

10 files changed

Lines changed: 170 additions & 72 deletions

File tree

example/App.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import LifecycleInteraction from './src/LifecycleInteraction';
2323
import GestureInteraction from './src/GestureInteraction';
2424
import SwitchWithStacks from './src/SwitchWithStacks';
2525
import StackWithDrawer from './src/StackWithDrawer';
26+
import StackWithInput from './src/StackWithInput';
2627
import HeaderPreset from './src/HeaderPreset';
2728
import {
2829
HeaderBackgroundDefault,
@@ -75,6 +76,11 @@ const data = [
7576
title: 'Stack with drawer inside',
7677
routeName: 'StackWithDrawer',
7778
},
79+
{
80+
component: StackWithInput,
81+
title: 'Stack with text input',
82+
routeName: 'StackWithInput',
83+
},
7884
{
7985
component: HeaderBackgroundDefault,
8086
title: 'Header background (UIKit transition)',

example/src/StackWithInput.js

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import * as React from 'react';
2+
import { Button, TextInput, View } from 'react-native';
3+
import {
4+
createStackNavigator,
5+
TransitionPresets,
6+
} from 'react-navigation-stack';
7+
8+
class Input extends React.Component {
9+
static navigationOptions = {
10+
title: 'Input screen',
11+
};
12+
13+
render() {
14+
return (
15+
<TextInput
16+
placeholder="Type something"
17+
style={{
18+
backgroundColor: 'white',
19+
paddingVertical: 12,
20+
paddingHorizontal: 16,
21+
margin: 24,
22+
}}
23+
/>
24+
);
25+
}
26+
}
27+
28+
class Home extends React.Component {
29+
static navigationOptions = {
30+
title: 'Home',
31+
};
32+
33+
render() {
34+
return (
35+
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
36+
<Button
37+
onPress={() => this.props.navigation.push('Input')}
38+
title="Push screen with input"
39+
/>
40+
</View>
41+
);
42+
}
43+
}
44+
45+
const App = createStackNavigator(
46+
{
47+
Home: { screen: Home },
48+
Input: { screen: Input },
49+
},
50+
{
51+
defaultNavigationOptions: {
52+
...TransitionPresets.SlideFromRightIOS,
53+
gesturesEnabled: true,
54+
},
55+
}
56+
);
57+
58+
export default App;

package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,6 @@
7676
},
7777
"peerDependencies": {
7878
"@react-navigation/core": "^3.0.0",
79-
"@react-navigation/native": "^3.0.0",
8079
"react": "*",
8180
"react-native": "*",
8281
"react-native-gesture-handler": "^1.0.0",

src/navigators/__tests__/__snapshots__/NestedNavigator.test.tsx.snap

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ Array [
3030
onClose={[Function]}
3131
onGestureBegin={[Function]}
3232
onGestureCanceled={[Function]}
33-
onGestureEnd={[Function]}
3433
onOpen={[Function]}
3534
onTransitionStart={[Function]}
3635
pointerEvents="box-none"
@@ -182,7 +181,6 @@ Array [
182181
onClose={[Function]}
183182
onGestureBegin={[Function]}
184183
onGestureCanceled={[Function]}
185-
onGestureEnd={[Function]}
186184
onOpen={[Function]}
187185
onTransitionStart={[Function]}
188186
pointerEvents="box-none"

src/navigators/__tests__/__snapshots__/StackNavigator.test.tsx.snap

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ Array [
3030
onClose={[Function]}
3131
onGestureBegin={[Function]}
3232
onGestureCanceled={[Function]}
33-
onGestureEnd={[Function]}
3433
onOpen={[Function]}
3534
onTransitionStart={[Function]}
3635
pointerEvents="box-none"
@@ -344,7 +343,6 @@ Array [
344343
onClose={[Function]}
345344
onGestureBegin={[Function]}
346345
onGestureCanceled={[Function]}
347-
onGestureEnd={[Function]}
348346
onOpen={[Function]}
349347
onTransitionStart={[Function]}
350348
pointerEvents="box-none"

src/navigators/createStackNavigator.tsx

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1+
import * as React from 'react';
12
import { StackRouter, createNavigator } from '@react-navigation/core';
2-
import { createKeyboardAwareNavigator } from '@react-navigation/native';
33
import { Platform } from 'react-native';
44
import StackView from '../views/Stack/StackView';
55
import {
@@ -8,6 +8,7 @@ import {
88
NavigationProp,
99
Screen,
1010
} from '../types';
11+
import KeyboardManager from '../views/KeyboardManager';
1112

1213
function createStackNavigator(
1314
routeConfigMap: {
@@ -26,13 +27,19 @@ function createStackNavigator(
2627
) {
2728
const router = StackRouter(routeConfigMap, stackConfig);
2829

29-
// Create a navigator with StackView as the view
30-
let Navigator = createNavigator(StackView, router, stackConfig);
31-
if (!stackConfig.disableKeyboardHandling && Platform.OS !== 'web') {
32-
Navigator = createKeyboardAwareNavigator(Navigator, stackConfig);
30+
if (stackConfig.disableKeyboardHandling || Platform.OS === 'web') {
31+
return createNavigator(StackView, router, stackConfig);
3332
}
3433

35-
return Navigator;
34+
return createNavigator(
35+
navigatorProps => (
36+
<KeyboardManager>
37+
{props => <StackView {...props} {...navigatorProps} />}
38+
</KeyboardManager>
39+
),
40+
router,
41+
stackConfig
42+
);
3643
}
3744

3845
export default createStackNavigator;

src/views/KeyboardManager.tsx

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import * as React from 'react';
2+
import { TextInput, Keyboard } from 'react-native';
3+
4+
type Props = {
5+
children: (props: {
6+
onPageChangeStart: () => void;
7+
onPageChangeConfirm: () => void;
8+
onPageChangeCancel: () => void;
9+
}) => React.ReactNode;
10+
};
11+
12+
export default class KeyboardManager extends React.Component<Props> {
13+
// Numeric id of the previously focused text input
14+
// When a gesture didn't change the tab, we can restore the focused input with this
15+
private previouslyFocusedTextInput: number | null = null;
16+
17+
private handlePageChangeStart = () => {
18+
const input = TextInput.State.currentlyFocusedField();
19+
20+
// When a page change begins, blur the currently focused input
21+
TextInput.State.blurTextInput(input);
22+
23+
// Store the id of this input so we can refocus it if change was cancelled
24+
this.previouslyFocusedTextInput = input;
25+
};
26+
27+
private handlePageChangeConfirm = () => {
28+
Keyboard.dismiss();
29+
30+
// Cleanup the ID on successful page change
31+
this.previouslyFocusedTextInput = null;
32+
};
33+
34+
private handlePageChangeCancel = () => {
35+
// The page didn't change, we should restore the focus of text input
36+
const input = this.previouslyFocusedTextInput;
37+
38+
if (input) {
39+
TextInput.State.focusTextInput(input);
40+
}
41+
42+
this.previouslyFocusedTextInput = null;
43+
};
44+
45+
render() {
46+
return this.props.children({
47+
onPageChangeStart: this.handlePageChangeStart,
48+
onPageChangeConfirm: this.handlePageChangeConfirm,
49+
onPageChangeCancel: this.handlePageChangeCancel,
50+
});
51+
}
52+
}

src/views/Stack/Stack.tsx

Lines changed: 11 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -46,13 +46,9 @@ type Props = {
4646
renderHeader: (props: HeaderContainerProps) => React.ReactNode;
4747
renderScene: (props: { route: Route }) => React.ReactNode;
4848
headerMode: HeaderMode;
49-
onTransitionStart?: (
50-
current: { index: number },
51-
previous: { index: number }
52-
) => void;
53-
onGestureBegin?: () => void;
54-
onGestureCanceled?: () => void;
55-
onGestureEnd?: () => void;
49+
onPageChangeStart?: () => void;
50+
onPageChangeConfirm?: () => void;
51+
onPageChangeCancel?: () => void;
5652
};
5753

5854
type State = {
@@ -258,20 +254,10 @@ export default class Stack extends React.Component<Props, State> {
258254
}));
259255
};
260256

261-
private handleTransitionStart = ({
262-
route,
263-
current,
264-
previous,
265-
}: {
266-
route: Route;
267-
current: { index: number };
268-
previous: { index: number };
269-
}) => {
270-
const { onTransitionStart, descriptors } = this.props;
257+
private handleTransitionStart = ({ route }: { route: Route }) => {
258+
const { descriptors } = this.props;
271259
const descriptor = descriptors[route.key];
272260

273-
onTransitionStart && onTransitionStart(current, previous);
274-
275261
descriptor &&
276262
descriptor.options.onTransitionStart &&
277263
descriptor.options.onTransitionStart();
@@ -300,9 +286,9 @@ export default class Stack extends React.Component<Props, State> {
300286
renderHeader,
301287
renderScene,
302288
headerMode,
303-
onGestureBegin,
304-
onGestureCanceled,
305-
onGestureEnd,
289+
onPageChangeStart,
290+
onPageChangeConfirm,
291+
onPageChangeCancel,
306292
} = this.props;
307293

308294
const { scenes, layout, progress, floatingHeaderHeights } = this.state;
@@ -386,9 +372,9 @@ export default class Stack extends React.Component<Props, State> {
386372
cardShadowEnabled={cardShadowEnabled}
387373
cardStyle={cardStyle}
388374
gesturesEnabled={index !== 0 && getGesturesEnabled({ route })}
389-
onGestureBegin={onGestureBegin}
390-
onGestureCanceled={onGestureCanceled}
391-
onGestureEnd={onGestureEnd}
375+
onPageChangeStart={onPageChangeStart}
376+
onPageChangeConfirm={onPageChangeConfirm}
377+
onPageChangeCancel={onPageChangeCancel}
392378
gestureResponseDistance={gestureResponseDistance}
393379
floatingHeaderHeight={floatingHeaderHeights[route.key]}
394380
hasCustomHeader={header === null}

src/views/Stack/StackItem.tsx

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -33,15 +33,11 @@ type Props = TransitionPreset & {
3333
onOpenRoute: (props: { route: Route }) => void;
3434
onCloseRoute: (props: { route: Route }) => void;
3535
onGoBack: (props: { route: Route }) => void;
36-
onTransitionStart?: (props: {
37-
route: Route;
38-
current: { index: number };
39-
previous: { index: number };
40-
}) => void;
36+
onTransitionStart?: (props: { route: Route }) => void;
4137
onTransitionEnd?: (props: { route: Route }) => void;
42-
onGestureBegin?: () => void;
43-
onGestureCanceled?: () => void;
44-
onGestureEnd?: () => void;
38+
onPageChangeStart?: () => void;
39+
onPageChangeConfirm?: () => void;
40+
onPageChangeCancel?: () => void;
4541
gestureResponseDistance?: {
4642
vertical?: number;
4743
horizontal?: number;
@@ -68,15 +64,21 @@ export default class StackItem extends React.PureComponent<Props> {
6864
};
6965

7066
private handleTransitionStart = ({ closing }: { closing: boolean }) => {
71-
const { index, scene, onTransitionStart, onGoBack } = this.props;
67+
const {
68+
scene,
69+
onTransitionStart,
70+
onPageChangeConfirm,
71+
onPageChangeCancel,
72+
onGoBack,
73+
} = this.props;
7274

73-
onTransitionStart &&
74-
onTransitionStart({
75-
route: scene.route,
76-
previous: { index: closing ? index - 1 : index },
77-
current: { index },
78-
});
75+
if (closing) {
76+
onPageChangeConfirm && onPageChangeConfirm();
77+
} else {
78+
onPageChangeCancel && onPageChangeCancel();
79+
}
7980

81+
onTransitionStart && onTransitionStart({ route: scene.route });
8082
closing && onGoBack({ route: scene.route });
8183
};
8284

@@ -96,9 +98,8 @@ export default class StackItem extends React.PureComponent<Props> {
9698
cardShadowEnabled,
9799
cardStyle,
98100
gesturesEnabled,
99-
onGestureBegin,
100-
onGestureCanceled,
101-
onGestureEnd,
101+
onPageChangeStart,
102+
onPageChangeCancel,
102103
gestureResponseDistance,
103104
floatingHeaderHeight,
104105
hasCustomHeader,
@@ -129,9 +130,8 @@ export default class StackItem extends React.PureComponent<Props> {
129130
shadowEnabled={cardShadowEnabled}
130131
gesturesEnabled={gesturesEnabled}
131132
onTransitionStart={this.handleTransitionStart}
132-
onGestureBegin={onGestureBegin}
133-
onGestureCanceled={onGestureCanceled}
134-
onGestureEnd={onGestureEnd}
133+
onGestureBegin={onPageChangeStart}
134+
onGestureCanceled={onPageChangeCancel}
135135
gestureResponseDistance={gestureResponseDistance}
136136
transitionSpec={transitionSpec}
137137
styleInterpolator={cardStyleInterpolator}

src/views/Stack/StackView.tsx

Lines changed: 9 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,9 @@ type Props = {
1616
navigation: NavigationProp;
1717
descriptors: SceneDescriptorMap;
1818
navigationConfig: NavigationStackConfig;
19-
onTransitionStart?: (
20-
current: { index: number },
21-
previous: { index: number }
22-
) => void;
23-
onGestureBegin?: () => void;
24-
onGestureCanceled?: () => void;
25-
onGestureEnd?: () => void;
19+
onPageChangeStart?: () => void;
20+
onPageChangeConfirm?: () => void;
21+
onPageChangeCancel?: () => void;
2622
screenProps?: unknown;
2723
};
2824

@@ -275,10 +271,9 @@ class StackView extends React.Component<Props, State> {
275271
const {
276272
navigation,
277273
navigationConfig,
278-
onTransitionStart,
279-
onGestureBegin,
280-
onGestureCanceled,
281-
onGestureEnd,
274+
onPageChangeStart,
275+
onPageChangeConfirm,
276+
onPageChangeCancel,
282277
} = this.props;
283278

284279
const { mode = 'card', ...config } = navigationConfig;
@@ -298,10 +293,9 @@ class StackView extends React.Component<Props, State> {
298293
onGoBack={this.handleGoBack}
299294
onOpenRoute={this.handleOpenRoute}
300295
onCloseRoute={this.handleCloseRoute}
301-
onTransitionStart={onTransitionStart}
302-
onGestureBegin={onGestureBegin}
303-
onGestureCanceled={onGestureCanceled}
304-
onGestureEnd={onGestureEnd}
296+
onPageChangeStart={onPageChangeStart}
297+
onPageChangeConfirm={onPageChangeConfirm}
298+
onPageChangeCancel={onPageChangeCancel}
305299
renderHeader={this.renderHeader}
306300
renderScene={this.renderScene}
307301
headerMode={headerMode}

0 commit comments

Comments
 (0)