diff --git a/.gitignore b/.gitignore
index b927355df..94fc86711 100644
--- a/.gitignore
+++ b/.gitignore
@@ -22,6 +22,12 @@ DerivedData
*.xcuserstate
project.xcworkspace
+# Android/IJ
+#
+.idea
+.gradle
+local.properties
+
# node.js
#
node_modules/
diff --git a/.idea/workspace.xml b/.idea/workspace.xml
index 6731fcfb1..45ea6a65d 100644
--- a/.idea/workspace.xml
+++ b/.idea/workspace.xml
@@ -1,12 +1,7 @@
-
-
-
-
-
-
+
diff --git a/.npmignore b/.npmignore
index 057840cd2..e2687ef57 100755
--- a/.npmignore
+++ b/.npmignore
@@ -1 +1,3 @@
Example/
+.idea
+
diff --git a/Animations.js b/Animations.js
index 48a6dfa02..5b1e8641e 100644
--- a/Animations.js
+++ b/Animations.js
@@ -1,13 +1,22 @@
-'use strict';
+import React from 'react-native';
+const {PixelRatio, Navigator, Dimensions} = React;
+import buildStyleInterpolator from 'react-native/Libraries/Utilities/buildStyleInterpolator';
-// Scene Config
-var {Navigator,Dimensions,PixelRatio} = require('react-native');
-var buildStyleInterpolator = require('react-native/Libraries/Utilities/buildStyleInterpolator');
-var FlatFloatFromRight = Object.assign({}, Navigator.SceneConfigs.FloatFromRight);
-var FlatFloatFromBottom = Object.assign({}, Navigator.SceneConfigs.FloatFromBottom);
-FlatFloatFromRight.gestures = {};
+var NoTransition = {
+ opacity: {
+ from: 1,
+ to: 1,
+ min: 1,
+ max: 1,
+ type: 'linear',
+ extrapolate: false,
+ round: 100,
+ },
+};
-var FlatFadeToTheLeft = {
+var FadeToTheLeft = {
+ // Rotate *requires* you to break out each individual component of
+ // rotation (x, y, z, w)
transformTranslate: {
from: {x: 0, y: 0, z: 0},
to: {x: -Math.round(Dimensions.get('window').width * 0.3), y: 0, z: 0},
@@ -17,6 +26,25 @@ var FlatFadeToTheLeft = {
extrapolate: true,
round: PixelRatio.get(),
},
+ // Uncomment to try rotation:
+ // Quick guide to reasoning about rotations:
+ // http://www.opengl-tutorial.org/intermediate-tutorials/tutorial-17-quaternions/#Quaternions
+ // transformRotateRadians: {
+ // from: {x: 0, y: 0, z: 0, w: 1},
+ // to: {x: 0, y: 0, z: -0.47, w: 0.87},
+ // min: 0,
+ // max: 1,
+ // type: 'linear',
+ // extrapolate: true
+ // },
+ transformScale: {
+ from: {x: 1, y: 1, z: 1},
+ to: {x: 0.95, y: 1, z: 1},
+ min: 0,
+ max: 1,
+ type: 'linear',
+ extrapolate: true
+ },
opacity: {
from: 1,
to: 0.3,
@@ -35,43 +63,85 @@ var FlatFadeToTheLeft = {
extrapolate: true,
round: PixelRatio.get(),
},
+ scaleX: {
+ from: 1,
+ to: 0.95,
+ min: 0,
+ max: 1,
+ type: 'linear',
+ extrapolate: true
+ },
+ scaleY: {
+ from: 1,
+ to: 0.95,
+ min: 0,
+ max: 1,
+ type: 'linear',
+ extrapolate: true
+ },
};
-var FlatFadeToTheUp = {
+
+
+
+var FromTheRight = {
opacity: {
value: 1.0,
type: 'constant',
},
- translateY: {
- from: 0,
- to: -Math.round(Dimensions.get('window').height * 0.3),
+ transformTranslate: {
+ from: {x: Dimensions.get('window').width, y: 0, z: 0},
+ to: {x: 0, y: 0, z: 0},
min: 0,
max: 1,
type: 'linear',
extrapolate: true,
round: PixelRatio.get(),
},
-};
-FlatFloatFromBottom.animationInterpolators.out = buildStyleInterpolator(FlatFadeToTheUp);
-FlatFloatFromRight.animationInterpolators.out = buildStyleInterpolator(FlatFadeToTheLeft);
+ translateX: {
+ from: Dimensions.get('window').width,
+ to: 0,
+ min: 0,
+ max: 1,
+ type: 'linear',
+ extrapolate: true,
+ round: PixelRatio.get(),
+ },
-var None = {
- gestures: {
+ scaleX: {
+ value: 1,
+ type: 'constant',
+ },
+ scaleY: {
+ value: 1,
+ type: 'constant',
},
+};
- // Rebound spring parameters when transitioning FROM this scene
- springFriction: 0,
- springTension: 2000,
- // Velocity to start at when transitioning without gesture
- defaultTransitionVelocity: 1.5,
- // Animation interpolators for horizontal transitioning:
- animationInterpolators: {
- into: buildStyleInterpolator(FlatFadeToTheUp),
- out: buildStyleInterpolator(FlatFadeToTheUp),
+const Animations = {
+ FlatFloatFromRight: {
+ ...Navigator.SceneConfigs.FloatFromRight,
+ // Animation interpolators for horizontal transitioning:
+ animationInterpolators: {
+ into: buildStyleInterpolator(FromTheRight),
+ out: buildStyleInterpolator(FadeToTheLeft),
+ },
+ // We will want to customize this soon
},
-};
-module.exports = {FlatFloatFromRight, FlatFloatFromBottom, None};
+
+ None: {
+ ...Navigator.SceneConfigs.FloatFromRight,
+ gestures: null,
+ defaultTransitionVelocity: 100,
+ animationInterpolators: {
+ into: buildStyleInterpolator(NoTransition),
+ out: buildStyleInterpolator(NoTransition),
+ }
+ }
+}
+
+export default Animations;
\ No newline at end of file
diff --git a/Container.js b/Container.js
deleted file mode 100644
index 0f402e598..000000000
--- a/Container.js
+++ /dev/null
@@ -1,162 +0,0 @@
-'use strict';
-
-var React = require('react-native');
-var Actions = require('./actions');
-var Store = require('./ContainerStore');
-var {View, Navigator, Text} = React;
-var Animations = require('./Animations');
-var alt = require('./alt');
-var AltNativeContainer = require('alt/AltNativeContainer');
-
-class Item extends React.Component {
- render(){
- return null;
- }
-}
-class Container extends React.Component {
- constructor(props){
- super(props);
- this.state = {};
- this.routes = {};
- this.initial = props.initial;
- var self = this;
-
- React.Children.forEach(props.children, function (child, index){
- var name = child.props.name;
- // check initial route
- if (child.props.initial || !self.initial || name==props.initial) {
- self.initial = name;
- }
- // add action
- Actions[name] = alt.createAction(name, function(data){
- Actions.switch({name: name, data:data});
- });
- self.routes[name] = child.props;
-
- });
- this.initialRoute = this.routes[this.initial];
- }
-
- componentDidMount(){
- this.unlisten = Store.listen(this.onChange.bind(this))
- }
-
- componentWillUnmount() {
- this.unlisten();
- }
-
- onChange({page}){
- //console.log(page.name);
- if (!this.routes[page.name]){
- console.error("No route for page:"+page.name);
- }
- var route = this.getRoute(this.routes[page.name], page.data)
- var found = false;
- var self = this;
- // check if route exists
- this.refs.nav.getCurrentRoutes().forEach(function(navRoute){
- if (navRoute.name == route.name){
- self.refs.nav.jumpTo(navRoute);
- found = true;
- return;
- }
- });
-
- if (!found){
- this.refs.nav.push(route);
- }
-
- }
-
- renderScene(route, navigator) {
- var Component = route.component;
- var navBar = route.navigationBar;
- var footer = route.footer;
-
- if (navBar) {
- navBar = React.addons.cloneWithProps(navBar, {
- navigator: navigator,
- route: route
- });
- }
- if (footer){
- footer = React.addons.cloneWithProps(footer, {
- navigator: navigator,
- route: route
- });
- }
- var child = Component ?
- : React.Children.only(this.routes[route.name].children);
-
- // wrap with AltNativeContainer if 'store' is defined
- if (this.routes[route.name].store ){
- child = (
- {child}
- );
- }
-
- return (
-
- {navBar}
- {child}
- {footer}
-
- )
- }
-
- getRoute(route, data) {
- if (!route){
- console.error("No route for DATA:"+JSON.stringify(data));
- }
- var schema = this.props.schemas[route.schema || 'default'] || {};
- var sceneConfig = Animations.None;
-// var sceneConfig = route.sceneConfig || schema.sceneConfig || Animations.None;
- var NavBar = route.navBar || schema.navBar;
- var Footer = route.footer || schema.footer;
-
- var navBar;
- if (NavBar){
- navBar =
- }
-
- var footer;
- if (Footer){
- footer =
- }
- return {
- name: route.name,
- component: route.component,
- sceneConfig: {
- ...sceneConfig,
- gestures: {}
- },
- footer: footer,
- navigationBar: route.hideNavBar ? null : navBar,
- passProps: { ...route, ...data }
- }
- }
-
- render(){
- var Component = this.props.component;
- if (!this.initialRoute) {
- console.error("No initial route!");
- return ;
- }
-
- return (
-
- { return route.sceneConfig;}}
- ref="nav"
- initialRoute={this.getRoute(this.initialRoute)}
- />
- {Component && }
-
- );
- }
-}
-
-Container.Item = Item;
-
-module.exports = Container;
\ No newline at end of file
diff --git a/ContainerStore.js b/ContainerStore.js
deleted file mode 100644
index 093cdbfea..000000000
--- a/ContainerStore.js
+++ /dev/null
@@ -1,23 +0,0 @@
-'use strict';
-
-var alt = require('./alt');
-var Actions = require('./actions');
-
-class ContainerStore {
- constructor() {
- this.page = {};
- this.mode = null;
- Actions.switch = alt.createAction('switch', (x)=>x);
- this.bindListeners({
- onSwitch: Actions.switch
- });
- }
-
- onSwitch(page){
- this.mode = 'switch';
- this.page = page;
- }
-
-}
-
-module.exports = alt.createStore(ContainerStore);
\ No newline at end of file
diff --git a/Example/.flowconfig b/Example/.flowconfig
index 8989253d4..8eadd339f 100644
--- a/Example/.flowconfig
+++ b/Example/.flowconfig
@@ -7,16 +7,24 @@
# Some modules have their own node_modules with overlap
.*/node_modules/node-haste/.*
-# Ignore react-tools where there are overlaps, but don't ignore anything that
-# react-native relies on
-.*/node_modules/react-tools/src/React.js
-.*/node_modules/react-tools/src/renderers/shared/reconciler/ReactInstanceHandles.js
-.*/node_modules/react-tools/src/renderers/shared/event/EventPropagators.js
-.*/node_modules/react-tools/src/renderers/shared/event/eventPlugins/ResponderEventPlugin.js
-.*/node_modules/react-tools/src/renderers/shared/event/eventPlugins/ResponderSyntheticEvent.js
-.*/node_modules/react-tools/src/renderers/shared/event/eventPlugins/ResponderTouchHistoryStore.js
-.*/node_modules/react-tools/src/shared/vendor/core/ExecutionEnvironment.js
-
+# Ugh
+.*/node_modules/babel.*
+.*/node_modules/babylon.*
+.*/node_modules/invariant.*
+
+# Ignore react and fbjs where there are overlaps, but don't ignore
+# anything that react-native relies on
+.*/node_modules/fbjs-haste/.*/__tests__/.*
+.*/node_modules/fbjs-haste/__forks__/Map.js
+.*/node_modules/fbjs-haste/__forks__/Promise.js
+.*/node_modules/fbjs-haste/__forks__/fetch.js
+.*/node_modules/fbjs-haste/core/ExecutionEnvironment.js
+.*/node_modules/fbjs-haste/core/isEmpty.js
+.*/node_modules/fbjs-haste/crypto/crc32.js
+.*/node_modules/fbjs-haste/stubs/ErrorUtils.js
+.*/node_modules/react-haste/React.js
+.*/node_modules/react-haste/renderers/dom/ReactDOM.js
+.*/node_modules/react-haste/renderers/shared/event/eventPlugins/ResponderEventPlugin.js
# Ignore commoner tests
.*/node_modules/commoner/test/.*
@@ -25,7 +33,10 @@
.*/react-tools/node_modules/commoner/lib/reader.js
# Ignore jest
-.*/react-native/node_modules/jest-cli/.*
+.*/node_modules/jest-cli/.*
+
+# Ignore Website
+.*/website/.*
[include]
@@ -35,13 +46,18 @@ node_modules/react-native/Libraries/react-native/react-native-interface.js
[options]
module.system=haste
+munge_underscores=true
+
+module.name_mapper='^image![a-zA-Z0-9$_-]+$' -> 'GlobalImageStub'
+module.name_mapper='^[./a-zA-Z0-9$_-]+\.png$' -> 'RelativeImageStub'
+
suppress_type=$FlowIssue
suppress_type=$FlowFixMe
suppress_type=$FixMe
-suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(>=0\\.\\(1[0-3]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)
-suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(>=0\\.\\(1[0-3]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)? #[0-9]+
+suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(>=0\\.\\(1[0-8]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)
+suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(>=0\\.\\(1[0-8]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)? #[0-9]+
suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy
[version]
-0.13.1
+0.18.1
diff --git a/Example/.gitignore b/Example/.gitignore
index b927355df..94fc86711 100644
--- a/Example/.gitignore
+++ b/Example/.gitignore
@@ -22,6 +22,12 @@ DerivedData
*.xcuserstate
project.xcworkspace
+# Android/IJ
+#
+.idea
+.gradle
+local.properties
+
# node.js
#
node_modules/
diff --git a/Example/.idea/encodings.xml b/Example/.idea/encodings.xml
new file mode 100644
index 000000000..97626ba45
--- /dev/null
+++ b/Example/.idea/encodings.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Example/.idea/misc.xml b/Example/.idea/misc.xml
index 19f74da8e..72abef0a7 100644
--- a/Example/.idea/misc.xml
+++ b/Example/.idea/misc.xml
@@ -10,5 +10,4 @@
-
\ No newline at end of file
diff --git a/Example/.idea/workspace.xml b/Example/.idea/workspace.xml
index 4a2ee9682..f789a4c9b 100644
--- a/Example/.idea/workspace.xml
+++ b/Example/.idea/workspace.xml
@@ -1,9 +1,7 @@
-
-
-
+
@@ -22,98 +20,104 @@
-
-
-
+
+
+
-
+
-
-
-
-
+
-
-
+
+
-
-
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
+
-
-
+
+
-
+
-
-
-
-
-
+
+
+
+
+
+
+
+
+
-
-
+
+
+
+
+
+
+
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
+
@@ -128,7 +132,6 @@
+
+
+
true
-
-
-
-
+
-
-
+
+
@@ -187,10 +201,13 @@
-
+
+
+
+
@@ -241,6 +258,116 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -258,7 +385,6 @@
-
@@ -266,7 +392,7 @@
-
+
@@ -274,17 +400,6 @@
-
-
-
-
-
-
-
-
-
-
-
@@ -298,13 +413,6 @@
-
-
-
-
-
-
-
@@ -323,6 +431,24 @@
+
+
+
+
+
+
+
+
+ $PROJECT_DIR$
+ true
+
+ bdd
+
+ DIRECTORY
+
+ false
+
+
@@ -338,26 +464,27 @@
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -378,467 +505,382 @@
-
+
-
+
-
+
-
-
-
-
-
-
-
+
-
+
-
-
-
-
+
+
-
+
-
-
+
-
+
-
-
+
-
+
-
+
-
-
-
-
-
-
-
-
-
-
-
+
-
+
-
-
-
-
-
-
-
+
-
+
-
-
-
-
+
-
+
-
-
+
-
+
-
+
-
+
-
-
+
-
+
-
-
+
-
+
-
+
-
-
-
-
-
-
-
+
+
-
+
-
+
+
-
-
-
-
-
-
-
+
+
-
+
-
+
-
+
-
-
-
-
-
-
-
+
-
+
-
+
-
+
-
+
-
+
-
-
-
-
-
-
-
+
-
+
-
+
-
+
-
+
-
-
+
+
-
+
-
+
-
+
-
-
-
-
-
-
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
-
-
-
-
-
-
+
-
+
-
-
-
-
-
-
-
+
-
+
-
-
-
-
-
-
-
+
-
+
-
+
-
+
-
-
+
+
-
+
-
-
+
+
-
+
-
+
-
+
-
+
+
-
+
-
+
+
-
+
-
+
+
-
+
-
+
+
-
+
+
-
+
-
+
+
-
+
-
-
-
-
-
-
-
+
+
-
+
-
+
-
+
-
+
-
+
-
-
-
-
-
-
-
-
-
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
-
+
+
diff --git a/Example/.watchmanconfig b/Example/.watchmanconfig
new file mode 100644
index 000000000..9e26dfeeb
--- /dev/null
+++ b/Example/.watchmanconfig
@@ -0,0 +1 @@
+{}
\ No newline at end of file
diff --git a/Example/Example.js b/Example/Example.js
new file mode 100644
index 000000000..8b91f1bf9
--- /dev/null
+++ b/Example/Example.js
@@ -0,0 +1,58 @@
+'use strict';
+
+var React = require('react-native');
+var {AppRegistry, Navigator, StyleSheet,Text,View} = React;
+var Launch = require('./components/Launch');
+var Register = require('./components/Register');
+var Login = require('./components/Login');
+var Login2 = require('./components/Login2');
+var {Router, Route, Schema, Animations, TabBar} = require('react-native-router-flux');
+var Error = require('./components/Error');
+var Home = require('./components/Home');
+var TabView = require('./components/TabView');
+
+class TabIcon extends React.Component {
+ render(){
+ return (
+ {this.props.title}
+ );
+ }
+}
+
+export default class Example extends React.Component {
+ render() {
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+ }
+}
diff --git a/Example/android/app/build.gradle b/Example/android/app/build.gradle
new file mode 100644
index 000000000..69a527768
--- /dev/null
+++ b/Example/android/app/build.gradle
@@ -0,0 +1,78 @@
+apply plugin: "com.android.application"
+
+/**
+ * The react.gradle file registers two tasks: bundleDebugJsAndAssets and bundleReleaseJsAndAssets.
+ * These basically call `react-native bundle` with the correct arguments during the Android build
+ * cycle. By default, bundleDebugJsAndAssets is skipped, as in debug/dev mode we prefer to load the
+ * bundle directly from the development server. Below you can see all the possible configurations
+ * and their defaults. If you decide to add a configuration block, make sure to add it before the
+ * `apply from: "react.gradle"` line.
+ *
+ * project.ext.react = [
+ * // the name of the generated asset file containing your JS bundle
+ * bundleAssetName: "index.android.bundle",
+ *
+ * // the entry file for bundle generation
+ * entryFile: "index.android.js",
+ *
+ * // whether to bundle JS and assets in debug mode
+ * bundleInDebug: false,
+ *
+ * // whether to bundle JS and assets in release mode
+ * bundleInRelease: true,
+ *
+ * // the root of your project, i.e. where "package.json" lives
+ * root: "../../",
+ *
+ * // where to put the JS bundle asset in debug mode
+ * jsBundleDirDebug: "$buildDir/intermediates/assets/debug",
+ *
+ * // where to put the JS bundle asset in release mode
+ * jsBundleDirRelease: "$buildDir/intermediates/assets/release",
+ *
+ * // where to put drawable resources / React Native assets, e.g. the ones you use via
+ * // require('./image.png')), in debug mode
+ * resourcesDirDebug: "$buildDir/intermediates/res/merged/debug",
+ *
+ * // where to put drawable resources / React Native assets, e.g. the ones you use via
+ * // require('./image.png')), in release mode
+ * resourcesDirRelease: "$buildDir/intermediates/res/merged/release",
+ *
+ * // by default the gradle tasks are skipped if none of the JS files or assets change; this means
+ * // that we don't look at files in android/ or ios/ to determine whether the tasks are up to
+ * // date; if you have any other folders that you want to ignore for performance reasons (gradle
+ * // indexes the entire tree), add them here. Alternatively, if you have JS files in android/
+ * // for example, you might want to remove it from here.
+ * inputExcludes: ["android/**", "ios/**"]
+ * ]
+ */
+
+apply from: "react.gradle"
+
+android {
+ compileSdkVersion 23
+ buildToolsVersion "23.0.1"
+
+ defaultConfig {
+ applicationId "com.example"
+ minSdkVersion 16
+ targetSdkVersion 22
+ versionCode 1
+ versionName "1.0"
+ ndk {
+ abiFilters "armeabi-v7a", "x86"
+ }
+ }
+ buildTypes {
+ release {
+ minifyEnabled false // Set this to true to enable Proguard
+ proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
+ }
+ }
+}
+
+dependencies {
+ compile fileTree(dir: "libs", include: ["*.jar"])
+ compile "com.android.support:appcompat-v7:23.0.1"
+ compile "com.facebook.react:react-native:0.16.+"
+}
diff --git a/Example/android/app/proguard-rules.pro b/Example/android/app/proguard-rules.pro
new file mode 100644
index 000000000..ffa8c9f64
--- /dev/null
+++ b/Example/android/app/proguard-rules.pro
@@ -0,0 +1,60 @@
+# Add project specific ProGuard rules here.
+# By default, the flags in this file are appended to flags specified
+# in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt
+# You can edit the include path and order by changing the proguardFiles
+# directive in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# Add any project specific keep options here:
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Disabling obfuscation is useful if you collect stack traces from production crashes
+# (unless you are using a system that supports de-obfuscate the stack traces).
+-dontobfuscate
+
+# React Native
+
+# Keep our interfaces so they can be used by other ProGuard rules.
+# See http://sourceforge.net/p/proguard/bugs/466/
+-keep,allowobfuscation @interface com.facebook.proguard.annotations.DoNotStrip
+-keep,allowobfuscation @interface com.facebook.proguard.annotations.KeepGettersAndSetters
+
+# Do not strip any method/class that is annotated with @DoNotStrip
+-keep @com.facebook.proguard.annotations.DoNotStrip class *
+-keepclassmembers class * {
+ @com.facebook.proguard.annotations.DoNotStrip *;
+}
+
+-keepclassmembers @com.facebook.proguard.annotations.KeepGettersAndSetters class * {
+ void set*(***);
+ *** get*();
+}
+
+-keep class * extends com.facebook.react.bridge.JavaScriptModule { *; }
+-keep class * extends com.facebook.react.bridge.NativeModule { *; }
+-keepclassmembers class * { @com.facebook.react.uimanager.UIProp ; }
+-keepclassmembers class * { @com.facebook.react.uimanager.ReactProp ; }
+-keepclassmembers class * { @com.facebook.react.uimanager.ReactPropGroup ; }
+
+# okhttp
+
+-keepattributes Signature
+-keepattributes *Annotation*
+-keep class com.squareup.okhttp.** { *; }
+-keep interface com.squareup.okhttp.** { *; }
+-dontwarn com.squareup.okhttp.**
+
+# okio
+
+-keep class sun.misc.Unsafe { *; }
+-dontwarn java.nio.file.*
+-dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement
+-dontwarn okio.**
diff --git a/Example/android/app/react.gradle b/Example/android/app/react.gradle
new file mode 100644
index 000000000..1e08b00f1
--- /dev/null
+++ b/Example/android/app/react.gradle
@@ -0,0 +1,87 @@
+import org.apache.tools.ant.taskdefs.condition.Os
+
+def config = project.hasProperty("react") ? project.react : [];
+
+def bundleAssetName = config.bundleAssetName ?: "index.android.bundle"
+def entryFile = config.entryFile ?: "index.android.js"
+
+// because elvis operator
+def elvisFile(thing) {
+ return thing ? file(thing) : null;
+}
+
+def reactRoot = elvisFile(config.root) ?: file("../../")
+def jsBundleDirDebug = elvisFile(config.jsBundleDirDebug) ?:
+ file("$buildDir/intermediates/assets/debug")
+def jsBundleDirRelease = elvisFile(config.jsBundleDirRelease) ?:
+ file("$buildDir/intermediates/assets/release")
+def resourcesDirDebug = elvisFile(config.resourcesDirDebug) ?:
+ file("$buildDir/intermediates/res/merged/debug")
+def resourcesDirRelease = elvisFile(config.resourcesDirRelease) ?:
+ file("$buildDir/intermediates/res/merged/release")
+def inputExcludes = config.inputExcludes ?: ["android/**", "ios/**"]
+
+def jsBundleFileDebug = file("$jsBundleDirDebug/$bundleAssetName")
+def jsBundleFileRelease = file("$jsBundleDirRelease/$bundleAssetName")
+
+task bundleDebugJsAndAssets(type: Exec) {
+ // create dirs if they are not there (e.g. the "clean" task just ran)
+ doFirst {
+ jsBundleDirDebug.mkdirs()
+ resourcesDirDebug.mkdirs()
+ }
+
+ // set up inputs and outputs so gradle can cache the result
+ inputs.files fileTree(dir: reactRoot, excludes: inputExcludes)
+ outputs.dir jsBundleDirDebug
+ outputs.dir resourcesDirDebug
+
+ // set up the call to the react-native cli
+ workingDir reactRoot
+ if (Os.isFamily(Os.FAMILY_WINDOWS)) {
+ commandLine "cmd", "/c", "react-native", "bundle", "--platform", "android", "--dev", "true", "--entry-file",
+ entryFile, "--bundle-output", jsBundleFileDebug, "--assets-dest", resourcesDirDebug
+ } else {
+ commandLine "react-native", "bundle", "--platform", "android", "--dev", "true", "--entry-file",
+ entryFile, "--bundle-output", jsBundleFileDebug, "--assets-dest", resourcesDirDebug
+ }
+
+ enabled config.bundleInDebug ?: false
+}
+
+task bundleReleaseJsAndAssets(type: Exec) {
+ // create dirs if they are not there (e.g. the "clean" task just ran)
+ doFirst {
+ jsBundleDirRelease.mkdirs()
+ resourcesDirRelease.mkdirs()
+ }
+
+ // set up inputs and outputs so gradle can cache the result
+ inputs.files fileTree(dir: reactRoot, excludes: inputExcludes)
+ outputs.dir jsBundleDirRelease
+ outputs.dir resourcesDirRelease
+
+ // set up the call to the react-native cli
+ workingDir reactRoot
+ if (Os.isFamily(Os.FAMILY_WINDOWS)) {
+ commandLine "cmd","/c", "react-native", "bundle", "--platform", "android", "--dev", "false", "--entry-file",
+ entryFile, "--bundle-output", jsBundleFileRelease, "--assets-dest", resourcesDirRelease
+ } else {
+ commandLine "react-native", "bundle", "--platform", "android", "--dev", "false", "--entry-file",
+ entryFile, "--bundle-output", jsBundleFileRelease, "--assets-dest", resourcesDirRelease
+ }
+
+ enabled config.bundleInRelease ?: true
+}
+
+gradle.projectsEvaluated {
+ // hook bundleDebugJsAndAssets into the android build process
+ bundleDebugJsAndAssets.dependsOn mergeDebugResources
+ bundleDebugJsAndAssets.dependsOn mergeDebugAssets
+ processDebugResources.dependsOn bundleDebugJsAndAssets
+
+ // hook bundleReleaseJsAndAssets into the android build process
+ bundleReleaseJsAndAssets.dependsOn mergeReleaseResources
+ bundleReleaseJsAndAssets.dependsOn mergeReleaseAssets
+ processReleaseResources.dependsOn bundleReleaseJsAndAssets
+}
diff --git a/Example/android/app/src/main/AndroidManifest.xml b/Example/android/app/src/main/AndroidManifest.xml
new file mode 100644
index 000000000..99e1c9b19
--- /dev/null
+++ b/Example/android/app/src/main/AndroidManifest.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Example/android/app/src/main/java/com/example/MainActivity.java b/Example/android/app/src/main/java/com/example/MainActivity.java
new file mode 100644
index 000000000..3793a9806
--- /dev/null
+++ b/Example/android/app/src/main/java/com/example/MainActivity.java
@@ -0,0 +1,78 @@
+package com.example;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.KeyEvent;
+
+import com.facebook.react.LifecycleState;
+import com.facebook.react.ReactInstanceManager;
+import com.facebook.react.ReactRootView;
+import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler;
+import com.facebook.react.shell.MainReactPackage;
+import com.facebook.soloader.SoLoader;
+
+public class MainActivity extends Activity implements DefaultHardwareBackBtnHandler {
+
+ private ReactInstanceManager mReactInstanceManager;
+ private ReactRootView mReactRootView;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ mReactRootView = new ReactRootView(this);
+
+ mReactInstanceManager = ReactInstanceManager.builder()
+ .setApplication(getApplication())
+ .setBundleAssetName("index.android.bundle")
+ .setJSMainModuleName("index.android")
+ .addPackage(new MainReactPackage())
+ .setUseDeveloperSupport(BuildConfig.DEBUG)
+ .setInitialLifecycleState(LifecycleState.RESUMED)
+ .build();
+
+ mReactRootView.startReactApplication(mReactInstanceManager, "Example", null);
+
+ setContentView(mReactRootView);
+ }
+
+ @Override
+ public boolean onKeyUp(int keyCode, KeyEvent event) {
+ if (keyCode == KeyEvent.KEYCODE_MENU && mReactInstanceManager != null) {
+ mReactInstanceManager.showDevOptionsDialog();
+ return true;
+ }
+ return super.onKeyUp(keyCode, event);
+ }
+
+ @Override
+ public void onBackPressed() {
+ if (mReactInstanceManager != null) {
+ mReactInstanceManager.onBackPressed();
+ } else {
+ super.onBackPressed();
+ }
+ }
+
+ @Override
+ public void invokeDefaultOnBackPressed() {
+ super.onBackPressed();
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+
+ if (mReactInstanceManager != null) {
+ mReactInstanceManager.onPause();
+ }
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+
+ if (mReactInstanceManager != null) {
+ mReactInstanceManager.onResume(this, this);
+ }
+ }
+}
diff --git a/Example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/Example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 000000000..cde69bccc
Binary files /dev/null and b/Example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/Example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/Example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 000000000..c133a0cbd
Binary files /dev/null and b/Example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/Example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/Example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 000000000..bfa42f0e7
Binary files /dev/null and b/Example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/Example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/Example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 000000000..324e72cdd
Binary files /dev/null and b/Example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/Example/android/app/src/main/res/values/strings.xml b/Example/android/app/src/main/res/values/strings.xml
new file mode 100644
index 000000000..0057fcb99
--- /dev/null
+++ b/Example/android/app/src/main/res/values/strings.xml
@@ -0,0 +1,3 @@
+
+ Example
+
diff --git a/Example/android/app/src/main/res/values/styles.xml b/Example/android/app/src/main/res/values/styles.xml
new file mode 100644
index 000000000..319eb0ca1
--- /dev/null
+++ b/Example/android/app/src/main/res/values/styles.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
diff --git a/Example/android/build.gradle b/Example/android/build.gradle
new file mode 100644
index 000000000..bdb0fcc6d
--- /dev/null
+++ b/Example/android/build.gradle
@@ -0,0 +1,23 @@
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
+
+buildscript {
+ repositories {
+ jcenter()
+ }
+ dependencies {
+ classpath 'com.android.tools.build:gradle:1.3.1'
+
+ // NOTE: Do not place your application dependencies here; they belong
+ // in the individual module build.gradle files
+ }
+}
+
+allprojects {
+ repositories {
+ mavenLocal()
+ jcenter()
+ jcenter {
+ url "http://dl.bintray.com/mkonicek/maven"
+ }
+ }
+}
diff --git a/Example/android/gradle.properties b/Example/android/gradle.properties
new file mode 100644
index 000000000..1fd964e90
--- /dev/null
+++ b/Example/android/gradle.properties
@@ -0,0 +1,20 @@
+# Project-wide Gradle settings.
+
+# IDE (e.g. Android Studio) users:
+# Gradle settings configured through the IDE *will override*
+# any settings specified in this file.
+
+# For more details on how to configure your build environment visit
+# http://www.gradle.org/docs/current/userguide/build_environment.html
+
+# Specifies the JVM arguments used for the daemon process.
+# The setting is particularly useful for tweaking memory settings.
+# Default value: -Xmx10248m -XX:MaxPermSize=256m
+# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
+
+# When configured, Gradle will run in incubating parallel mode.
+# This option should only be used with decoupled projects. More details, visit
+# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
+# org.gradle.parallel=true
+
+android.useDeprecatedNdk=true
diff --git a/Example/android/gradle/wrapper/gradle-wrapper.jar b/Example/android/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 000000000..b5166dad4
Binary files /dev/null and b/Example/android/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/Example/android/gradle/wrapper/gradle-wrapper.properties b/Example/android/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 000000000..b9fbfaba0
--- /dev/null
+++ b/Example/android/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,5 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-2.4-all.zip
diff --git a/Example/android/gradlew b/Example/android/gradlew
new file mode 100755
index 000000000..91a7e269e
--- /dev/null
+++ b/Example/android/gradlew
@@ -0,0 +1,164 @@
+#!/usr/bin/env bash
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn ( ) {
+ echo "$*"
+}
+
+die ( ) {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+esac
+
+# For Cygwin, ensure paths are in UNIX format before anything is touched.
+if $cygwin ; then
+ [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
+fi
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >&-
+APP_HOME="`pwd -P`"
+cd "$SAVED" >&-
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=$((i+1))
+ done
+ case $i in
+ (0) set -- ;;
+ (1) set -- "$args0" ;;
+ (2) set -- "$args0" "$args1" ;;
+ (3) set -- "$args0" "$args1" "$args2" ;;
+ (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
+function splitJvmOpts() {
+ JVM_OPTS=("$@")
+}
+eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
+JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
+
+exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
diff --git a/Example/android/gradlew.bat b/Example/android/gradlew.bat
new file mode 100644
index 000000000..aec99730b
--- /dev/null
+++ b/Example/android/gradlew.bat
@@ -0,0 +1,90 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windowz variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+if "%@eval[2+2]" == "4" goto 4NT_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+goto execute
+
+:4NT_args
+@rem Get arguments from the 4NT Shell from JP Software
+set CMD_LINE_ARGS=%$
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/Example/android/settings.gradle b/Example/android/settings.gradle
new file mode 100644
index 000000000..54b22e1c6
--- /dev/null
+++ b/Example/android/settings.gradle
@@ -0,0 +1,3 @@
+rootProject.name = 'Example'
+
+include ':app'
diff --git a/Example/components/Home.js b/Example/components/Home.js
index 50e2f211e..063940113 100644
--- a/Example/components/Home.js
+++ b/Example/components/Home.js
@@ -9,7 +9,7 @@ class Register extends React.Component {
render(){
return (
- Home
+ Replace screen
);
diff --git a/Example/components/Launch.js b/Example/components/Launch.js
index a5bb3c369..4e1ab53a5 100644
--- a/Example/components/Launch.js
+++ b/Example/components/Launch.js
@@ -13,7 +13,6 @@ class Launch extends React.Component {
-
);
diff --git a/Example/components/Login.js b/Example/components/Login.js
index d072d23cf..afad22378 100644
--- a/Example/components/Login.js
+++ b/Example/components/Login.js
@@ -10,6 +10,7 @@ class Login extends React.Component {
return (
Login page: {this.props.data}
+
);
diff --git a/Example/components/Login2.js b/Example/components/Login2.js
new file mode 100644
index 000000000..9744c775d
--- /dev/null
+++ b/Example/components/Login2.js
@@ -0,0 +1,40 @@
+'use strict';
+
+var React = require('react-native');
+var {View, Text, StyleSheet} = React;
+var Button = require('react-native-button');
+var Actions = require('react-native-router-flux').Actions;
+
+class Login extends React.Component {
+ render(){
+ return (
+
+ Login2 page: {this.props.data}
+
+
+ );
+ }
+}
+
+var 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,
+ },
+});
+
+
+
+module.exports = Login;
\ No newline at end of file
diff --git a/Example/components/Register.js b/Example/components/Register.js
index 6bfd07b85..064f5d9ff 100644
--- a/Example/components/Register.js
+++ b/Example/components/Register.js
@@ -10,7 +10,7 @@ class Register extends React.Component {
return (
Register page
-
+
);
diff --git a/Example/components/TabBarFlux.js b/Example/components/TabBarFlux.js
index cce4289b2..5ff484da2 100644
--- a/Example/components/TabBarFlux.js
+++ b/Example/components/TabBarFlux.js
@@ -3,12 +3,12 @@
var React = require('react-native');
var {View, Text, StyleSheet} = React;
var Button = require('react-native-button');
-var {Actions, ContainerStore} = require('react-native-router-flux');
+var {Actions} = require('react-native-router-flux');
var Tabs = require('react-native-tabs');
class TabBarFlux extends React.Component {
onSelect(el){
- Actions.switch({name: el.props.name, data:el.props});
+ Actions[el.props.name](el.props);
return {selected: true};
}
render(){
@@ -21,7 +21,7 @@ class TabBarFlux extends React.Component {
});
return (
-
+
{children}
);
diff --git a/Example/components/TabView.js b/Example/components/TabView.js
index 7caf809a8..51625c000 100644
--- a/Example/components/TabView.js
+++ b/Example/components/TabView.js
@@ -2,12 +2,20 @@
var React = require('react-native');
var {View, Text, StyleSheet} = React;
+var Button = require('react-native-button');
+var Actions = require('react-native-router-flux').Actions;
+
class TabView extends React.Component {
render(){
+ console.log("RENDER!"+this.props.name);
return (
- Tab #{this.props.name}
+ Tab {this.props.title}
+ {this.props.name === "tab1_1" &&
+
+ }
+
);
}
diff --git a/Example/components/TabView2.js b/Example/components/TabView2.js
index e69de29bb..7caf809a8 100644
--- a/Example/components/TabView2.js
+++ b/Example/components/TabView2.js
@@ -0,0 +1,35 @@
+'use strict';
+
+var React = require('react-native');
+var {View, Text, StyleSheet} = React;
+
+class TabView extends React.Component {
+ render(){
+ return (
+
+ Tab #{this.props.name}
+
+ );
+ }
+}
+
+var 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,
+ },
+});
+
+module.exports = TabView;
\ No newline at end of file
diff --git a/Example/index.android.js b/Example/index.android.js
new file mode 100644
index 000000000..456a93e80
--- /dev/null
+++ b/Example/index.android.js
@@ -0,0 +1,7 @@
+'use strict';
+
+var React = require('react-native');
+var {AppRegistry, Navigator, StyleSheet,Text,View} = React;
+import Example from './Example';
+
+AppRegistry.registerComponent('Example', () => Example);
diff --git a/Example/index.ios.js b/Example/index.ios.js
index dfd2b1535..456a93e80 100644
--- a/Example/index.ios.js
+++ b/Example/index.ios.js
@@ -1,49 +1,7 @@
'use strict';
var React = require('react-native');
-var {AppRegistry, StyleSheet,Text,View} = React;
-var Launch = require('./components/Launch');
-var Register = require('./components/Register');
-var Login = require('./components/Login');
-var {Router, Route, Container, Actions, Animations, Schema} = require('react-native-router-flux');
-var {NavBar, NavBarModal} = require('./components/NavBar');
-var Error = require('./components/Error');
-var Home = require('./components/Home');
-var TabView = require('./components/TabView');
-var TabIcon = require('./components/TabIcon');
-var TabBarFlux = require('./components/TabBarFlux');
-
-class Example extends React.Component {
- render() {
- return (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- );
- }
-}
+var {AppRegistry, Navigator, StyleSheet,Text,View} = React;
+import Example from './Example';
AppRegistry.registerComponent('Example', () => Example);
diff --git a/Example/package.json b/Example/package.json
index 65b3728d1..dbf59e901 100644
--- a/Example/package.json
+++ b/Example/package.json
@@ -6,10 +6,9 @@
"start": "node_modules/react-native/packager/packager.sh"
},
"dependencies": {
- "react-native": "^0.13.2",
+ "react-native": "^0.16",
"react-native-button": "^1.2.1",
- "react-native-navbar": "^0.8.0",
- "react-native-router-flux": "^0.3.2",
- "react-native-tabs": "^0.0.5"
+ "react-native-router-flux": "^1.0.0",
+ "react-native-tabs": "^0.1.4"
}
}
diff --git a/README.md b/README.md
index dccf3eafc..c83c0d24d 100644
--- a/README.md
+++ b/README.md
@@ -1,84 +1,92 @@
# react-native-router-flux
-React Native Router using Flux architecture
+React Native Router Actions based on exNavigator (https://github.com/exponentjs/ex-navigator)
-## Redux support
-It is version for Flux architecture (alt.js.org implementation), for version with Redux support, use react-native-redux-router (https://github.com/aksonov/react-native-redux-router)
-
-## Why I need to use it?
-- Use Flux actions to replace/push/pop screens with easy syntax like Actions.login for navigation to login screen
+## Why?
+- Use Actions to replace/push/pop screens with easy syntax like Actions.login for navigation to login screen
- Forget about passing navigator object to all React elements, use actions from anywhere in your UI code.
- Configure all of your screens ("routes") once (define animations, nav bars, etc.), at one place and then just use short actions commands. For example if you use some special animation for Login screen, you don't need to code it anywhere where an user should be redirected to login screen.
- Use route "schemas" to define common property for some screens. For example some screens are "modal" (i.e. have animation from bottom and have Cancel/Close nav button), so you could define group for them to avoid any code repeatition.
-- Use popup with Flux actions (see Error popup within Example project)
- Hide nav bar for some screens easily
-- Use tab bars for some screens with Flux actions (see demo)
-- Simplify processing of data flow in your app (see Getting Started, #4)
-- Define your custom Flux actions (like fetch or validation actions) with the component too, so you will have all app actions in the one place.
+- Use built-in tab bar for some screens (see demo)
+- Nested Navigators are supported (i.e. separate navigator for each tab view inside root navigator). push/pop actions will automatically use latest navigator.
+
+## Redux or other Flux support
+The component doesn't depend from any Flux implementation and allows to intercept all route actions by adding Actions.onPush/onReplace/onPop handlers from your store(s).
+If handler returns false route action is ignored. For Redux Don't forget to 'connect' your component to your store.
+
## Example

```javascript
-'use strict';
-
var React = require('react-native');
-var {AppRegistry, StyleSheet,Text,View} = React;
+var {AppRegistry, Navigator, StyleSheet,Text,View} = React;
var Launch = require('./components/Launch');
var Register = require('./components/Register');
var Login = require('./components/Login');
-var {Router, Route, Container, Actions, Animations, Schema} = require('react-native-router-flux');
-var {NavBar, NavBarModal} = require('./components/NavBar');
+var Login2 = require('./components/Login2');
+var {Router, Route, Schema, Animations, TabBar} = require('react-native-router-flux');
var Error = require('./components/Error');
var Home = require('./components/Home');
var TabView = require('./components/TabView');
-var TabIcon = require('./components/TabIcon');
-var TabBarFlux = require('./components/TabBarFlux');
-class Example extends React.Component {
- render() {
+class TabIcon extends React.Component {
+ render(){
return (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ {this.props.title}
);
}
}
-AppRegistry.registerComponent('Example', () => Example);
+export default class Example extends React.Component {
+ render() {
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+ }
+}
```
components/Launch.js (initial screen)
-```javascript
+```
'use strict';
var React = require('react-native');
var {View, Text, StyleSheet, TouchableHighlight} = React;
var Button = require('react-native-button');
var Actions = require('react-native-router-flux').Actions;
+
class Launch extends React.Component {
render(){
return (
@@ -86,7 +94,8 @@ class Launch extends React.Component {
Launch page
-
+
+
);
}
@@ -97,7 +106,7 @@ var styles = StyleSheet.create({
flex: 1,
justifyContent: 'center',
alignItems: 'center',
- backgroundColor: '#F5FCFF',
+ backgroundColor: 'transparent',
}
});
@@ -108,37 +117,12 @@ module.exports = Launch;
1. `npm install react-native-router-flux --save`
2. In top-level index.js:
* Define Route for each app screen. Its 'type' attribute is 'push' by default, but you also could define 'replace', so navigator will replace current route with new route.
+ 'switch' type represents tab screen.
'component' attribute is React component class which will be created for this route and all route attributes will be passed to it.
+'wrapRouter' - wraps Route inside new navigator.
'name' is unique name of Route.
* If some your Routes have common attributes, you may define Schema element and just use 'schema' attribute for 'route'
* If you want to define some your custom actions, just add 'Action' element inside Router. That action will not be processed by the component, it will call Actions.custom({name:ACTION_NAME, ...params}) so you could handle it in your stores. It allows to add Fetch actions (which downloads web content), etc.
3. In any app screen:
* var {Actions} = require('react-native-router-flux');
* Actions.ACTION_NAME(PARAMS) will call appropriate action and params will be passed to next screen.
-4. In your Flux stores (optional). You may subscribe to any push/replace/pop 'page' actions in your store.
-It could be necessary if you want to process user data somehow. For example, if some component manages user form and have "Save" button which should store that data and pop the screen, you may use Actions.pop(this.state) in that component and then subscribe to Actions.pop actions within store:
-
- ```javascript
- class SearchFilterStore {
- constructor(){
- this.bindAction(Actions.pop, this.onSet);
- }
-
- onSet(data){
- this.waitFor(PageStore.dispatchToken);
- var route = PageStore.getState().currentRoute;
-
- if (route == 'yourFORM'){
- // save data
-
- this.saveData(data);
- return true;
- }
- return false;
- }
- }
- module.exports = alt.createStore(SearchFilterStore, 'SearchFilterStore');
- ```
-
-
-Here PageStore.getState().currentRoute is used to check current page, so the store will process only data for needed route.
diff --git a/__mocks__/react-native.js b/__mocks__/react-native.js
deleted file mode 100644
index c48d5fb31..000000000
--- a/__mocks__/react-native.js
+++ /dev/null
@@ -1,50 +0,0 @@
-'use strict';
-var React = require('react');
-
-var ReactNative = React;
-ReactNative.StyleSheet = {
- create: function(styles) {
- return styles;
- }
-};
-class View extends React.Component {
- render(){
- return
- }
-}
-
-class Navigator extends React.Component {
- constructor(props){
- super(props);
- this._currentRoutes = [props.initialRoute];
- this.state = {route : props.initialRoute};
- }
- getCurrentRoutes(){
- return this._currentRoutes;
- }
- push(route){
- this._currentRoutes.push(route);
- this.setState({route: route});
- }
- immediatelyResetRouteStack(routes){
- this._currentRoutes = routes;
- }
- replace(route){
- this._currentRoutes.pop();
- this._currentRoutes.push(route);
- this.setState({route: route});
- }
- popToRoute(route){
- while (this._currentRoutes[this._currentRoutes.length-1] != route){
- this._currentRoutes.pop();
- }
- this.setState({route: route});
- }
- render(){
- return this.props.renderScene(this.state.route, this);
- }
-}
-ReactNative.View = View;
-ReactNative.Navigator = Navigator;
-
-module.exports = ReactNative;
\ No newline at end of file
diff --git a/__tests__/router-tests.js b/__tests__/router-tests.js
deleted file mode 100644
index 67cea9b04..000000000
--- a/__tests__/router-tests.js
+++ /dev/null
@@ -1,170 +0,0 @@
-jest.setMock('../Animations', {FlatFloatFromRight:{}, FlatFloatFromBottom:{}, None:{}});
-jest.setMock('alt/components/AltNativeContainer');
-var React = require('react/addons');
-var alt = require('../alt');
-var TestUtils = React.addons.TestUtils;
-jest.dontMock('../store');
-jest.dontMock('../actions');
-jest.dontMock('../index');
-
-var Actions = require('../actions');
-
-var {Router, Route, Schema, Action} = require('../index');
-
-class Store {
- constructor(){
- this.bindAction(Actions.custom, this.onCustom);
- this.data = undefined;
- }
-
- onCustom(data){
- this.setState({data})
- }
-
-}
-var TestStore = alt.createStore(Store ,"TestStore");
-
-describe('Router', function() {
- beforeEach(function(){
- this.router = TestUtils.renderIntoDocument(
-
-
-
-
-
-
-
-
-
-
-
-
-
- );
- });
-
- it('route', function () {
- var router = this.router;
- expect(router.refs.nav.props.initialRoute.name).toEqual('launch');
- var len = router.refs.nav.getCurrentRoutes().length;
- expect(len).toEqual(1);
- var launchComponent = TestUtils.findRenderedDOMComponentWithTag(
- router, 'launchComponent');
-
- expect(launchComponent.props.customProp).toEqual("a");
-
- expect(function(){TestUtils.findRenderedDOMComponentWithTag(
- router, 'navBar1')}).toThrow(new Error("Did not find exactly one match for tag:navBar1"));
- expect(function(){TestUtils.findRenderedDOMComponentWithTag(
- router, 'signinComponent')}).toThrow(new Error("Did not find exactly one match for tag:signinComponent"));
-
- Actions.signin("Hello world!");
- len = router.refs.nav.getCurrentRoutes().length;
- expect(len).toEqual(2);
- expect(router.refs.nav.getCurrentRoutes()[len-1].name).toEqual('signin');
- expect(router.refs.nav.getCurrentRoutes()[len-1].passProps.data).toEqual("Hello world!");
-
- Actions.signin({data:"Hello world2!", id:1});
- len = router.refs.nav.getCurrentRoutes().length;
- expect(len).toEqual(3);
- expect(router.refs.nav.getCurrentRoutes()[len-1].name).toEqual('signin');
- expect(router.refs.nav.getCurrentRoutes()[len-1].passProps.data).toEqual("Hello world2!");
- expect(router.refs.nav.getCurrentRoutes()[len-1].passProps.id).toEqual(1);
-
- var signinComponent = TestUtils.findRenderedDOMComponentWithTag(
- router, 'signinComponent');
-
- var navBar = TestUtils.findRenderedDOMComponentWithTag(
- router, 'navBar2');
-
- expect(signinComponent.props.data).toEqual('Hello world2!');
- expect(navBar.props.customProp).toEqual("b");
- expect(navBar.props.ownProp).toEqual("c");
- expect(navBar.props.data).toEqual('Hello world2!');
- expect(navBar.props.id).toEqual(1);
-
- Actions.main();
- len = router.refs.nav.getCurrentRoutes().length;
- expect(len).toEqual(4);
- expect(router.refs.nav.getCurrentRoutes()[len-1].name).toEqual('main');
- expect(router.refs.nav.getCurrentRoutes()[len-1].passProps.data).toEqual(undefined);
- expect(router.refs.nav.getCurrentRoutes()[len-1].passProps.id).toEqual(undefined);
-
- expect(function(){TestUtils.findRenderedDOMComponentWithTag(
- router, 'navBar2')}).toThrow(new Error("Did not find exactly one match for tag:navBar2"));
- navBar = TestUtils.findRenderedDOMComponentWithTag(
- router, 'navBar1');
-
- expect(navBar.props.customProp).toEqual("a");
- expect(navBar.props.ownProp).toEqual(undefined);
-
- // let's test "replace" action
- Actions.home({data:"Hello world home!", id:111, customProp:'bb'});
- len = router.refs.nav.getCurrentRoutes().length;
- expect(len).toEqual(4);
- var homeComponent = TestUtils.findRenderedDOMComponentWithTag(
- router, 'homeComponent');
-
- expect(homeComponent.props.data).toEqual('Hello world home!');
- expect(homeComponent.props.customProp).toEqual('bb');
- navBar = TestUtils.findRenderedDOMComponentWithTag(
- router, 'navBar2');
-
- expect(navBar.props.customProp).toEqual("bb");
- expect(navBar.props.ownProp).toEqual("c");
- expect(navBar.props.id).toEqual(111);
- expect(navBar.props.data).toEqual("Hello world home!");
-
- expect(navBar.props.customProp).toEqual("bb");
- expect(navBar.props.ownProp).toEqual("c");
-
- Actions.pop(2);
- len = router.refs.nav.getCurrentRoutes().length;
- expect(len).toEqual(2);
-
- expect(router.refs.nav.getCurrentRoutes()[len-1].name).toEqual('signin');
- expect(router.refs.nav.getCurrentRoutes()[len-1].passProps.data).toEqual("Hello world!");
- expect(router.refs.nav.getCurrentRoutes()[len-1].passProps.id).toEqual(undefined);
-
- Actions.pop();
- len = router.refs.nav.getCurrentRoutes().length;
- expect(len).toEqual(1);
-
- expect(router.refs.nav.getCurrentRoutes()[len-1].name).toEqual('launch');
- launchComponent = TestUtils.findRenderedDOMComponentWithTag(
- router, 'launchComponent');
-
- expect(launchComponent.props.customProp).toEqual("a");
-
-
-
- });
-
- it('custom actions', function(){
- var router = this.router;
- expect(router.refs.nav.props.initialRoute.name).toEqual('launch');
- var len = router.refs.nav.getCurrentRoutes().length;
- expect(len).toEqual(1);
- var launchComponent = TestUtils.findRenderedDOMComponentWithTag(
- router, 'launchComponent');
-
- expect(launchComponent.props.customProp).toEqual("a");
- var state = TestStore.getState();
- expect(state.data).toEqual(undefined);
-
-
- // no changes within current component should be
- Actions.custom1({url: 'hello world'});
-
- len = router.refs.nav.getCurrentRoutes().length;
- expect(len).toEqual(1);
- var launchComponent = TestUtils.findRenderedDOMComponentWithTag(
- router, 'launchComponent');
-
- expect(launchComponent.props.customProp).toEqual("a");
- state = TestStore.getState();
- expect(state.data.name).toEqual("custom1");
- expect(state.data.data.url).toEqual('hello world');
-
- });
-});
\ No newline at end of file
diff --git a/__tests__/store-tests.js b/__tests__/store-tests.js
deleted file mode 100644
index eff312c67..000000000
--- a/__tests__/store-tests.js
+++ /dev/null
@@ -1,77 +0,0 @@
-jest.dontMock('../store');
-jest.dontMock('../actions');
-var actions = require('../actions');
-var alt = require('../alt');
-var PageStore = require('../store');
-
-describe('PageStore', function() {
- it('init action', function() {
- var state = PageStore.getState();
- expect(state.routes.length).toBe(0);
- expect(state.currentRoute).toBe(null);
-
- actions.init("launch");
- state = PageStore.getState();
- expect(state.routes.length).toBe(1);
- expect(state.routes[0]).toBe("launch");
- expect(state.currentRoute).toBe("launch");
-
- actions.init("home");
- state = PageStore.getState();
- expect(state.routes.length).toBe(1);
- expect(state.routes[0]).toBe("home");
- expect(state.currentRoute).toBe("home");
- });
-
- it('push action', function() {
- actions.init("init");
-
- var state = PageStore.getState();
- expect(state.routes.length).toBe(1);
- expect(state.currentRoute).toBe("init");
-
- actions.push({name: "launch", data: "test"});
- state = PageStore.getState();
- expect(state.routes.length).toBe(2);
- expect(state.routes[1]).toBe("launch");
- expect(state.currentRoute).toBe("launch");
- expect(state.mode).toBe("push");
- expect(state.data).toBe("test");
-
- actions.push({name: "home", data: "homeData"});
- state = PageStore.getState();
- expect(state.routes.length).toBe(3);
- expect(state.routes[2]).toBe("home");
- expect(state.mode).toBe("push");
- expect(state.data).toBe("homeData");
- expect(state.currentRoute).toBe("home");
- });
-
- it('pop action', function() {
- actions.push({name: "launch", data: "test"});
- actions.push({name: "home"});
- actions.push({name: "home2"});
- actions.push({name: "home3"});
- actions.push({name: "home4"});
- var state = PageStore.getState();
- expect(state.currentRoute).toBe("home4");
- actions.pop();
- state = PageStore.getState();
- expect(state.currentRoute).toBe("home3");
- expect(state.mode).toBe("pop");
- expect(state.num).toBe(1);
-
- actions.pop(2);
- state = PageStore.getState();
- expect(state.currentRoute).toBe("home");
- expect(state.mode).toBe("pop");
- expect(state.num).toBe(2);
-
- expect(state.customData).toBe(undefined);
- actions.pop({customData: 'customData'});
- state = PageStore.getState();
- expect(state.currentRoute).toBe("launch");
- expect(state.customData).toBe("customData");
- });
-
-});
\ No newline at end of file
diff --git a/actions.js b/actions.js
deleted file mode 100644
index 5884e34e8..000000000
--- a/actions.js
+++ /dev/null
@@ -1,48 +0,0 @@
-'use strict';
-var alt = require('./alt');
-
-function filterParam(data){
- if (typeof(data)!='object')
- return data;
- if (!data){
- return;
- }
- var proto = (data||{}).constructor.name;
- // avoid passing React Native parameters
- if (proto != 'Object'){
- data = {};
- }
- if (data.data){
- data.data = filterParam(data.data);
- }
- return data;
-}
-
-class Actions {
- constructor(){
-
- }
- push(data){
- this.dispatch(filterParam(data));
- }
- pop(data){
- this.dispatch(filterParam(data));
- }
- dismiss(data){
- this.dispatch(filterParam(data));
- }
- reset(data){
- this.dispatch(filterParam(data));
- }
- init(data){
- this.dispatch(filterParam(data));
- }
- custom(data){
- this.dispatch(filterParam(data));
- }
- replace(data){
- this.dispatch(filterParam(data));
- }
-}
-
-module.exports = alt.createActions(Actions);
\ No newline at end of file
diff --git a/alt.js b/alt.js
deleted file mode 100644
index 4b8979e00..000000000
--- a/alt.js
+++ /dev/null
@@ -1,4 +0,0 @@
-var Alt = require('alt')
-var alt = new Alt()
-
-module.exports = alt
\ No newline at end of file
diff --git a/index.js b/index.js
index 7112892a6..135817fd0 100644
--- a/index.js
+++ b/index.js
@@ -1,267 +1,477 @@
-'use strict';
-var React = require('react-native');
-var {View, Navigator, Text, StyleSheet} = React;
-var alt = require('./alt');
-var PageStore = require('./store');
-var Actions = require('./actions');
-var Animations = require('./Animations');
-var Container = require('./Container');
-var AltNativeContainer = require('alt/AltNativeContainer');
+/**
+ * Copyright (c) 2015-present, Pavel Aksonov
+ * 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.
+ *
+ */
-// schema class represents schema for routes and it is processed inside Router component
-class Schema extends React.Component {
- className(){
- return "Schema";
+import React from 'react-native';
+const {View, Navigator, Text, StyleSheet, TouchableOpacity} = React;
+import ExNavigator from '@exponent/react-native-navigator';
+import Button from 'react-native-button';
+import Animations from './Animations';
+import Tabs from 'react-native-tabs';
+function filterParam(data){
+ if (typeof(data)!='object')
+ return data;
+ if (!data){
+ return;
}
- render(){
- return null;
+ var proto = (data||{}).constructor.name;
+ // avoid passing React Native parameters
+ if (proto != 'Object'){
+ data = {};
}
+ if (data.data){
+ data.data = filterParam(data.data);
+ }
+ return data;
}
-// action class represents simple action which will be handled by user-defined stores
-class Action extends React.Component {
- className(){
- return "Action";
+function isNumeric(n){
+ return !isNaN(parseFloat(n)) && isFinite(n);
+}
+
+/***
+ * Class represents navigation 'actions' (push, pop, replace, switch) and also allows to add custom actions
+ */
+class ActionContainer {
+ constructor(){
+ this.onPush = null;
+ this.onPop = null;
+ this.onReplace = null;
+ this.onSwitch = null;
+ this.navs = {};
+ this.push = this.push.bind(this);
+ this.pop = this.pop.bind(this);
+ this.replace = this.replace.bind(this);
+ this.currentRoute = null;
+ this.navsParent = {};
}
- render(){
- return null;
+
+ onDidFocus(name, isLeaf){
+ // if route is leaf, set current route to it, otherwise, find leaf
+ console.log("onDidFocus"+name+isLeaf);
+ if (isLeaf){
+ console.log("SETTING CURRENT ROUTE TO "+name);
+ this.currentRoute = name;
+ } else if (this.navsParent[name]){
+ console.log("GETTING LATEST SCENE FOR "+name);
+ const routes = this.navsParent[name].getCurrentRoutes();
+ console.log("SETTING CURRENT ROUTE TO "+routes[routes.length-1].getName());
+ this.currentRoute = routes[routes.length-1].getName();
+ }
+
}
-}
-// route class processed inside Router component
-class Route extends React.Component {
- className(){
- return "Route";
+ /***
+ * Sets navigator instance for action with given name
+ * @param name action name
+ * @param nav navigator instance
+ */
+ setNavigator(name, nav){
+ console.log("SETTING NAV "+nav.props._parent+" TO NAME="+name);
+ this.navs[name] = nav;
+ this.navsParent[nav.props._parent || 'root'] = nav;
}
- render(){
- return null;
+
+ /**
+ * Add new action with given name, props and schemas
+ * @param name action name
+ * @param props route props
+ * @param schemas route schemas
+ */
+ addAction(name, props, schemas){
+ if (!name) {
+ throw Error("No name is defined for the router");
+ }
+ if (!props) {
+ throw Error("No props is defined for the route=" + name);
+ }
+ const self = this;
+ this[name] = function(data) {
+ if (typeof(data) != 'object') {
+ data = {data: data};
+ }
+ data = filterParam(data);
+ const route = new ExRoute({...props, ...data, name}, schemas);
+ var action = route.getType();
+ if (!self[action]){
+ throw Error("No action="+action+" exist for route="+route.getName());
+ }
+ self[action](route);
+
+ }
}
-}
+ isFocused(navigator){
+ // get current route
+ const routes = navigator.getCurrentRoutes();
+ const curRoute = routes[routes.length - 1];
+ return curRoute.focused;
+ }
-class Router extends React.Component {
- constructor(props){
- super(props);
- this.routes = {};
- this.schemas = {};
+ /***
+ * Push new route to current nav stack
+ * @param route defined route
+ */
+ push(route){
+ const name = route.getName();
+ let navigator = this.navs[name];
+ // if route is leaf, push it from latest route navigator, not from root navigator
+ if (route.isLeaf()){
+ navigator = this.navs[this.currentRoute];
+ this.navs[name] = navigator;// save it for future pop()
- var self = this;
- var RouterActions = props.actions || Actions;
- var RouterStore = props.store|| PageStore;
- this.initial = props.initial;
+ }
- React.Children.forEach(props.children, function (child, index){
- var name = child.props.name;
- if (child.type.prototype.className() == "Schema") {
- self.schemas[name] = child.props;
- } else if (child.type.prototype.className() == "Route") {
-// console.log("Added route: " + name);
- if (child.props.initial || !self.initial) {
- self.initial = name;
- }
- if (!(RouterActions[name])) {
- RouterActions[name] = alt.createAction(name, function (data) {
- if (typeof(data)!='object'){
- data={data:data};
- }
- var args = {name: name, data:data};
- var action = child.props.type || 'push';
- return RouterActions[action](args);
- });
- }
- self.routes[name] = child.props;
- if (!child.props.component && !child.props.children){
- console.error("No route component is defined for name: "+name);
- return;
- }
+ if (!this.isFocused(navigator)){
+ return;
+ }
- } else if (child.type.prototype.className() == "Action") {
- //console.log("Added action: " + name);
- if (!(RouterActions[name])) {
- RouterActions[name] = alt.createAction(name, function(data){
- var props = self.extend({}, self.props);
- props = self.extend(props, child.props);
- return RouterActions.custom({name, props, data})});
- }
+ if (this.onPush){
+ // don't do action if it is not allowed (onPush returned false)
+ if (!this.onPush(navigator, route)){
+ return;
}
- });
- this.initialRoute = this.routes[this.initial] || console.error("No initial route "+this.initial);
- this.state = {initial: this.initial};
+ }
+ navigator.push(route);
}
- onChange(page){
- if (page.mode=='push' || page.mode=='replace'){
- if (!page.name){
- console.error("Page name is not defined for action");
+ /***
+ * Replace current route with defined route
+ * @param route defined route
+ */
+ replace(route){
+ const name = route.getName();
+ let navigator = this.navs[name];
+ // if route is leaf, push it from latest route navigator, not from root navigator
+ if (route.isLeaf()){
+ navigator = this.navs[this.currentRoute];
+ this.navs[name] = navigator;// save it for future pop()
+ }
+
+ if (!this.isFocused(navigator)){
+ return;
+ }
+
+ if (this.onReplace){
+ // don't do action if it is not allowed (onPush returned false)
+ if (!this.onReplace(navigator, route)){
return;
}
- var route = this.routes[page.name];
- if (!route){
- console.error("No route is defined for name: "+page.name);
+ }
+ navigator.replace(route);
+ }
+
+ /***
+ * Switch to defined route (so it will jump to existing route if it exists within nav stack or push otherwise), usable for tab bar.
+ * @param route defined route
+ */
+ switch(route){
+ const name = route.getName();
+ const navigator = this.navs[name];
+
+ if (this.onSwitch){
+ // don't do action if it is not allowed (onPush returned false)
+ if (!this.onSwitch(navigator, route)){
return;
}
- // check if route is popup
- if (route.schema=='popup'){
- var element = React.createElement(route.component, Object.assign({}, route, page.data));
- if (route.store){
- element = (
- {element}
- );
- }
- this.setState({modal: element});
- } else {
- if (page.mode == 'replace'){
- this.refs.nav.replace(this.getRoute(route, page.data))
- } else {
- this.refs.nav.push(this.getRoute(route, page.data))
- }
- }
}
- if (page.mode=='pop'){
- var num = page.num || 1;
- var routes = this.refs.nav.getCurrentRoutes();
- // pop only existing routes!
- if (num < routes.length) {
- this.refs.nav.popToRoute(routes[routes.length - 1 - num]);
+ const routes = navigator.getCurrentRoutes();
+ const exist = routes.filter(el=>el.getName()==route.getName());
+ if (exist.length){
+ navigator.jumpTo(exist[0]);
+ } else {
+ navigator.push(route);
+
+ }
+ }
+
+ /***
+ * Pop current scene from navigator, data could be number indicates number of screens to pop
+ * @param data
+ */
+ pop(data){
+ data = filterParam(data);
+ const number = isNumeric(data) ? data : 1;
+ let navigator = this.navs[this.currentRoute];
+ console.log("LATEST NAV:"+this.navs[this.currentRoute].props._parent);
+ let routes = navigator.getCurrentRoutes();
+ console.log("NAV LATEST SCENE:"+routes[routes.length-1].getName()+" "+routes.length);
+ while (routes.length <= number || routes[routes.length-1].getType() === 'switch'){
+ // try parent navigator if we cannot pop current one
+ if (navigator.parentNavigator){
+ console.log("pop to parent navigator");
+ navigator = navigator.parentNavigator;
+ routes = navigator.getCurrentRoutes();
} else {
- if (this.props.onExit){
- this.props.onExit(routes[0], page.data || {});
- }
+ throw new Error("Cannot pop navigator with less than "+number+" screens");
}
}
- if (page.mode=='dismiss') {
- this.setState({modal: null});
+ const route = routes[routes.length-number-1];
+ if (this.onPop){
+ // don't do action if it is not allowed (onPop returned false)
+ if (!this.onPop(navigator, route)){
+ return;
+ }
}
+ const name = route.getName();// name of route
+ navigator.popToRoute(routes[routes.length-number-1]);
+ }
+}
- if (page.mode=='reset'){
- // reset navigation stack
- this.refs.nav.immediatelyResetRouteStack([this.getRoute(this.routes[page.initial], {})])
+const Actions = new ActionContainer();
+class Container extends React.Component {
+ render(){
+ return ;
+ }
+}
+class ExRoute {
+ /**
+ * All properties for this route. name field is required and should be unique for the route
+ * 'title' represents title
+ *
+ * @param name
+ * @param title
+ * @param onRightButton
+ * @param rightButtonTitle
+ * @param header
+ * @param footer
+ * @param component
+ * @param child
+ * @param props
+ * @param schemas
+ */
+ constructor(props, schemas) {
+ if (!props) {
+ throw new Error("No props is defined for this Route");
+ }
+ if (!props.name) {
+ throw new Error("No name is defined for this Route");
+ }
+ if (props.schema && (!schemas || !schemas[props.schema])) {
+ throw new Error("No schema=" + props.schema + " is defined for route=" + props.name);
}
+ const schema = schemas ? schemas[props.schema || 'default'] || {} : {};
+ const {name, type, title, hideNavBar, wrapRouter, sceneConfig, onRight, rightTitle, header, footer, component, children} = {...schema, ...props};
+ if (!component && !children) {
+ throw new Error("Component class or scene instance (child) should be passed");
+ }
+ this.title = title;
+ this.onRight = onRight;
+ this.rightTitle = rightTitle;
+ this.sceneConfig = sceneConfig;
+ this.wrapRouter = wrapRouter;
+ this.props = props;
+ this.type = type;
+ this.focused = false;
+ this.name = name;
+ this.header = header;
+ this.footer = footer;
+ this.hideNavBar = hideNavBar;
+ this.schemas = schemas;
+ this.component = component;
+ this.children = children;
+ this.leaf = this.component && !(this.getType() === 'switch' || this.wrapRouter);
}
- componentDidMount(){
- var RouterStore = this.props.store|| PageStore;
- Actions.init(this.initial);
- this.routerUnlisten = RouterStore.listen(this.onChange.bind(this));
+ onDidFocus(event){
+ this.focused = true;
+ Actions.onDidFocus(this.getName(), this.isLeaf());
}
- componentWillUnmount() {
- this.routerUnlisten();
+ onWillBlur(event){
+ this.focused = false;
+ console.log("LOSE FOCUS!"+this.getName());
}
- renderScene(route, navigator) {
- var Component = route.component;
- var navBar = route.navigationBar;
- var footer = route.footer;
+ isLeaf(){
+ return this.leaf;
+ }
- if (navBar) {
- navBar = React.addons.cloneWithProps(navBar, {
- navigator: navigator,
- route: route
- });
- }
- if (footer){
- footer = React.addons.cloneWithProps(footer, {
- navigator: navigator,
- route: route
- });
- }
- var child = null;
- if (Component){
- child =
- } else {
- child = React.Children.only(this.routes[route.name].children);
- child = React.addons.cloneWithProps(child, {schemas: this.schemas});
- }
+ configureScene() {
+ return this.getType() === 'switch' ? Animations.None : this.sceneConfig || Animations.None;
+ }
- // wrap with AltNativeContainer if 'store' is defined
- if (this.routes[route.name].store ){
- if (!this.routes[route.name]){
- console.error("Cannot found route for name: "+ route.name);
- return;
+ renderScene(navigator) {
+ const Component = this.component;
+ const Header = this.header;
+ const Footer = this.footer;
+ let child;
+ if (Component){
+ // separate processing for 'switch' routes - they should be wrapped into separate Router
+ if (!this.isLeaf()){
+ child = (
+
+ );
+ } else {
+ child =
+ this.leaf = true;
}
- child = (
- {child}
- );
+ } else {
+ child = React.Children.only(this.children);
+ child = React.cloneElement(child, {navigator, schemas: this.schemas, _parent:this.props.name});
}
-
return (
-
- {navBar}
+
+ {Header && }
{child}
- {footer}
-
+ {Footer && }
+
)
}
- extend(destination, source) {
- for (var property in source) {
- if (source.hasOwnProperty(property)) {
- destination[property] = source[property];
- }
- }
- return destination;
+ getName(){
+ return this.name;
}
- getRoute(route, data) {
- if (!route){
- console.error("No route for data:"+JSON.stringify(data));
- }
- var schema = this.schemas[route.schema || 'default'] || {};
- var sceneConfig = route.sceneConfig || schema.sceneConfig || Animations.None;
- var NavBar = route.navBar || schema.navBar;
- var Footer = route.footer || schema.footer;
-
- var navBar;
- if (NavBar){
- navBar =
- }
+ getTitle() {
+ return this.title || "";
+ }
+
+ getType() {
+ return this.type || "push";
+ }
+
+ getBackButtonTitle(navigator, index, state){
+ let previousIndex = index - 1;
+ let previousRoute = state.routeStack[previousIndex];
+ let title = previousRoute.getTitle(navigator, previousIndex, state);
+ return title.length>10 ? null : title;
+ }
- var footer;
- if (Footer){
- footer =
+ renderRightButton() {
+ if (this.onRight && this.rightTitle){
+ return ( this.onRight(this.props)}
+ style={ExNavigator.Styles.barRightButton}>
+ {this.rightTitle}
+ );
+ } else {
+ return null;
}
- var props = this.extend({}, route);
- props = this.extend(props, data);
- return {
- name: route.name,
- component: route.component,
- sceneConfig: {
- ...sceneConfig,
- },
- navigationBar: route.hideNavBar ? null : navBar,
- footer: route.hideFooter ? null : footer,
- passProps: props
+ }
+}
+
+class TabBar extends React.Component {
+ 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](el.props);
+ return {selected: true};
+ }
+ render(){
+ var children = [];
+ var self = this;
+ let selected = false;
+ React.Children.forEach(this.props.children, function(el, index){
+ const schema = self.props.schemas && el.props.schema && self.props.schemas[el.props.schema] ? self.props.schemas[el.props.schema] : {};
+ let props = {...schema, ...el.props};
+
+ if (!el.props.name)
+ console.error("No name is defined for element");
+ var Icon = props.icon || console.error("No icon class is defined for "+el.name);
+ children.push();
+ });
+
+ return (
+
+ {children}
+
+ );
+ }
+}
+
+
+
+// schema class represents schema for routes and it is processed inside Router component
+class Schema extends React.Component {
+ className(){
+ return "Schema";
+ }
+ render(){
+ return null;
+ }
+}
+
+// route class processed inside Router component
+class Route extends React.Component {
+ className(){
+ return "Route";
+ }
+ render(){
+ return null;
+ }
+
+}
+
+class Router extends React.Component {
+ constructor(props) {
+ super(props);
+ this.routes = {};
+ this.schemas = {...props.schemas};
+ this.initial = props.initial;
+
+ const self = this;
+ React.Children.forEach(this.props.children, function (child, index) {
+ const name = child.props.name;
+ if (child.type.prototype.className() === "Schema") {
+ self.schemas[name] = child.props;
+ }
+ });
+ React.Children.forEach(this.props.children, function (child, index) {
+ const name = child.props.name;
+ if (child.type.prototype.className() === "Route") {
+ if (child.props.initial || !self.initial) {
+ self.initial = name;
+ }
+ // declare function with null navigator to avoid undefined Actions
+ Actions.addAction(name, child.props, self.schemas)
+ self.routes[name] = child.props;
+ }
+ });
+ this.state = {initial: this.initial};
+ }
+
+ componentDidMount() {
+ const self = this;
+ React.Children.forEach(this.props.children, function (child, index) {
+ const name = child.props.name;
+ if (child.type.prototype.className() === "Route") {
+ Actions.setNavigator(name, self.refs.nav);
+
+ }
+ });
}
render(){
- if (!(this.props.initial || this.initial)){
+ if (!this.state.initial){
console.error("No initial attribute!");
}
- this.initialRoute = this.routes[this.props.initial || this.initial];
- if (!this.initialRoute) {
- console.error("No initial route!");
+ const initialRoute = this.routes[this.state.initial];
+ if (!initialRoute) {
+ console.error("No initial route!"+JSON.stringify(this.routes));
}
- var modal = null;
- if (this.state.modal){
- modal = (
-
- {this.state.modal}
+ const Footer = this.props.footer;
+ const footer = Footer ? : null;
-
- );
- }
return (
- { return route.sceneConfig;}}
- ref="nav"
- initialRoute={this.getRoute(this.initialRoute)}
- />
- {modal}
+
+ {footer}
);
@@ -281,9 +491,15 @@ var styles = StyleSheet.create({
alignItems: 'center',
},
transparent: {
- flex:1,
- backgroundColor: "transparent"
- }
+ flex:1,
+ backgroundColor: "transparent"
+ },
+ barTitleText: {
+ fontFamily: '.HelveticaNeueInterface-MediumP4',
+ fontSize: 17,
+ marginTop: 11,
+ },
+
});
-module.exports = {Router, Container, Actions, Action, PageStore, Route, Animations, Schema, alt}
+module.exports = {Router, Actions, Route, Schema, TabBar, ExNavigator, Animations}
diff --git a/jestSupport/env.js b/jestSupport/env.js
deleted file mode 100644
index 0bb465e0b..000000000
--- a/jestSupport/env.js
+++ /dev/null
@@ -1,14 +0,0 @@
-/**
- * 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.
- */
-'use strict';
-
-window.__DEV__ = true;
-window.Env = {};
-
-require.requireActual('./setupEnvPolyfills');
diff --git a/jestSupport/scriptPreprocess.js b/jestSupport/scriptPreprocess.js
deleted file mode 100644
index 065b662a0..000000000
--- a/jestSupport/scriptPreprocess.js
+++ /dev/null
@@ -1,16 +0,0 @@
-'use strict';
-
-// Babel is an ES6 transpiler. Read more about it at https://babeljs.io/
-var babel = require('babel-core');
-
-module.exports = {
- process: function (src, filename) {
- // Don't transpile node modules.
- if (filename.match(/node_modules/)) {
- return src;
- }
-
- var result = babel.transform(src, {filename: filename});
- return result.code;
- }
-};
\ No newline at end of file
diff --git a/jestSupport/setupEnvPolyfills.js b/jestSupport/setupEnvPolyfills.js
deleted file mode 100644
index be12e0d7c..000000000
--- a/jestSupport/setupEnvPolyfills.js
+++ /dev/null
@@ -1,67 +0,0 @@
-/**
- * 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.
- *
- * This pipes all of our console logging functions to native logging so that
- * JavaScript errors in required modules show up in Xcode via NSLog.
- */
-
-'use strict';
-
-// WARNING: This is an optimized version that fails on hasOwnProperty checks
-// and non objects. It's not spec-compliant. It's a perf optimization.
-
-Object.assign = function(target, sources) {
- if (__DEV__) {
- if (target == null) {
- throw new TypeError('Object.assign target cannot be null or undefined');
- }
- if (typeof target !== 'object' && typeof target !== 'function') {
- throw new TypeError(
- 'In this environment the target of assign MUST be an object.' +
- 'This error is a performance optimization and not spec compliant.'
- );
- }
- }
-
- for (var nextIndex = 1; nextIndex < arguments.length; nextIndex++) {
- var nextSource = arguments[nextIndex];
- if (nextSource == null) {
- continue;
- }
-
- if (__DEV__) {
- if (typeof nextSource !== 'object' &&
- typeof nextSource !== 'function') {
- throw new TypeError(
- 'In this environment the target of assign MUST be an object.' +
- 'This error is a performance optimization and not spec compliant.'
- );
- }
- }
-
- // We don't currently support accessors nor proxies. Therefore this
- // copy cannot throw. If we ever supported this then we must handle
- // exceptions and side-effects.
-
- for (var key in nextSource) {
- if (__DEV__) {
- var hasOwnProperty = Object.prototype.hasOwnProperty;
- if (!hasOwnProperty.call(nextSource, key)) {
- throw new TypeError(
- 'One of the sources to assign has an enumerable key on the ' +
- 'prototype chain. This is an edge case that we do not support. ' +
- 'This error is a performance optimization and not spec compliant.'
- );
- }
- }
- target[key] = nextSource[key];
- }
- }
-
- return target;
-};
diff --git a/package.json b/package.json
index 0e4352cbf..90f027817 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "react-native-router-flux",
- "version": "0.3.4",
+ "version": "1.0.0",
"description": "React Native Router using Flux architecture",
"main": "index.js",
"scripts": {
@@ -23,9 +23,6 @@
"url": "http://aksonov.com"
},
"license": "ISC",
- "dependencies": {
- "alt": "^0.17.1"
- },
"gitHead": "ac054cfda0894ba1db6c4901ebdddc83b3b2d083",
"_id": "react-native-router-flux@0.3.3",
"_shasum": "074748258f7ff6b6d7e2d509123d15a8ec84cb45",
@@ -36,42 +33,15 @@
"name": "aksonov",
"email": "pavlo.aksonov@gmail.com"
},
- "dist": {
- "shasum": "0e4671550c307ce7ea940eb4ff624e217bcc5225",
- "tarball": "http://registry.npmjs.org/react-native-router-flux/-/react-native-router-flux-0.1.8.tgz"
- },
"maintainers": [
{
"name": "aksonov",
"email": "pavlo.aksonov@gmail.com"
}
],
- "directories": {},
- "_resolved": "https://registry.npmjs.org/react-native-router-flux/-/react-native-router-flux-0.1.8.tgz",
- "readme": "ERROR: No README data found!",
- "devDependencies": {
- "alt": "^0.17.3",
- "babel-core": "^5.8.25",
- "jest-cli": "^0.5.8",
- "react": "^0.13.3",
- "react-tools": "^0.13.3"
- },
- "jest": {
- "unmockedModulePathPatterns": [
- "react",
- "promise",
- "node_modules/alt",
- "alt.js",
- "source-map"
- ],
- "scriptPreprocessor": "jestSupport/scriptPreprocess.js",
- "setupEnvScriptFile": "jestSupport/env.js",
- "testPathIgnorePatterns": [
- "/node_modules/",
- "packager/react-packager/src/Activity/"
- ],
- "testFileExtensions": [
- "js"
- ]
+ "dependencies": {
+ "@exponent/react-native-navigator": "^0.3.5",
+ "react-native-button": "^1.3.1",
+ "react-native-tabs": "^0.1.4"
}
}
diff --git a/store.js b/store.js
deleted file mode 100644
index d4db09e50..000000000
--- a/store.js
+++ /dev/null
@@ -1,90 +0,0 @@
-'use strict';
-var alt = require('./alt');
-var actions = require('./actions');
-
-function isNumeric(n) {
- return !isNaN(parseFloat(n)) && isFinite(n);
-}
-
-function clone(map){
- var el = {};
- for (var i in map)
- if (typeof(map[i])!='object')
- el[i] = map[i];
- return el;
-}
-
-class RouterStore {
- constructor(){
- this.routes = [];
- this.currentRoute = null;
- this.bindAction(actions.init, this.onInit);
- this.bindAction(actions.push, this.onPush);
- this.bindAction(actions.pop, this.onPop);
- this.bindAction(actions.dismiss, this.onDismiss);
- this.bindAction(actions.reset, this.onReset);
- this.bindAction(actions.replace, this.onReplace);
- }
-
- onInit(initial){
-// console.log("Init:"+initial);
- this.routes = [initial];
- this.currentRoute = this.routes[this.routes.length-1];
- return false;
- }
-
- onPush(data){
- data.mode = 'push';
- this.routes.push(data.name);
- this.currentRoute = this.routes[this.routes.length-1];
- this.setState(data);
- }
-
- onReplace(data){
- data.mode = 'replace';
- this.routes.pop();
- this.routes.push(data.name);
- this.currentRoute = this.routes[this.routes.length-1];
- this.setState(data);
- }
-
- onPop(data){
- if (!data){
- data = {};
- }
- if (isNumeric(data)){
- data = {num: data};
- } else {
- data.num = 1;
- }
- data.mode = 'pop';
- // add name of closed page
- data.name = this.currentRoute;
- for (var i=0;i1;i++){
- this.routes.pop();
- }
- this.currentRoute = this.routes[this.routes.length-1];
- this.setState(data);
- }
-
- onDismiss(data){
- if (this.routes.length>1){
- this.routes.pop();
- }
- this.currentRoute = this.routes[this.routes.length-1];
- if (!data){
- data = {};
- }
- data.mode = 'dismiss';
- this.setState(data);
- }
-
- onReset(data){
- this.routes = [data];
- this.setState({mode:'reset', initial:data});
- }
-
-}
-
-
-module.exports = alt.createStore(RouterStore, "RouterStore");
\ No newline at end of file
diff --git a/test.sh b/test.sh
deleted file mode 100644
index 944e5bc3a..000000000
--- a/test.sh
+++ /dev/null
@@ -1,2 +0,0 @@
-#!/usr/bin/env bash
-npm test