This repository has been archived by the owner on Dec 18, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 68
/
Copy pathExNavigator.js
166 lines (141 loc) · 5.04 KB
/
ExNavigator.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
'use strict';
import PropTypes from 'prop-types';
import React from 'react';
import { Navigator } from 'react-native-deprecated-custom-components';
import invariant from 'invariant';
import cloneReferencedElement from 'react-clone-referenced-element';
import ExNavigatorMixin from './ExNavigatorMixin';
import ExNavigatorStyles from './ExNavigatorStyles';
import ExRouteRenderer from './ExRouteRenderer';
import ExSceneConfigs from './ExSceneConfigs';
import * as ExNavigatorIcons from './ExNavigatorIcons';
import type * as ExRoute from './ExRoute';
export default class ExNavigator extends React.Component {
static Styles = ExNavigatorStyles;
static SceneConfigs = ExSceneConfigs;
static Icons = ExNavigatorIcons;
static propTypes = {
...Navigator.props,
showNavigationBar: PropTypes.bool,
navigationBarStyle: PropTypes.any,
titleStyle: PropTypes.any,
barButtonTextStyle: PropTypes.any,
barButtonIconStyle: PropTypes.any,
renderNavigationBar: PropTypes.func,
renderBackButton: PropTypes.func,
augmentScene: PropTypes.func,
};
static defaultProps = {
...Navigator.defaultProps,
showNavigationBar: true,
renderNavigationBar: props => {
return <Navigator.NavigationBar {...props} />;
},
};
constructor(props, context) {
super(props, context);
// NOTE: currently only the initial props are honored
this._routeRenderer = new ExRouteRenderer(this, {
titleStyle: props.titleStyle,
barButtonTextStyle: props.barButtonTextStyle,
barButtonIconStyle: props.barButtonIconStyle,
});
this._renderScene = this._renderScene.bind(this);
this._setNavigatorRef = this._setNavigatorRef.bind(this);
}
render() {
return (
<Navigator
{...this.props}
ref={this._setNavigatorRef}
configureScene={route => this._routeRenderer.configureScene(route)}
renderScene={this._renderScene}
navigationBar={this._renderNavigationBar()}
sceneStyle={[ExNavigatorStyles.scene, this.props.sceneStyle]}
style={[ExNavigatorStyles.navigator, this.props.style]}
/>
);
}
_renderScene(route: ExRoute, navigator: Navigator) {
// We need to subscribe to the navigation context before the navigator is
// mounted because it emits a didfocus event when it is mounted, before we
// can get a ref to it
if (!this._subscribedToFocusEvents) {
this._subscribeToFocusEvents(navigator);
}
// We need to save a reference to the navigator already. Otherwise this
// would crash if the route calls any method on us in the first render-pass.
this.__navigator = navigator;
let scene = this._routeRenderer.renderScene(route, this);
if (typeof this.props.augmentScene === 'function') {
scene = this.props.augmentScene(scene, route);
}
let firstRoute = navigator.getCurrentRoutes()[0];
if (route === firstRoute) {
scene = cloneReferencedElement(scene, {
ref: component => {
this._firstScene = component;
},
});
}
return scene;
}
_renderNavigationBar(): ?Navigator.NavigationBar {
if (!this.props.showNavigationBar) {
return null;
}
return this.props.renderNavigationBar({
routeMapper: this._routeRenderer.navigationBarRouteMapper,
style: [ExNavigatorStyles.bar, this.props.navigationBarStyle],
});
}
_setNavigatorRef(navigator) {
this.__navigator = navigator;
if (navigator) {
invariant(
this._subscribedToFocusEvents,
'Expected to have subscribed to the navigator before it was mounted.'
);
} else {
this._unsubscribeFromFocusEvents(navigator);
}
}
_subscribeToFocusEvents(navigator) {
invariant(
!this._subscribedToFocusEvents,
'The navigator is already subscribed to focus events'
);
let navigationContext = navigator.navigationContext;
this._onWillFocusSubscription = navigationContext.addListener(
'willfocus',
event => this._routeRenderer.onWillFocus(event)
);
this._onDidFocusSubscription = navigationContext.addListener(
'didfocus',
event => this._routeRenderer.onDidFocus(event)
);
this._subscribedToFocusEvents = true;
}
_unsubscribeFromFocusEvents() {
this._onWillFocusSubscription.remove();
this._onDidFocusSubscription.remove();
this._subscribedToFocusEvents = false;
}
// Navigator properties
get navigationContext() {
return this.__navigator.navigationContext;
}
get parentNavigator() {
// Navigator sets its `parentNavigator` property in componentWillMount, but
// we don't get a reference to the Navigator until it has been mounted. So
// there is a window of time during which the Navigator's `parentNavigator`
// property has been set but we don't have a reference to the Navigator;
// when that happens we'll simulate Navigator and return our `navigator`
// prop.
return !this.__navigator
? this.props.navigator
: this.__navigator.parentNavigator;
}
}
Object.assign(ExNavigator.prototype, ExNavigatorMixin);
export * from './ExRoute';