Clean up APIs.
Reviewed By: ericvicenti Differential Revision: D3010136 fb-gh-sync-id: 310864450bfc86ebc2d696f8ef4876b14fa3a57f shipit-source-id: 310864450bfc86ebc2d696f8ef4876b14fa3a57f
This commit is contained in:
parent
fbef6f6893
commit
71e59761c9
|
@ -48,7 +48,10 @@ const NavigationBasicReducer = NavigationReducer.StackReducer({
|
||||||
|
|
||||||
class NavigationAnimatedExample extends React.Component {
|
class NavigationAnimatedExample extends React.Component {
|
||||||
componentWillMount() {
|
componentWillMount() {
|
||||||
this._renderNavigated = this._renderNavigated.bind(this);
|
this._renderNavigation = this._renderNavigation.bind(this);
|
||||||
|
this._renderCard = this._renderCard.bind(this);
|
||||||
|
this._renderScene = this._renderScene.bind(this);
|
||||||
|
this._renderHeader = this._renderHeader.bind(this);
|
||||||
}
|
}
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
|
@ -56,7 +59,7 @@ class NavigationAnimatedExample extends React.Component {
|
||||||
reducer={NavigationBasicReducer}
|
reducer={NavigationBasicReducer}
|
||||||
ref={navRootContainer => { this.navRootContainer = navRootContainer; }}
|
ref={navRootContainer => { this.navRootContainer = navRootContainer; }}
|
||||||
persistenceKey="NavigationAnimExampleState"
|
persistenceKey="NavigationAnimExampleState"
|
||||||
renderNavigation={this._renderNavigated}
|
renderNavigation={this._renderNavigation}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -66,7 +69,7 @@ class NavigationAnimatedExample extends React.Component {
|
||||||
this.navRootContainer.handleNavigation(NavigationRootContainer.getBackAction())
|
this.navRootContainer.handleNavigation(NavigationRootContainer.getBackAction())
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
_renderNavigated(navigationState, onNavigate) {
|
_renderNavigation(navigationState, onNavigate) {
|
||||||
if (!navigationState) {
|
if (!navigationState) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -74,46 +77,56 @@ class NavigationAnimatedExample extends React.Component {
|
||||||
<NavigationAnimatedView
|
<NavigationAnimatedView
|
||||||
navigationState={navigationState}
|
navigationState={navigationState}
|
||||||
style={styles.animatedView}
|
style={styles.animatedView}
|
||||||
renderOverlay={(props) => (
|
renderOverlay={this._renderHeader}
|
||||||
<NavigationHeader
|
|
||||||
navigationState={props.navigationParentState}
|
|
||||||
position={props.position}
|
|
||||||
getTitle={state => state.key}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
setTiming={(pos, navState) => {
|
setTiming={(pos, navState) => {
|
||||||
Animated.timing(pos, {toValue: navState.index, duration: 1000}).start();
|
Animated.timing(pos, {toValue: navState.index, duration: 1000}).start();
|
||||||
}}
|
}}
|
||||||
renderScene={(props) => (
|
renderScene={this._renderCard}
|
||||||
<NavigationCard
|
|
||||||
key={props.navigationState.key}
|
|
||||||
index={props.index}
|
|
||||||
navigationState={props.navigationParentState}
|
|
||||||
position={props.position}
|
|
||||||
layout={props.layout}>
|
|
||||||
<ScrollView style={styles.scrollView}>
|
|
||||||
<NavigationExampleRow
|
|
||||||
text={props.navigationState.key}
|
|
||||||
/>
|
|
||||||
<NavigationExampleRow
|
|
||||||
text="Push!"
|
|
||||||
onPress={() => {
|
|
||||||
onNavigate({
|
|
||||||
type: 'push',
|
|
||||||
key: 'Route #' + props.navigationParentState.children.length
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<NavigationExampleRow
|
|
||||||
text="Exit Animated Nav Example"
|
|
||||||
onPress={this.props.onExampleExit}
|
|
||||||
/>
|
|
||||||
</ScrollView>
|
|
||||||
</NavigationCard>
|
|
||||||
)}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_renderHeader(/*NavigationSceneRendererProps*/ props) {
|
||||||
|
return (
|
||||||
|
<NavigationHeader
|
||||||
|
{...props}
|
||||||
|
getTitle={state => state.key}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
_renderCard(/*NavigationSceneRendererProps*/ props) {
|
||||||
|
return (
|
||||||
|
<NavigationCard
|
||||||
|
{...props}
|
||||||
|
key={'card_' + props.scene.navigationState.key}
|
||||||
|
renderScene={this._renderScene}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
_renderScene(/*NavigationSceneRendererProps*/ props) {
|
||||||
|
return (
|
||||||
|
<ScrollView style={styles.scrollView}>
|
||||||
|
<NavigationExampleRow
|
||||||
|
text={props.scene.navigationState.key}
|
||||||
|
/>
|
||||||
|
<NavigationExampleRow
|
||||||
|
text="Push!"
|
||||||
|
onPress={() => {
|
||||||
|
props.onNavigate({
|
||||||
|
type: 'push',
|
||||||
|
key: 'Route #' + props.scenes.length,
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<NavigationExampleRow
|
||||||
|
text="Exit Animated Nav Example"
|
||||||
|
onPress={this.props.onExampleExit}
|
||||||
|
/>
|
||||||
|
</ScrollView>
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
|
|
|
@ -49,6 +49,7 @@ function reduceNavigationState(initialState) {
|
||||||
|
|
||||||
const ExampleReducer = reduceNavigationState({
|
const ExampleReducer = reduceNavigationState({
|
||||||
index: 0,
|
index: 0,
|
||||||
|
key: 'exmaple',
|
||||||
children: [{key: 'First Route'}],
|
children: [{key: 'First Route'}],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -56,12 +57,13 @@ class NavigationCardStackExample extends React.Component {
|
||||||
|
|
||||||
constructor(props, context) {
|
constructor(props, context) {
|
||||||
super(props, context);
|
super(props, context);
|
||||||
|
this.state = {isHorizontal: true};
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillMount() {
|
||||||
this._renderNavigation = this._renderNavigation.bind(this);
|
this._renderNavigation = this._renderNavigation.bind(this);
|
||||||
this._renderScene = this._renderScene.bind(this);
|
this._renderScene = this._renderScene.bind(this);
|
||||||
this._toggleDirection = this._toggleDirection.bind(this);
|
this._toggleDirection = this._toggleDirection.bind(this);
|
||||||
|
|
||||||
this.state = {isHorizontal: true};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
@ -86,8 +88,7 @@ class NavigationCardStackExample extends React.Component {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
_renderScene(props) {
|
_renderScene(/*NavigationSceneRendererProps*/ props) {
|
||||||
const {navigationParentState, onNavigate} = props;
|
|
||||||
return (
|
return (
|
||||||
<ScrollView style={styles.scrollView}>
|
<ScrollView style={styles.scrollView}>
|
||||||
<NavigationExampleRow
|
<NavigationExampleRow
|
||||||
|
@ -99,21 +100,21 @@ class NavigationCardStackExample extends React.Component {
|
||||||
onPress={this._toggleDirection}
|
onPress={this._toggleDirection}
|
||||||
/>
|
/>
|
||||||
<NavigationExampleRow
|
<NavigationExampleRow
|
||||||
text={'route = ' + props.navigationState.key}
|
text={'route = ' + props.scene.navigationState.key}
|
||||||
/>
|
/>
|
||||||
<NavigationExampleRow
|
<NavigationExampleRow
|
||||||
text="Push Route"
|
text="Push Route"
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
onNavigate({
|
props.onNavigate({
|
||||||
type: 'push',
|
type: 'push',
|
||||||
key: 'Route ' + navigationParentState.children.length,
|
key: 'Route ' + props.scenes.length,
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<NavigationExampleRow
|
<NavigationExampleRow
|
||||||
text="Pop Route"
|
text="Pop Route"
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
onNavigate({
|
props.onNavigate({
|
||||||
type: 'pop',
|
type: 'pop',
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
|
|
|
@ -16,25 +16,32 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const React = require('react-native');
|
const React = require('react-native');
|
||||||
|
const NavigationExampleRow = require('./NavigationExampleRow');
|
||||||
|
const NavigationExampleTabBar = require('./NavigationExampleTabBar');
|
||||||
|
|
||||||
const {
|
const {
|
||||||
NavigationExperimental,
|
NavigationExperimental,
|
||||||
ScrollView,
|
ScrollView,
|
||||||
StyleSheet,
|
StyleSheet,
|
||||||
View,
|
View,
|
||||||
} = React;
|
} = React;
|
||||||
|
|
||||||
const {
|
const {
|
||||||
AnimatedView: NavigationAnimatedView,
|
AnimatedView: NavigationAnimatedView,
|
||||||
Card: NavigationCard,
|
CardStack: NavigationCardStack,
|
||||||
Container: NavigationContainer,
|
Container: NavigationContainer,
|
||||||
RootContainer: NavigationRootContainer,
|
|
||||||
Header: NavigationHeader,
|
Header: NavigationHeader,
|
||||||
Reducer: NavigationReducer,
|
Reducer: NavigationReducer,
|
||||||
|
RootContainer: NavigationRootContainer,
|
||||||
View: NavigationView,
|
View: NavigationView,
|
||||||
} = NavigationExperimental;
|
} = NavigationExperimental;
|
||||||
const NavigationExampleRow = require('./NavigationExampleRow');
|
|
||||||
const NavigationExampleTabBar = require('./NavigationExampleTabBar');
|
|
||||||
|
|
||||||
import type {NavigationParentState} from 'NavigationStateUtils';
|
|
||||||
|
import type {
|
||||||
|
NavigationParentState,
|
||||||
|
NavigationSceneRenderer,
|
||||||
|
NavigationSceneRendererProps,
|
||||||
|
} from 'NavigationTypeDefinition';
|
||||||
|
|
||||||
type Action = {
|
type Action = {
|
||||||
isExitAction?: boolean,
|
isExitAction?: boolean,
|
||||||
|
@ -43,6 +50,7 @@ type Action = {
|
||||||
const ExampleExitAction = () => ({
|
const ExampleExitAction = () => ({
|
||||||
isExitAction: true,
|
isExitAction: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
ExampleExitAction.match = (action: Action) => (
|
ExampleExitAction.match = (action: Action) => (
|
||||||
action && action.isExitAction === true
|
action && action.isExitAction === true
|
||||||
);
|
);
|
||||||
|
@ -51,6 +59,7 @@ const PageAction = (type) => ({
|
||||||
type,
|
type,
|
||||||
isPageAction: true,
|
isPageAction: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
PageAction.match = (action) => (
|
PageAction.match = (action) => (
|
||||||
action && action.isPageAction === true
|
action && action.isPageAction === true
|
||||||
);
|
);
|
||||||
|
@ -59,6 +68,7 @@ const ExampleProfilePageAction = (type) => ({
|
||||||
...PageAction(type),
|
...PageAction(type),
|
||||||
isProfilePageAction: true,
|
isProfilePageAction: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
ExampleProfilePageAction.match = (action) => (
|
ExampleProfilePageAction.match = (action) => (
|
||||||
action && action.isProfilePageAction === true
|
action && action.isProfilePageAction === true
|
||||||
);
|
);
|
||||||
|
@ -68,7 +78,9 @@ const ExampleInfoAction = () => PageAction('InfoPage');
|
||||||
const ExampleNotifProfileAction = () => ExampleProfilePageAction('NotifProfilePage');
|
const ExampleNotifProfileAction = () => ExampleProfilePageAction('NotifProfilePage');
|
||||||
|
|
||||||
const _jsInstanceUniqueId = '' + Date.now();
|
const _jsInstanceUniqueId = '' + Date.now();
|
||||||
|
|
||||||
let _uniqueIdCount = 0;
|
let _uniqueIdCount = 0;
|
||||||
|
|
||||||
function pageStateActionMap(action) {
|
function pageStateActionMap(action) {
|
||||||
return {
|
return {
|
||||||
key: 'page-' + _jsInstanceUniqueId + '-' + (_uniqueIdCount++),
|
key: 'page-' + _jsInstanceUniqueId + '-' + (_uniqueIdCount++),
|
||||||
|
@ -144,55 +156,57 @@ function stateTypeTitleMap(pageState) {
|
||||||
}
|
}
|
||||||
|
|
||||||
class ExampleTabScreen extends React.Component {
|
class ExampleTabScreen extends React.Component {
|
||||||
|
_renderCard: NavigationSceneRenderer;
|
||||||
|
_renderHeader: NavigationSceneRenderer;
|
||||||
|
_renderScene: NavigationSceneRenderer;
|
||||||
|
|
||||||
|
componentWillMount() {
|
||||||
|
this._renderHeader = this._renderHeader.bind(this);
|
||||||
|
this._renderScene = this._renderScene.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<NavigationAnimatedView
|
<NavigationCardStack
|
||||||
style={styles.tabContent}
|
style={styles.tabContent}
|
||||||
navigationState={this.props.navigationState}
|
navigationState={this.props.navigationState}
|
||||||
renderOverlay={this._renderHeader.bind(this)}
|
renderOverlay={this._renderHeader}
|
||||||
renderScene={this._renderScene.bind(this)}
|
renderScene={this._renderScene}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
_renderHeader(props) {
|
_renderHeader(props: NavigationSceneRendererProps) {
|
||||||
return (
|
return (
|
||||||
<NavigationHeader
|
<NavigationHeader
|
||||||
navigationState={props.navigationParentState}
|
{...props}
|
||||||
position={props.position}
|
|
||||||
layout={props.layout}
|
|
||||||
getTitle={state => stateTypeTitleMap(state)}
|
getTitle={state => stateTypeTitleMap(state)}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
_renderScene(props) {
|
|
||||||
|
_renderScene(props: NavigationSceneRendererProps) {
|
||||||
|
const {onNavigate} = props;
|
||||||
return (
|
return (
|
||||||
<NavigationCard
|
<ScrollView style={styles.scrollView}>
|
||||||
key={props.navigationState.key}
|
<NavigationExampleRow
|
||||||
index={props.index}
|
text="Open page"
|
||||||
navigationState={props.navigationParentState}
|
onPress={() => {
|
||||||
position={props.position}
|
onNavigate(ExampleInfoAction());
|
||||||
layout={props.layout}>
|
}}
|
||||||
<ScrollView style={styles.scrollView}>
|
/>
|
||||||
<NavigationExampleRow
|
<NavigationExampleRow
|
||||||
text="Open page"
|
text="Open a page in the profile tab"
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
this.props.onNavigate(ExampleInfoAction());
|
onNavigate(ExampleNotifProfileAction());
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<NavigationExampleRow
|
<NavigationExampleRow
|
||||||
text="Open a page in the profile tab"
|
text="Exit Composition Example"
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
this.props.onNavigate(ExampleNotifProfileAction());
|
onNavigate(ExampleExitAction());
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<NavigationExampleRow
|
</ScrollView>
|
||||||
text="Exit Composition Example"
|
|
||||||
onPress={() => {
|
|
||||||
this.props.onNavigate(ExampleExitAction());
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</ScrollView>
|
|
||||||
</NavigationCard>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,8 +36,7 @@ const {
|
||||||
} = React;
|
} = React;
|
||||||
|
|
||||||
const {
|
const {
|
||||||
AnimatedView: NavigationAnimatedView,
|
CardStack: NavigationCardStack,
|
||||||
Card: NavigationCard,
|
|
||||||
Header: NavigationHeader,
|
Header: NavigationHeader,
|
||||||
Reducer: NavigationReducer,
|
Reducer: NavigationReducer,
|
||||||
RootContainer: NavigationRootContainer,
|
RootContainer: NavigationRootContainer,
|
||||||
|
@ -45,7 +44,7 @@ const {
|
||||||
|
|
||||||
import type { Value } from 'Animated';
|
import type { Value } from 'Animated';
|
||||||
|
|
||||||
import type { NavigationStateRendererProps } from 'NavigationAnimatedView';
|
import type { NavigationSceneRendererProps } from 'NavigationTypeDefinition';
|
||||||
|
|
||||||
import type { UIExplorerNavigationState } from './UIExplorerNavigationReducer';
|
import type { UIExplorerNavigationState } from './UIExplorerNavigationReducer';
|
||||||
|
|
||||||
|
@ -78,7 +77,6 @@ function URIActionMap(uri: ?string): ?Object {
|
||||||
return PathActionMap(path);
|
return PathActionMap(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class UIExplorerApp extends React.Component {
|
class UIExplorerApp extends React.Component {
|
||||||
_navigationRootRef: ?NavigationRootContainer;
|
_navigationRootRef: ?NavigationRootContainer;
|
||||||
_renderNavigation: Function;
|
_renderNavigation: Function;
|
||||||
|
@ -89,7 +87,6 @@ class UIExplorerApp extends React.Component {
|
||||||
this._renderNavigation = this._renderNavigation.bind(this);
|
this._renderNavigation = this._renderNavigation.bind(this);
|
||||||
this._renderOverlay = this._renderOverlay.bind(this);
|
this._renderOverlay = this._renderOverlay.bind(this);
|
||||||
this._renderScene = this._renderScene.bind(this);
|
this._renderScene = this._renderScene.bind(this);
|
||||||
this._renderCard = this._renderCard.bind(this);
|
|
||||||
}
|
}
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
|
@ -118,39 +115,27 @@ class UIExplorerApp extends React.Component {
|
||||||
}
|
}
|
||||||
const {stack} = navigationState;
|
const {stack} = navigationState;
|
||||||
return (
|
return (
|
||||||
<NavigationAnimatedView
|
<NavigationCardStack
|
||||||
navigationState={stack}
|
navigationState={stack}
|
||||||
style={styles.container}
|
style={styles.container}
|
||||||
renderOverlay={this._renderOverlay}
|
renderOverlay={this._renderOverlay}
|
||||||
renderScene={this._renderCard}
|
renderScene={this._renderScene}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
_renderOverlay(props: NavigationStateRendererProps): ReactElement {
|
_renderOverlay(props: NavigationSceneRendererProps): ReactElement {
|
||||||
return (
|
return (
|
||||||
<NavigationHeader
|
<NavigationHeader
|
||||||
navigationState={props.navigationParentState}
|
{...props}
|
||||||
position={props.position}
|
key={'header_' + props.scene.navigationState.key}
|
||||||
getTitle={UIExplorerStateTitleMap}
|
getTitle={UIExplorerStateTitleMap}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
_renderCard(props: NavigationStateRendererProps): ReactElement {
|
_renderScene(props: NavigationSceneRendererProps): ?ReactElement {
|
||||||
return (
|
const state = props.scene.navigationState;
|
||||||
<NavigationCard
|
|
||||||
index={props.index}
|
|
||||||
key={props.navigationState.key}
|
|
||||||
layout={props.layout}
|
|
||||||
navigationState={props.navigationParentState}
|
|
||||||
position={props.position}>
|
|
||||||
{this._renderScene(props.navigationState)}
|
|
||||||
</NavigationCard>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
_renderScene(state: Object): ?ReactElement {
|
|
||||||
if (state.key === 'AppList') {
|
if (state.key === 'AppList') {
|
||||||
return (
|
return (
|
||||||
<UIExplorerExampleList
|
<UIExplorerExampleList
|
||||||
|
|
|
@ -26,7 +26,7 @@ const {
|
||||||
} = NavigationExperimental;
|
} = NavigationExperimental;
|
||||||
const StackReducer = NavigationReducer.StackReducer;
|
const StackReducer = NavigationReducer.StackReducer;
|
||||||
|
|
||||||
import type {NavigationState} from 'NavigationStateUtils';
|
import type {NavigationState} from 'NavigationTypeDefinition';
|
||||||
|
|
||||||
import type {UIExplorerAction} from './UIExplorerActions';
|
import type {UIExplorerAction} from './UIExplorerActions';
|
||||||
|
|
||||||
|
@ -93,7 +93,7 @@ function UIExplorerNavigationReducer(lastState: ?UIExplorerNavigationState, acti
|
||||||
if (newStack !== lastState.stack) {
|
if (newStack !== lastState.stack) {
|
||||||
return {
|
return {
|
||||||
externalExample: null,
|
externalExample: null,
|
||||||
stack: newStack,
|
stack: newStack,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return lastState;
|
return lastState;
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
// $FlowFixMe : This is a platform-forked component, and flow seems to only run on iOS?
|
// $FlowFixMe : This is a platform-forked component, and flow seems to only run on iOS?
|
||||||
const UIExplorerList = require('./UIExplorerList');
|
const UIExplorerList = require('./UIExplorerList');
|
||||||
|
|
||||||
import type {NavigationState} from 'NavigationStateUtils';
|
import type {NavigationState} from 'NavigationTypeDefinition';
|
||||||
|
|
||||||
function StateTitleMap(state: NavigationState): string {
|
function StateTitleMap(state: NavigationState): string {
|
||||||
if (UIExplorerList.Modules[state.key]) {
|
if (UIExplorerList.Modules[state.key]) {
|
||||||
|
|
|
@ -28,142 +28,260 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const Animated = require('Animated');
|
const Animated = require('Animated');
|
||||||
const NavigationRootContainer = require('NavigationRootContainer');
|
|
||||||
const NavigationContainer = require('NavigationContainer');
|
const NavigationContainer = require('NavigationContainer');
|
||||||
const PanResponder = require('PanResponder');
|
const NavigationLinearPanResponder = require('NavigationLinearPanResponder');
|
||||||
const Platform = require('Platform');
|
const NavigationPropTypes = require('NavigationPropTypes');
|
||||||
const React = require('React');
|
const React = require('React');
|
||||||
|
const ReactComponentWithPureRenderMixin = require('ReactComponentWithPureRenderMixin');
|
||||||
const StyleSheet = require('StyleSheet');
|
const StyleSheet = require('StyleSheet');
|
||||||
const View = require('View');
|
const View = require('View');
|
||||||
|
|
||||||
const ENABLE_GESTURES = Platform.OS !== 'android';
|
const {Directions} = NavigationLinearPanResponder;
|
||||||
|
|
||||||
|
import type {
|
||||||
|
NavigationAnimatedValue,
|
||||||
|
NavigationLayout,
|
||||||
|
NavigationPosition,
|
||||||
|
NavigationSceneRenderer,
|
||||||
|
NavigationSceneRendererProps,
|
||||||
|
} from 'NavigationTypeDefinition';
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
NavigationParentState
|
NavigationGestureDirection
|
||||||
} from 'NavigationStateUtils';
|
} from 'NavigationLinearPanResponder';
|
||||||
|
|
||||||
type Layout = {
|
type State = {
|
||||||
initWidth: number,
|
hash: string,
|
||||||
initHeight: number,
|
height: number,
|
||||||
width: Animated.Value;
|
width: number,
|
||||||
height: Animated.Value;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
type Props = {
|
type Props = NavigationSceneRendererProps & {
|
||||||
navigationState: NavigationParentState;
|
direction: NavigationGestureDirection,
|
||||||
index: number;
|
renderScene: NavigationSceneRenderer,
|
||||||
position: Animated.Value;
|
|
||||||
layout: Layout;
|
|
||||||
onNavigate: Function;
|
|
||||||
children: Object;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class NavigationCard extends React.Component {
|
const {PropTypes} = React;
|
||||||
_responder: ?Object;
|
|
||||||
_lastHeight: number;
|
const propTypes = {
|
||||||
_lastWidth: number;
|
...NavigationPropTypes.SceneRenderer,
|
||||||
_widthListener: string;
|
direction: PropTypes.oneOf([Directions.HORIZONTAL, Directions.VERTICAL]),
|
||||||
_heightListener: string;
|
renderScene: PropTypes.func.isRequired,
|
||||||
props: Props;
|
};
|
||||||
componentWillMount() {
|
|
||||||
if (ENABLE_GESTURES) {
|
const defaultProps = {
|
||||||
this._enableGestures();
|
direction: Directions.HORIZONTAL,
|
||||||
}
|
};
|
||||||
|
|
||||||
|
class AmimatedValueSubscription {
|
||||||
|
_value: NavigationAnimatedValue;
|
||||||
|
_token: string;
|
||||||
|
|
||||||
|
constructor(value: NavigationAnimatedValue, callback: Function) {
|
||||||
|
this._value = value;
|
||||||
|
this._token = value.addListener(callback);
|
||||||
}
|
}
|
||||||
_enableGestures() {
|
|
||||||
this._responder = PanResponder.create({
|
remove() {
|
||||||
onMoveShouldSetPanResponder: (e, {dx, dy, moveX, moveY, x0, y0}) => {
|
this._value.removeListener(this._token);
|
||||||
if (this.props.navigationState.index === 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (moveX > 30) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (dx > 5 && Math.abs(dy) < 4) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
onPanResponderGrant: (e, {dx, dy, moveX, moveY, x0, y0}) => {
|
|
||||||
},
|
|
||||||
onPanResponderMove: (e, {dx}) => {
|
|
||||||
const a = (-dx / this._lastWidth) + this.props.navigationState.index;
|
|
||||||
this.props.position.setValue(a);
|
|
||||||
},
|
|
||||||
onPanResponderRelease: (e, {vx, dx}) => {
|
|
||||||
const xRatio = dx / this._lastWidth;
|
|
||||||
const doesPop = (xRatio + vx) > 0.45;
|
|
||||||
if (doesPop) {
|
|
||||||
// todo: add an action which accepts velocity of the pop action/gesture, which is caught and used by NavigationAnimatedView
|
|
||||||
this.props.onNavigate(NavigationRootContainer.getBackAction());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Animated.spring(this.props.position, {
|
|
||||||
toValue: this.props.navigationState.index,
|
|
||||||
}).start();
|
|
||||||
},
|
|
||||||
onPanResponderTerminate: (e, {vx, dx}) => {
|
|
||||||
Animated.spring(this.props.position, {
|
|
||||||
toValue: this.props.navigationState.index,
|
|
||||||
}).start();
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
componentDidMount() {
|
|
||||||
this._lastHeight = this.props.layout.initHeight;
|
|
||||||
this._lastWidth = this.props.layout.initWidth;
|
|
||||||
this._widthListener = this.props.layout.width.addListener(({value}) => {
|
|
||||||
this._lastWidth = value;
|
|
||||||
});
|
|
||||||
this._heightListener = this.props.layout.height.addListener(({value}) => {
|
|
||||||
this._lastHeight = value;
|
|
||||||
});
|
|
||||||
// todo: fix listener and last layout dimentsions when props change. potential bugs here
|
|
||||||
}
|
|
||||||
componentWillUnmount() {
|
|
||||||
this.props.layout.width.removeListener(this._widthListener);
|
|
||||||
this.props.layout.height.removeListener(this._heightListener);
|
|
||||||
}
|
|
||||||
render() {
|
|
||||||
const cardPosition = Animated.add(this.props.position, new Animated.Value(-this.props.index));
|
|
||||||
const gestureValue = Animated.multiply(cardPosition, this.props.layout.width);
|
|
||||||
const touchResponderHandlers = this._responder ? this._responder.panHandlers : null;
|
|
||||||
return (
|
|
||||||
<Animated.View
|
|
||||||
{...touchResponderHandlers}
|
|
||||||
style={[
|
|
||||||
styles.card,
|
|
||||||
{
|
|
||||||
right: gestureValue,
|
|
||||||
left: gestureValue.interpolate({
|
|
||||||
inputRange: [0, 1],
|
|
||||||
outputRange: [0, -1],
|
|
||||||
}),
|
|
||||||
opacity: cardPosition.interpolate({
|
|
||||||
inputRange: [-1,0,1],
|
|
||||||
outputRange: [0,1,1],
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
]}>
|
|
||||||
{this.props.children}
|
|
||||||
</Animated.View>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
NavigationCard = NavigationContainer.create(NavigationCard);
|
/**
|
||||||
|
* Class that provides the required information for the
|
||||||
|
* `NavigationLinearPanResponder`. This class must implement
|
||||||
|
* the interface `NavigationLinearPanResponderDelegate`.
|
||||||
|
*/
|
||||||
|
class PanResponderDelegate {
|
||||||
|
_props : Props;
|
||||||
|
|
||||||
|
constructor(props: Props) {
|
||||||
|
this._props = props;
|
||||||
|
}
|
||||||
|
|
||||||
|
getDirection(): NavigationGestureDirection {
|
||||||
|
return this._props.direction;
|
||||||
|
}
|
||||||
|
|
||||||
|
getIndex(): number {
|
||||||
|
return this._props.navigationState.index;
|
||||||
|
}
|
||||||
|
|
||||||
|
getLayout(): NavigationLayout {
|
||||||
|
return this._props.layout;
|
||||||
|
}
|
||||||
|
|
||||||
|
getPosition(): NavigationPosition {
|
||||||
|
return this._props.position;
|
||||||
|
}
|
||||||
|
|
||||||
|
onNavigate(action: {type: string}): void {
|
||||||
|
this._props.onNavigate && this._props.onNavigate(action);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Component that renders the scene as card for the <NavigationCardStack />.
|
||||||
|
*/
|
||||||
|
class NavigationCard extends React.Component {
|
||||||
|
props: Props;
|
||||||
|
state: State;
|
||||||
|
_calculateState: (t: NavigationLayout) => State;
|
||||||
|
_layoutListeners: Array<AmimatedValueSubscription>;
|
||||||
|
|
||||||
|
constructor(props: Props, context: any) {
|
||||||
|
super(props, context);
|
||||||
|
|
||||||
|
this.state = this._calculateState(props.layout);
|
||||||
|
this._layoutListeners = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
shouldComponentUpdate(nextProps: Object, nextState: Object): boolean {
|
||||||
|
return ReactComponentWithPureRenderMixin.shouldComponentUpdate.call(
|
||||||
|
this,
|
||||||
|
nextProps,
|
||||||
|
nextState
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillMount(): void {
|
||||||
|
this._calculateState = this._calculateState.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount(): void {
|
||||||
|
this._applyLayout(this.props.layout);
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillUnmount(): void {
|
||||||
|
this._layoutListeners.forEach(subscription => subscription.remove);
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillReceiveProps(nextProps: Props): void {
|
||||||
|
this._applyLayout(nextProps.layout);
|
||||||
|
}
|
||||||
|
|
||||||
|
render(): ReactElement {
|
||||||
|
const {
|
||||||
|
direction,
|
||||||
|
layout,
|
||||||
|
navigationState,
|
||||||
|
onNavigate,
|
||||||
|
position,
|
||||||
|
scene,
|
||||||
|
scenes,
|
||||||
|
} = this.props;
|
||||||
|
|
||||||
|
const {
|
||||||
|
height,
|
||||||
|
width,
|
||||||
|
} = this.state;
|
||||||
|
|
||||||
|
const index = scene.index;
|
||||||
|
const isVertical = direction === 'vertical';
|
||||||
|
const inputRange = [index - 1, index, index + 1];
|
||||||
|
const animatedStyle = {
|
||||||
|
|
||||||
|
opacity: position.interpolate({
|
||||||
|
inputRange,
|
||||||
|
outputRange: [1, 1, 0.3],
|
||||||
|
}),
|
||||||
|
|
||||||
|
transform: [
|
||||||
|
{
|
||||||
|
scale: position.interpolate({
|
||||||
|
inputRange,
|
||||||
|
outputRange: [1, 1, 0.95],
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
translateX: isVertical ? 0 :
|
||||||
|
position.interpolate({
|
||||||
|
inputRange,
|
||||||
|
outputRange: [width, 0, -10],
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
translateY: !isVertical ? 0 :
|
||||||
|
position.interpolate({
|
||||||
|
inputRange,
|
||||||
|
outputRange: [height, 0, -10],
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
let panHandlers = null;
|
||||||
|
if (navigationState.index === index) {
|
||||||
|
const delegate = new PanResponderDelegate(this.props);
|
||||||
|
const panResponder = new NavigationLinearPanResponder(delegate);
|
||||||
|
panHandlers = panResponder.panHandlers;
|
||||||
|
}
|
||||||
|
|
||||||
|
const sceneProps = {
|
||||||
|
layout,
|
||||||
|
navigationState,
|
||||||
|
onNavigate,
|
||||||
|
position,
|
||||||
|
scene,
|
||||||
|
scenes,
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Animated.View
|
||||||
|
{...panHandlers}
|
||||||
|
style={[styles.main, animatedStyle]}>
|
||||||
|
{this.props.renderScene(sceneProps)}
|
||||||
|
</Animated.View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
_calculateState(layout: NavigationLayout): State {
|
||||||
|
const width = layout.width.__getValue();
|
||||||
|
const height = layout.height.__getValue();
|
||||||
|
const hash = 'layout-' + width + '-' + height;
|
||||||
|
const state = {
|
||||||
|
height,
|
||||||
|
width,
|
||||||
|
hash,
|
||||||
|
};
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
_applyLayout(layout: NavigationLayout) {
|
||||||
|
this._layoutListeners.forEach(subscription => subscription.remove);
|
||||||
|
|
||||||
|
this._layoutListeners.length = 0;
|
||||||
|
|
||||||
|
const callback = this._applyLayout.bind(this, layout);
|
||||||
|
|
||||||
|
this._layoutListeners.push(
|
||||||
|
new AmimatedValueSubscription(layout.width, callback),
|
||||||
|
new AmimatedValueSubscription(layout.height, callback),
|
||||||
|
);
|
||||||
|
|
||||||
|
const nextState = this._calculateState(layout);
|
||||||
|
if (nextState.hash !== this.state.hash) {
|
||||||
|
this.setState(nextState);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NavigationCard.propTypes = propTypes;
|
||||||
|
NavigationCard.defaultProps = defaultProps;
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
card: {
|
main: {
|
||||||
backgroundColor: '#E9E9EF',
|
backgroundColor: '#E9E9EF',
|
||||||
|
bottom: 0,
|
||||||
|
left: 0,
|
||||||
|
position: 'absolute',
|
||||||
|
right: 0,
|
||||||
shadowColor: 'black',
|
shadowColor: 'black',
|
||||||
shadowOpacity: 0.4,
|
|
||||||
shadowOffset: {width: 0, height: 0},
|
shadowOffset: {width: 0, height: 0},
|
||||||
|
shadowOpacity: 0.4,
|
||||||
shadowRadius: 10,
|
shadowRadius: 10,
|
||||||
top: 0,
|
top: 0,
|
||||||
bottom: 0,
|
|
||||||
position: 'absolute',
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
module.exports = NavigationCard;
|
module.exports = NavigationContainer.create(NavigationCard);
|
||||||
|
|
|
@ -29,9 +29,10 @@
|
||||||
|
|
||||||
const Animated = require('Animated');
|
const Animated = require('Animated');
|
||||||
const NavigationAnimatedView = require('NavigationAnimatedView');
|
const NavigationAnimatedView = require('NavigationAnimatedView');
|
||||||
const NavigationCardStackItem = require('NavigationCardStackItem');
|
const NavigationCard = require('NavigationCard');
|
||||||
const NavigationContainer = require('NavigationContainer');
|
const NavigationContainer = require('NavigationContainer');
|
||||||
const NavigationLinearPanResponder = require('NavigationLinearPanResponder');
|
const NavigationLinearPanResponder = require('NavigationLinearPanResponder');
|
||||||
|
const NavigationPropTypes = require('NavigationPropTypes');
|
||||||
const React = require('React');
|
const React = require('React');
|
||||||
const ReactComponentWithPureRenderMixin = require('ReactComponentWithPureRenderMixin');
|
const ReactComponentWithPureRenderMixin = require('ReactComponentWithPureRenderMixin');
|
||||||
const StyleSheet = require('StyleSheet');
|
const StyleSheet = require('StyleSheet');
|
||||||
|
@ -42,32 +43,48 @@ const {PropTypes} = React;
|
||||||
const {Directions} = NavigationLinearPanResponder;
|
const {Directions} = NavigationLinearPanResponder;
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
|
NavigationAnimatedValue,
|
||||||
|
NavigationAnimationSetter,
|
||||||
NavigationParentState,
|
NavigationParentState,
|
||||||
} from 'NavigationStateUtils';
|
NavigationSceneRenderer,
|
||||||
|
NavigationSceneRendererProps,
|
||||||
|
} from 'NavigationTypeDefinition';
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
NavigationStateRenderer,
|
NavigationGestureDirection,
|
||||||
NavigationStateRendererProps,
|
} from 'NavigationLinearPanResponder';
|
||||||
Position,
|
|
||||||
TimingSetter,
|
|
||||||
} from 'NavigationAnimatedView';
|
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
direction: string,
|
direction: NavigationGestureDirection,
|
||||||
navigationState: NavigationParentState,
|
navigationState: NavigationParentState,
|
||||||
renderOverlay: ?NavigationStateRenderer,
|
renderOverlay: ?NavigationSceneRenderer,
|
||||||
renderScene: NavigationStateRenderer,
|
renderScene: NavigationSceneRenderer,
|
||||||
|
};
|
||||||
|
|
||||||
|
const propTypes = {
|
||||||
|
direction: PropTypes.oneOf([Directions.HORIZONTAL, Directions.VERTICAL]),
|
||||||
|
navigationState: NavigationPropTypes.navigationParentState.isRequired,
|
||||||
|
renderOverlay: PropTypes.func,
|
||||||
|
renderScene: PropTypes.func.isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
|
const defaultProps = {
|
||||||
|
direction: Directions.HORIZONTAL,
|
||||||
|
renderOverlay: emptyFunction.thatReturnsNull,
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A controlled navigation view that renders a list of cards.
|
* A controlled navigation view that renders a list of cards.
|
||||||
*/
|
*/
|
||||||
class NavigationCardStack extends React.Component {
|
class NavigationCardStack extends React.Component {
|
||||||
_renderScene : NavigationStateRenderer;
|
_renderScene : NavigationSceneRenderer;
|
||||||
_setTiming: TimingSetter;
|
_setTiming: NavigationAnimationSetter;
|
||||||
|
|
||||||
constructor(props: Props, context: any) {
|
constructor(props: Props, context: any) {
|
||||||
super(props, context);
|
super(props, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillMount() {
|
||||||
this._renderScene = this._renderScene.bind(this);
|
this._renderScene = this._renderScene.bind(this);
|
||||||
this._setTiming = this._setTiming.bind(this);
|
this._setTiming = this._setTiming.bind(this);
|
||||||
}
|
}
|
||||||
|
@ -92,30 +109,21 @@ class NavigationCardStack extends React.Component {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
_renderScene(props: NavigationStateRendererProps): ReactElement {
|
_renderScene(props: NavigationSceneRendererProps): ReactElement {
|
||||||
const {
|
|
||||||
index,
|
|
||||||
layout,
|
|
||||||
navigationState,
|
|
||||||
position,
|
|
||||||
navigationParentState,
|
|
||||||
} = props;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<NavigationCardStackItem
|
<NavigationCard
|
||||||
|
{...props}
|
||||||
direction={this.props.direction}
|
direction={this.props.direction}
|
||||||
index={index}
|
key={'card_' + props.scene.navigationState.key}
|
||||||
key={navigationState.key}
|
|
||||||
layout={layout}
|
|
||||||
navigationParentState={navigationParentState}
|
|
||||||
navigationState={navigationState}
|
|
||||||
position={position}
|
|
||||||
renderScene={this.props.renderScene}
|
renderScene={this.props.renderScene}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
_setTiming(position: Position, navigationState: NavigationParentState): void {
|
_setTiming(
|
||||||
|
position: NavigationAnimatedValue,
|
||||||
|
navigationState: NavigationParentState,
|
||||||
|
): void {
|
||||||
Animated.timing(
|
Animated.timing(
|
||||||
position,
|
position,
|
||||||
{
|
{
|
||||||
|
@ -126,17 +134,8 @@ class NavigationCardStack extends React.Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
NavigationCardStack.propTypes = {
|
NavigationCardStack.propTypes = propTypes;
|
||||||
direction: PropTypes.oneOf([Directions.HORIZONTAL, Directions.VERTICAL]),
|
NavigationCardStack.defaultProps = defaultProps;
|
||||||
navigationState: PropTypes.object.isRequired,
|
|
||||||
renderOverlay: PropTypes.func,
|
|
||||||
renderScene: PropTypes.func.isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
NavigationCardStack.defaultProps = {
|
|
||||||
direction: Directions.HORIZONTAL,
|
|
||||||
renderOverlay: emptyFunction.thatReturnsNull,
|
|
||||||
};
|
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
animatedView: {
|
animatedView: {
|
||||||
|
|
|
@ -1,280 +0,0 @@
|
||||||
/**
|
|
||||||
* Copyright (c) 2015, Facebook, Inc. All rights reserved.
|
|
||||||
*
|
|
||||||
* Facebook, Inc. ("Facebook") owns all right, title and interest, including
|
|
||||||
* all intellectual property and other proprietary rights, in and to the React
|
|
||||||
* Native CustomComponents software (the "Software"). Subject to your
|
|
||||||
* compliance with these terms, you are hereby granted a non-exclusive,
|
|
||||||
* worldwide, royalty-free copyright license to (1) use and copy the Software;
|
|
||||||
* and (2) reproduce and distribute the Software as part of your own software
|
|
||||||
* ("Your Software"). Facebook reserves all rights not expressly granted to
|
|
||||||
* you in this license agreement.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE AND DOCUMENTATION, IF ANY, ARE PROVIDED "AS IS" AND ANY EXPRESS
|
|
||||||
* OR IMPLIED WARRANTIES (INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
||||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE) ARE DISCLAIMED.
|
|
||||||
* IN NO EVENT SHALL FACEBOOK OR ITS AFFILIATES, OFFICERS, DIRECTORS OR
|
|
||||||
* EMPLOYEES BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
||||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
|
||||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
||||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
|
||||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE SOFTWARE, EVEN IF
|
|
||||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* @providesModule NavigationCardStackItem
|
|
||||||
* @flow
|
|
||||||
*/
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
const Animated = require('Animated');
|
|
||||||
const NavigationContainer = require('NavigationContainer');
|
|
||||||
const NavigationLinearPanResponder = require('NavigationLinearPanResponder');
|
|
||||||
const React = require('React');
|
|
||||||
const ReactComponentWithPureRenderMixin = require('ReactComponentWithPureRenderMixin');
|
|
||||||
const StyleSheet = require('StyleSheet');
|
|
||||||
const View = require('View');
|
|
||||||
|
|
||||||
const {PropTypes} = React;
|
|
||||||
const {Directions} = NavigationLinearPanResponder;
|
|
||||||
|
|
||||||
import type {
|
|
||||||
NavigationParentState,
|
|
||||||
} from 'NavigationStateUtils';
|
|
||||||
|
|
||||||
import type {
|
|
||||||
Layout,
|
|
||||||
Position,
|
|
||||||
NavigationStateRenderer,
|
|
||||||
} from 'NavigationAnimatedView';
|
|
||||||
|
|
||||||
import type {
|
|
||||||
Direction,
|
|
||||||
OnNavigateHandler,
|
|
||||||
} from 'NavigationLinearPanResponder';
|
|
||||||
|
|
||||||
type AnimatedValue = Animated.Value;
|
|
||||||
|
|
||||||
type Props = {
|
|
||||||
direction: Direction,
|
|
||||||
index: number;
|
|
||||||
layout: Layout;
|
|
||||||
navigationParentState: NavigationParentState,
|
|
||||||
navigationState: NavigationParentState,
|
|
||||||
position: Position,
|
|
||||||
onNavigate: ?OnNavigateHandler,
|
|
||||||
renderScene: NavigationStateRenderer,
|
|
||||||
};
|
|
||||||
|
|
||||||
type State = {
|
|
||||||
hash: string,
|
|
||||||
height: number,
|
|
||||||
width: number,
|
|
||||||
};
|
|
||||||
|
|
||||||
class AmimatedValueSubscription {
|
|
||||||
_value: AnimatedValue;
|
|
||||||
_token: string;
|
|
||||||
|
|
||||||
constructor(value: AnimatedValue, callback: Function) {
|
|
||||||
this._value = value;
|
|
||||||
this._token = value.addListener(callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
remove() {
|
|
||||||
this._value.removeListener(this._token);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class that provides the required information for the
|
|
||||||
* `NavigationLinearPanResponder`. This class must implement
|
|
||||||
* the interface `NavigationLinearPanResponderDelegate`.
|
|
||||||
*/
|
|
||||||
class PanResponderDelegate {
|
|
||||||
_props : Props;
|
|
||||||
|
|
||||||
constructor(props: Props) {
|
|
||||||
this._props = props;
|
|
||||||
}
|
|
||||||
|
|
||||||
getDirection(): Direction {
|
|
||||||
return this._props.direction;
|
|
||||||
}
|
|
||||||
|
|
||||||
getIndex(): number {
|
|
||||||
return this._props.navigationParentState.index;
|
|
||||||
}
|
|
||||||
|
|
||||||
getLayout(): Layout {
|
|
||||||
return this._props.layout;
|
|
||||||
}
|
|
||||||
|
|
||||||
getPosition(): Position {
|
|
||||||
return this._props.position;
|
|
||||||
}
|
|
||||||
|
|
||||||
onNavigate(action: {type: string}): void {
|
|
||||||
this._props.onNavigate && this._props.onNavigate(action);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Component that renders the scene as card for the <NavigationCardStack />.
|
|
||||||
*/
|
|
||||||
class NavigationCardStackItem extends React.Component {
|
|
||||||
props: Props;
|
|
||||||
state: State;
|
|
||||||
_calculateState: (t: Layout) => State;
|
|
||||||
_layoutListeners: Array<AmimatedValueSubscription>;
|
|
||||||
|
|
||||||
constructor(props: Props, context: any) {
|
|
||||||
super(props, context);
|
|
||||||
|
|
||||||
this._calculateState = this._calculateState.bind(this);
|
|
||||||
this.state = this._calculateState(props.layout);
|
|
||||||
this._layoutListeners = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
shouldComponentUpdate(nextProps: Object, nextState: Object): boolean {
|
|
||||||
return ReactComponentWithPureRenderMixin.shouldComponentUpdate.call(
|
|
||||||
this,
|
|
||||||
nextProps,
|
|
||||||
nextState
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidMount(): void {
|
|
||||||
this._applyLayout(this.props.layout);
|
|
||||||
}
|
|
||||||
|
|
||||||
componentWillUnmount(): void {
|
|
||||||
this._layoutListeners.forEach(subscription => subscription.remove);
|
|
||||||
}
|
|
||||||
|
|
||||||
componentWillReceiveProps(nextProps: Props): void {
|
|
||||||
this._applyLayout(nextProps.layout);
|
|
||||||
}
|
|
||||||
|
|
||||||
render(): ReactElement {
|
|
||||||
const {
|
|
||||||
direction,
|
|
||||||
index,
|
|
||||||
navigationParentState,
|
|
||||||
position,
|
|
||||||
} = this.props;
|
|
||||||
const {
|
|
||||||
height,
|
|
||||||
width,
|
|
||||||
} = this.state;
|
|
||||||
|
|
||||||
const isVertical = direction === 'vertical';
|
|
||||||
const inputRange = [index - 1, index, index + 1];
|
|
||||||
const animatedStyle = {
|
|
||||||
|
|
||||||
opacity: position.interpolate({
|
|
||||||
inputRange,
|
|
||||||
outputRange: [1, 1, 0.3],
|
|
||||||
}),
|
|
||||||
|
|
||||||
transform: [
|
|
||||||
{
|
|
||||||
scale: position.interpolate({
|
|
||||||
inputRange,
|
|
||||||
outputRange: [1, 1, 0.95],
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
translateX: isVertical ? 0 :
|
|
||||||
position.interpolate({
|
|
||||||
inputRange,
|
|
||||||
outputRange: [width, 0, -10],
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
translateY: !isVertical ? 0 :
|
|
||||||
position.interpolate({
|
|
||||||
inputRange,
|
|
||||||
outputRange: [height, 0, -10],
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
let panHandlers = null;
|
|
||||||
if (navigationParentState.index === index) {
|
|
||||||
const delegate = new PanResponderDelegate(this.props);
|
|
||||||
const panResponder = new NavigationLinearPanResponder(delegate);
|
|
||||||
panHandlers = panResponder.panHandlers;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Animated.View
|
|
||||||
{...panHandlers}
|
|
||||||
style={[styles.main, animatedStyle]}>
|
|
||||||
{this.props.renderScene(this.props)}
|
|
||||||
</Animated.View>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
_calculateState(layout: Layout): State {
|
|
||||||
const width = layout.width.__getValue();
|
|
||||||
const height = layout.height.__getValue();
|
|
||||||
const hash = 'layout-' + width + '-' + height;
|
|
||||||
const state = {
|
|
||||||
height,
|
|
||||||
width,
|
|
||||||
hash,
|
|
||||||
};
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
|
|
||||||
_applyLayout(layout: Layout) {
|
|
||||||
this._layoutListeners.forEach(subscription => subscription.remove);
|
|
||||||
|
|
||||||
this._layoutListeners.length = 0;
|
|
||||||
|
|
||||||
const callback = this._applyLayout.bind(this, layout);
|
|
||||||
|
|
||||||
this._layoutListeners.push(
|
|
||||||
new AmimatedValueSubscription(layout.width, callback),
|
|
||||||
new AmimatedValueSubscription(layout.height, callback),
|
|
||||||
);
|
|
||||||
|
|
||||||
const nextState = this._calculateState(layout);
|
|
||||||
if (nextState.hash !== this.state.hash) {
|
|
||||||
this.setState(nextState);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
NavigationCardStackItem.propTypes = {
|
|
||||||
direction: PropTypes.oneOf([Directions.HORIZONTAL, Directions.VERTICAL]),
|
|
||||||
index: PropTypes.number.isRequired,
|
|
||||||
layout: PropTypes.object.isRequired,
|
|
||||||
navigationState: PropTypes.object.isRequired,
|
|
||||||
navigationParentState: PropTypes.object.isRequired,
|
|
||||||
position: PropTypes.object.isRequired,
|
|
||||||
renderScene: PropTypes.func.isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
NavigationCardStackItem.defaultProps = {
|
|
||||||
direction: Directions.HORIZONTAL,
|
|
||||||
};
|
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
|
||||||
main: {
|
|
||||||
backgroundColor: '#E9E9EF',
|
|
||||||
bottom: 0,
|
|
||||||
left: 0,
|
|
||||||
position: 'absolute',
|
|
||||||
right: 0,
|
|
||||||
shadowColor: 'black',
|
|
||||||
shadowOffset: {width: 0, height: 0},
|
|
||||||
shadowOpacity: 0.4,
|
|
||||||
shadowRadius: 10,
|
|
||||||
top: 0,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
module.exports = NavigationContainer.create(NavigationCardStackItem);
|
|
|
@ -30,6 +30,7 @@
|
||||||
const Animated = require('Animated');
|
const Animated = require('Animated');
|
||||||
const Image = require('Image');
|
const Image = require('Image');
|
||||||
const NavigationContainer = require('NavigationContainer');
|
const NavigationContainer = require('NavigationContainer');
|
||||||
|
const NavigationPropTypes = require('NavigationPropTypes');
|
||||||
const NavigationRootContainer = require('NavigationRootContainer');
|
const NavigationRootContainer = require('NavigationRootContainer');
|
||||||
const React = require('react-native');
|
const React = require('react-native');
|
||||||
const StyleSheet = require('StyleSheet');
|
const StyleSheet = require('StyleSheet');
|
||||||
|
@ -37,25 +38,32 @@ const Text = require('Text');
|
||||||
const TouchableOpacity = require('TouchableOpacity');
|
const TouchableOpacity = require('TouchableOpacity');
|
||||||
const View = require('View');
|
const View = require('View');
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
NavigationState,
|
NavigationState,
|
||||||
NavigationParentState
|
NavigationSceneRendererProps,
|
||||||
} from 'NavigationStateUtils';
|
} from 'NavigationTypeDefinition';
|
||||||
|
|
||||||
type Props = {
|
type Props = NavigationSceneRendererProps & {
|
||||||
navigationState: NavigationParentState,
|
|
||||||
onNavigate: Function,
|
|
||||||
position: Animated.Value,
|
|
||||||
getTitle: (navState: NavigationState) => string,
|
getTitle: (navState: NavigationState) => string,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const {PropTypes} = React;
|
||||||
|
|
||||||
|
const NavigationHeaderPropTypes = {
|
||||||
|
...NavigationPropTypes.SceneRenderer,
|
||||||
|
getTitle: PropTypes.func.isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
class NavigationHeader extends React.Component {
|
class NavigationHeader extends React.Component {
|
||||||
_handleBackPress: Function;
|
_handleBackPress: Function;
|
||||||
|
|
||||||
props: Props;
|
props: Props;
|
||||||
componentWillMount() {
|
|
||||||
|
componentWillMount(): void {
|
||||||
this._handleBackPress = this._handleBackPress.bind(this);
|
this._handleBackPress = this._handleBackPress.bind(this);
|
||||||
}
|
}
|
||||||
render() {
|
|
||||||
|
render(): ReactElement {
|
||||||
var state = this.props.navigationState;
|
var state = this.props.navigationState;
|
||||||
return (
|
return (
|
||||||
<Animated.View
|
<Animated.View
|
||||||
|
@ -67,7 +75,8 @@ class NavigationHeader extends React.Component {
|
||||||
</Animated.View>
|
</Animated.View>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
_renderBackButton() {
|
|
||||||
|
_renderBackButton(): ?ReactElement {
|
||||||
if (this.props.navigationState.index === 0) {
|
if (this.props.navigationState.index === 0) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -77,7 +86,8 @@ class NavigationHeader extends React.Component {
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
_renderTitle(childState, index) {
|
|
||||||
|
_renderTitle(childState: NavigationState, index:number): ?ReactElement {
|
||||||
return (
|
return (
|
||||||
<Animated.Text
|
<Animated.Text
|
||||||
key={childState.key}
|
key={childState.key}
|
||||||
|
@ -102,11 +112,14 @@ class NavigationHeader extends React.Component {
|
||||||
</Animated.Text>
|
</Animated.Text>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
_handleBackPress() {
|
|
||||||
|
_handleBackPress(): void {
|
||||||
this.props.onNavigate(NavigationRootContainer.getBackAction());
|
this.props.onNavigate(NavigationRootContainer.getBackAction());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NavigationHeader.propTypes = NavigationHeaderPropTypes;
|
||||||
|
|
||||||
NavigationHeader = NavigationContainer.create(NavigationHeader);
|
NavigationHeader = NavigationContainer.create(NavigationHeader);
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
|
|
|
@ -11,8 +11,7 @@ const invariant = require('fbjs/lib/invariant');
|
||||||
import type {
|
import type {
|
||||||
NavigationState,
|
NavigationState,
|
||||||
NavigationParentState,
|
NavigationParentState,
|
||||||
} from 'NavigationStateUtils';
|
} from 'NavigationTypeDefinition';
|
||||||
|
|
||||||
|
|
||||||
type IterationCallback = (route: any, index: number, key: string) => void;
|
type IterationCallback = (route: any, index: number, key: string) => void;
|
||||||
|
|
||||||
|
|
|
@ -11,23 +11,20 @@
|
||||||
*/
|
*/
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var Animated = require('Animated');
|
const Animated = require('Animated');
|
||||||
var Map = require('Map');
|
const NavigationContainer = require('NavigationContainer');
|
||||||
var NavigationStateUtils = require('NavigationStateUtils');
|
const NavigationPropTypes = require('NavigationPropTypes');
|
||||||
var NavigationContainer = require('NavigationContainer');
|
const NavigationStateUtils = require('NavigationStateUtils');
|
||||||
var React = require('React');
|
const React = require('react-native');
|
||||||
var View = require('View');
|
const View = require('View');
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
NavigationState,
|
NavigationAnimatedValue,
|
||||||
|
NavigationAnimationSetter,
|
||||||
NavigationParentState,
|
NavigationParentState,
|
||||||
} from 'NavigationStateUtils';
|
NavigationScene,
|
||||||
|
NavigationSceneRenderer,
|
||||||
type NavigationScene = {
|
} from 'NavigationTypeDefinition';
|
||||||
index: number,
|
|
||||||
state: NavigationState,
|
|
||||||
isStale: boolean,
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper function to compare route keys (e.g. "9", "11").
|
* Helper function to compare route keys (e.g. "9", "11").
|
||||||
|
@ -48,7 +45,7 @@ function compareKey(one: string, two: string): number {
|
||||||
*/
|
*/
|
||||||
function compareScenes(
|
function compareScenes(
|
||||||
one: NavigationScene,
|
one: NavigationScene,
|
||||||
two: NavigationScene
|
two: NavigationScene,
|
||||||
): number {
|
): number {
|
||||||
if (one.index > two.index) {
|
if (one.index > two.index) {
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -58,64 +55,62 @@ function compareScenes(
|
||||||
}
|
}
|
||||||
|
|
||||||
return compareKey(
|
return compareKey(
|
||||||
one.state.key,
|
one.navigationState.key,
|
||||||
two.state.key
|
two.navigationState.key,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
type Layout = {
|
|
||||||
initWidth: number,
|
|
||||||
initHeight: number,
|
|
||||||
width: Animated.Value;
|
|
||||||
height: Animated.Value;
|
|
||||||
};
|
|
||||||
|
|
||||||
type Position = Animated.Value;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Definition of the props object that is passed to the functions
|
|
||||||
* that render the overlay and the scene.
|
|
||||||
*/
|
|
||||||
type NavigationStateRendererProps = {
|
|
||||||
// The state of the child view.
|
|
||||||
navigationState: NavigationState,
|
|
||||||
// The index of the child view.
|
|
||||||
index: number,
|
|
||||||
// The "progressive index" of the containing navigation state.
|
|
||||||
position: Position,
|
|
||||||
// The layout of the the containing navigation view.
|
|
||||||
layout: Layout,
|
|
||||||
// The state of the the containing navigation view.
|
|
||||||
navigationParentState: NavigationParentState,
|
|
||||||
|
|
||||||
onNavigate: (action: any) => void,
|
|
||||||
};
|
|
||||||
|
|
||||||
type NavigationStateRenderer = (
|
|
||||||
props: NavigationStateRendererProps,
|
|
||||||
) => ReactElement;
|
|
||||||
|
|
||||||
type TimingSetter = (
|
|
||||||
position: Animated.Value,
|
|
||||||
newState: NavigationParentState,
|
|
||||||
lastState: NavigationParentState,
|
|
||||||
) => void;
|
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
navigationState: NavigationParentState,
|
navigationState: NavigationParentState,
|
||||||
onNavigate: (action: any) => void,
|
onNavigate: (action: any) => void,
|
||||||
renderScene: NavigationStateRenderer,
|
renderScene: NavigationSceneRenderer,
|
||||||
renderOverlay: ?NavigationStateRenderer,
|
renderOverlay: ?NavigationSceneRenderer,
|
||||||
style: any,
|
style: any,
|
||||||
setTiming: ?TimingSetter,
|
setTiming: NavigationAnimationSetter,
|
||||||
};
|
};
|
||||||
|
|
||||||
class NavigationAnimatedView extends React.Component {
|
type State = {
|
||||||
|
position: NavigationAnimatedValue,
|
||||||
|
scenes: Array<NavigationScene>,
|
||||||
|
};
|
||||||
|
|
||||||
|
const {PropTypes} = React;
|
||||||
|
|
||||||
|
const propTypes = {
|
||||||
|
navigationState: NavigationPropTypes.navigationState.isRequired,
|
||||||
|
onNavigate: PropTypes.func.isRequired,
|
||||||
|
renderScene: PropTypes.func.isRequired,
|
||||||
|
renderOverlay: PropTypes.func,
|
||||||
|
setTiming: PropTypes.func,
|
||||||
|
};
|
||||||
|
|
||||||
|
const defaultProps = {
|
||||||
|
setTiming: (
|
||||||
|
position: NavigationAnimatedValue,
|
||||||
|
navigationState: NavigationParentState,
|
||||||
|
) => {
|
||||||
|
Animated.spring(
|
||||||
|
position,
|
||||||
|
{
|
||||||
|
bounciness: 0,
|
||||||
|
toValue: navigationState.index,
|
||||||
|
}
|
||||||
|
).start();
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
class NavigationAnimatedView
|
||||||
|
extends React.Component<any, Props, State> {
|
||||||
|
|
||||||
_animatedHeight: Animated.Value;
|
_animatedHeight: Animated.Value;
|
||||||
_animatedWidth: Animated.Value;
|
_animatedWidth: Animated.Value;
|
||||||
_lastHeight: number;
|
_lastHeight: number;
|
||||||
_lastWidth: number;
|
_lastWidth: number;
|
||||||
|
_postionListener: any;
|
||||||
|
|
||||||
props: Props;
|
props: Props;
|
||||||
|
state: State;
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this._lastWidth = 0;
|
this._lastWidth = 0;
|
||||||
|
@ -125,7 +120,7 @@ class NavigationAnimatedView extends React.Component {
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
position: new Animated.Value(this.props.navigationState.index),
|
position: new Animated.Value(this.props.navigationState.index),
|
||||||
scenes: new Map(),
|
scenes: [],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
componentWillMount() {
|
componentWillMount() {
|
||||||
|
@ -134,7 +129,7 @@ class NavigationAnimatedView extends React.Component {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
this.postionListener = this.state.position.addListener(this._onProgressChange.bind(this));
|
this._postionListener = this.state.position.addListener(this._onProgressChange.bind(this));
|
||||||
}
|
}
|
||||||
componentWillReceiveProps(nextProps) {
|
componentWillReceiveProps(nextProps) {
|
||||||
if (nextProps.navigationState !== this.props.navigationState) {
|
if (nextProps.navigationState !== this.props.navigationState) {
|
||||||
|
@ -150,8 +145,8 @@ class NavigationAnimatedView extends React.Component {
|
||||||
}
|
}
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
if (this.postionListener) {
|
if (this.postionListener) {
|
||||||
this.state.position.removeListener(this.postionListener);
|
this.state.position.removeListener(this._postionListener);
|
||||||
this.postionListener = null;
|
this._postionListener = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_onProgressChange(data: Object): void {
|
_onProgressChange(data: Object): void {
|
||||||
|
@ -174,8 +169,8 @@ class NavigationAnimatedView extends React.Component {
|
||||||
let nextScenes = nextState.children.map((child, index) => {
|
let nextScenes = nextState.children.map((child, index) => {
|
||||||
return {
|
return {
|
||||||
index,
|
index,
|
||||||
state: child,
|
|
||||||
isStale: false,
|
isStale: false,
|
||||||
|
navigationState: child,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -184,8 +179,8 @@ class NavigationAnimatedView extends React.Component {
|
||||||
if (!NavigationStateUtils.get(nextState, child.key) && index !== nextState.index) {
|
if (!NavigationStateUtils.get(nextState, child.key) && index !== nextState.index) {
|
||||||
nextScenes.push({
|
nextScenes.push({
|
||||||
index,
|
index,
|
||||||
state: child,
|
|
||||||
isStale: true,
|
isStale: true,
|
||||||
|
navigationState: child,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -221,49 +216,57 @@ class NavigationAnimatedView extends React.Component {
|
||||||
initHeight: this._lastHeight,
|
initHeight: this._lastHeight,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
_renderScene(scene: NavigationScene) {
|
_renderScene(scene: NavigationScene) {
|
||||||
return this.props.renderScene({
|
const {
|
||||||
index: scene.index,
|
navigationState,
|
||||||
|
onNavigate,
|
||||||
|
renderScene,
|
||||||
|
} = this.props;
|
||||||
|
|
||||||
|
const {
|
||||||
|
position,
|
||||||
|
scenes,
|
||||||
|
} = this.state;
|
||||||
|
|
||||||
|
return renderScene({
|
||||||
layout: this._getLayout(),
|
layout: this._getLayout(),
|
||||||
navigationParentState: this.props.navigationState,
|
navigationState,
|
||||||
navigationState: scene.state,
|
onNavigate,
|
||||||
onNavigate: this.props.onNavigate,
|
position,
|
||||||
position: this.state.position,
|
scene,
|
||||||
|
scenes,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
_renderOverlay() {
|
_renderOverlay() {
|
||||||
const {
|
if (this.props.renderOverlay) {
|
||||||
onNavigate,
|
const {
|
||||||
renderOverlay,
|
navigationState,
|
||||||
navigationState,
|
onNavigate,
|
||||||
} = this.props;
|
renderOverlay,
|
||||||
if (renderOverlay) {
|
} = this.props;
|
||||||
|
|
||||||
|
const {
|
||||||
|
position,
|
||||||
|
scenes,
|
||||||
|
} = this.state;
|
||||||
|
|
||||||
return renderOverlay({
|
return renderOverlay({
|
||||||
index: navigationState.index,
|
|
||||||
layout: this._getLayout(),
|
layout: this._getLayout(),
|
||||||
navigationParentState: navigationState,
|
navigationState,
|
||||||
navigationState: navigationState.children[navigationState.index],
|
onNavigate,
|
||||||
onNavigate: onNavigate,
|
position,
|
||||||
position: this.state.position,
|
scene: scenes[navigationState.index],
|
||||||
|
scenes,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function setDefaultTiming(position, navigationState) {
|
NavigationAnimatedView.propTypes = propTypes;
|
||||||
Animated.spring(
|
NavigationAnimatedView.defaultProps = defaultProps;
|
||||||
position,
|
|
||||||
{
|
|
||||||
bounciness: 0,
|
|
||||||
toValue: navigationState.index,
|
|
||||||
}
|
|
||||||
).start();
|
|
||||||
}
|
|
||||||
|
|
||||||
NavigationAnimatedView.defaultProps = {
|
|
||||||
setTiming: setDefaultTiming,
|
|
||||||
};
|
|
||||||
|
|
||||||
NavigationAnimatedView = NavigationContainer.create(NavigationAnimatedView);
|
NavigationAnimatedView = NavigationContainer.create(NavigationAnimatedView);
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,9 @@
|
||||||
var React = require('React');
|
var React = require('React');
|
||||||
var NavigationRootContainer = require('NavigationRootContainer');
|
var NavigationRootContainer = require('NavigationRootContainer');
|
||||||
|
|
||||||
function createNavigationContainer(Component: React.Component): React.Component {
|
function createNavigationContainer(
|
||||||
|
Component: ReactClass<any, any, any>,
|
||||||
|
): ReactClass {
|
||||||
class NavigationComponent extends React.Component {
|
class NavigationComponent extends React.Component {
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -12,6 +12,12 @@ const NavigationAbstractPanResponder = require('NavigationAbstractPanResponder')
|
||||||
|
|
||||||
const clamp = require('clamp');
|
const clamp = require('clamp');
|
||||||
|
|
||||||
|
import {
|
||||||
|
NavigationActionCaller,
|
||||||
|
NavigationLayout,
|
||||||
|
NavigationPosition,
|
||||||
|
} from 'NavigationTypeDefinition';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The duration of the card animation in milliseconds.
|
* The duration of the card animation in milliseconds.
|
||||||
*/
|
*/
|
||||||
|
@ -42,6 +48,8 @@ const Directions = {
|
||||||
'VERTICAL': 'vertical',
|
'VERTICAL': 'vertical',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type NavigationGestureDirection = $Enum<typeof Directions>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Primitive gesture actions.
|
* Primitive gesture actions.
|
||||||
*/
|
*/
|
||||||
|
@ -52,25 +60,16 @@ const Actions = {
|
||||||
BACK: {type: 'back'},
|
BACK: {type: 'back'},
|
||||||
};
|
};
|
||||||
|
|
||||||
import type {
|
|
||||||
Layout,
|
|
||||||
Position,
|
|
||||||
} from 'NavigationAnimatedView';
|
|
||||||
|
|
||||||
export type OnNavigateHandler = (action: {type: string}) => void;
|
|
||||||
|
|
||||||
export type Direction = $Enum<typeof Directions>;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The type interface of the object that provides the information required by
|
* The type interface of the object that provides the information required by
|
||||||
* NavigationLinearPanResponder.
|
* NavigationLinearPanResponder.
|
||||||
*/
|
*/
|
||||||
export type NavigationLinearPanResponderDelegate = {
|
export type NavigationLinearPanResponderDelegate = {
|
||||||
getDirection: () => Direction;
|
getDirection: () => NavigationGestureDirection;
|
||||||
getIndex: () => number,
|
getIndex: () => number,
|
||||||
getLayout: () => Layout,
|
getLayout: () => NavigationLayout,
|
||||||
getPosition: () => Position,
|
getPosition: () => NavigationPosition,
|
||||||
onNavigate: OnNavigateHandler,
|
onNavigate: NavigationActionCaller,
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -0,0 +1,76 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2015-present, Facebook, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the BSD-style license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree. An additional grant
|
||||||
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||||||
|
*
|
||||||
|
* @providesModule NavigationPropTypes
|
||||||
|
* @flow
|
||||||
|
*/
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* React component PropTypes Definitions. Consider using this as a supplementary
|
||||||
|
* measure with `NavigationTypeDefinition`. This helps to capture the propType
|
||||||
|
* error at run-time, where as `NavigationTypeDefinition` capture the flow
|
||||||
|
* type check errors at build time.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const Animated = require('Animated');
|
||||||
|
const React = require('react-native');
|
||||||
|
|
||||||
|
const {PropTypes} = React;
|
||||||
|
|
||||||
|
/* NavigationAction */
|
||||||
|
const action = PropTypes.shape({
|
||||||
|
type: PropTypes.string.isRequired,
|
||||||
|
});
|
||||||
|
|
||||||
|
/* NavigationAnimatedValue */
|
||||||
|
const animatedValue = PropTypes.instanceOf(Animated.Value);
|
||||||
|
|
||||||
|
/* NavigationState */
|
||||||
|
const navigationState = PropTypes.shape({
|
||||||
|
key: PropTypes.string.isRequired,
|
||||||
|
});
|
||||||
|
|
||||||
|
/* NavigationParentState */
|
||||||
|
const navigationParentState = PropTypes.shape({
|
||||||
|
index: PropTypes.number.isRequired,
|
||||||
|
key: PropTypes.string.isRequired,
|
||||||
|
children: PropTypes.arrayOf(navigationState),
|
||||||
|
});
|
||||||
|
|
||||||
|
/* NavigationLayout */
|
||||||
|
const layout = PropTypes.shape({
|
||||||
|
height: animatedValue,
|
||||||
|
initHeight: PropTypes.number.isRequired,
|
||||||
|
initWidth: PropTypes.number.isRequired,
|
||||||
|
width: animatedValue,
|
||||||
|
});
|
||||||
|
|
||||||
|
/* NavigationScene */
|
||||||
|
const scene = PropTypes.shape({
|
||||||
|
index: PropTypes.number.isRequired,
|
||||||
|
isStale: PropTypes.bool.isRequired,
|
||||||
|
navigationState,
|
||||||
|
});
|
||||||
|
|
||||||
|
/* NavigationSceneRendererProps */
|
||||||
|
const SceneRenderer = {
|
||||||
|
layout: layout.isRequired,
|
||||||
|
navigationState: navigationParentState.isRequired,
|
||||||
|
onNavigate: PropTypes.func.isRequired,
|
||||||
|
position: animatedValue.isRequired,
|
||||||
|
scene: scene.isRequired,
|
||||||
|
scenes: PropTypes.arrayOf(scene).isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
SceneRenderer,
|
||||||
|
action,
|
||||||
|
navigationParentState,
|
||||||
|
navigationState,
|
||||||
|
};
|
|
@ -13,23 +13,18 @@
|
||||||
|
|
||||||
const AsyncStorage = require('AsyncStorage');
|
const AsyncStorage = require('AsyncStorage');
|
||||||
const Linking = require('Linking');
|
const Linking = require('Linking');
|
||||||
const React = require('React');
|
|
||||||
const BackAndroid = require('BackAndroid');
|
|
||||||
const Platform = require('Platform');
|
const Platform = require('Platform');
|
||||||
|
const React = require('React');
|
||||||
|
const NavigationPropTypes = require('NavigationPropTypes');
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
NavigationAction,
|
NavigationAction,
|
||||||
NavigationState,
|
NavigationReducer,
|
||||||
NavigationReducer
|
NavigationRenderer,
|
||||||
} from 'NavigationStateUtils';
|
} from 'NavigationTypeDefinition';
|
||||||
|
|
||||||
export type NavigationRenderer = (
|
|
||||||
navigationState: NavigationState,
|
|
||||||
onNavigate: Function
|
|
||||||
) => ReactElement;
|
|
||||||
|
|
||||||
export type BackAction = {
|
export type BackAction = {
|
||||||
type: 'BackAction';
|
type: 'BackAction',
|
||||||
};
|
};
|
||||||
|
|
||||||
function getBackAction(): BackAction {
|
function getBackAction(): BackAction {
|
||||||
|
@ -37,40 +32,60 @@ function getBackAction(): BackAction {
|
||||||
}
|
}
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
/*
|
|
||||||
* Set up the rendering of the app for a given navigation state
|
|
||||||
*/
|
|
||||||
renderNavigation: NavigationRenderer;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* A function that will output the latest navigation state as a function of
|
|
||||||
* the (optional) previous state, and an action
|
|
||||||
*/
|
|
||||||
reducer: NavigationReducer;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Provide this key, and the container will store the navigation state in
|
|
||||||
* AsyncStorage through refreshes, with the provided key
|
|
||||||
*/
|
|
||||||
persistenceKey: ?string;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The default action to be passed into the reducer when getting the first
|
* The default action to be passed into the reducer when getting the first
|
||||||
* state. Defaults to {type: 'RootContainerInitialAction'}
|
* state. Defaults to {type: 'RootContainerInitialAction'}
|
||||||
*/
|
*/
|
||||||
initialAction: NavigationAction;
|
initialAction: NavigationAction,
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Provide linkingActionMap to instruct the container to subscribe to linking
|
* Provide linkingActionMap to instruct the container to subscribe to linking
|
||||||
* events, and use this mapper to convert URIs into actions that your app can
|
* events, and use this mapper to convert URIs into actions that your app can
|
||||||
* handle
|
* handle
|
||||||
*/
|
*/
|
||||||
linkingActionMap: (uri: string) => NavigationAction;
|
linkingActionMap: ?((uri: string) => NavigationAction),
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Provide this key, and the container will store the navigation state in
|
||||||
|
* AsyncStorage through refreshes, with the provided key
|
||||||
|
*/
|
||||||
|
persistenceKey: ?string,
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A function that will output the latest navigation state as a function of
|
||||||
|
* the (optional) previous state, and an action
|
||||||
|
*/
|
||||||
|
reducer: NavigationReducer,
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set up the rendering of the app for a given navigation state
|
||||||
|
*/
|
||||||
|
renderNavigation: NavigationRenderer,
|
||||||
|
};
|
||||||
|
|
||||||
|
const {PropTypes} = React;
|
||||||
|
|
||||||
|
const propTypes = {
|
||||||
|
initialAction: NavigationPropTypes.action.isRequired,
|
||||||
|
linkingActionMap: PropTypes.func,
|
||||||
|
persistenceKey: PropTypes.string,
|
||||||
|
reducer: PropTypes.func.isRequired,
|
||||||
|
renderNavigation: PropTypes.func.isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
|
const defaultProps = {
|
||||||
|
initialAction: {
|
||||||
|
type: 'RootContainerInitialAction',
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
class NavigationRootContainer extends React.Component {
|
class NavigationRootContainer extends React.Component {
|
||||||
_handleOpenURLEvent: Function;
|
_handleOpenURLEvent: Function;
|
||||||
|
|
||||||
props: Props;
|
props: Props;
|
||||||
|
|
||||||
constructor(props: Props) {
|
constructor(props: Props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.handleNavigation = this.handleNavigation.bind(this);
|
this.handleNavigation = this.handleNavigation.bind(this);
|
||||||
|
@ -81,10 +96,11 @@ class NavigationRootContainer extends React.Component {
|
||||||
}
|
}
|
||||||
this.state = { navState };
|
this.state = { navState };
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
if (this.props.LinkingActionMap) {
|
if (this.props.LinkingActionMap) {
|
||||||
Linking.getInitialURL().then(this._handleOpenURL.bind(this));
|
Linking.getInitialURL().then(this._handleOpenURL.bind(this));
|
||||||
Platform.OS === 'ios' && Linking.addEventListener('url', this._handleOpenURLEvent);
|
Platform.OS === 'ios' && Linking.addEventListener('url', this._handleOpenURLEvent);
|
||||||
}
|
}
|
||||||
if (this.props.persistenceKey) {
|
if (this.props.persistenceKey) {
|
||||||
AsyncStorage.getItem(this.props.persistenceKey, (err, storedString) => {
|
AsyncStorage.getItem(this.props.persistenceKey, (err, storedString) => {
|
||||||
|
@ -100,12 +116,15 @@ class NavigationRootContainer extends React.Component {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
Platform.OS === 'ios' && Linking.removeEventListener('url', this._handleOpenURLEvent);
|
Platform.OS === 'ios' && Linking.removeEventListener('url', this._handleOpenURLEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
_handleOpenURLEvent(event: {url: string}) {
|
_handleOpenURLEvent(event: {url: string}) {
|
||||||
this._handleOpenURL(event.url);
|
this._handleOpenURL(event.url);
|
||||||
}
|
}
|
||||||
|
|
||||||
_handleOpenURL(url: ?string) {
|
_handleOpenURL(url: ?string) {
|
||||||
if (!this.props.LinkingActionMap) {
|
if (!this.props.LinkingActionMap) {
|
||||||
return;
|
return;
|
||||||
|
@ -115,11 +134,13 @@ class NavigationRootContainer extends React.Component {
|
||||||
this.handleNavigation(action);
|
this.handleNavigation(action);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getChildContext(): Object {
|
getChildContext(): Object {
|
||||||
return {
|
return {
|
||||||
onNavigate: this.handleNavigation,
|
onNavigate: this.handleNavigation,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
handleNavigation(action: Object): boolean {
|
handleNavigation(action: Object): boolean {
|
||||||
const navState = this.props.reducer(this.state.navState, action);
|
const navState = this.props.reducer(this.state.navState, action);
|
||||||
if (navState === this.state.navState) {
|
if (navState === this.state.navState) {
|
||||||
|
@ -128,11 +149,14 @@ class NavigationRootContainer extends React.Component {
|
||||||
this.setState({
|
this.setState({
|
||||||
navState,
|
navState,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (this.props.persistenceKey) {
|
if (this.props.persistenceKey) {
|
||||||
AsyncStorage.setItem(this.props.persistenceKey, JSON.stringify(navState));
|
AsyncStorage.setItem(this.props.persistenceKey, JSON.stringify(navState));
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
render(): ReactElement {
|
render(): ReactElement {
|
||||||
const navigation = this.props.renderNavigation(
|
const navigation = this.props.renderNavigation(
|
||||||
this.state.navState,
|
this.state.navState,
|
||||||
|
@ -143,15 +167,11 @@ class NavigationRootContainer extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
NavigationRootContainer.childContextTypes = {
|
NavigationRootContainer.childContextTypes = {
|
||||||
onNavigate: React.PropTypes.func,
|
onNavigate: PropTypes.func,
|
||||||
};
|
|
||||||
|
|
||||||
NavigationRootContainer.defaultProps = {
|
|
||||||
initialAction: {
|
|
||||||
type: 'RootContainerInitialAction',
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
NavigationRootContainer.propTypes = propTypes;
|
||||||
|
NavigationRootContainer.defaultProps = defaultProps;
|
||||||
NavigationRootContainer.getBackAction = getBackAction;
|
NavigationRootContainer.getBackAction = getBackAction;
|
||||||
|
|
||||||
module.exports = NavigationRootContainer;
|
module.exports = NavigationRootContainer;
|
||||||
|
|
|
@ -13,24 +13,10 @@
|
||||||
|
|
||||||
const invariant = require('fbjs/lib/invariant');
|
const invariant = require('fbjs/lib/invariant');
|
||||||
|
|
||||||
export type NavigationState = {
|
import type {
|
||||||
key: string;
|
NavigationState,
|
||||||
};
|
NavigationParentState,
|
||||||
|
} from 'NavigationTypeDefinition';
|
||||||
export type NavigationParentState = {
|
|
||||||
key: string;
|
|
||||||
index: number;
|
|
||||||
children: Array<NavigationState>;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type NavigationAction = {
|
|
||||||
type: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type NavigationReducer = (
|
|
||||||
state: ?NavigationState,
|
|
||||||
action: ?NavigationAction
|
|
||||||
) => NavigationState;
|
|
||||||
|
|
||||||
function getParent(state: NavigationState): ?NavigationParentState {
|
function getParent(state: NavigationState): ?NavigationParentState {
|
||||||
if (
|
if (
|
||||||
|
|
|
@ -0,0 +1,93 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2015-present, Facebook, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the BSD-style license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree. An additional grant
|
||||||
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||||||
|
*
|
||||||
|
* @providesModule NavigationTypeDefinition
|
||||||
|
* @flow
|
||||||
|
*/
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const Animated = require('Animated');
|
||||||
|
|
||||||
|
// Object Instances
|
||||||
|
|
||||||
|
export type NavigationAnimatedValue = Animated.Value;
|
||||||
|
|
||||||
|
// Value & Structs.
|
||||||
|
|
||||||
|
export type NavigationGestureDirection = 'horizontal' | 'vertical';
|
||||||
|
|
||||||
|
export type NavigationState = {
|
||||||
|
key: string,
|
||||||
|
};
|
||||||
|
|
||||||
|
export type NavigationParentState = {
|
||||||
|
index: number,
|
||||||
|
key: string,
|
||||||
|
children: Array<NavigationState>,
|
||||||
|
};
|
||||||
|
|
||||||
|
export type NavigationAction = any;
|
||||||
|
|
||||||
|
export type NavigationLayout = {
|
||||||
|
height: NavigationAnimatedValue,
|
||||||
|
initHeight: number,
|
||||||
|
initWidth: number,
|
||||||
|
width: NavigationAnimatedValue,
|
||||||
|
};
|
||||||
|
|
||||||
|
export type NavigationPosition = NavigationAnimatedValue;
|
||||||
|
|
||||||
|
export type NavigationScene = {
|
||||||
|
index: number,
|
||||||
|
isStale: boolean,
|
||||||
|
navigationState: NavigationState,
|
||||||
|
};
|
||||||
|
|
||||||
|
export type NavigationSceneRendererProps = {
|
||||||
|
// The layout of the containing view of the scenes.
|
||||||
|
layout: NavigationLayout,
|
||||||
|
|
||||||
|
// The navigation state of the containing view.
|
||||||
|
navigationState: NavigationParentState,
|
||||||
|
|
||||||
|
// Callback to navigation with an action.
|
||||||
|
onNavigate: NavigationActionCaller,
|
||||||
|
|
||||||
|
// The progressive index of the containing view's navigation state.
|
||||||
|
position: NavigationPosition,
|
||||||
|
|
||||||
|
// The scene to render.
|
||||||
|
scene: NavigationScene,
|
||||||
|
|
||||||
|
// All the scenes of the containing view's.
|
||||||
|
scenes: Array<NavigationScene>,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Functions.
|
||||||
|
|
||||||
|
export type NavigationActionCaller = Function;
|
||||||
|
|
||||||
|
export type NavigationAnimationSetter = (
|
||||||
|
position: NavigationAnimatedValue,
|
||||||
|
newState: NavigationParentState,
|
||||||
|
lastState: NavigationParentState,
|
||||||
|
) => void;
|
||||||
|
|
||||||
|
export type NavigationRenderer = (
|
||||||
|
navigationState: NavigationState,
|
||||||
|
onNavigate: NavigationActionCaller,
|
||||||
|
) => ReactElement;
|
||||||
|
|
||||||
|
export type NavigationReducer = (
|
||||||
|
state: ?NavigationState,
|
||||||
|
action: ?NavigationAction,
|
||||||
|
) => NavigationState;
|
||||||
|
|
||||||
|
export type NavigationSceneRenderer = (
|
||||||
|
props: NavigationSceneRendererProps,
|
||||||
|
) => ?ReactElement;
|
|
@ -20,9 +20,12 @@
|
||||||
import type {
|
import type {
|
||||||
NavigationState,
|
NavigationState,
|
||||||
NavigationReducer
|
NavigationReducer
|
||||||
} from 'NavigationStateUtils';
|
} from 'NavigationTypeDefinition';
|
||||||
|
|
||||||
function NavigationFindReducer(reducers: Array<NavigationReducer>, defaultState: NavigationState): NavigationReducer {
|
function NavigationFindReducer(
|
||||||
|
reducers: Array<NavigationReducer>,
|
||||||
|
defaultState: NavigationState,
|
||||||
|
): NavigationReducer {
|
||||||
return function(lastState: ?NavigationState, action: ?any): NavigationState {
|
return function(lastState: ?NavigationState, action: ?any): NavigationState {
|
||||||
for (let i = 0; i < reducers.length; i++) {
|
for (let i = 0; i < reducers.length; i++) {
|
||||||
let reducer = reducers[i];
|
let reducer = reducers[i];
|
||||||
|
|
|
@ -17,7 +17,7 @@ import type {
|
||||||
NavigationState,
|
NavigationState,
|
||||||
NavigationParentState,
|
NavigationParentState,
|
||||||
NavigationReducer,
|
NavigationReducer,
|
||||||
} from 'NavigationStateUtils';
|
} from 'NavigationTypeDefinition';
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
BackAction,
|
BackAction,
|
||||||
|
|
|
@ -17,8 +17,7 @@ const NavigationStateUtils = require('NavigationStateUtils');
|
||||||
import type {
|
import type {
|
||||||
NavigationReducer,
|
NavigationReducer,
|
||||||
NavigationState,
|
NavigationState,
|
||||||
NavigationParentState
|
} from 'NavigationTypeDefinition';
|
||||||
} from 'NavigationStateUtils';
|
|
||||||
|
|
||||||
const ActionTypes = {
|
const ActionTypes = {
|
||||||
JUMP_TO: 'react-native/NavigationExperimental/tabs-jumpTo',
|
JUMP_TO: 'react-native/NavigationExperimental/tabs-jumpTo',
|
||||||
|
|
|
@ -11,7 +11,6 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
jest
|
jest
|
||||||
.dontMock('NavigationRootContainer')
|
|
||||||
.dontMock('NavigationStackReducer')
|
.dontMock('NavigationStackReducer')
|
||||||
.dontMock('NavigationStateUtils');
|
.dontMock('NavigationStateUtils');
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2015-present, Facebook, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the BSD-style license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree. An additional grant
|
||||||
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const NavigationRootContainer = {
|
||||||
|
getBackAction: () => {
|
||||||
|
return { type: 'BackAction' };
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = NavigationRootContainer;
|
Loading…
Reference in New Issue