backed out changeset 87e6fe282c08
Reviewed By: ericvicenti Differential Revision: D3033857 fb-gh-sync-id: 7391ae943a88c675f8539f5cc81587caec36e80e shipit-source-id: 7391ae943a88c675f8539f5cc81587caec36e80e
This commit is contained in:
parent
f5a1600a20
commit
7da65a817c
|
@ -27,11 +27,266 @@
|
|||
*/
|
||||
'use strict';
|
||||
|
||||
const NavigationAnimatedView = require('NavigationAnimatedView');
|
||||
const NavigationCard = require('NavigationCard');
|
||||
const NavigationContext = require('NavigationContext');
|
||||
const NavigationLegacyNavigatorRouteStack = require('NavigationLegacyNavigatorRouteStack');
|
||||
const NavigatorBreadcrumbNavigationBar = require('NavigatorBreadcrumbNavigationBar');
|
||||
const NavigatorNavigationBar = require('NavigatorNavigationBar');
|
||||
const NavigatorSceneConfigs = require('NavigatorSceneConfigs');
|
||||
const React = require('react-native');
|
||||
const ReactComponentWithPureRenderMixin = require('ReactComponentWithPureRenderMixin');
|
||||
|
||||
const invariant = require('fbjs/lib/invariant');
|
||||
const guid = require('guid');
|
||||
|
||||
import type {
|
||||
NavigationSceneRenderer,
|
||||
NavigationSceneRendererProps,
|
||||
} from 'NavigationTypeDefinition';
|
||||
|
||||
type State = any;
|
||||
|
||||
type Props = {
|
||||
configureScene: any,
|
||||
initialRoute: any,
|
||||
initialRouteStack: any,
|
||||
renderScene: any,
|
||||
style: any,
|
||||
};
|
||||
|
||||
function getConfigPopDirection(config: any): ?string {
|
||||
if (config && config.gestures && config.gestures.pop) {
|
||||
const direction = config.gestures.pop.direction;
|
||||
return direction ? String(direction) : null;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
const RouteStack = NavigationLegacyNavigatorRouteStack;
|
||||
|
||||
/**
|
||||
* NavigationLegacyNavigator is meant to replace Navigator seemlessly without
|
||||
* API changes. While the APIs remain compatible with Navigator, it should
|
||||
* be built with the new Navigation API such as `NavigationAnimatedView`...etc.
|
||||
* NavigationLegacyNavigator is meant to replace Navigator seemlessly with
|
||||
* minimum API changes.
|
||||
*
|
||||
* While the APIs remain compatible with Navigator, it is built with good
|
||||
* intention by using the new Navigation API such as
|
||||
* `NavigationAnimatedView`...etc.
|
||||
*/
|
||||
const NavigationLegacyNavigator = require('Navigator');
|
||||
class NavigationLegacyNavigator extends React.Component<any, Props, State> {
|
||||
static BreadcrumbNavigationBar;
|
||||
static NavigationBar: any;
|
||||
static SceneConfigs: any;
|
||||
|
||||
_renderCard: NavigationSceneRenderer;
|
||||
_renderHeader: NavigationSceneRenderer;
|
||||
_renderScene: NavigationSceneRenderer;
|
||||
|
||||
navigationContext: NavigationContext;
|
||||
|
||||
constructor(props: Props, context: any) {
|
||||
super(props, context);
|
||||
|
||||
this.navigationContext = new NavigationContext();
|
||||
|
||||
const stack = this._getInitialRouteStack();
|
||||
this.state = {
|
||||
key: guid(),
|
||||
stack,
|
||||
};
|
||||
}
|
||||
|
||||
jumpTo(route: any): void {
|
||||
const index = this.state.stack.indexOf(route);
|
||||
invariant(
|
||||
index > -1,
|
||||
'Cannot jump to route that is not in the route stack'
|
||||
);
|
||||
this._jumpToIndex(index);
|
||||
}
|
||||
|
||||
jumpForward(): void {
|
||||
this._jumpToIndex(this.state.stack.index + 1);
|
||||
}
|
||||
|
||||
jumpBack(): void {
|
||||
this._jumpToIndex(this.state.stack.index - 1);
|
||||
}
|
||||
|
||||
push(route: any): void {
|
||||
this.setState({stack: this.state.stack.push(route)});
|
||||
}
|
||||
|
||||
pop(): void {
|
||||
const {stack} = this.state;
|
||||
if (stack.size > 1) {
|
||||
this.setState({stack: stack.pop()});
|
||||
}
|
||||
}
|
||||
|
||||
replaceAtIndex(route: any, index: number): void {
|
||||
const {stack} = this.state;
|
||||
|
||||
if (index < 0) {
|
||||
index += stack.size;
|
||||
}
|
||||
|
||||
if (index >= stack.size) {
|
||||
// Nothing to replace.
|
||||
return;
|
||||
}
|
||||
|
||||
this.setState({stack: stack.replaceAtIndex(index, route)});
|
||||
}
|
||||
|
||||
replace(route: any): void {
|
||||
this.replaceAtIndex(route, this.state.stack.index);
|
||||
}
|
||||
|
||||
replacePrevious(route: any): void {
|
||||
this.replaceAtIndex(route, this.state.stack.index - 1);
|
||||
}
|
||||
|
||||
popToTop(): void {
|
||||
this.setState({stack: this.state.stack.slice(0, 1)});
|
||||
}
|
||||
|
||||
popToRoute(route: any): void {
|
||||
const {stack} = this.state;
|
||||
const nextIndex = stack.indexOf(route);
|
||||
invariant(
|
||||
nextIndex > -1,
|
||||
'Calling popToRoute for a route that doesn\'t exist!'
|
||||
);
|
||||
this.setState({stack: stack.slice(0, nextIndex + 1)});
|
||||
}
|
||||
|
||||
replacePreviousAndPop(route: any): void {
|
||||
const {stack} = this.state;
|
||||
const nextIndex = stack.index - 1;
|
||||
if (nextIndex < 0) {
|
||||
return;
|
||||
}
|
||||
this.setState({stack: stack.replaceAtIndex(nextIndex, route).pop()});
|
||||
}
|
||||
|
||||
resetTo(route: any): void {
|
||||
invariant(!!route, 'Must supply route');
|
||||
this.setState({stack: this.state.stack.slice(0).replaceAtIndex(0, route)});
|
||||
}
|
||||
|
||||
immediatelyResetRouteStack(routes: Array<any>): void {
|
||||
const index = routes.length - 1;
|
||||
const stack = new RouteStack(index, routes);
|
||||
this.setState({
|
||||
key: guid(),
|
||||
stack,
|
||||
});
|
||||
}
|
||||
|
||||
getCurrentRoutes(): Array<any> {
|
||||
return this.state.stack.toArray();
|
||||
}
|
||||
|
||||
_jumpToIndex(index: number): void {
|
||||
const {stack} = this.state;
|
||||
if (index < 0 || index >= stack.size) {
|
||||
return;
|
||||
}
|
||||
const nextStack = stack.jumpToIndex(index);
|
||||
this.setState({stack: nextStack});
|
||||
}
|
||||
|
||||
// Lyfe cycle and private methods below.
|
||||
|
||||
shouldComponentUpdate(nextProps: Object, nextState: Object): boolean {
|
||||
return ReactComponentWithPureRenderMixin.shouldComponentUpdate.call(
|
||||
this,
|
||||
nextProps,
|
||||
nextState
|
||||
);
|
||||
}
|
||||
|
||||
componentWillMount(): void {
|
||||
this._renderCard = this._renderCard.bind(this);
|
||||
this._renderHeader = this._renderHeader.bind(this);
|
||||
this._renderScene = this._renderScene.bind(this);
|
||||
}
|
||||
|
||||
render(): ReactElement {
|
||||
return (
|
||||
<NavigationAnimatedView
|
||||
key={'main_' + this.state.key}
|
||||
navigationState={this.state.stack.toNavigationState()}
|
||||
renderOverlay={this._renderHeader}
|
||||
renderScene={this._renderCard}
|
||||
style={this.props.style}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
_getInitialRouteStack(): RouteStack {
|
||||
const {initialRouteStack, initialRoute} = this.props;
|
||||
const routes = initialRouteStack || [initialRoute];
|
||||
const index = initialRoute ?
|
||||
routes.indexOf(initialRoute) :
|
||||
routes.length - 1;
|
||||
return new RouteStack(index, routes);
|
||||
}
|
||||
|
||||
_renderHeader(props: NavigationSceneRendererProps): ?ReactElement {
|
||||
// TODO(hedger): Render the legacy header.
|
||||
return null;
|
||||
}
|
||||
|
||||
_renderCard(props: NavigationSceneRendererProps): ReactElement {
|
||||
let direction = 'horizontal';
|
||||
|
||||
const {navigationState} = props.scene;
|
||||
const {configureScene} = this.props;
|
||||
|
||||
if (configureScene) {
|
||||
const route = RouteStack.getRouteByNavigationState(navigationState);
|
||||
const config = configureScene(route, this.state.stack.toArray());
|
||||
|
||||
switch (getConfigPopDirection(config)) {
|
||||
case 'left-to-right':
|
||||
direction = 'horizontal';
|
||||
break;
|
||||
|
||||
case 'top-to-bottom':
|
||||
direction = 'vertical';
|
||||
break;
|
||||
|
||||
default:
|
||||
// unsupported config.
|
||||
if (__DEV__) {
|
||||
console.warn('unsupported scene configuration');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<NavigationCard
|
||||
{...props}
|
||||
direction={direction}
|
||||
key={'card_' + navigationState.key}
|
||||
renderScene={this._renderScene}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
_renderScene(props: NavigationSceneRendererProps): ReactElement {
|
||||
const {navigationState} = props.scene;
|
||||
const route = RouteStack.getRouteByNavigationState(navigationState);
|
||||
return this.props.renderScene(route, this);
|
||||
}
|
||||
}
|
||||
|
||||
// Legacy static members.
|
||||
NavigationLegacyNavigator.BreadcrumbNavigationBar = NavigatorBreadcrumbNavigationBar;
|
||||
NavigationLegacyNavigator.NavigationBar = NavigatorNavigationBar;
|
||||
NavigationLegacyNavigator.SceneConfigs = NavigatorSceneConfigs;
|
||||
|
||||
module.exports = NavigationLegacyNavigator;
|
||||
|
|
|
@ -46,6 +46,19 @@ let _nextRouteNodeID = 0;
|
|||
class RouteNode {
|
||||
key: string;
|
||||
route: any;
|
||||
|
||||
/**
|
||||
* Cast `navigationState` as `RouteNode`.
|
||||
* Also see `RouteNode#toNavigationState`.
|
||||
*/
|
||||
static fromNavigationState(navigationState: NavigationState): RouteNode {
|
||||
invariant(
|
||||
navigationState instanceof RouteNode,
|
||||
'navigationState should be an instacne of RouteNode'
|
||||
);
|
||||
return navigationState;
|
||||
}
|
||||
|
||||
constructor(route: any) {
|
||||
// Key value gets bigger incrementally. Developer can compare the
|
||||
// keys of two routes then know which route is added to the stack
|
||||
|
@ -84,11 +97,15 @@ let _nextRouteStackID = 0;
|
|||
* of the routes. This data structure is implemented as immutable data
|
||||
* and mutation (e.g. push, pop...etc) will yields a new instance.
|
||||
*/
|
||||
class RouteStack {
|
||||
class RouteStack {
|
||||
_index: number;
|
||||
_key: string;
|
||||
_routeNodes: Array<RouteNode>;
|
||||
|
||||
static getRouteByNavigationState(navigationState: NavigationState): any {
|
||||
return RouteNode.fromNavigationState(navigationState).route;
|
||||
}
|
||||
|
||||
constructor(index: number, routes: Array<any>) {
|
||||
invariant(
|
||||
routes.length > 0,
|
||||
|
|
|
@ -24,7 +24,6 @@
|
|||
*/
|
||||
'use strict';
|
||||
|
||||
|
||||
jest
|
||||
.autoMockOff()
|
||||
.mock('ErrorUtils');
|
||||
|
@ -73,13 +72,13 @@ describe('NavigationLegacyNavigatorRouteStack:', () => {
|
|||
});
|
||||
|
||||
it('throws at index out of bound', () => {
|
||||
expect(() => {
|
||||
new NavigationLegacyNavigatorRouteStack(-1, ['a', 'b']);
|
||||
}).toThrow();
|
||||
expect(
|
||||
() => new NavigationLegacyNavigatorRouteStack(-1, ['a', 'b'])
|
||||
).toThrow();
|
||||
|
||||
expect(() => {
|
||||
new NavigationLegacyNavigatorRouteStack(100, ['a', 'b']);
|
||||
}).toThrow();
|
||||
expect(
|
||||
() => new NavigationLegacyNavigatorRouteStack(100, ['a', 'b'])
|
||||
).toThrow();
|
||||
});
|
||||
|
||||
it('finds index', () => {
|
||||
|
@ -386,4 +385,11 @@ describe('NavigationLegacyNavigatorRouteStack:', () => {
|
|||
],
|
||||
});
|
||||
});
|
||||
|
||||
it('coverts from navigation state', () => {
|
||||
const stack = new NavigationLegacyNavigatorRouteStack(0, ['a', 'b']);
|
||||
const state = stack.toNavigationState().children[0];
|
||||
const route = NavigationLegacyNavigatorRouteStack.getRouteByNavigationState(state);
|
||||
expect(route).toBe('a');
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue