From b9b0f0b2755d5da4def838c9a89f6b79f69aa7a4 Mon Sep 17 00:00:00 2001 From: Joe Noon Date: Wed, 11 May 2016 00:03:12 -0700 Subject: [PATCH 01/24] 0.26-rc wip --- src/DefaultRenderer.js | 72 ++++++++++++++++++++++++++++++------------ src/Router.js | 2 +- src/Switch.js | 2 +- src/TabBar.js | 21 +++++------- 4 files changed, 61 insertions(+), 36 deletions(-) diff --git a/src/DefaultRenderer.js b/src/DefaultRenderer.js index 06a01fe94..66d3ab470 100644 --- a/src/DefaultRenderer.js +++ b/src/DefaultRenderer.js @@ -14,6 +14,7 @@ import { Animated, NavigationExperimental, View, + StyleSheet } from 'react-native'; import TabBar from './TabBar'; @@ -25,10 +26,16 @@ const { Card: NavigationCard, } = NavigationExperimental; +const { + CardStackPanResponder: NavigationCardStackPanResponder, + CardStackStyleInterpolator: NavigationCardStackStyleInterpolator +} = NavigationCard; + export default class DefaultRenderer extends Component { static propTypes = { navigationState: PropTypes.object, + onNavigate: PropTypes.func, }; static childContextTypes = { @@ -67,34 +74,49 @@ export default class DefaultRenderer extends Component { Actions.focus({ scene }); } - renderCard(/* NavigationSceneRendererProps*/ props) { - const { key, direction, panHandlers, getSceneStyle } = props.scene.navigationState; + renderCard(/* NavigationSceneRendererProps */ props) { + const { key, direction, getSceneStyle } = props.scene.navigationState; + let { panHandlers, animationStyle } = props.scene.navigationState; - const optionals = {}; - if (getSceneStyle) optionals.style = getSceneStyle(props); + // Since we always need to pass a style for the direction, we can avoid #526 + let style = getSceneStyle ? getSceneStyle(props) : null; + + const isVertical = direction === "vertical"; + + if (typeof(animationStyle) === 'undefined') { + animationStyle = (isVertical ? + NavigationCardStackStyleInterpolator.forVertical(props) : + NavigationCardStackStyleInterpolator.forHorizontal(props)); + } + + if (typeof(panHandlers) === 'undefined') { + panHandlers = panHandlers || (isVertical ? + NavigationCardStackPanResponder.forVertical(props) : + NavigationCardStackPanResponder.forHorizontal(props)); + } return ( ); } - renderScene(props: Object) { + renderScene(/* NavigationSceneRendererProps */ props) { return ( ); } - renderHeader(props) { + renderHeader(/* NavigationSceneRendererProps */ props) { const state = props.navigationState; const child = state.children[state.index]; let selected = state.children[state.index]; @@ -138,9 +160,9 @@ export default class DefaultRenderer extends Component { } render() { - const navigationState = this.props.navigationState; + const { navigationState, onNavigate } = this.props; - if (!navigationState) { + if (!navigationState || !onNavigate) { return null; } @@ -153,10 +175,11 @@ export default class DefaultRenderer extends Component { if (SceneComponent) { return ( @@ -167,7 +190,6 @@ export default class DefaultRenderer extends Component { const selected = navigationState.children[navigationState.index]; const applyAnimation = selected.applyAnimation || navigationState.applyAnimation; const style = selected.style || navigationState.style; - let direction = selected.direction || navigationState.direction || 'horizontal'; if (applyAnimation) { optionals.applyAnimation = applyAnimation; @@ -176,7 +198,11 @@ export default class DefaultRenderer extends Component { if (duration === null || duration === undefined) duration = navigationState.duration; if (duration !== null && duration !== undefined) { optionals.applyAnimation = (pos, navState) => { - Animated.timing(pos, { toValue: navState.index, duration }).start(); + if (duration === 0) { + pos.setValue(navState.index); + } else { + Animated.timing(pos, { toValue: navState.index, duration }).start(); + } }; } } @@ -184,19 +210,23 @@ export default class DefaultRenderer extends Component { return ( ); } + } + +const styles = StyleSheet.create({ + animatedView: { + flex: 1, + backgroundColor: "transparent" + }, + sceneStyle: { + flex: 1 + } +}); diff --git a/src/Router.js b/src/Router.js index cdb95476d..36d836a27 100644 --- a/src/Router.js +++ b/src/Router.js @@ -94,7 +94,7 @@ class Router extends Component { return onNavigate(props); }; - return ; + return ; } render() { diff --git a/src/Switch.js b/src/Switch.js index eb6f47f84..b5a215831 100644 --- a/src/Switch.js +++ b/src/Switch.js @@ -41,7 +41,7 @@ export default class extends Component { render() { if (this.state.navigationState) { - return ; + return ; } return null; diff --git a/src/TabBar.js b/src/TabBar.js index 8743fa64c..2b196a689 100644 --- a/src/TabBar.js +++ b/src/TabBar.js @@ -28,19 +28,14 @@ class TabBar extends React.Component { Actions[el.props.name](); } - renderScene(props) { - if (props.layout) { - // for 0.24+, props is /*NavigationSceneRendererProps*/ - // (add flow def above when phasing out < 0.24 support) - return ( - - ); - } - // for < 0.24 - return ; + renderScene(/* NavigationSceneRendererProps */ props) { + return ( + + ); } render() { From eae616d279084d7f40b9fefab13197fab2d00119 Mon Sep 17 00:00:00 2001 From: Joe Noon Date: Wed, 11 May 2016 21:12:53 -0700 Subject: [PATCH 02/24] add TabbedView which works like the *old* NavigationView and renders all tabs. currently experiencing a bug where the "selected" index is jumping around on load and need to investigate. --- src/TabBar.js | 74 +++++++++++++++++++++-------------------------- src/TabbedView.js | 47 ++++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+), 41 deletions(-) create mode 100644 src/TabbedView.js diff --git a/src/TabBar.js b/src/TabBar.js index 2b196a689..862bf6d6a 100644 --- a/src/TabBar.js +++ b/src/TabBar.js @@ -1,42 +1,33 @@ -import React, { PropTypes } from 'react'; -import { View, NavigationExperimental } from 'react-native'; +import React, { Component, PropTypes } from 'react'; +import { View, StyleSheet } from 'react-native'; import Tabs from 'react-native-tabs'; import DefaultRenderer from './DefaultRenderer'; import Actions from './Actions'; -const { - View: NavigationView, -} = NavigationExperimental; +import TabbedView from './TabbedView'; -const propTypes = { - navigationState: PropTypes.object, - tabIcon: PropTypes.any, -}; +class TabBar extends Component { -class TabBar extends React.Component { - constructor(props) { - super(props); - this.onSelect = this.onSelect.bind(this); - this.renderScene = this.renderScene.bind(this); - } + static propTypes = { + navigationState: PropTypes.object, + tabIcon: PropTypes.any, + }; - onSelect(el) { + onSelect = (el) => { if (!Actions[el.props.name]) { throw new Error( `No action is defined for name=${el.props.name} ` + `actions: ${JSON.stringify(Object.keys(Actions))}`); } Actions[el.props.name](); - } + }; - renderScene(/* NavigationSceneRendererProps */ props) { - return ( - - ); - } + renderScene = (navigationState, index) => { + return + }; render() { const state = this.props.navigationState; @@ -45,31 +36,32 @@ class TabBar extends React.Component { selected = selected.children[selected.index]; } const hideTabBar = state.hideTabBar || selected.hideTabBar; + return ( - - {!hideTabBar && state.children.filter(el => el.icon).length > 0 && - - {state.children.filter(el => el.icon || this.props.tabIcon).map(el => { - const Icon = el.icon || this.props.tabIcon; - return ; - })} - } + /> + {!hideTabBar && state.children.filter(el => el.icon).length > 0 && + + {state.children.filter(el => el.icon || this.props.tabIcon).map(el => { + const Icon = el.icon || this.props.tabIcon; + return ; + })} + + } ); } -} -TabBar.propTypes = propTypes; +} export default TabBar; diff --git a/src/TabbedView.js b/src/TabbedView.js new file mode 100644 index 000000000..d71c12f87 --- /dev/null +++ b/src/TabbedView.js @@ -0,0 +1,47 @@ +import React, { Component, PropTypes } from 'react'; +import { View, StyleSheet } from 'react-native'; + +class TabbedView extends Component { + + static propTypes = { + navigationState: PropTypes.object.isRequired, + renderScene: PropTypes.func.isRequired, + }; + + renderScene = (navigationState, index) => { + var isSelected = index === this.props.navigationState.index; + return ( + + {this.props.renderScene(navigationState, index)} + + ); + }; + + render() { + return ( + + {this.props.navigationState.children.map(this.renderScene)} + + ); + } + +} + +const styles = StyleSheet.create({ + scene: { + bottom: 0, + left: 0, + position: 'absolute', + right: 0, + top: 0, + }, +}); + +export default TabbedView; From 6c682b54083b3a002dbb5b83becd49e2bc7b8113 Mon Sep 17 00:00:00 2001 From: Pavlo Aksonov Date: Thu, 12 May 2016 10:18:45 +0200 Subject: [PATCH 03/24] try to run Example under RN0.26-rc --- Example/iOS/Example.xcodeproj/project.pbxproj | 37 +++++++++++-------- Example/package.json | 10 ++--- package.json | 9 +++-- src/TabBar.js | 3 +- 4 files changed, 33 insertions(+), 26 deletions(-) diff --git a/Example/iOS/Example.xcodeproj/project.pbxproj b/Example/iOS/Example.xcodeproj/project.pbxproj index 896792e53..ea71be87f 100644 --- a/Example/iOS/Example.xcodeproj/project.pbxproj +++ b/Example/iOS/Example.xcodeproj/project.pbxproj @@ -105,17 +105,17 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ - 008F07F21AC5B25A0029DE68 /* main.jsbundle */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = main.jsbundle; path = main.jsbundle; sourceTree = ""; }; - 00C302A71ABCB8CE00DB3ED1 /* RCTActionSheet.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTActionSheet.xcodeproj; path = ../node_modules/react-native/Libraries/ActionSheetIOS/RCTActionSheet.xcodeproj; sourceTree = ""; }; - 00C302B51ABCB90400DB3ED1 /* RCTGeolocation.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTGeolocation.xcodeproj; path = ../node_modules/react-native/Libraries/Geolocation/RCTGeolocation.xcodeproj; sourceTree = ""; }; - 00C302BB1ABCB91800DB3ED1 /* RCTImage.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTImage.xcodeproj; path = ../node_modules/react-native/Libraries/Image/RCTImage.xcodeproj; sourceTree = ""; }; - 00C302D31ABCB9D200DB3ED1 /* RCTNetwork.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTNetwork.xcodeproj; path = ../node_modules/react-native/Libraries/Network/RCTNetwork.xcodeproj; sourceTree = ""; }; - 00C302DF1ABCB9EE00DB3ED1 /* RCTVibration.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTVibration.xcodeproj; path = ../node_modules/react-native/Libraries/Vibration/RCTVibration.xcodeproj; sourceTree = ""; }; + 008F07F21AC5B25A0029DE68 /* main.jsbundle */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = main.jsbundle; sourceTree = ""; }; + 00C302A71ABCB8CE00DB3ED1 /* RCTActionSheet.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTActionSheet.xcodeproj; path = "../node_modules/react-native/Libraries/ActionSheetIOS/RCTActionSheet.xcodeproj"; sourceTree = ""; }; + 00C302B51ABCB90400DB3ED1 /* RCTGeolocation.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTGeolocation.xcodeproj; path = "../node_modules/react-native/Libraries/Geolocation/RCTGeolocation.xcodeproj"; sourceTree = ""; }; + 00C302BB1ABCB91800DB3ED1 /* RCTImage.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTImage.xcodeproj; path = "../node_modules/react-native/Libraries/Image/RCTImage.xcodeproj"; sourceTree = ""; }; + 00C302D31ABCB9D200DB3ED1 /* RCTNetwork.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTNetwork.xcodeproj; path = "../node_modules/react-native/Libraries/Network/RCTNetwork.xcodeproj"; sourceTree = ""; }; + 00C302DF1ABCB9EE00DB3ED1 /* RCTVibration.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTVibration.xcodeproj; path = "../node_modules/react-native/Libraries/Vibration/RCTVibration.xcodeproj"; sourceTree = ""; }; 00E356EE1AD99517003FC87E /* ExampleTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ExampleTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 00E356F11AD99517003FC87E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 00E356F21AD99517003FC87E /* ExampleTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ExampleTests.m; sourceTree = ""; }; - 139105B61AF99BAD00B5F7CC /* RCTSettings.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTSettings.xcodeproj; path = ../node_modules/react-native/Libraries/Settings/RCTSettings.xcodeproj; sourceTree = ""; }; - 139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTWebSocket.xcodeproj; path = ../node_modules/react-native/Libraries/WebSocket/RCTWebSocket.xcodeproj; sourceTree = ""; }; + 139105B61AF99BAD00B5F7CC /* RCTSettings.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTSettings.xcodeproj; path = "../node_modules/react-native/Libraries/Settings/RCTSettings.xcodeproj"; sourceTree = ""; }; + 139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTWebSocket.xcodeproj; path = "../node_modules/react-native/Libraries/WebSocket/RCTWebSocket.xcodeproj"; sourceTree = ""; }; 13B07F961A680F5B00A75B9A /* Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Example.app; sourceTree = BUILT_PRODUCTS_DIR; }; 13B07FAF1A68108700A75B9A /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = Example/AppDelegate.h; sourceTree = ""; }; 13B07FB01A68108700A75B9A /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AppDelegate.m; path = Example/AppDelegate.m; sourceTree = ""; }; @@ -123,9 +123,9 @@ 13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = Example/Images.xcassets; sourceTree = ""; }; 13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = Example/Info.plist; sourceTree = ""; }; 13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = Example/main.m; sourceTree = ""; }; - 146833FF1AC3E56700842450 /* React.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = React.xcodeproj; path = ../node_modules/react-native/React/React.xcodeproj; sourceTree = ""; }; - 78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTLinking.xcodeproj; path = ../node_modules/react-native/Libraries/LinkingIOS/RCTLinking.xcodeproj; sourceTree = ""; }; - 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTText.xcodeproj; path = ../node_modules/react-native/Libraries/Text/RCTText.xcodeproj; sourceTree = ""; }; + 146833FF1AC3E56700842450 /* React.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = React.xcodeproj; path = "../node_modules/react-native/React/React.xcodeproj"; sourceTree = ""; }; + 78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTLinking.xcodeproj; path = "../node_modules/react-native/Libraries/LinkingIOS/RCTLinking.xcodeproj"; sourceTree = ""; }; + 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTText.xcodeproj; path = "../node_modules/react-native/Libraries/Text/RCTText.xcodeproj"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -526,7 +526,6 @@ runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "export NODE_BINARY=node\n../node_modules/react-native/packager/react-native-xcode.sh"; - showEnvVarsInLog = 1; }; /* End PBXShellScriptBuildPhase section */ @@ -618,9 +617,12 @@ /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, "$(SRCROOT)/../node_modules/react-native/React/**", ); - INFOPLIST_FILE = "Example/Info.plist"; + INFOPLIST_FILE = Example/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - OTHER_LDFLAGS = "-ObjC"; + OTHER_LDFLAGS = ( + "-ObjC", + "-lc++", + ); PRODUCT_NAME = Example; }; name = Debug; @@ -634,9 +636,12 @@ /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, "$(SRCROOT)/../node_modules/react-native/React/**", ); - INFOPLIST_FILE = "Example/Info.plist"; + INFOPLIST_FILE = Example/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - OTHER_LDFLAGS = "-ObjC"; + OTHER_LDFLAGS = ( + "-ObjC", + "-lc++", + ); PRODUCT_NAME = Example; }; name = Release; diff --git a/Example/package.json b/Example/package.json index 0e6aa8fd4..bc7ce2d51 100644 --- a/Example/package.json +++ b/Example/package.json @@ -6,11 +6,11 @@ "start": "node_modules/react-native/packager/packager.sh" }, "dependencies": { - "react": "^0.14.7", - "react-native": "0.22.2", - "react-native-button": "^1.2.1", - "react-native-drawer": "^1.16.7", - "react-native-modalbox": "^1.3.0", + "react": "^15.0.2", + "react-native": "0.26.0-rc", + "react-native-button": "github:ide/react-native-button", + "react-native-drawer": "^2.2.2", + "react-native-modalbox": "^1.3.3", "react-native-router-flux": "file:../" } } diff --git a/package.json b/package.json index e0e3c7a4e..b0a46d4af 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-native-router-flux", - "version": "3.22.23", + "version": "3.26.0-rc", "description": "React Native Router using Flux architecture", "repository": { "type": "git", @@ -36,7 +36,8 @@ } ], "dependencies": { - "react-native-tabs": "^1.0.2" + "assert": "^1.3.0", + "react-native-tabs": "^1.0.7" }, "devDependencies": { "babel-cli": "^6.6.5", @@ -57,10 +58,10 @@ "expect": "^1.14.0", "mocha": "^2.4.5", "mocha-junit-reporter": "^1.11.1", - "react": "^0.14.8", + "react": "^15.0.2", "react-addons-test-utils": "^0.14.7", "react-dom": "^0.14.7", - "react-native": "^0.22.2", + "react-native": "^0.26.0-rc", "react-native-mock": "0.0.6", "sinon": "^1.17.3" } diff --git a/src/TabBar.js b/src/TabBar.js index 862bf6d6a..356dfda72 100644 --- a/src/TabBar.js +++ b/src/TabBar.js @@ -5,6 +5,7 @@ import DefaultRenderer from './DefaultRenderer'; import Actions from './Actions'; import TabbedView from './TabbedView'; +console.log("COMPONENT:", Component); class TabBar extends Component { static propTypes = { @@ -45,7 +46,7 @@ class TabBar extends Component { navigationState={this.props.navigationState} style={{ flex: 1 }} renderScene={this.renderScene} - /> + /> {!hideTabBar && state.children.filter(el => el.icon).length > 0 && Date: Thu, 12 May 2016 10:37:39 +0200 Subject: [PATCH 04/24] organize imports --- Example/components/TabIcon.js | 3 ++- Example/components/TabView.js | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Example/components/TabIcon.js b/Example/components/TabIcon.js index e4e5def63..49ccb00f7 100644 --- a/Example/components/TabIcon.js +++ b/Example/components/TabIcon.js @@ -1,5 +1,6 @@ import React from 'react'; -import { PropTypes, Text } from 'react-native'; +import {PropTypes} from "react"; +import {Text} from "react-native"; const propTypes = { selected: PropTypes.string, diff --git a/Example/components/TabView.js b/Example/components/TabView.js index 7f214bf1b..bd0911db7 100644 --- a/Example/components/TabView.js +++ b/Example/components/TabView.js @@ -1,5 +1,6 @@ import React from 'react'; -import { PropTypes, StyleSheet, Text, View } from 'react-native'; +import {PropTypes} from "react"; +import {StyleSheet, Text, View} from "react-native"; import Button from 'react-native-button'; import { Actions } from 'react-native-router-flux'; From 6510dab34a38674fc6bf1ee3ddc216f7e0ecd9e6 Mon Sep 17 00:00:00 2001 From: Pavlo Aksonov Date: Thu, 12 May 2016 11:16:49 +0200 Subject: [PATCH 05/24] fix to work with RN0.26 --- Example/components/Launch.js | 38 +++++++++++++------------- Example/components/NavigationDrawer.js | 2 +- src/DefaultRenderer.js | 3 +- src/Modal.js | 2 +- src/TabBar.js | 5 ++-- 5 files changed, 24 insertions(+), 26 deletions(-) diff --git a/Example/components/Launch.js b/Example/components/Launch.js index 16bea40e6..7329aa346 100644 --- a/Example/components/Launch.js +++ b/Example/components/Launch.js @@ -4,28 +4,28 @@ import Button from "react-native-button"; import {Actions} from "react-native-router-flux"; const styles = StyleSheet.create({ - container: { - flex: 1, - justifyContent: "center", - alignItems: "center", - backgroundColor: "transparent", - } + container: { + flex: 1, + justifyContent: "center", + alignItems: "center", + backgroundColor: "transparent", + } }); class Launch extends React.Component { - render(){ - return ( - - Launch page - - - - - - - - ); - } + render(){ + return ( + + Launch page + + + + + + + + ); + } } module.exports = Launch; diff --git a/Example/components/NavigationDrawer.js b/Example/components/NavigationDrawer.js index 6a8852109..6c4148d07 100644 --- a/Example/components/NavigationDrawer.js +++ b/Example/components/NavigationDrawer.js @@ -24,7 +24,7 @@ class NavigationDrawer extends React.Component { main: { opacity: Math.max(0.54, 1 - ratio) }, })} > - + ); } diff --git a/src/DefaultRenderer.js b/src/DefaultRenderer.js index 66d3ab470..6c9928e7e 100644 --- a/src/DefaultRenderer.js +++ b/src/DefaultRenderer.js @@ -94,7 +94,6 @@ export default class DefaultRenderer extends Component { NavigationCardStackPanResponder.forVertical(props) : NavigationCardStackPanResponder.forHorizontal(props)); } - return ( - + {children.length > 1 && children.map((el, i) => { if (i > 0 && el.component) { const Component = el.component; diff --git a/src/TabBar.js b/src/TabBar.js index 356dfda72..26ea61b7a 100644 --- a/src/TabBar.js +++ b/src/TabBar.js @@ -5,7 +5,6 @@ import DefaultRenderer from './DefaultRenderer'; import Actions from './Actions'; import TabbedView from './TabbedView'; -console.log("COMPONENT:", Component); class TabBar extends Component { static propTypes = { @@ -22,7 +21,7 @@ class TabBar extends Component { Actions[el.props.name](); }; - renderScene = (navigationState, index) => { + renderScene(navigationState, index) { return {!hideTabBar && state.children.filter(el => el.icon).length > 0 && Date: Thu, 12 May 2016 02:09:27 -0700 Subject: [PATCH 06/24] WIP! switch to react-native-tab-navigator. it renders more efficiently since it only renders the active tab, yet allows all of the tabbed content to be mounted its currently pinned to my branch, but hoping my upstream PR gets accepted. styling is a little tricky, so if we go with this then we'll need to figure out and document a good default and make sure its easy to customize --- package.json | 2 +- src/TabBar.js | 81 +++++++++++++++++++++++++++-------------------- src/TabbedView.js | 47 --------------------------- 3 files changed, 47 insertions(+), 83 deletions(-) delete mode 100644 src/TabbedView.js diff --git a/package.json b/package.json index b0a46d4af..acbd17507 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,7 @@ ], "dependencies": { "assert": "^1.3.0", - "react-native-tabs": "^1.0.7" + "react-native-tab-navigator": "joenoon/react-native-tab-navigator#master" }, "devDependencies": { "babel-cli": "^6.6.5", diff --git a/src/TabBar.js b/src/TabBar.js index 26ea61b7a..e2b3ab3f7 100644 --- a/src/TabBar.js +++ b/src/TabBar.js @@ -1,9 +1,8 @@ import React, { Component, PropTypes } from 'react'; import { View, StyleSheet } from 'react-native'; -import Tabs from 'react-native-tabs'; import DefaultRenderer from './DefaultRenderer'; import Actions from './Actions'; -import TabbedView from './TabbedView'; +import TabNavigator from 'react-native-tab-navigator'; class TabBar extends Component { @@ -12,52 +11,64 @@ class TabBar extends Component { tabIcon: PropTypes.any, }; - onSelect = (el) => { - if (!Actions[el.props.name]) { + constructor(props) { + super(props); + this.onSelect = this.onSelect.bind(this); + } + + onSelect(el) { + if (!Actions[el.sceneKey]) { throw new Error( - `No action is defined for name=${el.props.name} ` + + `No action is defined for sceneKey=${el.sceneKey} ` + `actions: ${JSON.stringify(Object.keys(Actions))}`); } - Actions[el.props.name](); - }; - - renderScene(navigationState, index) { - return - }; + Actions[el.sceneKey](); + } render() { const state = this.props.navigationState; let selected = state.children[state.index]; - while (selected.hasOwnProperty('children')) { - selected = selected.children[selected.index]; - } + // @todo not sure about this + // while (selected.hasOwnProperty('children')) { + // selected = selected.children[selected.index]; + // } const hideTabBar = state.hideTabBar || selected.hideTabBar; + // @todo document/correct various tab props + return ( - - {!hideTabBar && state.children.filter(el => el.icon).length > 0 && - - {state.children.filter(el => el.icon || this.props.tabIcon).map(el => { - const Icon = el.icon || this.props.tabIcon; - return ; - })} - - } + + {state.children.map(el => { + const isSelected = el.sceneKey === selected.sceneKey; + const Icon = el.icon || this.props.tabIcon; + return ( + } + renderSelectedIcon={() => } + onPress={() => this.onSelect(el)} + tabStyle={el.tabStyle} + titleStyle={el.titleStyle} + selectedTitleStyle={el.selectedTitleStyle} + > + + + + ); + })} + ); } diff --git a/src/TabbedView.js b/src/TabbedView.js deleted file mode 100644 index d71c12f87..000000000 --- a/src/TabbedView.js +++ /dev/null @@ -1,47 +0,0 @@ -import React, { Component, PropTypes } from 'react'; -import { View, StyleSheet } from 'react-native'; - -class TabbedView extends Component { - - static propTypes = { - navigationState: PropTypes.object.isRequired, - renderScene: PropTypes.func.isRequired, - }; - - renderScene = (navigationState, index) => { - var isSelected = index === this.props.navigationState.index; - return ( - - {this.props.renderScene(navigationState, index)} - - ); - }; - - render() { - return ( - - {this.props.navigationState.children.map(this.renderScene)} - - ); - } - -} - -const styles = StyleSheet.create({ - scene: { - bottom: 0, - left: 0, - position: 'absolute', - right: 0, - top: 0, - }, -}); - -export default TabbedView; From 1c94ee00f14828094b90b124b887c6cb01fc7b13 Mon Sep 17 00:00:00 2001 From: Joe Noon Date: Thu, 12 May 2016 12:15:45 -0700 Subject: [PATCH 07/24] remove unused view --- Example/components/TabView2.js | 33 --------------------------------- 1 file changed, 33 deletions(-) delete mode 100644 Example/components/TabView2.js diff --git a/Example/components/TabView2.js b/Example/components/TabView2.js deleted file mode 100644 index 87f4bf448..000000000 --- a/Example/components/TabView2.js +++ /dev/null @@ -1,33 +0,0 @@ -import React from 'react'; -import {View, Text, StyleSheet} from "react-native"; -import Button from "react-native-button"; -import {Actions} from "react-native-router-flux"; - -const styles = StyleSheet.create({ - container: { - flex: 1, - justifyContent: "center", - alignItems: "center", - backgroundColor: "#F5FCFF", - }, - welcome: { - fontSize: 20, - textAlign: "center", - margin: 10, - }, - instructions: { - textAlign: "center", - color: "#333333", - marginBottom: 5, - }, -}); - -export default class extends React.Component { - render(){ - return ( - - Tab #{this.props.name} - - ); - } -} From 7cee8d2e6c42ca4efd20435e817c159906293865 Mon Sep 17 00:00:00 2001 From: Joe Noon Date: Thu, 12 May 2016 12:16:00 -0700 Subject: [PATCH 08/24] temporarily ignore upstream RN bug --- Example/index.ios.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Example/index.ios.js b/Example/index.ios.js index 3661e0cd4..f6dd03ee1 100644 --- a/Example/index.ios.js +++ b/Example/index.ios.js @@ -1,5 +1,8 @@ import { AppRegistry } from 'react-native'; +// @todo remove when RN upstream is fixed +console.ignoredYellowBox = ['Warning: Failed propType: SceneView']; + import Example from './Example'; AppRegistry.registerComponent('Example', () => Example); From 91a64dfaacb47d1d55747757e5bd340ff2f6d862 Mon Sep 17 00:00:00 2001 From: Joe Noon Date: Thu, 12 May 2016 12:16:23 -0700 Subject: [PATCH 09/24] add borders to visualize nav/tab styling --- Example/components/EchoView.js | 2 ++ Example/components/Launch.js | 2 ++ Example/components/TabView.js | 2 ++ 3 files changed, 6 insertions(+) diff --git a/Example/components/EchoView.js b/Example/components/EchoView.js index e83e79885..4792039fe 100644 --- a/Example/components/EchoView.js +++ b/Example/components/EchoView.js @@ -9,6 +9,8 @@ const styles = StyleSheet.create({ justifyContent: "center", alignItems: "center", backgroundColor: "#F5FCFF", + borderWidth: 2, + borderColor: 'red', }, instructions: { textAlign: "center", diff --git a/Example/components/Launch.js b/Example/components/Launch.js index 7329aa346..3297c434d 100644 --- a/Example/components/Launch.js +++ b/Example/components/Launch.js @@ -9,6 +9,8 @@ const styles = StyleSheet.create({ justifyContent: "center", alignItems: "center", backgroundColor: "transparent", + borderWidth: 2, + borderColor: 'red', } }); diff --git a/Example/components/TabView.js b/Example/components/TabView.js index bd0911db7..35a2681d5 100644 --- a/Example/components/TabView.js +++ b/Example/components/TabView.js @@ -20,6 +20,8 @@ const styles = StyleSheet.create({ justifyContent: 'center', alignItems: 'center', backgroundColor: '#F5FCFF', + borderWidth: 2, + borderColor: 'red', }, }); From 19dab21ce900034f39b5c6b706a269f42bc657b1 Mon Sep 17 00:00:00 2001 From: Joe Noon Date: Thu, 12 May 2016 12:40:36 -0700 Subject: [PATCH 10/24] modify example to show hideNavBar and hideTabBar heirarchy cases --- Example/Example.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Example/Example.js b/Example/Example.js index 2a2f09d1c..8b002b0ef 100644 --- a/Example/Example.js +++ b/Example/Example.js @@ -51,7 +51,7 @@ export default class Example extends React.Component { return - + @@ -67,12 +67,12 @@ export default class Example extends React.Component { - + } /> alert("Left button!")} leftTitle="Left" duration={1} panHandlers={null}/> - }/> + From 486e03a642a1cba80b8beab79725783eb5d43bb4 Mon Sep 17 00:00:00 2001 From: Joe Noon Date: Thu, 12 May 2016 14:57:52 -0700 Subject: [PATCH 11/24] use hideNavBar passed-in prop to determine marginTop --- Example/components/EchoView.js | 37 ++++++++++++++++++++++++++++++++-- Example/components/TabView.js | 2 +- 2 files changed, 36 insertions(+), 3 deletions(-) diff --git a/Example/components/EchoView.js b/Example/components/EchoView.js index 4792039fe..990c70df6 100644 --- a/Example/components/EchoView.js +++ b/Example/components/EchoView.js @@ -17,16 +17,49 @@ const styles = StyleSheet.create({ color: "#333333", marginBottom: 5, }, + smaller: { + marginBottom: 5, + fontSize: 12, + }, }); export default class extends React.Component { render(){ return ( - + key: {this.props.navigationState.key} sceneKey: {this.props.navigationState.sceneKey} - + + + + + ); diff --git a/Example/components/TabView.js b/Example/components/TabView.js index 35a2681d5..9a18ab854 100644 --- a/Example/components/TabView.js +++ b/Example/components/TabView.js @@ -28,7 +28,7 @@ const styles = StyleSheet.create({ const TabView = (props, context) => { const drawer = context.drawer; return ( - + Tab {props.title} {props.name === 'tab1_1' && From 029170e2e12925271704583af535ba34ab792afb Mon Sep 17 00:00:00 2001 From: Joe Noon Date: Thu, 12 May 2016 15:58:10 -0700 Subject: [PATCH 12/24] dont preset echo example with hideNavBar --- Example/Example.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Example/Example.js b/Example/Example.js index 8b002b0ef..703f845f5 100644 --- a/Example/Example.js +++ b/Example/Example.js @@ -51,7 +51,7 @@ export default class Example extends React.Component { return - + From 0076380e3310259bcbb99fdf66e012ba6dace018 Mon Sep 17 00:00:00 2001 From: Joe Noon Date: Thu, 12 May 2016 16:04:06 -0700 Subject: [PATCH 13/24] changes to make hideNavBar and hideTabBar inherit their value unless explicitly overridden. set default tabbar styles. --- src/DefaultRenderer.js | 9 ++++++++- src/Modal.js | 1 + src/Scene.js | 15 ++++++++++++++- src/Switch.js | 7 ++++++- src/TabBar.js | 41 +++++++++++++++++++++-------------------- src/Util.js | 21 +++++++++++++++++++++ 6 files changed, 71 insertions(+), 23 deletions(-) diff --git a/src/DefaultRenderer.js b/src/DefaultRenderer.js index 6c9928e7e..65abcf887 100644 --- a/src/DefaultRenderer.js +++ b/src/DefaultRenderer.js @@ -20,6 +20,7 @@ import { import TabBar from './TabBar'; import NavBar from './NavBar'; import Actions from './Actions'; +import Util from './Util'; const { AnimatedView: NavigationAnimatedView, @@ -106,11 +107,14 @@ export default class DefaultRenderer extends Component { } renderScene(/* NavigationSceneRendererProps */ props) { + const hideNavBar = Util.deepestExplicitValueForKey(props.navigationState, 'hideNavBar'); + return ( ); } @@ -122,7 +126,9 @@ export default class DefaultRenderer extends Component { while (selected.hasOwnProperty('children')) { selected = selected.children[selected.index]; } - if (state.hideNavBar || selected.hideNavBar || child.hideNavBar) { + + const hideNavBar = Util.deepestExplicitValueForKey(state, 'hideNavBar'); + if (hideNavBar) { return null; } @@ -180,6 +186,7 @@ export default class DefaultRenderer extends Component { {...navigationState} onNavigate={this.props.onNavigate} navigationState={navigationState} + hideNavBar={this.props.hideNavBar} /> ); diff --git a/src/Modal.js b/src/Modal.js index aed1cd2ca..b3936e535 100644 --- a/src/Modal.js +++ b/src/Modal.js @@ -10,6 +10,7 @@ const propTypes = { navigationState: PropTypes.shape({ children: PropTypes.array, }), + onNavigate: PropTypes.func, }; export default function Modal(props: Object) { diff --git a/src/Scene.js b/src/Scene.js index d978c8581..d9dffa451 100644 --- a/src/Scene.js +++ b/src/Scene.js @@ -6,9 +6,22 @@ * LICENSE file in the root directory of this source tree. * */ -import React from 'react'; +import React, { PropTypes } from 'react'; +import { View, Text } from 'react-native'; export default class extends React.Component { + + // @todo - should all props be documented/specified here? + + static propTypes = { + tabBarStyle: View.propTypes.style, + tabSceneStyle: View.propTypes.style, + tabStyle: View.propTypes.style, + tabTitleStyle: Text.propTypes.style, + tabSelectedTitleStyle: Text.propTypes.style, + tabTitle: PropTypes.string, + }; + render() { return null; } diff --git a/src/Switch.js b/src/Switch.js index b5a215831..0e0c02043 100644 --- a/src/Switch.js +++ b/src/Switch.js @@ -1,8 +1,13 @@ -import React, { Component } from 'react'; +import React, { Component, PropTypes } from 'react'; import DefaultRenderer from './DefaultRenderer'; import Actions from './Actions'; export default class extends Component { + + static propTypes = { + onNavigate: PropTypes.func, + }; + constructor(props) { super(props); this.updateState = this.updateState.bind(this); diff --git a/src/TabBar.js b/src/TabBar.js index e2b3ab3f7..d8561308b 100644 --- a/src/TabBar.js +++ b/src/TabBar.js @@ -1,21 +1,20 @@ import React, { Component, PropTypes } from 'react'; -import { View, StyleSheet } from 'react-native'; +import { View } from 'react-native'; import DefaultRenderer from './DefaultRenderer'; import Actions from './Actions'; import TabNavigator from 'react-native-tab-navigator'; +import Util from './Util'; class TabBar extends Component { static propTypes = { navigationState: PropTypes.object, tabIcon: PropTypes.any, + onNavigate: PropTypes.func, + tabBarStyle: View.propTypes.style, + tabSceneStyle: View.propTypes.style, }; - constructor(props) { - super(props); - this.onSelect = this.onSelect.bind(this); - } - onSelect(el) { if (!Actions[el.sceneKey]) { throw new Error( @@ -27,22 +26,25 @@ class TabBar extends Component { render() { const state = this.props.navigationState; - let selected = state.children[state.index]; - // @todo not sure about this - // while (selected.hasOwnProperty('children')) { - // selected = selected.children[selected.index]; - // } - const hideTabBar = state.hideTabBar || selected.hideTabBar; + const selected = state.children[state.index]; + const hideTabBar = Util.deepestExplicitValueForKey(state, 'hideTabBar'); - // @todo document/correct various tab props + const tabBarStyle = {}; + const tabSceneStyle = {}; + + if (hideTabBar) { + tabBarStyle.opacity = 0; + tabBarStyle.height = 0; + tabSceneStyle.paddingBottom = 0; + } return ( {state.children.map(el => { const isSelected = el.sceneKey === selected.sceneKey; @@ -51,13 +53,13 @@ class TabBar extends Component { } - renderSelectedIcon={() => } + renderSelectedIcon={() => } onPress={() => this.onSelect(el)} tabStyle={el.tabStyle} - titleStyle={el.titleStyle} - selectedTitleStyle={el.selectedTitleStyle} + titleStyle={el.tabTitleStyle} + selectedTitleStyle={el.tabSelectedTitleStyle} > - ); })} diff --git a/src/Util.js b/src/Util.js index 03ad54f9c..2c3f27c08 100644 --- a/src/Util.js +++ b/src/Util.js @@ -3,3 +3,24 @@ export function assert(expr, failDescription) { throw new Error(`[react-native-router-flux] ${failDescription}`); } } + +export default { + + // searches for the deepest explicitly set value for a key + // in a navigationState tree. + deepestExplicitValueForKey(navigationState, key) { + const selected = navigationState.children[navigationState.index]; + let current = selected[key]; + if (typeof(current) === 'undefined') { + current = navigationState[key]; + } + let innerSelected = selected; + while (innerSelected.hasOwnProperty('children')) { + innerSelected = innerSelected.children[innerSelected.index]; + if (typeof(innerSelected[key]) !== 'undefined') { + current = innerSelected[key]; + } + } + return current; + }, +}; From ba85007a36b1d317e9114b9cd46086f4aba9d142 Mon Sep 17 00:00:00 2001 From: Joe Noon Date: Fri, 13 May 2016 00:06:48 -0700 Subject: [PATCH 14/24] add development helper --- Example/README.md | 14 ++++++++++++++ Example/package.json | 6 +++++- 2 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 Example/README.md diff --git a/Example/README.md b/Example/README.md new file mode 100644 index 000000000..5cd8b582a --- /dev/null +++ b/Example/README.md @@ -0,0 +1,14 @@ +## Example App + +Normally, after a code change to react-native-router-flux src files, +you must remove the node_modules/react-native-router-flux directory +and npm install. The react-native packager wont follow symlinks. + +To assist development, this command watches and rsyncs changes: + +``` +npm run sync-rnrf +``` + +Leave a terminal open running this command when running the Example +app and making react-native-router-flux src changes. diff --git a/Example/package.json b/Example/package.json index bc7ce2d51..5b88b1ee2 100644 --- a/Example/package.json +++ b/Example/package.json @@ -3,7 +3,8 @@ "version": "0.0.1", "private": true, "scripts": { - "start": "node_modules/react-native/packager/packager.sh" + "start": "node_modules/react-native/packager/packager.sh", + "sync-rnrf": "rm -rf ./node_modules/react-native-router-flux; sane '/usr/bin/rsync -v -a --exclude .git --exclude Example --exclude node_modules ../ ./node_modules/react-native-router-flux/' .. --glob='{**/*.json,**/*.js}'" }, "dependencies": { "react": "^15.0.2", @@ -12,5 +13,8 @@ "react-native-drawer": "^2.2.2", "react-native-modalbox": "^1.3.3", "react-native-router-flux": "file:../" + }, + "devDependencies": { + "sane": "^1.3.4" } } From acf1285dfc09f937590ca3cdc566e8208a408dea Mon Sep 17 00:00:00 2001 From: Joe Noon Date: Fri, 13 May 2016 11:32:04 -0700 Subject: [PATCH 15/24] make hideTabBar work like hideNavBar: both props are exposed directly to the SceneComponent. the Example app demos how to pass a sceneStyleFn that can use the hideNavBar and hideTabBar props to set styles based on an app's custom styling/dimensions/etc. by default a view will be allowed to use the full screen and render behind any tab or navbar. this is somewhat analogous to what ios allows with topLayoutGuide, bottomLayoutGuide. fixed logic for inheriting values in navigationState to take into account tabs and walks pushed children. --- Example/Example.js | 11 ++++++++++- Example/components/EchoView.js | 2 +- Example/components/Launch.js | 2 -- Example/components/TabView.js | 2 +- index.js | 2 ++ src/DefaultRenderer.js | 9 ++++++--- src/TabBar.js | 4 +--- src/Util.js | 31 ++++++++++++++++++++++--------- 8 files changed, 43 insertions(+), 20 deletions(-) diff --git a/Example/Example.js b/Example/Example.js index 703f845f5..71318d0f6 100644 --- a/Example/Example.js +++ b/Example/Example.js @@ -46,9 +46,18 @@ const reducerCreate = params=>{ } }; +// define this based on the styles/dimensions you use +const sceneStyleFn = function (props) { + return { + flex: 1, + marginTop: props.hideNavBar ? 0 : 64, + marginBottom: props.hideTabBar ? 0 : 49.5, + }; +} + export default class Example extends React.Component { render() { - return + return diff --git a/Example/components/EchoView.js b/Example/components/EchoView.js index 990c70df6..cecfce5bd 100644 --- a/Example/components/EchoView.js +++ b/Example/components/EchoView.js @@ -27,7 +27,7 @@ const styles = StyleSheet.create({ export default class extends React.Component { render(){ return ( - + key: {this.props.navigationState.key} sceneKey: {this.props.navigationState.sceneKey} diff --git a/index.js b/index.js index cc5c464d8..33a7dfb3b 100644 --- a/index.js +++ b/index.js @@ -8,6 +8,7 @@ import Scene from './src/Scene'; import Switch from './src/Switch'; import TabBar from './src/TabBar'; import getInitialState from './src/State'; +import Util from './src/Util'; export { Actions, @@ -20,4 +21,5 @@ export { Switch, TabBar, getInitialState, + Util, }; diff --git a/src/DefaultRenderer.js b/src/DefaultRenderer.js index 65abcf887..0f3b032d8 100644 --- a/src/DefaultRenderer.js +++ b/src/DefaultRenderer.js @@ -108,6 +108,7 @@ export default class DefaultRenderer extends Component { renderScene(/* NavigationSceneRendererProps */ props) { const hideNavBar = Util.deepestExplicitValueForKey(props.navigationState, 'hideNavBar'); + const hideTabBar = Util.deepestExplicitValueForKey(props.navigationState, 'hideTabBar'); return ( ); } @@ -165,7 +167,7 @@ export default class DefaultRenderer extends Component { } render() { - const { navigationState, onNavigate } = this.props; + const { navigationState, onNavigate, sceneStyleFn, hideNavBar, hideTabBar } = this.props; if (!navigationState || !onNavigate) { console.error("navigationState and onNavigate property should be not null"); @@ -184,9 +186,10 @@ export default class DefaultRenderer extends Component { > ); diff --git a/src/TabBar.js b/src/TabBar.js index d8561308b..c16e36453 100644 --- a/src/TabBar.js +++ b/src/TabBar.js @@ -30,12 +30,10 @@ class TabBar extends Component { const hideTabBar = Util.deepestExplicitValueForKey(state, 'hideTabBar'); const tabBarStyle = {}; - const tabSceneStyle = {}; if (hideTabBar) { tabBarStyle.opacity = 0; tabBarStyle.height = 0; - tabSceneStyle.paddingBottom = 0; } return ( @@ -44,7 +42,7 @@ class TabBar extends Component { > {state.children.map(el => { const isSelected = el.sceneKey === selected.sceneKey; diff --git a/src/Util.js b/src/Util.js index 2c3f27c08..fd246df80 100644 --- a/src/Util.js +++ b/src/Util.js @@ -9,18 +9,31 @@ export default { // searches for the deepest explicitly set value for a key // in a navigationState tree. deepestExplicitValueForKey(navigationState, key) { - const selected = navigationState.children[navigationState.index]; - let current = selected[key]; + let current; + let selected = navigationState; + + while (selected.hasOwnProperty('children')) { + if (!selected.tabs) { + // for pushed children, iterate through each, recording key value, + // until reaching the selected child + for (let i = 0; i < selected.index; i++) { + if (typeof(selected.children[i][key]) !== 'undefined') { + current = selected.children[i][key]; + } + } + } + // set the new selected child and check for a key value + selected = selected.children[selected.index]; + if (typeof(selected[key]) !== 'undefined') { + current = selected[key]; + } + } + + // fallback to the root key value if (typeof(current) === 'undefined') { current = navigationState[key]; } - let innerSelected = selected; - while (innerSelected.hasOwnProperty('children')) { - innerSelected = innerSelected.children[innerSelected.index]; - if (typeof(innerSelected[key]) !== 'undefined') { - current = innerSelected[key]; - } - } + return current; }, }; From 0d47d09ba793e452244d2cba4b7ebfd915dac8b3 Mon Sep 17 00:00:00 2001 From: Joe Noon Date: Sun, 15 May 2016 11:46:46 -0700 Subject: [PATCH 16/24] consolidate scene styling into existing getSceneStyle by passing hideNavBar and hideTabBar to this fn. show how to override NavigationCard's default shadow in Example --- Example/Example.js | 11 ++++++++--- Example/components/EchoView.js | 2 +- Example/components/TabView.js | 2 +- src/DefaultRenderer.js | 36 ++++++++++++++++------------------ 4 files changed, 27 insertions(+), 24 deletions(-) diff --git a/Example/Example.js b/Example/Example.js index 71318d0f6..bf5cb87ad 100644 --- a/Example/Example.js +++ b/Example/Example.js @@ -47,19 +47,24 @@ const reducerCreate = params=>{ }; // define this based on the styles/dimensions you use -const sceneStyleFn = function (props) { +const getSceneStyle = function (props) { return { flex: 1, marginTop: props.hideNavBar ? 0 : 64, marginBottom: props.hideTabBar ? 0 : 49.5, + backgroundColor: '#fff', + shadowColor: null, + shadowOffset: null, + shadowOpacity: null, + shadowRadius: null, }; } export default class Example extends React.Component { render() { - return + return - + diff --git a/Example/components/EchoView.js b/Example/components/EchoView.js index cecfce5bd..d2f7b6cde 100644 --- a/Example/components/EchoView.js +++ b/Example/components/EchoView.js @@ -27,7 +27,7 @@ const styles = StyleSheet.create({ export default class extends React.Component { render(){ return ( - + key: {this.props.navigationState.key} sceneKey: {this.props.navigationState.sceneKey} diff --git a/src/DefaultRenderer.js b/src/DefaultRenderer.js index 0f3b032d8..4a185eab7 100644 --- a/src/DefaultRenderer.js +++ b/src/DefaultRenderer.js @@ -14,7 +14,7 @@ import { Animated, NavigationExperimental, View, - StyleSheet + StyleSheet, } from 'react-native'; import TabBar from './TabBar'; @@ -29,7 +29,7 @@ const { const { CardStackPanResponder: NavigationCardStackPanResponder, - CardStackStyleInterpolator: NavigationCardStackStyleInterpolator + CardStackStyleInterpolator: NavigationCardStackStyleInterpolator, } = NavigationCard; export default class DefaultRenderer extends Component { @@ -80,9 +80,14 @@ export default class DefaultRenderer extends Component { let { panHandlers, animationStyle } = props.scene.navigationState; // Since we always need to pass a style for the direction, we can avoid #526 - let style = getSceneStyle ? getSceneStyle(props) : null; + let style; + if (getSceneStyle) { + const hideNavBar = Util.deepestExplicitValueForKey(props.navigationState, 'hideNavBar'); + const hideTabBar = Util.deepestExplicitValueForKey(props.navigationState, 'hideTabBar'); + style = getSceneStyle({ ...props, hideNavBar, hideTabBar }); + } - const isVertical = direction === "vertical"; + const isVertical = direction === 'vertical'; if (typeof(animationStyle) === 'undefined') { animationStyle = (isVertical ? @@ -99,7 +104,7 @@ export default class DefaultRenderer extends Component { @@ -107,16 +112,11 @@ export default class DefaultRenderer extends Component { } renderScene(/* NavigationSceneRendererProps */ props) { - const hideNavBar = Util.deepestExplicitValueForKey(props.navigationState, 'hideNavBar'); - const hideTabBar = Util.deepestExplicitValueForKey(props.navigationState, 'hideTabBar'); - return ( ); } @@ -167,10 +167,10 @@ export default class DefaultRenderer extends Component { } render() { - const { navigationState, onNavigate, sceneStyleFn, hideNavBar, hideTabBar } = this.props; + const { navigationState, onNavigate } = this.props; if (!navigationState || !onNavigate) { - console.error("navigationState and onNavigate property should be not null"); + console.error('navigationState and onNavigate property should be not null'); return null; } @@ -182,14 +182,12 @@ export default class DefaultRenderer extends Component { if (SceneComponent) { return ( ); @@ -219,7 +217,7 @@ export default class DefaultRenderer extends Component { return ( Date: Wed, 18 May 2016 14:04:57 -0700 Subject: [PATCH 17/24] lock assert to 1.3.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index acbd17507..e6069d05c 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ } ], "dependencies": { - "assert": "^1.3.0", + "assert": "1.3.0", "react-native-tab-navigator": "joenoon/react-native-tab-navigator#master" }, "devDependencies": { From 93e92e2ee2515b8eb2245217f4b9a176d7e51216 Mon Sep 17 00:00:00 2001 From: Joe Noon Date: Wed, 18 May 2016 19:46:51 -0700 Subject: [PATCH 18/24] bump react-native version --- Example/package.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Example/package.json b/Example/package.json index 5b88b1ee2..c76b89ba0 100644 --- a/Example/package.json +++ b/Example/package.json @@ -8,7 +8,7 @@ }, "dependencies": { "react": "^15.0.2", - "react-native": "0.26.0-rc", + "react-native": "^0.26.0", "react-native-button": "github:ide/react-native-button", "react-native-drawer": "^2.2.2", "react-native-modalbox": "^1.3.3", diff --git a/package.json b/package.json index e6069d05c..f34cae209 100644 --- a/package.json +++ b/package.json @@ -61,7 +61,7 @@ "react": "^15.0.2", "react-addons-test-utils": "^0.14.7", "react-dom": "^0.14.7", - "react-native": "^0.26.0-rc", + "react-native": "^0.26.0", "react-native-mock": "0.0.6", "sinon": "^1.17.3" } From 26b8b3f97879622c6f60142a072bfd7195f30312 Mon Sep 17 00:00:00 2001 From: Joe Noon Date: Wed, 18 May 2016 20:35:01 -0700 Subject: [PATCH 19/24] remove dependency on assert --- package.json | 1 - src/Util.js | 6 ++++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index f34cae209..e9203d2fc 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,6 @@ } ], "dependencies": { - "assert": "1.3.0", "react-native-tab-navigator": "joenoon/react-native-tab-navigator#master" }, "devDependencies": { diff --git a/src/Util.js b/src/Util.js index fd246df80..edad0c316 100644 --- a/src/Util.js +++ b/src/Util.js @@ -37,3 +37,9 @@ export default { return current; }, }; + +export function assert(expr, failDescription) { + if (!expr) { + throw new Error(`[react-native-router-flux] ${failDescription}`); + } +} From 236e449f8b65674f5b2bb54cb7718b659f9c5929 Mon Sep 17 00:00:00 2001 From: Joe Noon Date: Wed, 18 May 2016 20:44:32 -0700 Subject: [PATCH 20/24] change export/import style for Util --- src/DefaultRenderer.js | 8 +++--- src/TabBar.js | 4 +-- src/Util.js | 62 ++++++++++++++++++++---------------------- 3 files changed, 35 insertions(+), 39 deletions(-) diff --git a/src/DefaultRenderer.js b/src/DefaultRenderer.js index 4a185eab7..60a92f28b 100644 --- a/src/DefaultRenderer.js +++ b/src/DefaultRenderer.js @@ -20,7 +20,7 @@ import { import TabBar from './TabBar'; import NavBar from './NavBar'; import Actions from './Actions'; -import Util from './Util'; +import { deepestExplicitValueForKey } from './Util'; const { AnimatedView: NavigationAnimatedView, @@ -82,8 +82,8 @@ export default class DefaultRenderer extends Component { // Since we always need to pass a style for the direction, we can avoid #526 let style; if (getSceneStyle) { - const hideNavBar = Util.deepestExplicitValueForKey(props.navigationState, 'hideNavBar'); - const hideTabBar = Util.deepestExplicitValueForKey(props.navigationState, 'hideTabBar'); + const hideNavBar = deepestExplicitValueForKey(props.navigationState, 'hideNavBar'); + const hideTabBar = deepestExplicitValueForKey(props.navigationState, 'hideTabBar'); style = getSceneStyle({ ...props, hideNavBar, hideTabBar }); } @@ -129,7 +129,7 @@ export default class DefaultRenderer extends Component { selected = selected.children[selected.index]; } - const hideNavBar = Util.deepestExplicitValueForKey(state, 'hideNavBar'); + const hideNavBar = deepestExplicitValueForKey(state, 'hideNavBar'); if (hideNavBar) { return null; } diff --git a/src/TabBar.js b/src/TabBar.js index c16e36453..a9dc70c1e 100644 --- a/src/TabBar.js +++ b/src/TabBar.js @@ -3,7 +3,7 @@ import { View } from 'react-native'; import DefaultRenderer from './DefaultRenderer'; import Actions from './Actions'; import TabNavigator from 'react-native-tab-navigator'; -import Util from './Util'; +import { deepestExplicitValueForKey } from './Util'; class TabBar extends Component { @@ -27,7 +27,7 @@ class TabBar extends Component { render() { const state = this.props.navigationState; const selected = state.children[state.index]; - const hideTabBar = Util.deepestExplicitValueForKey(state, 'hideTabBar'); + const hideTabBar = deepestExplicitValueForKey(state, 'hideTabBar'); const tabBarStyle = {}; diff --git a/src/Util.js b/src/Util.js index edad0c316..834272fcb 100644 --- a/src/Util.js +++ b/src/Util.js @@ -1,45 +1,41 @@ -export function assert(expr, failDescription) { - if (!expr) { - throw new Error(`[react-native-router-flux] ${failDescription}`); - } -} +// searches for the deepest explicitly set value for a key +// in a navigationState tree. +export function deepestExplicitValueForKey(navigationState, key) { + let current; + let selected = navigationState; -export default { - - // searches for the deepest explicitly set value for a key - // in a navigationState tree. - deepestExplicitValueForKey(navigationState, key) { - let current; - let selected = navigationState; - - while (selected.hasOwnProperty('children')) { - if (!selected.tabs) { - // for pushed children, iterate through each, recording key value, - // until reaching the selected child - for (let i = 0; i < selected.index; i++) { - if (typeof(selected.children[i][key]) !== 'undefined') { - current = selected.children[i][key]; - } + while (selected.hasOwnProperty('children')) { + if (!selected.tabs) { + // for pushed children, iterate through each, recording key value, + // until reaching the selected child + for (let i = 0; i < selected.index; i++) { + if (typeof(selected.children[i][key]) !== 'undefined') { + current = selected.children[i][key]; } } - // set the new selected child and check for a key value - selected = selected.children[selected.index]; - if (typeof(selected[key]) !== 'undefined') { - current = selected[key]; - } } - - // fallback to the root key value - if (typeof(current) === 'undefined') { - current = navigationState[key]; + // set the new selected child and check for a key value + selected = selected.children[selected.index]; + if (typeof(selected[key]) !== 'undefined') { + current = selected[key]; } + } - return current; - }, -}; + // fallback to the root key value + if (typeof(current) === 'undefined') { + current = navigationState[key]; + } + + return current; +} export function assert(expr, failDescription) { if (!expr) { throw new Error(`[react-native-router-flux] ${failDescription}`); } } + +export default { + deepestExplicitValueForKey, + assert, +}; From 262ab2a6fa4a4eee61925ae1ff21ef4e9e2bbda6 Mon Sep 17 00:00:00 2001 From: Joe Noon Date: Thu, 19 May 2016 07:29:25 -0700 Subject: [PATCH 21/24] change tab library in readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b5d0597f1..d3d521b00 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ Router for React Native based on new React Native Navigation API. - **Highly Customizable Navigation Bar** - Show/hide the navbar depending on Scene or even the state of a Scene (e.g. Edit/Save navbar for edit mode). -- **Tab Bar Support** using [react-native-tabs](https://github.com/aksonov/react-native-tabs) (see demo). +- **Tab Bar Support** using [react-native-tab-navigator](https://github.com/exponentjs/react-native-tab-navigator) (see Example app). - **Nested Navigators** (e.g. Each tab can have its own navigator, nested in a root navigator). From bf4db6d20506fe279f23f47183f53fc850738e67 Mon Sep 17 00:00:00 2001 From: Joe Noon Date: Thu, 19 May 2016 07:49:50 -0700 Subject: [PATCH 22/24] fixes for eslint --- src/DefaultRenderer.js | 20 ++++++++++---------- src/Modal.js | 7 ++++++- src/Switch.js | 7 ++++++- 3 files changed, 22 insertions(+), 12 deletions(-) diff --git a/src/DefaultRenderer.js b/src/DefaultRenderer.js index 60a92f28b..420604f58 100644 --- a/src/DefaultRenderer.js +++ b/src/DefaultRenderer.js @@ -32,6 +32,16 @@ const { CardStackStyleInterpolator: NavigationCardStackStyleInterpolator, } = NavigationCard; +const styles = StyleSheet.create({ + animatedView: { + flex: 1, + backgroundColor: 'transparent', + }, + sceneStyle: { + flex: 1, + }, +}); + export default class DefaultRenderer extends Component { static propTypes = { @@ -227,13 +237,3 @@ export default class DefaultRenderer extends Component { } - -const styles = StyleSheet.create({ - animatedView: { - flex: 1, - backgroundColor: 'transparent', - }, - sceneStyle: { - flex: 1, - }, -}); diff --git a/src/Modal.js b/src/Modal.js index b3936e535..d9177b851 100644 --- a/src/Modal.js +++ b/src/Modal.js @@ -19,7 +19,12 @@ export default function Modal(props: Object) { return ( - + {children.length > 1 && children.map((el, i) => { if (i > 0 && el.component) { const Component = el.component; diff --git a/src/Switch.js b/src/Switch.js index 0e0c02043..2d6acf0c1 100644 --- a/src/Switch.js +++ b/src/Switch.js @@ -46,7 +46,12 @@ export default class extends Component { render() { if (this.state.navigationState) { - return ; + return ( + + ); } return null; From 3dd08c0b69d01c0f51228470648e3e2ccc0afd4c Mon Sep 17 00:00:00 2001 From: Joe Noon Date: Thu, 19 May 2016 07:51:52 -0700 Subject: [PATCH 23/24] bump to 3.26.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e9203d2fc..cc8191ac4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-native-router-flux", - "version": "3.26.0-rc", + "version": "3.26.0", "description": "React Native Router using Flux architecture", "repository": { "type": "git", From c04b03dc2c0f9bf7d3d0ab03f8b7c9bf363688a6 Mon Sep 17 00:00:00 2001 From: Joe Noon Date: Thu, 19 May 2016 09:16:59 -0700 Subject: [PATCH 24/24] lock react-native-tab-navigator more safely --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index cc8191ac4..265296c47 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ } ], "dependencies": { - "react-native-tab-navigator": "joenoon/react-native-tab-navigator#master" + "react-native-tab-navigator": "joenoon/react-native-tab-navigator#rnrf-lock" }, "devDependencies": { "babel-cli": "^6.6.5",