mirror of
https://github.com/status-im/react-native.git
synced 2025-01-27 09:45:04 +00:00
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 {
|
||||
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() {
|
||||
return (
|
||||
@ -56,7 +59,7 @@ class NavigationAnimatedExample extends React.Component {
|
||||
reducer={NavigationBasicReducer}
|
||||
ref={navRootContainer => { this.navRootContainer = navRootContainer; }}
|
||||
persistenceKey="NavigationAnimExampleState"
|
||||
renderNavigation={this._renderNavigated}
|
||||
renderNavigation={this._renderNavigation}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@ -66,7 +69,7 @@ class NavigationAnimatedExample extends React.Component {
|
||||
this.navRootContainer.handleNavigation(NavigationRootContainer.getBackAction())
|
||||
);
|
||||
}
|
||||
_renderNavigated(navigationState, onNavigate) {
|
||||
_renderNavigation(navigationState, onNavigate) {
|
||||
if (!navigationState) {
|
||||
return null;
|
||||
}
|
||||
@ -74,46 +77,56 @@ class NavigationAnimatedExample extends React.Component {
|
||||
<NavigationAnimatedView
|
||||
navigationState={navigationState}
|
||||
style={styles.animatedView}
|
||||
renderOverlay={(props) => (
|
||||
<NavigationHeader
|
||||
navigationState={props.navigationParentState}
|
||||
position={props.position}
|
||||
getTitle={state => state.key}
|
||||
/>
|
||||
)}
|
||||
renderOverlay={this._renderHeader}
|
||||
setTiming={(pos, navState) => {
|
||||
Animated.timing(pos, {toValue: navState.index, duration: 1000}).start();
|
||||
}}
|
||||
renderScene={(props) => (
|
||||
<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>
|
||||
)}
|
||||
renderScene={this._renderCard}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
_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({
|
||||
|
@ -49,6 +49,7 @@ function reduceNavigationState(initialState) {
|
||||
|
||||
const ExampleReducer = reduceNavigationState({
|
||||
index: 0,
|
||||
key: 'exmaple',
|
||||
children: [{key: 'First Route'}],
|
||||
});
|
||||
|
||||
@ -56,12 +57,13 @@ class NavigationCardStackExample extends React.Component {
|
||||
|
||||
constructor(props, context) {
|
||||
super(props, context);
|
||||
this.state = {isHorizontal: true};
|
||||
}
|
||||
|
||||
componentWillMount() {
|
||||
this._renderNavigation = this._renderNavigation.bind(this);
|
||||
this._renderScene = this._renderScene.bind(this);
|
||||
this._toggleDirection = this._toggleDirection.bind(this);
|
||||
|
||||
this.state = {isHorizontal: true};
|
||||
}
|
||||
|
||||
render() {
|
||||
@ -86,8 +88,7 @@ class NavigationCardStackExample extends React.Component {
|
||||
);
|
||||
}
|
||||
|
||||
_renderScene(props) {
|
||||
const {navigationParentState, onNavigate} = props;
|
||||
_renderScene(/*NavigationSceneRendererProps*/ props) {
|
||||
return (
|
||||
<ScrollView style={styles.scrollView}>
|
||||
<NavigationExampleRow
|
||||
@ -99,21 +100,21 @@ class NavigationCardStackExample extends React.Component {
|
||||
onPress={this._toggleDirection}
|
||||
/>
|
||||
<NavigationExampleRow
|
||||
text={'route = ' + props.navigationState.key}
|
||||
text={'route = ' + props.scene.navigationState.key}
|
||||
/>
|
||||
<NavigationExampleRow
|
||||
text="Push Route"
|
||||
onPress={() => {
|
||||
onNavigate({
|
||||
props.onNavigate({
|
||||
type: 'push',
|
||||
key: 'Route ' + navigationParentState.children.length,
|
||||
key: 'Route ' + props.scenes.length,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
<NavigationExampleRow
|
||||
text="Pop Route"
|
||||
onPress={() => {
|
||||
onNavigate({
|
||||
props.onNavigate({
|
||||
type: 'pop',
|
||||
});
|
||||
}}
|
||||
|
@ -16,25 +16,32 @@
|
||||
'use strict';
|
||||
|
||||
const React = require('react-native');
|
||||
const NavigationExampleRow = require('./NavigationExampleRow');
|
||||
const NavigationExampleTabBar = require('./NavigationExampleTabBar');
|
||||
|
||||
const {
|
||||
NavigationExperimental,
|
||||
ScrollView,
|
||||
StyleSheet,
|
||||
View,
|
||||
} = React;
|
||||
|
||||
const {
|
||||
AnimatedView: NavigationAnimatedView,
|
||||
Card: NavigationCard,
|
||||
CardStack: NavigationCardStack,
|
||||
Container: NavigationContainer,
|
||||
RootContainer: NavigationRootContainer,
|
||||
Header: NavigationHeader,
|
||||
Reducer: NavigationReducer,
|
||||
RootContainer: NavigationRootContainer,
|
||||
View: NavigationView,
|
||||
} = NavigationExperimental;
|
||||
const NavigationExampleRow = require('./NavigationExampleRow');
|
||||
const NavigationExampleTabBar = require('./NavigationExampleTabBar');
|
||||
|
||||
import type {NavigationParentState} from 'NavigationStateUtils';
|
||||
|
||||
import type {
|
||||
NavigationParentState,
|
||||
NavigationSceneRenderer,
|
||||
NavigationSceneRendererProps,
|
||||
} from 'NavigationTypeDefinition';
|
||||
|
||||
type Action = {
|
||||
isExitAction?: boolean,
|
||||
@ -43,6 +50,7 @@ type Action = {
|
||||
const ExampleExitAction = () => ({
|
||||
isExitAction: true,
|
||||
});
|
||||
|
||||
ExampleExitAction.match = (action: Action) => (
|
||||
action && action.isExitAction === true
|
||||
);
|
||||
@ -51,6 +59,7 @@ const PageAction = (type) => ({
|
||||
type,
|
||||
isPageAction: true,
|
||||
});
|
||||
|
||||
PageAction.match = (action) => (
|
||||
action && action.isPageAction === true
|
||||
);
|
||||
@ -59,6 +68,7 @@ const ExampleProfilePageAction = (type) => ({
|
||||
...PageAction(type),
|
||||
isProfilePageAction: true,
|
||||
});
|
||||
|
||||
ExampleProfilePageAction.match = (action) => (
|
||||
action && action.isProfilePageAction === true
|
||||
);
|
||||
@ -68,7 +78,9 @@ const ExampleInfoAction = () => PageAction('InfoPage');
|
||||
const ExampleNotifProfileAction = () => ExampleProfilePageAction('NotifProfilePage');
|
||||
|
||||
const _jsInstanceUniqueId = '' + Date.now();
|
||||
|
||||
let _uniqueIdCount = 0;
|
||||
|
||||
function pageStateActionMap(action) {
|
||||
return {
|
||||
key: 'page-' + _jsInstanceUniqueId + '-' + (_uniqueIdCount++),
|
||||
@ -144,55 +156,57 @@ function stateTypeTitleMap(pageState) {
|
||||
}
|
||||
|
||||
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() {
|
||||
return (
|
||||
<NavigationAnimatedView
|
||||
<NavigationCardStack
|
||||
style={styles.tabContent}
|
||||
navigationState={this.props.navigationState}
|
||||
renderOverlay={this._renderHeader.bind(this)}
|
||||
renderScene={this._renderScene.bind(this)}
|
||||
renderOverlay={this._renderHeader}
|
||||
renderScene={this._renderScene}
|
||||
/>
|
||||
);
|
||||
}
|
||||
_renderHeader(props) {
|
||||
_renderHeader(props: NavigationSceneRendererProps) {
|
||||
return (
|
||||
<NavigationHeader
|
||||
navigationState={props.navigationParentState}
|
||||
position={props.position}
|
||||
layout={props.layout}
|
||||
{...props}
|
||||
getTitle={state => stateTypeTitleMap(state)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
_renderScene(props) {
|
||||
|
||||
_renderScene(props: NavigationSceneRendererProps) {
|
||||
const {onNavigate} = props;
|
||||
return (
|
||||
<NavigationCard
|
||||
key={props.navigationState.key}
|
||||
index={props.index}
|
||||
navigationState={props.navigationParentState}
|
||||
position={props.position}
|
||||
layout={props.layout}>
|
||||
<ScrollView style={styles.scrollView}>
|
||||
<NavigationExampleRow
|
||||
text="Open page"
|
||||
onPress={() => {
|
||||
this.props.onNavigate(ExampleInfoAction());
|
||||
}}
|
||||
/>
|
||||
<NavigationExampleRow
|
||||
text="Open a page in the profile tab"
|
||||
onPress={() => {
|
||||
this.props.onNavigate(ExampleNotifProfileAction());
|
||||
}}
|
||||
/>
|
||||
<NavigationExampleRow
|
||||
text="Exit Composition Example"
|
||||
onPress={() => {
|
||||
this.props.onNavigate(ExampleExitAction());
|
||||
}}
|
||||
/>
|
||||
</ScrollView>
|
||||
</NavigationCard>
|
||||
<ScrollView style={styles.scrollView}>
|
||||
<NavigationExampleRow
|
||||
text="Open page"
|
||||
onPress={() => {
|
||||
onNavigate(ExampleInfoAction());
|
||||
}}
|
||||
/>
|
||||
<NavigationExampleRow
|
||||
text="Open a page in the profile tab"
|
||||
onPress={() => {
|
||||
onNavigate(ExampleNotifProfileAction());
|
||||
}}
|
||||
/>
|
||||
<NavigationExampleRow
|
||||
text="Exit Composition Example"
|
||||
onPress={() => {
|
||||
onNavigate(ExampleExitAction());
|
||||
}}
|
||||
/>
|
||||
</ScrollView>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -36,8 +36,7 @@ const {
|
||||
} = React;
|
||||
|
||||
const {
|
||||
AnimatedView: NavigationAnimatedView,
|
||||
Card: NavigationCard,
|
||||
CardStack: NavigationCardStack,
|
||||
Header: NavigationHeader,
|
||||
Reducer: NavigationReducer,
|
||||
RootContainer: NavigationRootContainer,
|
||||
@ -45,7 +44,7 @@ const {
|
||||
|
||||
import type { Value } from 'Animated';
|
||||
|
||||
import type { NavigationStateRendererProps } from 'NavigationAnimatedView';
|
||||
import type { NavigationSceneRendererProps } from 'NavigationTypeDefinition';
|
||||
|
||||
import type { UIExplorerNavigationState } from './UIExplorerNavigationReducer';
|
||||
|
||||
@ -78,7 +77,6 @@ function URIActionMap(uri: ?string): ?Object {
|
||||
return PathActionMap(path);
|
||||
}
|
||||
|
||||
|
||||
class UIExplorerApp extends React.Component {
|
||||
_navigationRootRef: ?NavigationRootContainer;
|
||||
_renderNavigation: Function;
|
||||
@ -89,7 +87,6 @@ class UIExplorerApp extends React.Component {
|
||||
this._renderNavigation = this._renderNavigation.bind(this);
|
||||
this._renderOverlay = this._renderOverlay.bind(this);
|
||||
this._renderScene = this._renderScene.bind(this);
|
||||
this._renderCard = this._renderCard.bind(this);
|
||||
}
|
||||
render() {
|
||||
return (
|
||||
@ -118,39 +115,27 @@ class UIExplorerApp extends React.Component {
|
||||
}
|
||||
const {stack} = navigationState;
|
||||
return (
|
||||
<NavigationAnimatedView
|
||||
<NavigationCardStack
|
||||
navigationState={stack}
|
||||
style={styles.container}
|
||||
renderOverlay={this._renderOverlay}
|
||||
renderScene={this._renderCard}
|
||||
renderScene={this._renderScene}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
_renderOverlay(props: NavigationStateRendererProps): ReactElement {
|
||||
_renderOverlay(props: NavigationSceneRendererProps): ReactElement {
|
||||
return (
|
||||
<NavigationHeader
|
||||
navigationState={props.navigationParentState}
|
||||
position={props.position}
|
||||
{...props}
|
||||
key={'header_' + props.scene.navigationState.key}
|
||||
getTitle={UIExplorerStateTitleMap}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
_renderCard(props: NavigationStateRendererProps): ReactElement {
|
||||
return (
|
||||
<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 {
|
||||
_renderScene(props: NavigationSceneRendererProps): ?ReactElement {
|
||||
const state = props.scene.navigationState;
|
||||
if (state.key === 'AppList') {
|
||||
return (
|
||||
<UIExplorerExampleList
|
||||
|
@ -26,7 +26,7 @@ const {
|
||||
} = NavigationExperimental;
|
||||
const StackReducer = NavigationReducer.StackReducer;
|
||||
|
||||
import type {NavigationState} from 'NavigationStateUtils';
|
||||
import type {NavigationState} from 'NavigationTypeDefinition';
|
||||
|
||||
import type {UIExplorerAction} from './UIExplorerActions';
|
||||
|
||||
@ -93,7 +93,7 @@ function UIExplorerNavigationReducer(lastState: ?UIExplorerNavigationState, acti
|
||||
if (newStack !== lastState.stack) {
|
||||
return {
|
||||
externalExample: null,
|
||||
stack: newStack,
|
||||
stack: newStack,
|
||||
}
|
||||
}
|
||||
return lastState;
|
||||
|
@ -18,7 +18,7 @@
|
||||
// $FlowFixMe : This is a platform-forked component, and flow seems to only run on iOS?
|
||||
const UIExplorerList = require('./UIExplorerList');
|
||||
|
||||
import type {NavigationState} from 'NavigationStateUtils';
|
||||
import type {NavigationState} from 'NavigationTypeDefinition';
|
||||
|
||||
function StateTitleMap(state: NavigationState): string {
|
||||
if (UIExplorerList.Modules[state.key]) {
|
||||
|
@ -28,142 +28,260 @@
|
||||
'use strict';
|
||||
|
||||
const Animated = require('Animated');
|
||||
const NavigationRootContainer = require('NavigationRootContainer');
|
||||
const NavigationContainer = require('NavigationContainer');
|
||||
const PanResponder = require('PanResponder');
|
||||
const Platform = require('Platform');
|
||||
const NavigationLinearPanResponder = require('NavigationLinearPanResponder');
|
||||
const NavigationPropTypes = require('NavigationPropTypes');
|
||||
const React = require('React');
|
||||
const ReactComponentWithPureRenderMixin = require('ReactComponentWithPureRenderMixin');
|
||||
const StyleSheet = require('StyleSheet');
|
||||
const View = require('View');
|
||||
|
||||
const ENABLE_GESTURES = Platform.OS !== 'android';
|
||||
const {Directions} = NavigationLinearPanResponder;
|
||||
|
||||
import type {
|
||||
NavigationAnimatedValue,
|
||||
NavigationLayout,
|
||||
NavigationPosition,
|
||||
NavigationSceneRenderer,
|
||||
NavigationSceneRendererProps,
|
||||
} from 'NavigationTypeDefinition';
|
||||
|
||||
import type {
|
||||
NavigationParentState
|
||||
} from 'NavigationStateUtils';
|
||||
NavigationGestureDirection
|
||||
} from 'NavigationLinearPanResponder';
|
||||
|
||||
type Layout = {
|
||||
initWidth: number,
|
||||
initHeight: number,
|
||||
width: Animated.Value;
|
||||
height: Animated.Value;
|
||||
type State = {
|
||||
hash: string,
|
||||
height: number,
|
||||
width: number,
|
||||
};
|
||||
|
||||
type Props = {
|
||||
navigationState: NavigationParentState;
|
||||
index: number;
|
||||
position: Animated.Value;
|
||||
layout: Layout;
|
||||
onNavigate: Function;
|
||||
children: Object;
|
||||
type Props = NavigationSceneRendererProps & {
|
||||
direction: NavigationGestureDirection,
|
||||
renderScene: NavigationSceneRenderer,
|
||||
};
|
||||
|
||||
class NavigationCard extends React.Component {
|
||||
_responder: ?Object;
|
||||
_lastHeight: number;
|
||||
_lastWidth: number;
|
||||
_widthListener: string;
|
||||
_heightListener: string;
|
||||
props: Props;
|
||||
componentWillMount() {
|
||||
if (ENABLE_GESTURES) {
|
||||
this._enableGestures();
|
||||
}
|
||||
const {PropTypes} = React;
|
||||
|
||||
const propTypes = {
|
||||
...NavigationPropTypes.SceneRenderer,
|
||||
direction: PropTypes.oneOf([Directions.HORIZONTAL, Directions.VERTICAL]),
|
||||
renderScene: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
const defaultProps = {
|
||||
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({
|
||||
onMoveShouldSetPanResponder: (e, {dx, dy, moveX, moveY, x0, y0}) => {
|
||||
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>
|
||||
);
|
||||
|
||||
remove() {
|
||||
this._value.removeListener(this._token);
|
||||
}
|
||||
}
|
||||
|
||||
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({
|
||||
card: {
|
||||
main: {
|
||||
backgroundColor: '#E9E9EF',
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
position: 'absolute',
|
||||
right: 0,
|
||||
shadowColor: 'black',
|
||||
shadowOpacity: 0.4,
|
||||
shadowOffset: {width: 0, height: 0},
|
||||
shadowOpacity: 0.4,
|
||||
shadowRadius: 10,
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
position: 'absolute',
|
||||
},
|
||||
});
|
||||
|
||||
module.exports = NavigationCard;
|
||||
module.exports = NavigationContainer.create(NavigationCard);
|
||||
|
@ -29,9 +29,10 @@
|
||||
|
||||
const Animated = require('Animated');
|
||||
const NavigationAnimatedView = require('NavigationAnimatedView');
|
||||
const NavigationCardStackItem = require('NavigationCardStackItem');
|
||||
const NavigationCard = require('NavigationCard');
|
||||
const NavigationContainer = require('NavigationContainer');
|
||||
const NavigationLinearPanResponder = require('NavigationLinearPanResponder');
|
||||
const NavigationPropTypes = require('NavigationPropTypes');
|
||||
const React = require('React');
|
||||
const ReactComponentWithPureRenderMixin = require('ReactComponentWithPureRenderMixin');
|
||||
const StyleSheet = require('StyleSheet');
|
||||
@ -42,32 +43,48 @@ const {PropTypes} = React;
|
||||
const {Directions} = NavigationLinearPanResponder;
|
||||
|
||||
import type {
|
||||
NavigationAnimatedValue,
|
||||
NavigationAnimationSetter,
|
||||
NavigationParentState,
|
||||
} from 'NavigationStateUtils';
|
||||
NavigationSceneRenderer,
|
||||
NavigationSceneRendererProps,
|
||||
} from 'NavigationTypeDefinition';
|
||||
|
||||
import type {
|
||||
NavigationStateRenderer,
|
||||
NavigationStateRendererProps,
|
||||
Position,
|
||||
TimingSetter,
|
||||
} from 'NavigationAnimatedView';
|
||||
NavigationGestureDirection,
|
||||
} from 'NavigationLinearPanResponder';
|
||||
|
||||
type Props = {
|
||||
direction: string,
|
||||
direction: NavigationGestureDirection,
|
||||
navigationState: NavigationParentState,
|
||||
renderOverlay: ?NavigationStateRenderer,
|
||||
renderScene: NavigationStateRenderer,
|
||||
renderOverlay: ?NavigationSceneRenderer,
|
||||
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.
|
||||
*/
|
||||
class NavigationCardStack extends React.Component {
|
||||
_renderScene : NavigationStateRenderer;
|
||||
_setTiming: TimingSetter;
|
||||
_renderScene : NavigationSceneRenderer;
|
||||
_setTiming: NavigationAnimationSetter;
|
||||
|
||||
constructor(props: Props, context: any) {
|
||||
super(props, context);
|
||||
}
|
||||
|
||||
componentWillMount() {
|
||||
this._renderScene = this._renderScene.bind(this);
|
||||
this._setTiming = this._setTiming.bind(this);
|
||||
}
|
||||
@ -92,30 +109,21 @@ class NavigationCardStack extends React.Component {
|
||||
);
|
||||
}
|
||||
|
||||
_renderScene(props: NavigationStateRendererProps): ReactElement {
|
||||
const {
|
||||
index,
|
||||
layout,
|
||||
navigationState,
|
||||
position,
|
||||
navigationParentState,
|
||||
} = props;
|
||||
|
||||
_renderScene(props: NavigationSceneRendererProps): ReactElement {
|
||||
return (
|
||||
<NavigationCardStackItem
|
||||
<NavigationCard
|
||||
{...props}
|
||||
direction={this.props.direction}
|
||||
index={index}
|
||||
key={navigationState.key}
|
||||
layout={layout}
|
||||
navigationParentState={navigationParentState}
|
||||
navigationState={navigationState}
|
||||
position={position}
|
||||
key={'card_' + props.scene.navigationState.key}
|
||||
renderScene={this.props.renderScene}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
_setTiming(position: Position, navigationState: NavigationParentState): void {
|
||||
_setTiming(
|
||||
position: NavigationAnimatedValue,
|
||||
navigationState: NavigationParentState,
|
||||
): void {
|
||||
Animated.timing(
|
||||
position,
|
||||
{
|
||||
@ -126,17 +134,8 @@ class NavigationCardStack extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
NavigationCardStack.propTypes = {
|
||||
direction: PropTypes.oneOf([Directions.HORIZONTAL, Directions.VERTICAL]),
|
||||
navigationState: PropTypes.object.isRequired,
|
||||
renderOverlay: PropTypes.func,
|
||||
renderScene: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
NavigationCardStack.defaultProps = {
|
||||
direction: Directions.HORIZONTAL,
|
||||
renderOverlay: emptyFunction.thatReturnsNull,
|
||||
};
|
||||
NavigationCardStack.propTypes = propTypes;
|
||||
NavigationCardStack.defaultProps = defaultProps;
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
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 Image = require('Image');
|
||||
const NavigationContainer = require('NavigationContainer');
|
||||
const NavigationPropTypes = require('NavigationPropTypes');
|
||||
const NavigationRootContainer = require('NavigationRootContainer');
|
||||
const React = require('react-native');
|
||||
const StyleSheet = require('StyleSheet');
|
||||
@ -37,25 +38,32 @@ const Text = require('Text');
|
||||
const TouchableOpacity = require('TouchableOpacity');
|
||||
const View = require('View');
|
||||
|
||||
import type {
|
||||
import type {
|
||||
NavigationState,
|
||||
NavigationParentState
|
||||
} from 'NavigationStateUtils';
|
||||
NavigationSceneRendererProps,
|
||||
} from 'NavigationTypeDefinition';
|
||||
|
||||
type Props = {
|
||||
navigationState: NavigationParentState,
|
||||
onNavigate: Function,
|
||||
position: Animated.Value,
|
||||
type Props = NavigationSceneRendererProps & {
|
||||
getTitle: (navState: NavigationState) => string,
|
||||
};
|
||||
|
||||
const {PropTypes} = React;
|
||||
|
||||
const NavigationHeaderPropTypes = {
|
||||
...NavigationPropTypes.SceneRenderer,
|
||||
getTitle: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
class NavigationHeader extends React.Component {
|
||||
_handleBackPress: Function;
|
||||
|
||||
props: Props;
|
||||
componentWillMount() {
|
||||
|
||||
componentWillMount(): void {
|
||||
this._handleBackPress = this._handleBackPress.bind(this);
|
||||
}
|
||||
render() {
|
||||
|
||||
render(): ReactElement {
|
||||
var state = this.props.navigationState;
|
||||
return (
|
||||
<Animated.View
|
||||
@ -67,7 +75,8 @@ class NavigationHeader extends React.Component {
|
||||
</Animated.View>
|
||||
);
|
||||
}
|
||||
_renderBackButton() {
|
||||
|
||||
_renderBackButton(): ?ReactElement {
|
||||
if (this.props.navigationState.index === 0) {
|
||||
return null;
|
||||
}
|
||||
@ -77,7 +86,8 @@ class NavigationHeader extends React.Component {
|
||||
</TouchableOpacity>
|
||||
);
|
||||
}
|
||||
_renderTitle(childState, index) {
|
||||
|
||||
_renderTitle(childState: NavigationState, index:number): ?ReactElement {
|
||||
return (
|
||||
<Animated.Text
|
||||
key={childState.key}
|
||||
@ -102,11 +112,14 @@ class NavigationHeader extends React.Component {
|
||||
</Animated.Text>
|
||||
);
|
||||
}
|
||||
_handleBackPress() {
|
||||
|
||||
_handleBackPress(): void {
|
||||
this.props.onNavigate(NavigationRootContainer.getBackAction());
|
||||
}
|
||||
}
|
||||
|
||||
NavigationHeader.propTypes = NavigationHeaderPropTypes;
|
||||
|
||||
NavigationHeader = NavigationContainer.create(NavigationHeader);
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
|
@ -11,8 +11,7 @@ const invariant = require('fbjs/lib/invariant');
|
||||
import type {
|
||||
NavigationState,
|
||||
NavigationParentState,
|
||||
} from 'NavigationStateUtils';
|
||||
|
||||
} from 'NavigationTypeDefinition';
|
||||
|
||||
type IterationCallback = (route: any, index: number, key: string) => void;
|
||||
|
||||
|
@ -11,23 +11,20 @@
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var Animated = require('Animated');
|
||||
var Map = require('Map');
|
||||
var NavigationStateUtils = require('NavigationStateUtils');
|
||||
var NavigationContainer = require('NavigationContainer');
|
||||
var React = require('React');
|
||||
var View = require('View');
|
||||
const Animated = require('Animated');
|
||||
const NavigationContainer = require('NavigationContainer');
|
||||
const NavigationPropTypes = require('NavigationPropTypes');
|
||||
const NavigationStateUtils = require('NavigationStateUtils');
|
||||
const React = require('react-native');
|
||||
const View = require('View');
|
||||
|
||||
import type {
|
||||
NavigationState,
|
||||
NavigationAnimatedValue,
|
||||
NavigationAnimationSetter,
|
||||
NavigationParentState,
|
||||
} from 'NavigationStateUtils';
|
||||
|
||||
type NavigationScene = {
|
||||
index: number,
|
||||
state: NavigationState,
|
||||
isStale: boolean,
|
||||
};
|
||||
NavigationScene,
|
||||
NavigationSceneRenderer,
|
||||
} from 'NavigationTypeDefinition';
|
||||
|
||||
/**
|
||||
* Helper function to compare route keys (e.g. "9", "11").
|
||||
@ -48,7 +45,7 @@ function compareKey(one: string, two: string): number {
|
||||
*/
|
||||
function compareScenes(
|
||||
one: NavigationScene,
|
||||
two: NavigationScene
|
||||
two: NavigationScene,
|
||||
): number {
|
||||
if (one.index > two.index) {
|
||||
return 1;
|
||||
@ -58,64 +55,62 @@ function compareScenes(
|
||||
}
|
||||
|
||||
return compareKey(
|
||||
one.state.key,
|
||||
two.state.key
|
||||
one.navigationState.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 = {
|
||||
navigationState: NavigationParentState,
|
||||
onNavigate: (action: any) => void,
|
||||
renderScene: NavigationStateRenderer,
|
||||
renderOverlay: ?NavigationStateRenderer,
|
||||
renderScene: NavigationSceneRenderer,
|
||||
renderOverlay: ?NavigationSceneRenderer,
|
||||
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;
|
||||
_animatedWidth: Animated.Value;
|
||||
_lastHeight: number;
|
||||
_lastWidth: number;
|
||||
_postionListener: any;
|
||||
|
||||
props: Props;
|
||||
state: State;
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this._lastWidth = 0;
|
||||
@ -125,7 +120,7 @@ class NavigationAnimatedView extends React.Component {
|
||||
|
||||
this.state = {
|
||||
position: new Animated.Value(this.props.navigationState.index),
|
||||
scenes: new Map(),
|
||||
scenes: [],
|
||||
};
|
||||
}
|
||||
componentWillMount() {
|
||||
@ -134,7 +129,7 @@ class NavigationAnimatedView extends React.Component {
|
||||
});
|
||||
}
|
||||
componentDidMount() {
|
||||
this.postionListener = this.state.position.addListener(this._onProgressChange.bind(this));
|
||||
this._postionListener = this.state.position.addListener(this._onProgressChange.bind(this));
|
||||
}
|
||||
componentWillReceiveProps(nextProps) {
|
||||
if (nextProps.navigationState !== this.props.navigationState) {
|
||||
@ -150,8 +145,8 @@ class NavigationAnimatedView extends React.Component {
|
||||
}
|
||||
componentWillUnmount() {
|
||||
if (this.postionListener) {
|
||||
this.state.position.removeListener(this.postionListener);
|
||||
this.postionListener = null;
|
||||
this.state.position.removeListener(this._postionListener);
|
||||
this._postionListener = null;
|
||||
}
|
||||
}
|
||||
_onProgressChange(data: Object): void {
|
||||
@ -174,8 +169,8 @@ class NavigationAnimatedView extends React.Component {
|
||||
let nextScenes = nextState.children.map((child, index) => {
|
||||
return {
|
||||
index,
|
||||
state: child,
|
||||
isStale: false,
|
||||
navigationState: child,
|
||||
};
|
||||
});
|
||||
|
||||
@ -184,8 +179,8 @@ class NavigationAnimatedView extends React.Component {
|
||||
if (!NavigationStateUtils.get(nextState, child.key) && index !== nextState.index) {
|
||||
nextScenes.push({
|
||||
index,
|
||||
state: child,
|
||||
isStale: true,
|
||||
navigationState: child,
|
||||
});
|
||||
}
|
||||
});
|
||||
@ -221,49 +216,57 @@ class NavigationAnimatedView extends React.Component {
|
||||
initHeight: this._lastHeight,
|
||||
};
|
||||
}
|
||||
|
||||
_renderScene(scene: NavigationScene) {
|
||||
return this.props.renderScene({
|
||||
index: scene.index,
|
||||
const {
|
||||
navigationState,
|
||||
onNavigate,
|
||||
renderScene,
|
||||
} = this.props;
|
||||
|
||||
const {
|
||||
position,
|
||||
scenes,
|
||||
} = this.state;
|
||||
|
||||
return renderScene({
|
||||
layout: this._getLayout(),
|
||||
navigationParentState: this.props.navigationState,
|
||||
navigationState: scene.state,
|
||||
onNavigate: this.props.onNavigate,
|
||||
position: this.state.position,
|
||||
navigationState,
|
||||
onNavigate,
|
||||
position,
|
||||
scene,
|
||||
scenes,
|
||||
});
|
||||
}
|
||||
|
||||
_renderOverlay() {
|
||||
const {
|
||||
onNavigate,
|
||||
renderOverlay,
|
||||
navigationState,
|
||||
} = this.props;
|
||||
if (renderOverlay) {
|
||||
if (this.props.renderOverlay) {
|
||||
const {
|
||||
navigationState,
|
||||
onNavigate,
|
||||
renderOverlay,
|
||||
} = this.props;
|
||||
|
||||
const {
|
||||
position,
|
||||
scenes,
|
||||
} = this.state;
|
||||
|
||||
return renderOverlay({
|
||||
index: navigationState.index,
|
||||
layout: this._getLayout(),
|
||||
navigationParentState: navigationState,
|
||||
navigationState: navigationState.children[navigationState.index],
|
||||
onNavigate: onNavigate,
|
||||
position: this.state.position,
|
||||
navigationState,
|
||||
onNavigate,
|
||||
position,
|
||||
scene: scenes[navigationState.index],
|
||||
scenes,
|
||||
});
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function setDefaultTiming(position, navigationState) {
|
||||
Animated.spring(
|
||||
position,
|
||||
{
|
||||
bounciness: 0,
|
||||
toValue: navigationState.index,
|
||||
}
|
||||
).start();
|
||||
}
|
||||
|
||||
NavigationAnimatedView.defaultProps = {
|
||||
setTiming: setDefaultTiming,
|
||||
};
|
||||
NavigationAnimatedView.propTypes = propTypes;
|
||||
NavigationAnimatedView.defaultProps = defaultProps;
|
||||
|
||||
NavigationAnimatedView = NavigationContainer.create(NavigationAnimatedView);
|
||||
|
||||
|
@ -14,7 +14,9 @@
|
||||
var React = require('React');
|
||||
var NavigationRootContainer = require('NavigationRootContainer');
|
||||
|
||||
function createNavigationContainer(Component: React.Component): React.Component {
|
||||
function createNavigationContainer(
|
||||
Component: ReactClass<any, any, any>,
|
||||
): ReactClass {
|
||||
class NavigationComponent extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
|
@ -12,6 +12,12 @@ const NavigationAbstractPanResponder = require('NavigationAbstractPanResponder')
|
||||
|
||||
const clamp = require('clamp');
|
||||
|
||||
import {
|
||||
NavigationActionCaller,
|
||||
NavigationLayout,
|
||||
NavigationPosition,
|
||||
} from 'NavigationTypeDefinition';
|
||||
|
||||
/**
|
||||
* The duration of the card animation in milliseconds.
|
||||
*/
|
||||
@ -42,6 +48,8 @@ const Directions = {
|
||||
'VERTICAL': 'vertical',
|
||||
};
|
||||
|
||||
export type NavigationGestureDirection = $Enum<typeof Directions>;
|
||||
|
||||
/**
|
||||
* Primitive gesture actions.
|
||||
*/
|
||||
@ -52,25 +60,16 @@ const Actions = {
|
||||
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
|
||||
* NavigationLinearPanResponder.
|
||||
*/
|
||||
export type NavigationLinearPanResponderDelegate = {
|
||||
getDirection: () => Direction;
|
||||
getDirection: () => NavigationGestureDirection;
|
||||
getIndex: () => number,
|
||||
getLayout: () => Layout,
|
||||
getPosition: () => Position,
|
||||
onNavigate: OnNavigateHandler,
|
||||
getLayout: () => NavigationLayout,
|
||||
getPosition: () => NavigationPosition,
|
||||
onNavigate: NavigationActionCaller,
|
||||
};
|
||||
|
||||
/**
|
||||
|
76
Libraries/NavigationExperimental/NavigationPropTypes.js
Normal file
76
Libraries/NavigationExperimental/NavigationPropTypes.js
Normal file
@ -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 Linking = require('Linking');
|
||||
const React = require('React');
|
||||
const BackAndroid = require('BackAndroid');
|
||||
const Platform = require('Platform');
|
||||
const React = require('React');
|
||||
const NavigationPropTypes = require('NavigationPropTypes');
|
||||
|
||||
import type {
|
||||
NavigationAction,
|
||||
NavigationState,
|
||||
NavigationReducer
|
||||
} from 'NavigationStateUtils';
|
||||
|
||||
export type NavigationRenderer = (
|
||||
navigationState: NavigationState,
|
||||
onNavigate: Function
|
||||
) => ReactElement;
|
||||
NavigationReducer,
|
||||
NavigationRenderer,
|
||||
} from 'NavigationTypeDefinition';
|
||||
|
||||
export type BackAction = {
|
||||
type: 'BackAction';
|
||||
type: 'BackAction',
|
||||
};
|
||||
|
||||
function getBackAction(): BackAction {
|
||||
@ -37,40 +32,60 @@ function getBackAction(): BackAction {
|
||||
}
|
||||
|
||||
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
|
||||
* state. Defaults to {type: 'RootContainerInitialAction'}
|
||||
*/
|
||||
initialAction: NavigationAction;
|
||||
initialAction: NavigationAction,
|
||||
|
||||
/*
|
||||
* Provide linkingActionMap to instruct the container to subscribe to linking
|
||||
* events, and use this mapper to convert URIs into actions that your app can
|
||||
* 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 {
|
||||
_handleOpenURLEvent: Function;
|
||||
|
||||
props: Props;
|
||||
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
this.handleNavigation = this.handleNavigation.bind(this);
|
||||
@ -81,10 +96,11 @@ class NavigationRootContainer extends React.Component {
|
||||
}
|
||||
this.state = { navState };
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
if (this.props.LinkingActionMap) {
|
||||
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) {
|
||||
AsyncStorage.getItem(this.props.persistenceKey, (err, storedString) => {
|
||||
@ -100,12 +116,15 @@ class NavigationRootContainer extends React.Component {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
Platform.OS === 'ios' && Linking.removeEventListener('url', this._handleOpenURLEvent);
|
||||
}
|
||||
|
||||
_handleOpenURLEvent(event: {url: string}) {
|
||||
this._handleOpenURL(event.url);
|
||||
}
|
||||
|
||||
_handleOpenURL(url: ?string) {
|
||||
if (!this.props.LinkingActionMap) {
|
||||
return;
|
||||
@ -115,11 +134,13 @@ class NavigationRootContainer extends React.Component {
|
||||
this.handleNavigation(action);
|
||||
}
|
||||
}
|
||||
|
||||
getChildContext(): Object {
|
||||
return {
|
||||
onNavigate: this.handleNavigation,
|
||||
};
|
||||
}
|
||||
|
||||
handleNavigation(action: Object): boolean {
|
||||
const navState = this.props.reducer(this.state.navState, action);
|
||||
if (navState === this.state.navState) {
|
||||
@ -128,11 +149,14 @@ class NavigationRootContainer extends React.Component {
|
||||
this.setState({
|
||||
navState,
|
||||
});
|
||||
|
||||
if (this.props.persistenceKey) {
|
||||
AsyncStorage.setItem(this.props.persistenceKey, JSON.stringify(navState));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
render(): ReactElement {
|
||||
const navigation = this.props.renderNavigation(
|
||||
this.state.navState,
|
||||
@ -143,15 +167,11 @@ class NavigationRootContainer extends React.Component {
|
||||
}
|
||||
|
||||
NavigationRootContainer.childContextTypes = {
|
||||
onNavigate: React.PropTypes.func,
|
||||
};
|
||||
|
||||
NavigationRootContainer.defaultProps = {
|
||||
initialAction: {
|
||||
type: 'RootContainerInitialAction',
|
||||
},
|
||||
onNavigate: PropTypes.func,
|
||||
};
|
||||
|
||||
NavigationRootContainer.propTypes = propTypes;
|
||||
NavigationRootContainer.defaultProps = defaultProps;
|
||||
NavigationRootContainer.getBackAction = getBackAction;
|
||||
|
||||
module.exports = NavigationRootContainer;
|
||||
|
@ -13,24 +13,10 @@
|
||||
|
||||
const invariant = require('fbjs/lib/invariant');
|
||||
|
||||
export type NavigationState = {
|
||||
key: string;
|
||||
};
|
||||
|
||||
export type NavigationParentState = {
|
||||
key: string;
|
||||
index: number;
|
||||
children: Array<NavigationState>;
|
||||
};
|
||||
|
||||
export type NavigationAction = {
|
||||
type: string;
|
||||
};
|
||||
|
||||
export type NavigationReducer = (
|
||||
state: ?NavigationState,
|
||||
action: ?NavigationAction
|
||||
) => NavigationState;
|
||||
import type {
|
||||
NavigationState,
|
||||
NavigationParentState,
|
||||
} from 'NavigationTypeDefinition';
|
||||
|
||||
function getParent(state: NavigationState): ?NavigationParentState {
|
||||
if (
|
||||
|
93
Libraries/NavigationExperimental/NavigationTypeDefinition.js
Normal file
93
Libraries/NavigationExperimental/NavigationTypeDefinition.js
Normal file
@ -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 {
|
||||
NavigationState,
|
||||
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 {
|
||||
for (let i = 0; i < reducers.length; i++) {
|
||||
let reducer = reducers[i];
|
||||
|
@ -17,7 +17,7 @@ import type {
|
||||
NavigationState,
|
||||
NavigationParentState,
|
||||
NavigationReducer,
|
||||
} from 'NavigationStateUtils';
|
||||
} from 'NavigationTypeDefinition';
|
||||
|
||||
import type {
|
||||
BackAction,
|
||||
|
@ -17,8 +17,7 @@ const NavigationStateUtils = require('NavigationStateUtils');
|
||||
import type {
|
||||
NavigationReducer,
|
||||
NavigationState,
|
||||
NavigationParentState
|
||||
} from 'NavigationStateUtils';
|
||||
} from 'NavigationTypeDefinition';
|
||||
|
||||
const ActionTypes = {
|
||||
JUMP_TO: 'react-native/NavigationExperimental/tabs-jumpTo',
|
||||
|
@ -11,7 +11,6 @@
|
||||
'use strict';
|
||||
|
||||
jest
|
||||
.dontMock('NavigationRootContainer')
|
||||
.dontMock('NavigationStackReducer')
|
||||
.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…
x
Reference in New Issue
Block a user