From 3c4ebc3ab5c370135e9247c6f4de94952025d30b Mon Sep 17 00:00:00 2001 From: fr1n63 Date: Tue, 1 May 2018 14:40:11 +0100 Subject: [PATCH 01/40] Fix onTransitionStart and onTransitionEnd in StackView These functions weren't firing anymore as they are passed as part of navigationConfig. Not sure if this is the best way to fix, but it solves my issue. --- src/views/StackView/StackView.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/views/StackView/StackView.js b/src/views/StackView/StackView.js index 2d1a61a7f7..5db80320e1 100644 --- a/src/views/StackView/StackView.js +++ b/src/views/StackView/StackView.js @@ -24,9 +24,9 @@ class StackView extends React.Component { configureTransition={this._configureTransition} navigation={this.props.navigation} descriptors={this.props.descriptors} - onTransitionStart={this.props.onTransitionStart} + onTransitionStart={this.props.navigationConfig.onTransitionStart} onTransitionEnd={(transition, lastTransition) => { - const { onTransitionEnd, navigation } = this.props; + const { navigationConfig, navigation } = this.props; if ( transition.navigation.state.isTransitioning && !lastTransition.navigation.state.isTransitioning @@ -37,7 +37,7 @@ class StackView extends React.Component { }) ); } - onTransitionEnd && onTransitionEnd(transition, lastTransition); + navigationConfig.onTransitionEnd && navigationConfig.onTransitionEnd(transition, lastTransition); }} /> ); From 8eb41ca89cd67c596d9a8edfee0da297625c5151 Mon Sep 17 00:00:00 2001 From: fr1n63 Date: Tue, 1 May 2018 14:48:28 +0100 Subject: [PATCH 02/40] Prettier --- src/views/StackView/StackView.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/views/StackView/StackView.js b/src/views/StackView/StackView.js index 5db80320e1..8b3f39ed17 100644 --- a/src/views/StackView/StackView.js +++ b/src/views/StackView/StackView.js @@ -37,7 +37,8 @@ class StackView extends React.Component { }) ); } - navigationConfig.onTransitionEnd && navigationConfig.onTransitionEnd(transition, lastTransition); + navigationConfig.onTransitionEnd && + navigationConfig.onTransitionEnd(transition, lastTransition); }} /> ); From 80ea5f3ae452562475691ebee23a578790900152 Mon Sep 17 00:00:00 2001 From: fr1n63 Date: Tue, 1 May 2018 14:50:57 +0100 Subject: [PATCH 03/40] Prettierr --- src/views/StackView/StackView.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/views/StackView/StackView.js b/src/views/StackView/StackView.js index 8b3f39ed17..0e7ef3b77b 100644 --- a/src/views/StackView/StackView.js +++ b/src/views/StackView/StackView.js @@ -37,8 +37,8 @@ class StackView extends React.Component { }) ); } - navigationConfig.onTransitionEnd && - navigationConfig.onTransitionEnd(transition, lastTransition); + + navigationConfig.onTransitionEnd && navigationConfig.onTransitionEnd(transition, lastTransition); }} /> ); From fd7ca9271708d183b5c8bb697ddac62f2d2d8eb4 Mon Sep 17 00:00:00 2001 From: martin Date: Tue, 1 May 2018 15:00:17 +0100 Subject: [PATCH 04/40] Run prettier properly, remove dead import --- src/views/StackView/StackView.js | 5 +- yarn.lock | 119 ++++++++++++++++++++++++------- 2 files changed, 96 insertions(+), 28 deletions(-) diff --git a/src/views/StackView/StackView.js b/src/views/StackView/StackView.js index 0e7ef3b77b..13f401e979 100644 --- a/src/views/StackView/StackView.js +++ b/src/views/StackView/StackView.js @@ -3,7 +3,6 @@ import { NativeModules } from 'react-native'; import StackViewLayout from './StackViewLayout'; import Transitioner from '../Transitioner'; -import NavigationActions from '../../NavigationActions'; import StackActions from '../../routers/StackActions'; import TransitionConfigs from './StackViewTransitionConfigs'; @@ -37,8 +36,8 @@ class StackView extends React.Component { }) ); } - - navigationConfig.onTransitionEnd && navigationConfig.onTransitionEnd(transition, lastTransition); + navigationConfig.onTransitionEnd && + navigationConfig.onTransitionEnd(transition, lastTransition); }} /> ); diff --git a/yarn.lock b/yarn.lock index 31331a9b2a..20660924a7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -108,7 +108,7 @@ ansi-gray@^0.1.1: dependencies: ansi-wrap "0.1.0" -ansi-regex@^2.0.0, ansi-regex@^2.1.1: +ansi-regex@^2.0.0: version "2.1.1" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" @@ -120,7 +120,7 @@ ansi-styles@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" -ansi-styles@^3.0.0, ansi-styles@^3.2.0, ansi-styles@^3.2.1: +ansi-styles@^3.2.0, ansi-styles@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" dependencies: @@ -1915,7 +1915,7 @@ escodegen@^1.9.0: optionalDependencies: source-map "~0.6.1" -eslint-config-prettier@^2.3.0: +eslint-config-prettier@^2.9.0: version "2.9.0" resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-2.9.0.tgz#5ecd65174d486c22dff389fe036febf502d468a3" dependencies: @@ -1962,7 +1962,7 @@ eslint-plugin-jsx-a11y@^6.0.2: emoji-regex "^6.1.0" jsx-ast-utils "^2.0.0" -eslint-plugin-prettier@^2.1.2: +eslint-plugin-prettier@^2.6.0: version "2.6.0" resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-2.6.0.tgz#33e4e228bdb06142d03c560ce04ec23f6c767dd7" dependencies: @@ -1989,7 +1989,50 @@ eslint-visitor-keys@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#3f3180fb2e291017716acb4c9d6d5b5c34a6a81d" -eslint@^4.2.0, eslint@^4.5.0: +eslint@^4.0.0: + version "4.19.1" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-4.19.1.tgz#32d1d653e1d90408854bfb296f076ec7e186a300" + dependencies: + ajv "^5.3.0" + babel-code-frame "^6.22.0" + chalk "^2.1.0" + concat-stream "^1.6.0" + cross-spawn "^5.1.0" + debug "^3.1.0" + doctrine "^2.1.0" + eslint-scope "^3.7.1" + eslint-visitor-keys "^1.0.0" + espree "^3.5.4" + esquery "^1.0.0" + esutils "^2.0.2" + file-entry-cache "^2.0.0" + functional-red-black-tree "^1.0.1" + glob "^7.1.2" + globals "^11.0.1" + ignore "^3.3.3" + imurmurhash "^0.1.4" + inquirer "^3.0.6" + is-resolvable "^1.0.0" + js-yaml "^3.9.1" + json-stable-stringify-without-jsonify "^1.0.1" + levn "^0.3.0" + lodash "^4.17.4" + minimatch "^3.0.2" + mkdirp "^0.5.1" + natural-compare "^1.4.0" + optionator "^0.8.2" + path-is-inside "^1.0.2" + pluralize "^7.0.0" + progress "^2.0.0" + regexpp "^1.0.1" + require-uncached "^1.0.3" + semver "^5.3.0" + strip-ansi "^4.0.0" + strip-json-comments "~2.0.1" + table "4.0.2" + text-table "~0.2.0" + +eslint@^4.2.0: version "4.18.2" resolved "https://registry.yarnpkg.com/eslint/-/eslint-4.18.2.tgz#0f81267ad1012e7d2051e186a9004cc2267b8d45" dependencies: @@ -2031,7 +2074,7 @@ eslint@^4.2.0, eslint@^4.5.0: table "4.0.2" text-table "~0.2.0" -espree@^3.5.2: +espree@^3.5.2, espree@^3.5.4: version "3.5.4" resolved "https://registry.yarnpkg.com/espree/-/espree-3.5.4.tgz#b0f447187c8a8bed944b815a660bddf5deb5d1a7" dependencies: @@ -3903,6 +3946,10 @@ lodash.throttle@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/lodash.throttle/-/lodash.throttle-4.1.1.tgz#c23e91b710242ac70c37f1e1cda9274cc39bf2f4" +lodash.unescape@4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/lodash.unescape/-/lodash.unescape-4.0.1.tgz#bf2249886ce514cda112fae9218cdc065211fc9c" + lodash@^3.5.0: version "3.10.1" resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6" @@ -4688,30 +4735,26 @@ preserve@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" -prettier-eslint@^6.4.2: - version "6.4.3" - resolved "https://registry.yarnpkg.com/prettier-eslint/-/prettier-eslint-6.4.3.tgz#8335b7a8bd50d01879a9d505bc0b9208caa9ecfc" +prettier-eslint@^8.8.1: + version "8.8.1" + resolved "https://registry.yarnpkg.com/prettier-eslint/-/prettier-eslint-8.8.1.tgz#38505163274742f2a0b31653c39e40f37ebd07da" dependencies: + babel-runtime "^6.26.0" common-tags "^1.4.0" dlv "^1.1.0" - eslint "^4.5.0" + eslint "^4.0.0" indent-string "^3.2.0" lodash.merge "^4.6.0" loglevel-colored-level-prefix "^1.0.0" - prettier "^1.6.0" - pretty-format "^20.0.3" + prettier "^1.7.0" + pretty-format "^22.0.3" require-relative "^0.8.7" + typescript "^2.5.1" + typescript-eslint-parser "^11.0.0" -prettier@^1.5.3, prettier@^1.6.0: - version "1.11.1" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.11.1.tgz#61e43fc4cd44e68f2b0dfc2c38cd4bb0fccdcc75" - -pretty-format@^20.0.3: - version "20.0.3" - resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-20.0.3.tgz#020e350a560a1fe1a98dc3beb6ccffb386de8b14" - dependencies: - ansi-regex "^2.1.1" - ansi-styles "^3.0.0" +prettier@^1.12.1, prettier@^1.7.0: + version "1.12.1" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.12.1.tgz#c1ad20e803e7749faf905a409d2367e06bbe7325" pretty-format@^21.2.1: version "21.2.1" @@ -4720,6 +4763,13 @@ pretty-format@^21.2.1: ansi-regex "^3.0.0" ansi-styles "^3.2.0" +pretty-format@^22.0.3: + version "22.4.3" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-22.4.3.tgz#f873d780839a9c02e9664c8a082e9ee79eaac16f" + dependencies: + ansi-regex "^3.0.0" + ansi-styles "^3.2.0" + pretty-format@^22.4.0: version "22.4.0" resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-22.4.0.tgz#237b1f7e1c50ed03bc65c03ccc29d7c8bb7beb94" @@ -4961,9 +5011,9 @@ react-navigation-deprecated-tab-navigator@1.1.0: dependencies: react-native-tab-view "^0.0.74" -react-navigation-tabs@0.1.0-alpha.7: - version "0.1.0-alpha.7" - resolved "https://registry.yarnpkg.com/react-navigation-tabs/-/react-navigation-tabs-0.1.0-alpha.7.tgz#bcea5b031a3db3b4230be63f17fed721bf78e198" +react-navigation-tabs@0.1.0-alpha.8: + version "0.1.0-alpha.8" + resolved "https://registry.yarnpkg.com/react-navigation-tabs/-/react-navigation-tabs-0.1.0-alpha.8.tgz#bb18699f8496a00f9911c9c75cce243d299c2423" dependencies: hoist-non-react-statics "^2.5.0" prop-types "^15.6.0" @@ -5106,6 +5156,10 @@ regex-not@^1.0.0, regex-not@^1.0.2: extend-shallow "^3.0.2" safe-regex "^1.1.0" +regexpp@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-1.1.0.tgz#0e3516dd0b7904f413d2d4193dce4618c3a689ab" + regexpu-core@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-2.0.0.tgz#49d038837b8dcf8bfa5b9a42139938e6ea2ae240" @@ -5397,6 +5451,10 @@ sax@~1.1.1: version "5.5.0" resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab" +semver@5.4.1: + version "5.4.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.4.1.tgz#e059c09d8571f0540823733433505d3a2f00b18e" + send@0.13.2: version "0.13.2" resolved "https://registry.yarnpkg.com/send/-/send-0.13.2.tgz#765e7607c8055452bba6f0b052595350986036de" @@ -5975,6 +6033,17 @@ typedarray@^0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" +typescript-eslint-parser@^11.0.0: + version "11.0.0" + resolved "https://registry.yarnpkg.com/typescript-eslint-parser/-/typescript-eslint-parser-11.0.0.tgz#37dba6a0130dd307504aa4b4b21b0d3dc7d4e9f2" + dependencies: + lodash.unescape "4.0.1" + semver "5.4.1" + +typescript@^2.5.1: + version "2.8.3" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.8.3.tgz#5d817f9b6f31bb871835f4edf0089f21abe6c170" + ua-parser-js@^0.7.9: version "0.7.17" resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.17.tgz#e9ec5f9498b9ec910e7ae3ac626a805c4d09ecac" From c641bee11bbbfce7244f147e213de7ff51545d78 Mon Sep 17 00:00:00 2001 From: Eric Vicenti Date: Wed, 2 May 2018 09:17:00 -0700 Subject: [PATCH 05/40] Fix initial action dispatch for nonPersisted apps (#4104) --- src/createNavigationContainer.js | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/createNavigationContainer.js b/src/createNavigationContainer.js index a13fc36b35..9d1944bbca 100644 --- a/src/createNavigationContainer.js +++ b/src/createNavigationContainer.js @@ -252,12 +252,7 @@ export default function createNavigationContainer(Component) { } } - if (startupState === this.state.nav) { - return; - } - - this.setState({ nav: startupState }, () => { - _reactNavigationIsHydratingState = false; + const dispatchActions = () => this._actionEventSubscribers.forEach(subscriber => subscriber({ type: 'action', @@ -266,6 +261,15 @@ export default function createNavigationContainer(Component) { lastState: null, }) ); + + if (startupState === this.state.nav) { + dispatchActions(); + return; + } + + this.setState({ nav: startupState }, () => { + _reactNavigationIsHydratingState = false; + dispatchActions(); }); } From 47fe858d4ec339d2b1f4b96f3a5444aed8f6f900 Mon Sep 17 00:00:00 2001 From: simonbuerger Date: Thu, 3 May 2018 05:01:20 +0200 Subject: [PATCH 06/40] StateUtils: Use Array.prototype.findIndex instead of map => indexOf (#4106) * Use Array.prototype.findIndex instead of map => indexOf Creating a new array and iterating over all the routes is inefficient compared to findIndex, which does not create a new array and exits as soon as it finds a match. Since the indexOf method is used extensively this should provide a minor performance improvement * reverted yarn.lock edits --- src/StateUtils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/StateUtils.js b/src/StateUtils.js index c743eac3a5..2fa2ab8e3b 100644 --- a/src/StateUtils.js +++ b/src/StateUtils.js @@ -21,7 +21,7 @@ const StateUtils = { * routes of the navigation state, or -1 if it is not present. */ indexOf(state, key) { - return state.routes.map(route => route.key).indexOf(key); + return state.routes.findIndex(route => route.key === key); }, /** From 2440af66e4bad6b89704f930953591713cea389d Mon Sep 17 00:00:00 2001 From: Vojtech Novak Date: Thu, 3 May 2018 05:02:03 +0200 Subject: [PATCH 07/40] add a test so that #2856 can be closed (#4102) * add test for 2856 * rename variables --- src/views/__tests__/Transitioner-test.js | 49 ++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 src/views/__tests__/Transitioner-test.js diff --git a/src/views/__tests__/Transitioner-test.js b/src/views/__tests__/Transitioner-test.js new file mode 100644 index 0000000000..bd011b1f9a --- /dev/null +++ b/src/views/__tests__/Transitioner-test.js @@ -0,0 +1,49 @@ +/* eslint react/display-name:0 */ +import * as React from 'react'; +import renderer from 'react-test-renderer'; +import Transitioner from '../Transitioner'; + +describe('Transitioner', () => { + it('should not trigger onTransitionStart and onTransitionEnd when route params are changed', () => { + const onTransitionStartCallback = jest.fn(); + const onTransitionEndCallback = jest.fn(); + + const transitionerProps = { + configureTransition: (transitionProps, prevTransitionProps) => ({}), + navigation: { + state: { + index: 0, + routes: [ + { key: '1', routeName: 'Foo' }, + { key: '2', routeName: 'Bar' }, + ], + }, + goBack: () => false, + dispatch: () => false, + setParams: () => false, + navigate: () => false, + }, + render: () =>
, + onTransitionStart: onTransitionStartCallback, + onTransitionEnd: onTransitionEndCallback, + }; + + const nextTransitionerProps = { + ...transitionerProps, + navigation: { + ...transitionerProps.navigation, + state: { + index: 0, + routes: [ + { key: '1', routeName: 'Foo', params: { name: 'Zoom' } }, + { key: '2', routeName: 'Bar' }, + ], + }, + }, + }; + const component = renderer.create(); + component.update(); + expect(onTransitionStartCallback).not.toBeCalled(); + expect(onTransitionEndCallback).not.toBeCalled(); + }); +}); From e0df3cf74aa33a5bc110ee6ece558de69a6d77d1 Mon Sep 17 00:00:00 2001 From: Eric Vicenti Date: Thu, 3 May 2018 10:13:43 -0700 Subject: [PATCH 08/40] Fix issue with nested navigation actions in stack (#4114) --- src/routers/StackRouter.js | 6 ++- src/routers/__tests__/Routers-test.js | 70 +++++++++++++++++++++++++++ 2 files changed, 75 insertions(+), 1 deletion(-) diff --git a/src/routers/StackRouter.js b/src/routers/StackRouter.js index 00ba9b2d11..5f6f7dbdf4 100644 --- a/src/routers/StackRouter.js +++ b/src/routers/StackRouter.js @@ -257,9 +257,13 @@ export default (routeConfigs, stackConfig = {}) => { let childRouter = childRouters[childRoute.routeName]; let debug = action.params && action.params.debug; + let childAction = + action.routeName === childRoute.routeName && action.action + ? action.action + : action; if (childRouter) { const nextRouteState = childRouter.getStateForAction( - action, + childAction, childRoute ); diff --git a/src/routers/__tests__/Routers-test.js b/src/routers/__tests__/Routers-test.js index 38e344577f..33e3a5af50 100644 --- a/src/routers/__tests__/Routers-test.js +++ b/src/routers/__tests__/Routers-test.js @@ -4,6 +4,7 @@ import React from 'react'; import StackRouter from '../StackRouter'; import TabRouter from '../TabRouter'; +import SwitchRouter from '../SwitchRouter'; import NavigationActions from '../../NavigationActions'; import { _TESTING_ONLY_normalize_keys } from '../KeyGenerator'; @@ -89,6 +90,75 @@ Object.keys(ROUTERS).forEach(routerName => { }); }); +test('Nested navigate behavior test', () => { + const Leaf = () =>
; + + const First = () =>
; + First.router = StackRouter({ + First1: Leaf, + First2: Leaf, + }); + + const Second = () =>
; + Second.router = StackRouter({ + Second1: Leaf, + Second2: Leaf, + }); + + const Main = () =>
; + Main.router = StackRouter({ + First, + Second, + }); + const TestRouter = SwitchRouter({ + Login: Leaf, + Main, + }); + + const state1 = TestRouter.getStateForAction({ type: NavigationActions.INIT }); + + const state2 = TestRouter.getStateForAction( + { type: NavigationActions.NAVIGATE, routeName: 'First' }, + state1 + ); + expect(state2.index).toEqual(1); + expect(state2.routes[1].index).toEqual(0); + expect(state2.routes[1].routes[0].index).toEqual(0); + + const state3 = TestRouter.getStateForAction( + { type: NavigationActions.NAVIGATE, routeName: 'Second2' }, + state2 + ); + expect(state3.index).toEqual(1); + expect(state3.routes[1].index).toEqual(1); // second + expect(state3.routes[1].routes[1].index).toEqual(1); //second.second2 + + const state4 = TestRouter.getStateForAction( + { + type: NavigationActions.NAVIGATE, + routeName: 'First', + action: { type: NavigationActions.NAVIGATE, routeName: 'First2' }, + }, + state3, + true + ); + expect(state4.index).toEqual(1); // main + expect(state4.routes[1].index).toEqual(0); // first + expect(state4.routes[1].routes[0].index).toEqual(1); // first2 + + const state5 = TestRouter.getStateForAction( + { + type: NavigationActions.NAVIGATE, + routeName: 'First', + action: { type: NavigationActions.NAVIGATE, routeName: 'First1' }, + }, + state3 // second.second2 is active on state3 + ); + expect(state5.index).toEqual(1); // main + expect(state5.routes[1].index).toEqual(0); // first + expect(state5.routes[1].routes[0].index).toEqual(0); // first.first1 +}); + test('Handles no-op actions with tabs within stack router', () => { const BarView = () =>
; const FooTabNavigator = () =>
; From df281cfed057adae873b79dd83b8763cee5ef34a Mon Sep 17 00:00:00 2001 From: Brent Vatne Date: Thu, 3 May 2018 15:42:23 -0700 Subject: [PATCH 09/40] Add router tests to clarify route resolution --- src/routers/StackRouter.js | 3 +- src/routers/__tests__/StackRouter-test.js | 117 +++++++++++++++++++++ src/routers/__tests__/SwitchRouter-test.js | 90 ++++++++++++++++ 3 files changed, 208 insertions(+), 2 deletions(-) diff --git a/src/routers/StackRouter.js b/src/routers/StackRouter.js index 5f6f7dbdf4..779f1c76b3 100644 --- a/src/routers/StackRouter.js +++ b/src/routers/StackRouter.js @@ -255,12 +255,11 @@ export default (routeConfigs, stackConfig = {}) => { // active route has the first opportunity, then the one before it, etc. for (let childRoute of state.routes.slice().reverse()) { let childRouter = childRouters[childRoute.routeName]; - let debug = action.params && action.params.debug; - let childAction = action.routeName === childRoute.routeName && action.action ? action.action : action; + if (childRouter) { const nextRouteState = childRouter.getStateForAction( childAction, diff --git a/src/routers/__tests__/StackRouter-test.js b/src/routers/__tests__/StackRouter-test.js index 1bb80792ba..b71dea8670 100644 --- a/src/routers/__tests__/StackRouter-test.js +++ b/src/routers/__tests__/StackRouter-test.js @@ -1850,3 +1850,120 @@ test('Handles deep navigate completion action', () => { expect(state3 && state3.routes[0].index).toEqual(1); expect(state3 && state3.routes[0].isTransitioning).toEqual(false); }); + +test('order of handling navigate action is correct for nested stackrouters', () => { + const Screen = () =>
; + const NestedStack = () =>
; + let nestedRouter = StackRouter({ + Foo: Screen, + Bar: Screen, + }); + + NestedStack.router = nestedRouter; + + let router = StackRouter( + { + NestedStack, + Bar: Screen, + Baz: Screen, + }, + { + initialRouteName: 'Baz', + } + ); + + const state = router.getStateForAction({ type: NavigationActions.INIT }); + expect(state.routes[state.index].routeName).toEqual('Baz'); + + const state2 = router.getStateForAction( + { + type: NavigationActions.NAVIGATE, + routeName: 'Bar', + }, + state + ); + expect(state2.routes[state2.index].routeName).toEqual('Bar'); + + const state3 = router.getStateForAction( + { + type: NavigationActions.NAVIGATE, + routeName: 'Baz', + }, + state2 + ); + expect(state3.routes[state3.index].routeName).toEqual('Baz'); + + const state4 = router.getStateForAction( + { + type: NavigationActions.NAVIGATE, + routeName: 'Foo', + }, + state3 + ); + let activeState4 = state4.routes[state4.index]; + expect(activeState4.routeName).toEqual('NestedStack'); + expect(activeState4.routes[activeState4.index].routeName).toEqual('Foo'); + + const state5 = router.getStateForAction( + { + type: NavigationActions.NAVIGATE, + routeName: 'Bar', + }, + state4 + ); + let activeState5 = state5.routes[state5.index]; + expect(activeState5.routeName).toEqual('NestedStack'); + expect(activeState5.routes[activeState5.index].routeName).toEqual('Bar'); +}); + +test('order of handling navigate action is correct for nested stackrouters', () => { + const Screen = () =>
; + const NestedStack = () =>
; + const OtherNestedStack = () =>
; + + let nestedRouter = StackRouter({ Foo: Screen, Bar: Screen }); + let otherNestedRouter = StackRouter({ Foo: Screen }); + NestedStack.router = nestedRouter; + OtherNestedStack.router = otherNestedRouter; + + let router = StackRouter( + { + NestedStack, + OtherNestedStack, + Bar: Screen, + }, + { + initialRouteName: 'OtherNestedStack', + } + ); + + const state = router.getStateForAction({ type: NavigationActions.INIT }); + expect(state.routes[state.index].routeName).toEqual('OtherNestedStack'); + + const state2 = router.getStateForAction( + { + type: NavigationActions.NAVIGATE, + routeName: 'Bar', + }, + state + ); + expect(state2.routes[state2.index].routeName).toEqual('Bar'); + + const state3 = router.getStateForAction( + { + type: NavigationActions.NAVIGATE, + routeName: 'NestedStack', + }, + state2 + ); + const state4 = router.getStateForAction( + { + type: NavigationActions.NAVIGATE, + routeName: 'Bar', + }, + state3 + ); + let activeState4 = state4.routes[state4.index]; + expect(activeState4.routeName).toEqual('NestedStack'); + expect(activeState4.routes[activeState4.index].routeName).toEqual('Bar'); +}); diff --git a/src/routers/__tests__/SwitchRouter-test.js b/src/routers/__tests__/SwitchRouter-test.js index 04929465d1..198a291f62 100644 --- a/src/routers/__tests__/SwitchRouter-test.js +++ b/src/routers/__tests__/SwitchRouter-test.js @@ -127,6 +127,96 @@ describe('SwitchRouter', () => { }, }); }); + + test('order of handling navigate action is correct for nested switchrouters', () => { + // router = switch({ Nested: switch({ Foo, Bar }), Other: switch({ Foo }), Bar }) + // if we are focused on Other and navigate to Bar, what should happen? + + const Screen = () =>
; + const NestedSwitch = () =>
; + const OtherNestedSwitch = () =>
; + + let nestedRouter = SwitchRouter({ Foo: Screen, Bar: Screen }); + let otherNestedRouter = SwitchRouter({ Foo: Screen }); + NestedSwitch.router = nestedRouter; + OtherNestedSwitch.router = otherNestedRouter; + + let router = SwitchRouter( + { + NestedSwitch, + OtherNestedSwitch, + Bar: Screen, + }, + { + initialRouteName: 'OtherNestedSwitch', + } + ); + + const state = router.getStateForAction({ type: NavigationActions.INIT }); + expect(state.routes[state.index].routeName).toEqual('OtherNestedSwitch'); + + const state2 = router.getStateForAction( + { + type: NavigationActions.NAVIGATE, + routeName: 'Bar', + }, + state + ); + expect(state2.routes[state2.index].routeName).toEqual('Bar'); + + const state3 = router.getStateForAction( + { + type: NavigationActions.NAVIGATE, + routeName: 'NestedSwitch', + }, + state2 + ); + const state4 = router.getStateForAction( + { + type: NavigationActions.NAVIGATE, + routeName: 'Bar', + }, + state3 + ); + let activeState4 = state4.routes[state4.index]; + expect(activeState4.routeName).toEqual('NestedSwitch'); + expect(activeState4.routes[activeState4.index].routeName).toEqual('Bar'); + }); + + test('order of handling navigate action is correct for nested stackrouters', () => { + // router = switch({ Nested: switch({ Foo, Bar }), Other: switch({ Foo }), Bar }) + // if we are focused on Other and navigate to Bar, what should happen? + + const Screen = () =>
; + + const MainStack = () =>
; + const LoginStack = () =>
; + MainStack.router = StackRouter({ Home: Screen, Profile: Screen }); + LoginStack.router = StackRouter({ Form: Screen, ForgotPassword: Screen }); + + let router = SwitchRouter( + { + Home: Screen, + Login: LoginStack, + Main: MainStack, + }, + { + initialRouteName: 'Login', + } + ); + + const state = router.getStateForAction({ type: NavigationActions.INIT }); + expect(state.routes[state.index].routeName).toEqual('Login'); + + const state2 = router.getStateForAction( + { + type: NavigationActions.NAVIGATE, + routeName: 'Home', + }, + state + ); + expect(state2.routes[state2.index].routeName).toEqual('Home'); + }); }); const getExampleRouter = (config = {}) => { From ab5481a290a78d75a7bc9f983ced803a0f933ceb Mon Sep 17 00:00:00 2001 From: Brent Vatne Date: Thu, 3 May 2018 15:43:37 -0700 Subject: [PATCH 10/40] Add context around a test in switchrouter --- src/routers/__tests__/SwitchRouter-test.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/routers/__tests__/SwitchRouter-test.js b/src/routers/__tests__/SwitchRouter-test.js index 198a291f62..d22edde5f9 100644 --- a/src/routers/__tests__/SwitchRouter-test.js +++ b/src/routers/__tests__/SwitchRouter-test.js @@ -183,12 +183,9 @@ describe('SwitchRouter', () => { expect(activeState4.routes[activeState4.index].routeName).toEqual('Bar'); }); + // https://github.com/react-navigation/react-navigation.github.io/issues/117#issuecomment-385597628 test('order of handling navigate action is correct for nested stackrouters', () => { - // router = switch({ Nested: switch({ Foo, Bar }), Other: switch({ Foo }), Bar }) - // if we are focused on Other and navigate to Bar, what should happen? - const Screen = () =>
; - const MainStack = () =>
; const LoginStack = () =>
; MainStack.router = StackRouter({ Home: Screen, Profile: Screen }); From 723c5f2149b362a4e0218a5b263bef503f43496e Mon Sep 17 00:00:00 2001 From: Eric Vicenti Date: Fri, 4 May 2018 09:48:45 -0700 Subject: [PATCH 11/40] Fix drawer navigation dispatch (#4121) --- src/views/Drawer/DrawerSidebar.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/views/Drawer/DrawerSidebar.js b/src/views/Drawer/DrawerSidebar.js index eaf4ecf413..310bd3b980 100644 --- a/src/views/Drawer/DrawerSidebar.js +++ b/src/views/Drawer/DrawerSidebar.js @@ -57,7 +57,12 @@ class DrawerSidebar extends React.PureComponent { ], }); } - this.props.navigation.navigate(route.routeName, undefined, subAction); + this.props.navigation.dispatch( + NavigationActions.navigate({ + routeName: route.routeName, + action: subAction, + }) + ); } }; From eda9bfd567624596ec72b7415d2e8dc046bf0389 Mon Sep 17 00:00:00 2001 From: Brent Vatne Date: Fri, 4 May 2018 10:10:14 -0700 Subject: [PATCH 12/40] Update react-lifecycles-compat --- package.json | 2 +- src/createNavigationContainer.js | 4 +- src/views/ResourceSavingSceneView.js | 4 +- yarn.lock | 121 +++++++++++++++++++++------ 4 files changed, 100 insertions(+), 31 deletions(-) diff --git a/package.json b/package.json index fd35f536af..a3ee428ef1 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "hoist-non-react-statics": "^2.2.0", "path-to-regexp": "^1.7.0", "prop-types": "^15.5.10", - "react-lifecycles-compat": "^1.0.2", + "react-lifecycles-compat": "^3", "react-native-drawer-layout-polyfill": "^1.3.2", "react-native-safe-area-view": "^0.7.0", "react-navigation-deprecated-tab-navigator": "1.1.0", diff --git a/src/createNavigationContainer.js b/src/createNavigationContainer.js index 9d1944bbca..bfd08bbf1c 100644 --- a/src/createNavigationContainer.js +++ b/src/createNavigationContainer.js @@ -1,6 +1,6 @@ import React from 'react'; import { Linking, AsyncStorage } from 'react-native'; -import withLifecyclePolyfill from 'react-lifecycles-compat'; +import { polyfill } from 'react-lifecycles-compat'; import { BackHandler } from './PlatformHelpers'; import NavigationActions from './NavigationActions'; @@ -367,5 +367,5 @@ export default function createNavigationContainer(Component) { } } - return withLifecyclePolyfill(NavigationContainer); + return polyfill(NavigationContainer); } diff --git a/src/views/ResourceSavingSceneView.js b/src/views/ResourceSavingSceneView.js index 63b4f4ac03..fc7fa47530 100644 --- a/src/views/ResourceSavingSceneView.js +++ b/src/views/ResourceSavingSceneView.js @@ -1,7 +1,7 @@ import React from 'react'; import { Platform, StyleSheet, View } from 'react-native'; import PropTypes from 'prop-types'; -import withLifecyclePolyfill from 'react-lifecycles-compat'; +import { polyfill } from 'react-lifecycles-compat'; import SceneView from './SceneView'; @@ -77,4 +77,4 @@ const styles = StyleSheet.create({ }, }); -export default withLifecyclePolyfill(ResourceSavingSceneView); +export default polyfill(ResourceSavingSceneView); diff --git a/yarn.lock b/yarn.lock index 31331a9b2a..f793b7144d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -108,7 +108,7 @@ ansi-gray@^0.1.1: dependencies: ansi-wrap "0.1.0" -ansi-regex@^2.0.0, ansi-regex@^2.1.1: +ansi-regex@^2.0.0: version "2.1.1" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" @@ -120,7 +120,7 @@ ansi-styles@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" -ansi-styles@^3.0.0, ansi-styles@^3.2.0, ansi-styles@^3.2.1: +ansi-styles@^3.2.0, ansi-styles@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" dependencies: @@ -1915,7 +1915,7 @@ escodegen@^1.9.0: optionalDependencies: source-map "~0.6.1" -eslint-config-prettier@^2.3.0: +eslint-config-prettier@^2.9.0: version "2.9.0" resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-2.9.0.tgz#5ecd65174d486c22dff389fe036febf502d468a3" dependencies: @@ -1962,7 +1962,7 @@ eslint-plugin-jsx-a11y@^6.0.2: emoji-regex "^6.1.0" jsx-ast-utils "^2.0.0" -eslint-plugin-prettier@^2.1.2: +eslint-plugin-prettier@^2.6.0: version "2.6.0" resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-2.6.0.tgz#33e4e228bdb06142d03c560ce04ec23f6c767dd7" dependencies: @@ -1989,7 +1989,50 @@ eslint-visitor-keys@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#3f3180fb2e291017716acb4c9d6d5b5c34a6a81d" -eslint@^4.2.0, eslint@^4.5.0: +eslint@^4.0.0: + version "4.19.1" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-4.19.1.tgz#32d1d653e1d90408854bfb296f076ec7e186a300" + dependencies: + ajv "^5.3.0" + babel-code-frame "^6.22.0" + chalk "^2.1.0" + concat-stream "^1.6.0" + cross-spawn "^5.1.0" + debug "^3.1.0" + doctrine "^2.1.0" + eslint-scope "^3.7.1" + eslint-visitor-keys "^1.0.0" + espree "^3.5.4" + esquery "^1.0.0" + esutils "^2.0.2" + file-entry-cache "^2.0.0" + functional-red-black-tree "^1.0.1" + glob "^7.1.2" + globals "^11.0.1" + ignore "^3.3.3" + imurmurhash "^0.1.4" + inquirer "^3.0.6" + is-resolvable "^1.0.0" + js-yaml "^3.9.1" + json-stable-stringify-without-jsonify "^1.0.1" + levn "^0.3.0" + lodash "^4.17.4" + minimatch "^3.0.2" + mkdirp "^0.5.1" + natural-compare "^1.4.0" + optionator "^0.8.2" + path-is-inside "^1.0.2" + pluralize "^7.0.0" + progress "^2.0.0" + regexpp "^1.0.1" + require-uncached "^1.0.3" + semver "^5.3.0" + strip-ansi "^4.0.0" + strip-json-comments "~2.0.1" + table "4.0.2" + text-table "~0.2.0" + +eslint@^4.2.0: version "4.18.2" resolved "https://registry.yarnpkg.com/eslint/-/eslint-4.18.2.tgz#0f81267ad1012e7d2051e186a9004cc2267b8d45" dependencies: @@ -2031,7 +2074,7 @@ eslint@^4.2.0, eslint@^4.5.0: table "4.0.2" text-table "~0.2.0" -espree@^3.5.2: +espree@^3.5.2, espree@^3.5.4: version "3.5.4" resolved "https://registry.yarnpkg.com/espree/-/espree-3.5.4.tgz#b0f447187c8a8bed944b815a660bddf5deb5d1a7" dependencies: @@ -3903,6 +3946,10 @@ lodash.throttle@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/lodash.throttle/-/lodash.throttle-4.1.1.tgz#c23e91b710242ac70c37f1e1cda9274cc39bf2f4" +lodash.unescape@4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/lodash.unescape/-/lodash.unescape-4.0.1.tgz#bf2249886ce514cda112fae9218cdc065211fc9c" + lodash@^3.5.0: version "3.10.1" resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6" @@ -4688,30 +4735,26 @@ preserve@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" -prettier-eslint@^6.4.2: - version "6.4.3" - resolved "https://registry.yarnpkg.com/prettier-eslint/-/prettier-eslint-6.4.3.tgz#8335b7a8bd50d01879a9d505bc0b9208caa9ecfc" +prettier-eslint@^8.8.1: + version "8.8.1" + resolved "https://registry.yarnpkg.com/prettier-eslint/-/prettier-eslint-8.8.1.tgz#38505163274742f2a0b31653c39e40f37ebd07da" dependencies: + babel-runtime "^6.26.0" common-tags "^1.4.0" dlv "^1.1.0" - eslint "^4.5.0" + eslint "^4.0.0" indent-string "^3.2.0" lodash.merge "^4.6.0" loglevel-colored-level-prefix "^1.0.0" - prettier "^1.6.0" - pretty-format "^20.0.3" + prettier "^1.7.0" + pretty-format "^22.0.3" require-relative "^0.8.7" + typescript "^2.5.1" + typescript-eslint-parser "^11.0.0" -prettier@^1.5.3, prettier@^1.6.0: - version "1.11.1" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.11.1.tgz#61e43fc4cd44e68f2b0dfc2c38cd4bb0fccdcc75" - -pretty-format@^20.0.3: - version "20.0.3" - resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-20.0.3.tgz#020e350a560a1fe1a98dc3beb6ccffb386de8b14" - dependencies: - ansi-regex "^2.1.1" - ansi-styles "^3.0.0" +prettier@^1.12.1, prettier@^1.7.0: + version "1.12.1" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.12.1.tgz#c1ad20e803e7749faf905a409d2367e06bbe7325" pretty-format@^21.2.1: version "21.2.1" @@ -4720,6 +4763,13 @@ pretty-format@^21.2.1: ansi-regex "^3.0.0" ansi-styles "^3.2.0" +pretty-format@^22.0.3: + version "22.4.3" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-22.4.3.tgz#f873d780839a9c02e9664c8a082e9ee79eaac16f" + dependencies: + ansi-regex "^3.0.0" + ansi-styles "^3.2.0" + pretty-format@^22.4.0: version "22.4.0" resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-22.4.0.tgz#237b1f7e1c50ed03bc65c03ccc29d7c8bb7beb94" @@ -4840,7 +4890,7 @@ react-lifecycles-compat@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-1.0.2.tgz#551d8b1d156346e5fcf30ffac9b32ce3f78b8850" -react-lifecycles-compat@^3.0.2: +react-lifecycles-compat@^3, react-lifecycles-compat@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.2.tgz#7279047275bd727a912e25f734c0559527e84eff" @@ -4961,9 +5011,9 @@ react-navigation-deprecated-tab-navigator@1.1.0: dependencies: react-native-tab-view "^0.0.74" -react-navigation-tabs@0.1.0-alpha.7: - version "0.1.0-alpha.7" - resolved "https://registry.yarnpkg.com/react-navigation-tabs/-/react-navigation-tabs-0.1.0-alpha.7.tgz#bcea5b031a3db3b4230be63f17fed721bf78e198" +react-navigation-tabs@0.1.0-alpha.8: + version "0.1.0-alpha.8" + resolved "https://registry.yarnpkg.com/react-navigation-tabs/-/react-navigation-tabs-0.1.0-alpha.8.tgz#bb18699f8496a00f9911c9c75cce243d299c2423" dependencies: hoist-non-react-statics "^2.5.0" prop-types "^15.6.0" @@ -5106,6 +5156,10 @@ regex-not@^1.0.0, regex-not@^1.0.2: extend-shallow "^3.0.2" safe-regex "^1.1.0" +regexpp@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-1.1.0.tgz#0e3516dd0b7904f413d2d4193dce4618c3a689ab" + regexpu-core@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-2.0.0.tgz#49d038837b8dcf8bfa5b9a42139938e6ea2ae240" @@ -5397,6 +5451,10 @@ sax@~1.1.1: version "5.5.0" resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab" +semver@5.4.1: + version "5.4.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.4.1.tgz#e059c09d8571f0540823733433505d3a2f00b18e" + send@0.13.2: version "0.13.2" resolved "https://registry.yarnpkg.com/send/-/send-0.13.2.tgz#765e7607c8055452bba6f0b052595350986036de" @@ -5975,6 +6033,17 @@ typedarray@^0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" +typescript-eslint-parser@^11.0.0: + version "11.0.0" + resolved "https://registry.yarnpkg.com/typescript-eslint-parser/-/typescript-eslint-parser-11.0.0.tgz#37dba6a0130dd307504aa4b4b21b0d3dc7d4e9f2" + dependencies: + lodash.unescape "4.0.1" + semver "5.4.1" + +typescript@^2.5.1: + version "2.8.3" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.8.3.tgz#5d817f9b6f31bb871835f4edf0089f21abe6c170" + ua-parser-js@^0.7.9: version "0.7.17" resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.17.tgz#e9ec5f9498b9ec910e7ae3ac626a805c4d09ecac" From 8ed3817c9030f4b790f0e24e0197d8dde9b724d1 Mon Sep 17 00:00:00 2001 From: Eric Vicenti Date: Fri, 4 May 2018 10:14:22 -0700 Subject: [PATCH 13/40] Fix event unsubscription logic (#4116) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Events were getting unsubscribed too early, so that the inner willBlur event was getting skipped when trying to “dismiss” a deep navigation stack. --- src/getChildEventSubscriber.js | 5 ++++- src/navigators/createNavigator.js | 5 ++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/getChildEventSubscriber.js b/src/getChildEventSubscriber.js index 0900bfe9f9..8839248a01 100644 --- a/src/getChildEventSubscriber.js +++ b/src/getChildEventSubscriber.js @@ -138,11 +138,14 @@ export default function getChildEventSubscriber(addListener, key) { emit((lastEmittedEvent = 'didBlur'), childPayload); } } + + if (lastEmittedEvent === 'didBlur' && !newRoute) { + removeAll(); + } }) ); return { - removeAll, addListener(eventName, eventHandler) { const subscribers = getChildSubscribers(eventName); if (!subscribers) { diff --git a/src/navigators/createNavigator.js b/src/navigators/createNavigator.js index 6401aeb6cf..35a1d4f5af 100644 --- a/src/navigators/createNavigator.js +++ b/src/navigators/createNavigator.js @@ -14,15 +14,14 @@ function createNavigator(NavigatorView, router, navigationConfig) { const activeKeys = this.props.navigation.state.routes.map(r => r.key); Object.keys(this.childEventSubscribers).forEach(key => { if (!activeKeys.includes(key)) { - this.childEventSubscribers[key].removeAll(); delete this.childEventSubscribers[key]; } }); } - // Remove all subscriptions + // Remove all subscription references componentWillUnmount() { - Object.values(this.childEventSubscribers).map(s => s.removeAll()); + this.childEventSubscribers = {}; } _isRouteFocused = route => { From 8e52995ef33ce603b891b9b3ee0dc3f79c9e373e Mon Sep 17 00:00:00 2001 From: Brent Vatne Date: Fri, 4 May 2018 10:14:34 -0700 Subject: [PATCH 14/40] Release 2.0.0-rc.8 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index a3ee428ef1..95d789c98c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-navigation", - "version": "2.0.0-rc.7", + "version": "2.0.0-rc.8", "description": "Routing and navigation for your React Native apps", "main": "src/react-navigation.js", "repository": { From 2643f690a98ecf9394ffa2f3671795feabc989f3 Mon Sep 17 00:00:00 2001 From: Brent Vatne Date: Fri, 4 May 2018 11:06:51 -0700 Subject: [PATCH 15/40] Pull createMaterialBottomTabNavigator into separate repo --- examples/NavigationPlayground/js/App.js | 2 +- .../js/TabsWithNavigationFocus.js | 36 +++++++----- examples/NavigationPlayground/package.json | 3 +- examples/NavigationPlayground/yarn.lock | 52 ++++++++++++----- flow/react-navigation.js | 4 -- package.json | 2 +- src/react-navigation.js | 3 - yarn.lock | 58 ++----------------- 8 files changed, 68 insertions(+), 92 deletions(-) diff --git a/examples/NavigationPlayground/js/App.js b/examples/NavigationPlayground/js/App.js index 9db6a2cbb3..6435338e82 100644 --- a/examples/NavigationPlayground/js/App.js +++ b/examples/NavigationPlayground/js/App.js @@ -322,7 +322,7 @@ const AppNavigator = createStackNavigator( } ); -export default () => ; +export default AppNavigator; const styles = StyleSheet.create({ item: { diff --git a/examples/NavigationPlayground/js/TabsWithNavigationFocus.js b/examples/NavigationPlayground/js/TabsWithNavigationFocus.js index 79effb2c97..e40b3125bd 100644 --- a/examples/NavigationPlayground/js/TabsWithNavigationFocus.js +++ b/examples/NavigationPlayground/js/TabsWithNavigationFocus.js @@ -4,10 +4,8 @@ import React from 'react'; import { SafeAreaView, StatusBar, Text, View } from 'react-native'; -import { - createBottomTabNavigator, - withNavigationFocus, -} from 'react-navigation'; +import { withNavigationFocus } from 'react-navigation'; +import { createMaterialBottomTabNavigator } from 'react-navigation-material-bottom-tabs'; import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons'; import { Button } from './commonComponents/ButtonWithMargin'; @@ -80,16 +78,26 @@ const createTabScreen = (name, icon, focusedIcon, tintColor = '#673ab7') => { return withNavigationFocus(TabScreen); }; -const TabsWithNavigationFocus = createBottomTabNavigator({ - One: { - screen: createTabScreen('One', 'numeric-1-box-outline', 'numeric-1-box'), - }, - Two: { - screen: createTabScreen('Two', 'numeric-2-box-outline', 'numeric-2-box'), - }, - Three: { - screen: createTabScreen('Three', 'numeric-3-box-outline', 'numeric-3-box'), +const TabsWithNavigationFocus = createMaterialBottomTabNavigator( + { + One: { + screen: createTabScreen('One', 'numeric-1-box-outline', 'numeric-1-box'), + }, + Two: { + screen: createTabScreen('Two', 'numeric-2-box-outline', 'numeric-2-box'), + }, + Three: { + screen: createTabScreen( + 'Three', + 'numeric-3-box-outline', + 'numeric-3-box' + ), + }, }, -}); + { + shifting: false, + activeTintColor: '#F44336', + } +); export default TabsWithNavigationFocus; diff --git a/examples/NavigationPlayground/package.json b/examples/NavigationPlayground/package.json index e60490a6a7..7a8da1126c 100644 --- a/examples/NavigationPlayground/package.json +++ b/examples/NavigationPlayground/package.json @@ -16,7 +16,8 @@ "react-native": "^0.54.0", "react-native-iphone-x-helper": "^1.0.2", "react-navigation": "link:../..", - "react-navigation-header-buttons": "^0.0.4" + "react-navigation-header-buttons": "^0.0.4", + "react-navigation-material-bottom-tabs": "0.1.3" }, "devDependencies": { "babel-jest": "^22.4.1", diff --git a/examples/NavigationPlayground/yarn.lock b/examples/NavigationPlayground/yarn.lock index 08ee41e75f..209b983430 100644 --- a/examples/NavigationPlayground/yarn.lock +++ b/examples/NavigationPlayground/yarn.lock @@ -2110,6 +2110,13 @@ create-react-context@^0.2.1: fbjs "^0.8.0" gud "^1.0.0" +create-react-context@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/create-react-context/-/create-react-context-0.2.2.tgz#9836542f9aaa22868cd7d4a6f82667df38019dca" + dependencies: + fbjs "^0.8.0" + gud "^1.0.0" + cross-spawn@^5.0.1, cross-spawn@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" @@ -2220,7 +2227,7 @@ deepmerge@^1.3.0, deepmerge@^1.5.1: version "1.5.2" resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-1.5.2.tgz#10499d868844cdad4fee0842df8c7f6f0c95a753" -deepmerge@^2.0.1: +deepmerge@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-2.1.0.tgz#511a54fff405fc346f0240bb270a3e9533a31102" @@ -5550,6 +5557,10 @@ react-lifecycles-compat@^1.0.2: version "1.1.4" resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-1.1.4.tgz#fc005c72849b7ed364de20a0f64ff58ebdc2009a" +react-lifecycles-compat@^3, react-lifecycles-compat@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.2.tgz#7279047275bd727a912e25f734c0559527e84eff" + react-native-branch@2.0.0-beta.3: version "2.0.0-beta.3" resolved "https://registry.yarnpkg.com/react-native-branch/-/react-native-branch-2.0.0-beta.3.tgz#2167af86bbc9f964bd45bd5f37684e5b54965e32" @@ -5589,14 +5600,15 @@ react-native-iphone-x-helper@^1.0.2: babel-plugin-module-resolver "^2.3.0" babel-preset-react-native "1.9.0" -react-native-paper@^1.2.5: - version "1.2.5" - resolved "https://registry.yarnpkg.com/react-native-paper/-/react-native-paper-1.2.5.tgz#3a4480ca967aae4b3e65a987116973dd012d1fa8" +react-native-paper@=1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/react-native-paper/-/react-native-paper-1.4.0.tgz#33bd477cde1468b63e60bdb0c9a500822d03cdca" dependencies: color "^2.0.1" - create-react-context "^0.2.1" - deepmerge "^2.0.1" + create-react-context "^0.2.2" + deepmerge "^2.1.0" hoist-non-react-statics "^2.5.0" + react-lifecycles-compat "^3.0.2" react-native-platform-touchable@^1.1.1: version "1.1.1" @@ -5642,9 +5654,9 @@ react-native-svg@6.2.2: lodash "^4.16.6" pegjs "^0.10.0" -"react-native-tab-view@github:react-navigation/react-native-tab-view": +react-native-tab-view@^0.0.74: version "0.0.74" - resolved "https://codeload.github.com/react-navigation/react-native-tab-view/tar.gz/36ebd834d78b841fc19778c966465d02fd1213bb" + resolved "https://registry.yarnpkg.com/react-native-tab-view/-/react-native-tab-view-0.0.74.tgz#62c0c882d9232b461ce181d440d683b4f99d1bd8" dependencies: prop-types "^15.6.0" @@ -5725,11 +5737,11 @@ react-native@^0.54.0: xmldoc "^0.4.0" yargs "^9.0.0" -react-navigation-deprecated-tab-navigator@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/react-navigation-deprecated-tab-navigator/-/react-navigation-deprecated-tab-navigator-1.0.1.tgz#a869d749d16116630411d6c7761c51484ba90175" +react-navigation-deprecated-tab-navigator@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/react-navigation-deprecated-tab-navigator/-/react-navigation-deprecated-tab-navigator-1.1.0.tgz#58945c1c4c7c21b54954e814e8721e98423df75d" dependencies: - react-native-tab-view react-navigation/react-native-tab-view + react-native-tab-view "^0.0.74" react-navigation-header-buttons@^0.0.4: version "0.0.4" @@ -5737,14 +5749,22 @@ react-navigation-header-buttons@^0.0.4: dependencies: react-native-platform-touchable "^1.1.1" -react-navigation-tabs@0.1.0-alpha.5: - version "0.1.0-alpha.5" - resolved "https://registry.yarnpkg.com/react-navigation-tabs/-/react-navigation-tabs-0.1.0-alpha.5.tgz#51cae3ea5f0f77bdf0deb50a855a5dcaa2f9bf1e" +react-navigation-material-bottom-tabs@0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/react-navigation-material-bottom-tabs/-/react-navigation-material-bottom-tabs-0.1.3.tgz#8e11c3d57ebb72d19adf5e4764390729ed964072" + dependencies: + hoist-non-react-statics "^2.5.0" + prop-types "^15.6.0" + react-native-paper "=1.4.0" + react-navigation-tabs "0.2.0-rc.0" + +react-navigation-tabs@0.2.0-rc.0: + version "0.2.0-rc.0" + resolved "https://registry.yarnpkg.com/react-navigation-tabs/-/react-navigation-tabs-0.2.0-rc.0.tgz#671e8c9914b915796879329752f7240147494038" dependencies: hoist-non-react-statics "^2.5.0" prop-types "^15.6.0" react-lifecycles-compat "^1.0.2" - react-native-paper "^1.2.5" react-native-safe-area-view "^0.7.0" react-native-tab-view "~0.0.77" diff --git a/flow/react-navigation.js b/flow/react-navigation.js index 57df21db1c..30ea9dd477 100644 --- a/flow/react-navigation.js +++ b/flow/react-navigation.js @@ -809,10 +809,6 @@ declare module 'react-navigation' { routeConfigs: NavigationRouteConfigMap, config?: _TabNavigatorConfig ): NavigationContainer<*, *, *>; - declare export function createMaterialBottomTabNavigator( - routeConfigs: NavigationRouteConfigMap, - config?: _TabNavigatorConfig - ): NavigationContainer<*, *, *>; declare export function createMaterialTopTabNavigator( routeConfigs: NavigationRouteConfigMap, config?: _TabNavigatorConfig diff --git a/package.json b/package.json index 95d789c98c..127a55bad0 100644 --- a/package.json +++ b/package.json @@ -38,7 +38,7 @@ "react-native-drawer-layout-polyfill": "^1.3.2", "react-native-safe-area-view": "^0.7.0", "react-navigation-deprecated-tab-navigator": "1.1.0", - "react-navigation-tabs": "0.1.0-alpha.8" + "react-navigation-tabs": "0.2.0-rc.0" }, "devDependencies": { "babel-cli": "^6.24.1", diff --git a/src/react-navigation.js b/src/react-navigation.js index e0d59c2eee..d93c0dcc79 100644 --- a/src/react-navigation.js +++ b/src/react-navigation.js @@ -57,9 +57,6 @@ module.exports = { get createBottomTabNavigator() { return require('react-navigation-tabs').createBottomTabNavigator; }, - get createMaterialBottomTabNavigator() { - return require('react-navigation-tabs').createMaterialBottomTabNavigator; - }, get createMaterialTopTabNavigator() { return require('react-navigation-tabs').createMaterialTopTabNavigator; }, diff --git a/yarn.lock b/yarn.lock index f793b7144d..25b0a25324 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1372,34 +1372,20 @@ collection-visit@^1.0.0: map-visit "^1.0.0" object-visit "^1.0.0" -color-convert@^1.9.0, color-convert@^1.9.1: +color-convert@^1.9.0: version "1.9.1" resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.1.tgz#c1261107aeb2f294ebffec9ed9ecad529a6097ed" dependencies: color-name "^1.1.1" -color-name@^1.0.0, color-name@^1.1.1: +color-name@^1.1.1: version "1.1.3" resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" -color-string@^1.5.2: - version "1.5.2" - resolved "https://registry.yarnpkg.com/color-string/-/color-string-1.5.2.tgz#26e45814bc3c9a7cbd6751648a41434514a773a9" - dependencies: - color-name "^1.0.0" - simple-swizzle "^0.2.2" - color-support@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/color-support/-/color-support-1.1.3.tgz#93834379a1cc9a0c61f82f52f0d04322251bd5a2" -color@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/color/-/color-2.0.1.tgz#e4ed78a3c4603d0891eba5430b04b86314f4c839" - dependencies: - color-convert "^1.9.1" - color-string "^1.5.2" - combined-stream@1.0.6, combined-stream@^1.0.5, combined-stream@~1.0.5: version "1.0.6" resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.6.tgz#723e7df6e801ac5613113a7e445a9b69cb632818" @@ -1594,13 +1580,6 @@ create-react-context@^0.2.1: fbjs "^0.8.0" gud "^1.0.0" -create-react-context@^0.2.2: - version "0.2.2" - resolved "https://registry.yarnpkg.com/create-react-context/-/create-react-context-0.2.2.tgz#9836542f9aaa22868cd7d4a6f82667df38019dca" - dependencies: - fbjs "^0.8.0" - gud "^1.0.0" - cross-spawn@^5.0.1, cross-spawn@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" @@ -1700,10 +1679,6 @@ deep-is@~0.1.3: version "0.1.3" resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" -deepmerge@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-2.1.0.tgz#511a54fff405fc346f0240bb270a3e9533a31102" - default-require-extensions@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/default-require-extensions/-/default-require-extensions-1.0.0.tgz#f37ea15d3e13ffd9b437d33e1a75b5fb97874cb8" @@ -2933,10 +2908,6 @@ is-arrayish@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" -is-arrayish@^0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.3.1.tgz#c2dfc386abaa0c3e33c48db3fe87059e69065efd" - is-binary-path@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898" @@ -4890,7 +4861,7 @@ react-lifecycles-compat@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-1.0.2.tgz#551d8b1d156346e5fcf30ffac9b32ce3f78b8850" -react-lifecycles-compat@^3, react-lifecycles-compat@^3.0.2: +react-lifecycles-compat@^3: version "3.0.2" resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.2.tgz#7279047275bd727a912e25f734c0559527e84eff" @@ -4910,16 +4881,6 @@ react-native-drawer-layout@1.3.2: dependencies: react-native-dismiss-keyboard "1.0.0" -react-native-paper@^1.4.0: - version "1.4.1" - resolved "https://registry.yarnpkg.com/react-native-paper/-/react-native-paper-1.4.1.tgz#81df909c14d9ae78274662df97c3b35224aa39a9" - dependencies: - color "^2.0.1" - create-react-context "^0.2.2" - deepmerge "^2.1.0" - hoist-non-react-statics "^2.5.0" - react-lifecycles-compat "^3.0.2" - react-native-safe-area-view@^0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/react-native-safe-area-view/-/react-native-safe-area-view-0.7.0.tgz#38f5ab9368d6ef9e5d18ab64212938af3ec39421" @@ -5011,14 +4972,13 @@ react-navigation-deprecated-tab-navigator@1.1.0: dependencies: react-native-tab-view "^0.0.74" -react-navigation-tabs@0.1.0-alpha.8: - version "0.1.0-alpha.8" - resolved "https://registry.yarnpkg.com/react-navigation-tabs/-/react-navigation-tabs-0.1.0-alpha.8.tgz#bb18699f8496a00f9911c9c75cce243d299c2423" +react-navigation-tabs@0.2.0-rc.0: + version "0.2.0-rc.0" + resolved "https://registry.yarnpkg.com/react-navigation-tabs/-/react-navigation-tabs-0.2.0-rc.0.tgz#671e8c9914b915796879329752f7240147494038" dependencies: hoist-non-react-statics "^2.5.0" prop-types "^15.6.0" react-lifecycles-compat "^1.0.2" - react-native-paper "^1.4.0" react-native-safe-area-view "^0.7.0" react-native-tab-view "~0.0.77" @@ -5570,12 +5530,6 @@ simple-plist@^0.2.1: bplist-parser "0.1.1" plist "2.0.1" -simple-swizzle@^0.2.2: - version "0.2.2" - resolved "https://registry.yarnpkg.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a" - dependencies: - is-arrayish "^0.3.1" - slash@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" From ad7cde9eb9e689395e8d11fdba4d70b6e5d085a6 Mon Sep 17 00:00:00 2001 From: Brent Vatne Date: Fri, 4 May 2018 11:16:34 -0700 Subject: [PATCH 16/40] Release 2.0.0-rc.9 --- package.json | 4 ++-- yarn.lock | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 127a55bad0..99bd0a7f90 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-navigation", - "version": "2.0.0-rc.8", + "version": "2.0.0-rc.9", "description": "Routing and navigation for your React Native apps", "main": "src/react-navigation.js", "repository": { @@ -38,7 +38,7 @@ "react-native-drawer-layout-polyfill": "^1.3.2", "react-native-safe-area-view": "^0.7.0", "react-navigation-deprecated-tab-navigator": "1.1.0", - "react-navigation-tabs": "0.2.0-rc.0" + "react-navigation-tabs": "0.2.0" }, "devDependencies": { "babel-cli": "^6.24.1", diff --git a/yarn.lock b/yarn.lock index 25b0a25324..dadb288bbe 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4972,9 +4972,9 @@ react-navigation-deprecated-tab-navigator@1.1.0: dependencies: react-native-tab-view "^0.0.74" -react-navigation-tabs@0.2.0-rc.0: - version "0.2.0-rc.0" - resolved "https://registry.yarnpkg.com/react-navigation-tabs/-/react-navigation-tabs-0.2.0-rc.0.tgz#671e8c9914b915796879329752f7240147494038" +react-navigation-tabs@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/react-navigation-tabs/-/react-navigation-tabs-0.2.0.tgz#d25be64e01a728c893a93cfeee6b176ab74d67de" dependencies: hoist-non-react-statics "^2.5.0" prop-types "^15.6.0" From c1a94895f5f816d7fbe6ba6edb281e4ebbe600bf Mon Sep 17 00:00:00 2001 From: Eric Vicenti Date: Sun, 6 May 2018 09:51:18 -0700 Subject: [PATCH 17/40] Fix drawer stack reset-to-top behavior (#4132) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit “reset” is not a NavigationAction anymore. The correct fix, for v3, to this is to navigate to the first screen inside the stack. With the less-pushy navigate behavior in v2, this will result in the first route getting selected if you specify it by routeName. --- src/views/Drawer/DrawerSidebar.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/views/Drawer/DrawerSidebar.js b/src/views/Drawer/DrawerSidebar.js index 310bd3b980..faf3adf0e0 100644 --- a/src/views/Drawer/DrawerSidebar.js +++ b/src/views/Drawer/DrawerSidebar.js @@ -2,6 +2,7 @@ import React from 'react'; import { StyleSheet, View } from 'react-native'; import NavigationActions from '../../NavigationActions'; +import StackActions from '../../routers/StackActions'; import invariant from '../../utils/invariant'; /** @@ -46,9 +47,10 @@ class DrawerSidebar extends React.PureComponent { _onItemPress = ({ route, focused }) => { if (!focused) { let subAction; + // TODO (v3): Revisit and repeal this behavior: // if the child screen is a StackRouter then always navigate to its first screen (see #1914) - if (route.index !== undefined && route.index !== 0) { - subAction = NavigationActions.reset({ + if (route.index != null && route.index !== 0) { + subAction = StackActions.reset({ index: 0, actions: [ NavigationActions.navigate({ From f6bd3e4306c2d9d39986c27e0f9b4e0099bc5db5 Mon Sep 17 00:00:00 2001 From: Serge Lebedev Date: Sun, 6 May 2018 23:04:57 +0600 Subject: [PATCH 18/40] Fix setting undefined value to isTransitioning (#4124) --- src/routers/StackRouter.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routers/StackRouter.js b/src/routers/StackRouter.js index 779f1c76b3..ba314044c9 100644 --- a/src/routers/StackRouter.js +++ b/src/routers/StackRouter.js @@ -327,7 +327,7 @@ export default (routeConfigs, stackConfig = {}) => { isTransitioning: state.index !== lastRouteIndex ? action.immediate !== true - : undefined, + : state.isTransitioning, index: lastRouteIndex, routes, }; From 9f95a7f10bd3d471eeed0241a5c8393bdc4553f8 Mon Sep 17 00:00:00 2001 From: Eric Vicenti Date: Sun, 6 May 2018 11:57:51 -0700 Subject: [PATCH 19/40] Fix CompletionAction trigger (#4115) --- src/views/StackView/StackView.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/views/StackView/StackView.js b/src/views/StackView/StackView.js index 2d1a61a7f7..fbbc511dd4 100644 --- a/src/views/StackView/StackView.js +++ b/src/views/StackView/StackView.js @@ -27,10 +27,7 @@ class StackView extends React.Component { onTransitionStart={this.props.onTransitionStart} onTransitionEnd={(transition, lastTransition) => { const { onTransitionEnd, navigation } = this.props; - if ( - transition.navigation.state.isTransitioning && - !lastTransition.navigation.state.isTransitioning - ) { + if (transition.navigation.state.isTransitioning) { navigation.dispatch( StackActions.completeTransition({ key: navigation.state.key, From 4e8d8ce12ff241950530def18d704209b82bbc94 Mon Sep 17 00:00:00 2001 From: Eric Vicenti Date: Sun, 6 May 2018 11:59:40 -0700 Subject: [PATCH 20/40] Fixes to drawer router handling of child routers (#4131) Addresses #4129, and also lets child routers swallow actions with null. Tests added --- src/routers/DrawerRouter.js | 72 ++++++++++++---------- src/routers/__tests__/DrawerRouter-test.js | 46 ++++++++++++++ 2 files changed, 86 insertions(+), 32 deletions(-) diff --git a/src/routers/DrawerRouter.js b/src/routers/DrawerRouter.js index 03716a8dc4..a38a806096 100644 --- a/src/routers/DrawerRouter.js +++ b/src/routers/DrawerRouter.js @@ -33,44 +33,52 @@ export default (routeConfigs, config = {}) => { const isRouterTargeted = action.key == null || action.key === state.key; - if ( - isRouterTargeted && - action.type === DrawerActions.CLOSE_DRAWER && - state.isDrawerOpen - ) { - return { - ...state, - isDrawerOpen: false, - }; - } + if (isRouterTargeted) { + // Only handle actions that are meant for this drawer, as specified by action.key. + + if (action.type === DrawerActions.CLOSE_DRAWER && state.isDrawerOpen) { + return { + ...state, + isDrawerOpen: false, + }; + } + + if (action.type === DrawerActions.OPEN_DRAWER && !state.isDrawerOpen) { + return { + ...state, + isDrawerOpen: true, + }; + } - if ( - isRouterTargeted && - action.type === DrawerActions.OPEN_DRAWER && - !state.isDrawerOpen - ) { - return { - ...state, - isDrawerOpen: true, - }; + if (action.type === DrawerActions.TOGGLE_DRAWER) { + return { + ...state, + isDrawerOpen: !state.isDrawerOpen, + }; + } } - if (isRouterTargeted && action.type === DrawerActions.TOGGLE_DRAWER) { - return { - ...state, - isDrawerOpen: !state.isDrawerOpen, - }; + // Fall back on switch router for screen switching logic, and handling of child routers + const switchedState = switchRouter.getStateForAction(action, state); + + if (switchedState === null) { + // The switch router or a child router is attempting to swallow this action. We return null to allow this. + return null; } - // Fall back on tab router for screen switching logic - const childState = switchRouter.getStateForAction(action, state); - if (childState !== null && childState !== state) { - // If the tabs have changed, make sure to close the drawer - return { - ...childState, - isDrawerOpen: false, - }; + if (switchedState !== state) { + if (switchedState.index !== state.index) { + // If the tabs have changed, make sure to close the drawer + return { + ...switchedState, + isDrawerOpen: false, + }; + } + // Return the state new state, as returned by the switch router. + // The index hasn't changed, so this most likely means that a child router has returned a new state + return switchedState; } + return state; }, }; diff --git a/src/routers/__tests__/DrawerRouter-test.js b/src/routers/__tests__/DrawerRouter-test.js index f1a588c2cf..42f9bff5dc 100644 --- a/src/routers/__tests__/DrawerRouter-test.js +++ b/src/routers/__tests__/DrawerRouter-test.js @@ -91,3 +91,49 @@ describe('DrawerRouter', () => { expect(state3.isDrawerOpen).toEqual(true); }); }); + +test('Nested routers bubble up blocked actions', () => { + const ScreenA = () =>
; + ScreenA.router = { + getStateForAction(action, lastState) { + if (action.type === 'CHILD_ACTION') return null; + return lastState; + }, + }; + const ScreenB = () =>
; + const router = DrawerRouter({ + Foo: { screen: ScreenA }, + Bar: { screen: ScreenB }, + }); + const state = router.getStateForAction(INIT_ACTION); + + const state2 = router.getStateForAction({ type: 'CHILD_ACTION' }, state); + expect(state2).toEqual(null); +}); + +test('Drawer stays open when child routers return new state', () => { + const ScreenA = () =>
; + ScreenA.router = { + getStateForAction(action, lastState = { changed: false }) { + if (action.type === 'CHILD_ACTION') + return { ...lastState, changed: true }; + return lastState; + }, + }; + const router = DrawerRouter({ + Foo: { screen: ScreenA }, + }); + + const state = router.getStateForAction(INIT_ACTION); + expect(state.isDrawerOpen).toEqual(false); + + const state2 = router.getStateForAction( + { type: DrawerActions.OPEN_DRAWER, key: state.key }, + state + ); + expect(state2.isDrawerOpen).toEqual(true); + + const state3 = router.getStateForAction({ type: 'CHILD_ACTION' }, state2); + expect(state3.isDrawerOpen).toEqual(true); + expect(state3.routes[0].changed).toEqual(true); +}); From 1bd6593edeec3a0c06f5a393747cac3972e3fe97 Mon Sep 17 00:00:00 2001 From: Brent Vatne Date: Sun, 6 May 2018 12:00:02 -0700 Subject: [PATCH 21/40] Release 2.0.0-rc.10 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 99bd0a7f90..4aeae21f25 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-navigation", - "version": "2.0.0-rc.9", + "version": "2.0.0-rc.10", "description": "Routing and navigation for your React Native apps", "main": "src/react-navigation.js", "repository": { From 8ec2466fefc7b0a22dde088bd982e20bdfb2c767 Mon Sep 17 00:00:00 2001 From: spaceye Date: Sun, 6 May 2018 22:42:22 +0300 Subject: [PATCH 22/40] Fix for broken swipe back gesture in RTL mode (#4119) * 3127: Fixed gestureDirectionInverted variable declaration and condition in onPanResponderMove method in regards to swipe back action in RTL mode. * - 4118: Put axis check first; - Fixed default BackButton mask in RTL mode. --- src/views/Header/Header.js | 2 ++ src/views/StackView/StackViewLayout.js | 8 ++++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/views/Header/Header.js b/src/views/Header/Header.js index 9f31bd4f66..2319ec6c4a 100644 --- a/src/views/Header/Header.js +++ b/src/views/Header/Header.js @@ -7,6 +7,7 @@ import { Platform, StyleSheet, View, + I18nManager, ViewPropTypes, } from 'react-native'; import { MaskedViewIOS } from '../../PlatformHelpers'; @@ -565,6 +566,7 @@ const styles = StyleSheet.create({ marginTop: -0.5, // resizes down to 20.5 alignSelf: 'center', resizeMode: 'contain', + transform: [{ scaleX: I18nManager.isRTL ? -1 : 1 }], }, title: { bottom: 0, diff --git a/src/views/StackView/StackViewLayout.js b/src/views/StackView/StackViewLayout.js index 60de24302c..76f9d41378 100644 --- a/src/views/StackView/StackViewLayout.js +++ b/src/views/StackView/StackViewLayout.js @@ -227,8 +227,12 @@ class StackViewLayout extends React.Component { const { index } = navigation.state; const isVertical = mode === 'modal'; const { options } = scene.descriptor; + const gestureDirection = options.gestureDirection; - const gestureDirectionInverted = options.gestureDirection === 'inverted'; + const gestureDirectionInverted = + typeof gestureDirection === 'string' + ? gestureDirection === 'inverted' + : I18nManager.isRTL; const gesturesEnabled = typeof options.gesturesEnabled === 'boolean' @@ -302,7 +306,7 @@ class StackViewLayout extends React.Component { ? layout.height.__getValue() : layout.width.__getValue(); const currentValue = - (I18nManager.isRTL && axis === 'dx') !== gestureDirectionInverted + axis === 'dx' && gestureDirectionInverted ? startValue + gesture[axis] / axisDistance : startValue - gesture[axis] / axisDistance; const value = clamp(index - 1, currentValue, index); From 4533883ba762976f5a565c7d4712be9a3639ff64 Mon Sep 17 00:00:00 2001 From: Brent Vatne Date: Sun, 6 May 2018 13:41:53 -0700 Subject: [PATCH 23/40] Release 2.0.0-rc.11 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 4aeae21f25..460e4eca4a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-navigation", - "version": "2.0.0-rc.10", + "version": "2.0.0-rc.11", "description": "Routing and navigation for your React Native apps", "main": "src/react-navigation.js", "repository": { From 1ceda5f04ddbe322bfdb384f60dffbfcd5383c0f Mon Sep 17 00:00:00 2001 From: Brent Vatne Date: Mon, 7 May 2018 11:13:34 -0700 Subject: [PATCH 24/40] Update react-navigation-deprecated-tab-navigator. Closes #4147 --- package.json | 2 +- yarn.lock | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 460e4eca4a..0a7821dd34 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,7 @@ "react-lifecycles-compat": "^3", "react-native-drawer-layout-polyfill": "^1.3.2", "react-native-safe-area-view": "^0.7.0", - "react-navigation-deprecated-tab-navigator": "1.1.0", + "react-navigation-deprecated-tab-navigator": "1.2.0", "react-navigation-tabs": "0.2.0" }, "devDependencies": { diff --git a/yarn.lock b/yarn.lock index dadb288bbe..0d613db603 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4966,9 +4966,9 @@ react-native@^0.52.0: xmldoc "^0.4.0" yargs "^9.0.0" -react-navigation-deprecated-tab-navigator@1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/react-navigation-deprecated-tab-navigator/-/react-navigation-deprecated-tab-navigator-1.1.0.tgz#58945c1c4c7c21b54954e814e8721e98423df75d" +react-navigation-deprecated-tab-navigator@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/react-navigation-deprecated-tab-navigator/-/react-navigation-deprecated-tab-navigator-1.2.0.tgz#e0d969c196dcd3a4a440770a7bd97fa058eb4aaf" dependencies: react-native-tab-view "^0.0.74" From 39d5714ac06a439a3d81b600971c45e1720dbc3c Mon Sep 17 00:00:00 2001 From: Brent Vatne Date: Mon, 7 May 2018 11:14:03 -0700 Subject: [PATCH 25/40] Release 2.0.0-rc.12 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 0a7821dd34..b0044a17d6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-navigation", - "version": "2.0.0-rc.11", + "version": "2.0.0-rc.12", "description": "Routing and navigation for your React Native apps", "main": "src/react-navigation.js", "repository": { From 6499f0215749bbcd631fa2d95a0f533c3c946d8f Mon Sep 17 00:00:00 2001 From: Brent Vatne Date: Mon, 7 May 2018 11:47:56 -0700 Subject: [PATCH 26/40] Only blur input when index changes on transition start (Fixes #4148) --- .../js/KeyboardHandlingExample.js | 7 ++++--- src/navigators/createKeyboardAwareNavigator.js | 12 +++++++++--- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/examples/NavigationPlayground/js/KeyboardHandlingExample.js b/examples/NavigationPlayground/js/KeyboardHandlingExample.js index 7a0674a514..01e2ce765d 100644 --- a/examples/NavigationPlayground/js/KeyboardHandlingExample.js +++ b/examples/NavigationPlayground/js/KeyboardHandlingExample.js @@ -24,9 +24,9 @@ class ScreenOne extends React.Component { } class ScreenTwo extends React.Component { - static navigationOptions = { - title: 'Screen w/ Input', - }; + static navigationOptions = ({ navigation }) => ({ + title: navigation.getParam('inputValue', 'Screen w/ Input'), + }); componentDidMount() { InteractionManager.runAfterInteractions(() => { @@ -41,6 +41,7 @@ class ScreenTwo extends React.Component { (this._textInput = c)} + onChangeText={inputValue => navigation.setParams({ inputValue })} style={{ backgroundColor: 'white', height: 24, diff --git a/src/navigators/createKeyboardAwareNavigator.js b/src/navigators/createKeyboardAwareNavigator.js index 8da2d5bfe6..5b76a5acd2 100644 --- a/src/navigators/createKeyboardAwareNavigator.js +++ b/src/navigators/createKeyboardAwareNavigator.js @@ -39,10 +39,16 @@ export default Navigator => }; _handleTransitionStart = (transitionProps, prevTransitionProps) => { - const currentField = TextInput.State.currentlyFocusedField(); - if (currentField) { - TextInput.State.blurTextInput(currentField); + // TODO: We should not even have received the transition start event + // in the case where the index did not change, I believe. We + // should revisit this after 2.0 release. + if (transitionProps.index !== prevTransitionProps.index) { + const currentField = TextInput.State.currentlyFocusedField(); + if (currentField) { + TextInput.State.blurTextInput(currentField); + } } + this.props.onTransitionStart && this.props.onTransitionStart(transitionProps, prevTransitionProps); }; From 2fd7284fe211d825d87157c85694a8a26fd9fd17 Mon Sep 17 00:00:00 2001 From: Brent Vatne Date: Mon, 7 May 2018 11:54:50 -0700 Subject: [PATCH 27/40] Release candidate lucky number 13 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b0044a17d6..8f07a65248 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-navigation", - "version": "2.0.0-rc.12", + "version": "2.0.0-rc.13", "description": "Routing and navigation for your React Native apps", "main": "src/react-navigation.js", "repository": { From 364144d6394a28b943b735266bd45bf5a586acbe Mon Sep 17 00:00:00 2001 From: Eric Vicenti Date: Mon, 7 May 2018 12:56:35 -0700 Subject: [PATCH 28/40] Navigation Action Helpers at root (#4151) --- src/createNavigationContainer.js | 6 ++++++ src/routers/StackRouter.js | 2 +- src/routers/SwitchRouter.js | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/createNavigationContainer.js b/src/createNavigationContainer.js index bfd08bbf1c..4f8d9461bc 100644 --- a/src/createNavigationContainer.js +++ b/src/createNavigationContainer.js @@ -5,6 +5,7 @@ import { polyfill } from 'react-lifecycles-compat'; import { BackHandler } from './PlatformHelpers'; import NavigationActions from './NavigationActions'; import invariant from './utils/invariant'; +import getNavigationActionCreators from './routers/getNavigationActionCreators'; import docsUrl from './utils/docsUrl'; function isStateful(props) { @@ -359,6 +360,11 @@ export default function createNavigationContainer(Component) { }; }, }; + const actionCreators = getNavigationActionCreators(nav); + Object.keys(actionCreators).forEach(actionName => { + this._navigation[actionName] = (...args) => + this.dispatch(actionCreators[actionName](...args)); + }); } navigation = this._navigation; } diff --git a/src/routers/StackRouter.js b/src/routers/StackRouter.js index ba314044c9..2f94620c8a 100644 --- a/src/routers/StackRouter.js +++ b/src/routers/StackRouter.js @@ -164,7 +164,7 @@ export default (routeConfigs, stackConfig = {}) => { getActionCreators(route, navStateKey) { return { - ...getNavigationActionCreators(route, navStateKey), + ...getNavigationActionCreators(route), ...getCustomActionCreators(route, navStateKey), pop: (n, params) => StackActions.pop({ diff --git a/src/routers/SwitchRouter.js b/src/routers/SwitchRouter.js index 01fb6195b3..cd375c1b3a 100644 --- a/src/routers/SwitchRouter.js +++ b/src/routers/SwitchRouter.js @@ -108,7 +108,7 @@ export default (routeConfigs, config = {}) => { getActionCreators(route, stateKey) { return { - ...getNavigationActionCreators(route, stateKey), + ...getNavigationActionCreators(route), ...getCustomActionCreators(route, stateKey), }; }, From 589b80b2fabcf0e2447481ae42fa15ae42b5678a Mon Sep 17 00:00:00 2001 From: Brent Vatne Date: Mon, 7 May 2018 13:01:22 -0700 Subject: [PATCH 29/40] Update drawer example --- examples/NavigationPlayground/js/Drawer.js | 32 ++++++++++++++-------- 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/examples/NavigationPlayground/js/Drawer.js b/examples/NavigationPlayground/js/Drawer.js index e80b070735..5c4c5a0386 100644 --- a/examples/NavigationPlayground/js/Drawer.js +++ b/examples/NavigationPlayground/js/Drawer.js @@ -32,14 +32,7 @@ const InboxScreen = ({ navigation }) => ( ); InboxScreen.navigationOptions = { - drawerLabel: 'Inbox', - drawerIcon: ({ tintColor }) => ( - - ), + headerTitle: 'Inbox', }; const EmailScreen = ({ navigation }) => ( @@ -50,10 +43,7 @@ const DraftsScreen = ({ navigation }) => ( ); DraftsScreen.navigationOptions = { - drawerLabel: 'Drafts', - drawerIcon: ({ tintColor }) => ( - - ), + headerTitle: 'Drafts', }; const InboxStack = createStackNavigator({ @@ -61,11 +51,29 @@ const InboxStack = createStackNavigator({ Email: { screen: EmailScreen }, }); +InboxStack.navigationOptions = { + drawerLabel: 'Inbox', + drawerIcon: ({ tintColor }) => ( + + ), +}; + const DraftsStack = createStackNavigator({ Drafts: { screen: DraftsScreen }, Email: { screen: EmailScreen }, }); +DraftsStack.navigationOptions = { + drawerLabel: 'Drafts', + drawerIcon: ({ tintColor }) => ( + + ), +}; + const DrawerExample = createDrawerNavigator( { Inbox: { From 93db7d0c959d9e97bba303e8569b2f7b0c0dde2f Mon Sep 17 00:00:00 2001 From: Brent Vatne Date: Mon, 7 May 2018 13:03:21 -0700 Subject: [PATCH 30/40] Release 2.0.0-rc.14 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 8f07a65248..942861b864 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-navigation", - "version": "2.0.0-rc.13", + "version": "2.0.0-rc.14", "description": "Routing and navigation for your React Native apps", "main": "src/react-navigation.js", "repository": { From ec1694f909f895b2be60c5d44b4fb5b278032aff Mon Sep 17 00:00:00 2001 From: Brent Vatne Date: Mon, 7 May 2018 13:47:13 -0700 Subject: [PATCH 31/40] Release 2.0.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 942861b864..06d18cc0e6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-navigation", - "version": "2.0.0-rc.14", + "version": "2.0.0", "description": "Routing and navigation for your React Native apps", "main": "src/react-navigation.js", "repository": { From e97d6b26a827daa0bba1a071606434ca08816cca Mon Sep 17 00:00:00 2001 From: Eric Vicenti Date: Tue, 8 May 2018 17:41:08 -0700 Subject: [PATCH 32/40] Fix dispatch implementation (#4168) Previously we had been emiting an action event with a null state when the router handles the action by returning null from getStateForAction. - Fixes the case of null state getting emitted - Renames a few things for clarity - Refactors conditionals to read easier - Comments to explain intent --- src/createNavigationContainer.js | 47 +++++++++++++++++++++----------- 1 file changed, 31 insertions(+), 16 deletions(-) diff --git a/src/createNavigationContainer.js b/src/createNavigationContainer.js index 4f8d9461bc..f29251d89c 100644 --- a/src/createNavigationContainer.js +++ b/src/createNavigationContainer.js @@ -185,9 +185,9 @@ export default function createNavigationContainer(Component) { } componentDidUpdate() { - // Clear cached _nav every tick - if (this._nav === this.state.nav) { - this._nav = null; + // Clear cached _navState every tick + if (this._navState === this.state.nav) { + this._navState = null; } } @@ -308,32 +308,47 @@ export default function createNavigationContainer(Component) { if (this.props.navigation) { return this.props.navigation.dispatch(action); } - this._nav = this._nav || this.state.nav; - const oldNav = this._nav; - invariant(oldNav, 'should be set in constructor if stateful'); - const nav = Component.router.getStateForAction(action, oldNav); + + // navState will have the most up-to-date value, because setState sometimes behaves asyncronously + this._navState = this._navState || this.state.nav; + const lastNavState = this._navState; + invariant(lastNavState, 'should be set in constructor if stateful'); + const reducedState = Component.router.getStateForAction( + action, + lastNavState + ); + const navState = reducedState === null ? lastNavState : reducedState; + const dispatchActionEvents = () => { this._actionEventSubscribers.forEach(subscriber => subscriber({ type: 'action', action, - state: nav, - lastState: oldNav, + state: navState, + lastState: lastNavState, }) ); }; - if (nav && nav !== oldNav) { + + if (reducedState === null) { + // The router will return null when action has been handled and the state hasn't changed. + // dispatch returns true when something has been handled. + dispatchActionEvents(); + return true; + } + + if (navState !== lastNavState) { // Cache updates to state.nav during the tick to ensure that subsequent calls will not discard this change - this._nav = nav; - this.setState({ nav }, () => { - this._onNavigationStateChange(oldNav, nav, action); + this._navState = navState; + this.setState({ nav: navState }, () => { + this._onNavigationStateChange(lastNavState, navState, action); dispatchActionEvents(); - this._persistNavigationState(nav); + this._persistNavigationState(navState); }); return true; - } else { - dispatchActionEvents(); } + + dispatchActionEvents(); return false; }; From 1876706bad01e80181cb339d35ee6d6871e5877b Mon Sep 17 00:00:00 2001 From: Brent Vatne Date: Tue, 8 May 2018 17:45:02 -0700 Subject: [PATCH 33/40] Release 2.0.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 06d18cc0e6..40f8b6eed4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-navigation", - "version": "2.0.0", + "version": "2.0.1", "description": "Routing and navigation for your React Native apps", "main": "src/react-navigation.js", "repository": { From 931271198b4b7325c2072e4694171bd8c8fd3587 Mon Sep 17 00:00:00 2001 From: Steven Kabbes Date: Wed, 9 May 2018 16:53:06 -0500 Subject: [PATCH 34/40] Remove unused code addNavigationHelpers (#4179) --- src/__tests__/addNavigationHelpers-test.js | 144 ------------------ src/addNavigationHelpers.js | 105 ------------- .../__tests__/createConfigGetter-test.js | 37 +++-- 3 files changed, 18 insertions(+), 268 deletions(-) delete mode 100644 src/__tests__/addNavigationHelpers-test.js delete mode 100644 src/addNavigationHelpers.js diff --git a/src/__tests__/addNavigationHelpers-test.js b/src/__tests__/addNavigationHelpers-test.js deleted file mode 100644 index 642d7677da..0000000000 --- a/src/__tests__/addNavigationHelpers-test.js +++ /dev/null @@ -1,144 +0,0 @@ -import NavigationActions from '../NavigationActions'; -import addNavigationHelpers from '../addNavigationHelpers'; - -const dummyEventSubscriber = (name: string, handler: (*) => void) => ({ - remove: () => {}, -}); - -describe('addNavigationHelpers', () => { - it('handles dismiss action', () => { - const mockedDispatch = jest - .fn(() => false) - .mockImplementationOnce(() => true); - const child = { key: 'A', routeName: 'Home' }; - expect( - addNavigationHelpers({ - state: child, - dispatch: mockedDispatch, - addListener: dummyEventSubscriber, - dangerouslyGetParent: () => ({ - state: { - key: 'P', - routeName: 'Parent', - routes: [child], - }, - }), - }).dismiss() - ).toEqual(true); - expect(mockedDispatch).toBeCalledWith({ - type: NavigationActions.BACK, - key: 'P', - }); - expect(mockedDispatch.mock.calls.length).toBe(1); - }); - - it('handles Back action', () => { - const mockedDispatch = jest - .fn(() => false) - .mockImplementationOnce(() => true); - expect( - addNavigationHelpers({ - state: { key: 'A', routeName: 'Home' }, - dispatch: mockedDispatch, - addListener: dummyEventSubscriber, - }).goBack('A') - ).toEqual(true); - expect(mockedDispatch).toBeCalledWith({ - type: NavigationActions.BACK, - key: 'A', - }); - expect(mockedDispatch.mock.calls.length).toBe(1); - }); - - it('handles Back action when the key is not defined', () => { - const mockedDispatch = jest - .fn(() => false) - .mockImplementationOnce(() => true); - expect( - addNavigationHelpers({ - state: { routeName: 'Home' }, - dispatch: mockedDispatch, - addListener: dummyEventSubscriber, - }).goBack() - ).toEqual(true); - expect(mockedDispatch).toBeCalledWith({ type: NavigationActions.BACK }); - expect(mockedDispatch.mock.calls.length).toBe(1); - }); - - it('handles Navigate action', () => { - const mockedDispatch = jest - .fn(() => false) - .mockImplementationOnce(() => true); - expect( - addNavigationHelpers({ - state: { routeName: 'Home' }, - dispatch: mockedDispatch, - addListener: dummyEventSubscriber, - }).navigate('Profile', { name: 'Matt' }) - ).toEqual(true); - expect(mockedDispatch).toBeCalledWith({ - type: NavigationActions.NAVIGATE, - params: { name: 'Matt' }, - routeName: 'Profile', - }); - expect(mockedDispatch.mock.calls.length).toBe(1); - }); - - it('handles SetParams action', () => { - const mockedDispatch = jest - .fn(() => false) - .mockImplementationOnce(() => true); - expect( - addNavigationHelpers({ - state: { key: 'B', routeName: 'Settings' }, - dispatch: mockedDispatch, - addListener: dummyEventSubscriber, - }).setParams({ notificationsEnabled: 'yes' }) - ).toEqual(true); - expect(mockedDispatch).toBeCalledWith({ - type: NavigationActions.SET_PARAMS, - key: 'B', - params: { notificationsEnabled: 'yes' }, - }); - expect(mockedDispatch.mock.calls.length).toBe(1); - }); - - it('handles GetParams action', () => { - const mockedDispatch = jest - .fn(() => false) - .mockImplementationOnce(() => true); - expect( - addNavigationHelpers({ - state: { key: 'B', routeName: 'Settings', params: { name: 'Peter' } }, - dispatch: mockedDispatch, - addListener: dummyEventSubscriber, - }).getParam('name', 'Brent') - ).toEqual('Peter'); - }); - - it('handles GetParams action with default param', () => { - const mockedDispatch = jest - .fn(() => false) - .mockImplementationOnce(() => true); - expect( - addNavigationHelpers({ - state: { key: 'B', routeName: 'Settings' }, - dispatch: mockedDispatch, - addListener: dummyEventSubscriber, - }).getParam('name', 'Brent') - ).toEqual('Brent'); - }); - - it('handles GetParams action with param value as null', () => { - const mockedDispatch = jest - .fn(() => false) - .mockImplementationOnce(() => true); - expect( - addNavigationHelpers({ - state: { key: 'B', routeName: 'Settings', params: { name: null } }, - dispatch: mockedDispatch, - addListener: dummyEventSubscriber, - }).getParam('name') - ).toEqual(null); - }); -}); diff --git a/src/addNavigationHelpers.js b/src/addNavigationHelpers.js deleted file mode 100644 index 57bbd0f74e..0000000000 --- a/src/addNavigationHelpers.js +++ /dev/null @@ -1,105 +0,0 @@ -/* Helpers for navigation */ - -import NavigationActions from './NavigationActions'; -import invariant from './utils/invariant'; -export default function(navigation) { - return { - ...navigation, - // Go back from the given key, default to active key - goBack: key => { - let actualizedKey = key; - if (key === undefined && navigation.state.key) { - invariant( - typeof navigation.state.key === 'string', - 'key should be a string' - ); - actualizedKey = navigation.state.key; - } - return navigation.dispatch( - NavigationActions.back({ key: actualizedKey }) - ); - }, - // Go back from the parent key. If this is a nested stack, the entire - // stack will be dismissed. - dismiss: () => { - let parent = navigation.dangerouslyGetParent(); - if (parent && parent.state) { - return navigation.dispatch( - NavigationActions.back({ key: parent.state.key }) - ); - } else { - return false; - } - }, - navigate: (navigateTo, params, action) => { - if (typeof navigateTo === 'string') { - return navigation.dispatch( - NavigationActions.navigate({ routeName: navigateTo, params, action }) - ); - } - invariant( - typeof navigateTo === 'object', - 'Must navigateTo an object or a string' - ); - invariant( - params == null, - 'Params must not be provided to .navigate() when specifying an object' - ); - invariant( - action == null, - 'Child action must not be provided to .navigate() when specifying an object' - ); - return navigation.dispatch(NavigationActions.navigate(navigateTo)); - }, - pop: (n, params) => - navigation.dispatch( - NavigationActions.pop({ n, immediate: params && params.immediate }) - ), - popToTop: params => - navigation.dispatch( - NavigationActions.popToTop({ immediate: params && params.immediate }) - ), - /** - * For updating current route params. For example the nav bar title and - * buttons are based on the route params. - * This means `setParams` can be used to update nav bar for example. - */ - setParams: params => { - invariant( - navigation.state.key && typeof navigation.state.key === 'string', - 'setParams cannot be called by root navigator' - ); - const key = navigation.state.key; - return navigation.dispatch(NavigationActions.setParams({ params, key })); - }, - - getParam: (paramName, defaultValue) => { - const params = navigation.state.params; - - if (params && paramName in params) { - return params[paramName]; - } - - return defaultValue; - }, - - push: (routeName, params, action) => - navigation.dispatch( - NavigationActions.push({ routeName, params, action }) - ), - - replace: (routeName, params, action) => - navigation.dispatch( - NavigationActions.replace({ - routeName, - params, - action, - key: navigation.state.key, - }) - ), - - openDrawer: () => navigation.dispatch(NavigationActions.openDrawer()), - closeDrawer: () => navigation.dispatch(NavigationActions.closeDrawer()), - toggleDrawer: () => navigation.dispatch(NavigationActions.toggleDrawer()), - }; -} diff --git a/src/routers/__tests__/createConfigGetter-test.js b/src/routers/__tests__/createConfigGetter-test.js index 3852598f7a..0a79d88642 100644 --- a/src/routers/__tests__/createConfigGetter-test.js +++ b/src/routers/__tests__/createConfigGetter-test.js @@ -1,6 +1,5 @@ import { Component } from 'react'; import createConfigGetter from '../createConfigGetter'; -import addNavigationHelpers from '../../addNavigationHelpers'; const dummyEventSubscriber = (name: string, handler: (*) => void) => ({ remove: () => {}, @@ -67,81 +66,81 @@ test('should get config for screen', () => { expect( getScreenOptions( - addNavigationHelpers({ + { state: routes[0], dispatch: () => false, addListener: dummyEventSubscriber, - }), + }, {} ).title ).toEqual('Welcome anonymous'); expect( getScreenOptions( - addNavigationHelpers({ + { state: routes[1], dispatch: () => false, addListener: dummyEventSubscriber, - }), + }, {} ).title ).toEqual('Welcome jane'); expect( getScreenOptions( - addNavigationHelpers({ + { state: routes[0], dispatch: () => false, addListener: dummyEventSubscriber, - }), + }, {} ).gesturesEnabled ).toEqual(true); expect( getScreenOptions( - addNavigationHelpers({ + { state: routes[2], dispatch: () => false, addListener: dummyEventSubscriber, - }), + }, {} ).title ).toEqual('Settings!!!'); expect( getScreenOptions( - addNavigationHelpers({ + { state: routes[2], dispatch: () => false, addListener: dummyEventSubscriber, - }), + }, {} ).gesturesEnabled ).toEqual(false); expect( getScreenOptions( - addNavigationHelpers({ + { state: routes[3], dispatch: () => false, addListener: dummyEventSubscriber, - }), + }, {} ).title ).toEqual('10 new notifications'); expect( getScreenOptions( - addNavigationHelpers({ + { state: routes[3], dispatch: () => false, addListener: dummyEventSubscriber, - }), + }, {} ).gesturesEnabled ).toEqual(true); expect( getScreenOptions( - addNavigationHelpers({ + { state: routes[4], dispatch: () => false, addListener: dummyEventSubscriber, - }), + }, {} ).gesturesEnabled ).toEqual(false); @@ -164,11 +163,11 @@ test('should throw if the route does not exist', () => { expect(() => getScreenOptions( - addNavigationHelpers({ + { state: routes[0], dispatch: () => false, addListener: dummyEventSubscriber, - }), + }, {} ) ).toThrowError( From 2243528e97c871e9a2ca55853f87002a6601dafc Mon Sep 17 00:00:00 2001 From: Eric Vicenti Date: Wed, 9 May 2018 17:36:57 -0700 Subject: [PATCH 35/40] Cache panResponder in StackView (#4183) * fix swipe gesture bug * panresponder as instance prop --- src/views/StackView/StackViewLayout.js | 315 ++++++++++++++----------- 1 file changed, 181 insertions(+), 134 deletions(-) diff --git a/src/views/StackView/StackViewLayout.js b/src/views/StackView/StackViewLayout.js index 76f9d41378..eb660c19f5 100644 --- a/src/views/StackView/StackViewLayout.js +++ b/src/views/StackView/StackViewLayout.js @@ -209,6 +209,186 @@ class StackViewLayout extends React.Component { } } + _panResponder = PanResponder.create({ + onPanResponderTerminate: () => { + this._isResponding = false; + this._reset(index, 0); + this.props.onGestureCanceled && this.props.onGestureCanceled(); + }, + onPanResponderGrant: () => { + const { + transitionProps: { navigation, position, scene }, + } = this.props; + const { index } = navigation.state; + + if (index !== scene.index) { + return false; + } + + position.stopAnimation((value: number) => { + this._isResponding = true; + this._gestureStartValue = value; + }); + this.props.onGestureBegin && this.props.onGestureBegin(); + }, + onMoveShouldSetPanResponder: (event, gesture) => { + const { + transitionProps: { navigation, position, layout, scene, scenes }, + mode, + } = this.props; + const { index } = navigation.state; + const isVertical = mode === 'modal'; + const { options } = scene.descriptor; + const gestureDirection = options.gestureDirection; + + const gestureDirectionInverted = + typeof gestureDirection === 'string' + ? gestureDirection === 'inverted' + : I18nManager.isRTL; + + if (index !== scene.index) { + return false; + } + + const immediateIndex = + this._immediateIndex == null ? index : this._immediateIndex; + const currentDragDistance = gesture[isVertical ? 'dy' : 'dx']; + const currentDragPosition = + event.nativeEvent[isVertical ? 'pageY' : 'pageX']; + const axisLength = isVertical + ? layout.height.__getValue() + : layout.width.__getValue(); + const axisHasBeenMeasured = !!axisLength; + + // Measure the distance from the touch to the edge of the screen + const screenEdgeDistance = gestureDirectionInverted + ? axisLength - (currentDragPosition - currentDragDistance) + : currentDragPosition - currentDragDistance; + // Compare to the gesture distance relavant to card or modal + + const { + gestureResponseDistance: userGestureResponseDistance = {}, + } = options; + const gestureResponseDistance = isVertical + ? userGestureResponseDistance.vertical || + GESTURE_RESPONSE_DISTANCE_VERTICAL + : userGestureResponseDistance.horizontal || + GESTURE_RESPONSE_DISTANCE_HORIZONTAL; + // GESTURE_RESPONSE_DISTANCE is about 25 or 30. Or 135 for modals + if (screenEdgeDistance > gestureResponseDistance) { + // Reject touches that started in the middle of the screen + return false; + } + + const hasDraggedEnough = + Math.abs(currentDragDistance) > RESPOND_THRESHOLD; + + const isOnFirstCard = immediateIndex === 0; + const shouldSetResponder = + hasDraggedEnough && axisHasBeenMeasured && !isOnFirstCard; + return shouldSetResponder; + }, + onPanResponderMove: (event, gesture) => { + const { + transitionProps: { navigation, position, layout, scene }, + mode, + } = this.props; + const { index } = navigation.state; + const isVertical = mode === 'modal'; + const { options } = scene.descriptor; + const gestureDirection = options.gestureDirection; + + const gestureDirectionInverted = + typeof gestureDirection === 'string' + ? gestureDirection === 'inverted' + : I18nManager.isRTL; + + // Handle the moving touches for our granted responder + const startValue = this._gestureStartValue; + const axis = isVertical ? 'dy' : 'dx'; + const axisDistance = isVertical + ? layout.height.__getValue() + : layout.width.__getValue(); + const currentValue = + axis === 'dx' && gestureDirectionInverted + ? startValue + gesture[axis] / axisDistance + : startValue - gesture[axis] / axisDistance; + const value = clamp(index - 1, currentValue, index); + position.setValue(value); + }, + onPanResponderTerminationRequest: () => + // Returning false will prevent other views from becoming responder while + // the navigation view is the responder (mid-gesture) + false, + onPanResponderRelease: (event, gesture) => { + const { + transitionProps: { navigation, position, layout, scene }, + mode, + } = this.props; + const { index } = navigation.state; + const isVertical = mode === 'modal'; + const { options } = scene.descriptor; + const gestureDirection = options.gestureDirection; + + const gestureDirectionInverted = + typeof gestureDirection === 'string' + ? gestureDirection === 'inverted' + : I18nManager.isRTL; + + if (!this._isResponding) { + return; + } + this._isResponding = false; + + const immediateIndex = + this._immediateIndex == null ? index : this._immediateIndex; + + // Calculate animate duration according to gesture speed and moved distance + const axisDistance = isVertical + ? layout.height.__getValue() + : layout.width.__getValue(); + const movementDirection = gestureDirectionInverted ? -1 : 1; + const movedDistance = + movementDirection * gesture[isVertical ? 'dy' : 'dx']; + const gestureVelocity = + movementDirection * gesture[isVertical ? 'vy' : 'vx']; + const defaultVelocity = axisDistance / ANIMATION_DURATION; + const velocity = Math.max(Math.abs(gestureVelocity), defaultVelocity); + const resetDuration = gestureDirectionInverted + ? (axisDistance - movedDistance) / velocity + : movedDistance / velocity; + const goBackDuration = gestureDirectionInverted + ? movedDistance / velocity + : (axisDistance - movedDistance) / velocity; + + // To asyncronously get the current animated value, we need to run stopAnimation: + position.stopAnimation(value => { + // If the speed of the gesture release is significant, use that as the indication + // of intent + if (gestureVelocity < -0.5) { + this.props.onGestureCanceled && this.props.onGestureCanceled(); + this._reset(immediateIndex, resetDuration); + return; + } + if (gestureVelocity > 0.5) { + this.props.onGestureFinish && this.props.onGestureFinish(); + this._goBack(immediateIndex, goBackDuration); + return; + } + + // Then filter based on the distance the screen was moved. Over a third of the way swiped, + // and the back will happen. + if (value <= index - POSITION_THRESHOLD) { + this.props.onGestureFinish && this.props.onGestureFinish(); + this._goBack(immediateIndex, goBackDuration); + } else { + this.props.onGestureCanceled && this.props.onGestureCanceled(); + this._reset(immediateIndex, resetDuration); + } + }); + }, + }); + render() { let floatingHeader = null; const headerMode = this._getHeaderMode(); @@ -239,140 +419,7 @@ class StackViewLayout extends React.Component { ? options.gesturesEnabled : Platform.OS === 'ios'; - const responder = !gesturesEnabled - ? null - : PanResponder.create({ - onPanResponderTerminate: () => { - this._isResponding = false; - this._reset(index, 0); - this.props.onGestureCanceled && this.props.onGestureCanceled(); - }, - onPanResponderGrant: () => { - position.stopAnimation((value: number) => { - this._isResponding = true; - this._gestureStartValue = value; - }); - this.props.onGestureBegin && this.props.onGestureBegin(); - }, - onMoveShouldSetPanResponder: (event, gesture) => { - if (index !== scene.index) { - return false; - } - const immediateIndex = - this._immediateIndex == null ? index : this._immediateIndex; - const currentDragDistance = gesture[isVertical ? 'dy' : 'dx']; - const currentDragPosition = - event.nativeEvent[isVertical ? 'pageY' : 'pageX']; - const axisLength = isVertical - ? layout.height.__getValue() - : layout.width.__getValue(); - const axisHasBeenMeasured = !!axisLength; - - // Measure the distance from the touch to the edge of the screen - const screenEdgeDistance = gestureDirectionInverted - ? axisLength - (currentDragPosition - currentDragDistance) - : currentDragPosition - currentDragDistance; - // Compare to the gesture distance relavant to card or modal - - const { options } = scene.descriptor; - - const { - gestureResponseDistance: userGestureResponseDistance = {}, - } = options; - const gestureResponseDistance = isVertical - ? userGestureResponseDistance.vertical || - GESTURE_RESPONSE_DISTANCE_VERTICAL - : userGestureResponseDistance.horizontal || - GESTURE_RESPONSE_DISTANCE_HORIZONTAL; - // GESTURE_RESPONSE_DISTANCE is about 25 or 30. Or 135 for modals - if (screenEdgeDistance > gestureResponseDistance) { - // Reject touches that started in the middle of the screen - return false; - } - - const hasDraggedEnough = - Math.abs(currentDragDistance) > RESPOND_THRESHOLD; - - const isOnFirstCard = immediateIndex === 0; - const shouldSetResponder = - hasDraggedEnough && axisHasBeenMeasured && !isOnFirstCard; - return shouldSetResponder; - }, - onPanResponderMove: (event, gesture) => { - // Handle the moving touches for our granted responder - const startValue = this._gestureStartValue; - const axis = isVertical ? 'dy' : 'dx'; - const axisDistance = isVertical - ? layout.height.__getValue() - : layout.width.__getValue(); - const currentValue = - axis === 'dx' && gestureDirectionInverted - ? startValue + gesture[axis] / axisDistance - : startValue - gesture[axis] / axisDistance; - const value = clamp(index - 1, currentValue, index); - position.setValue(value); - }, - onPanResponderTerminationRequest: () => - // Returning false will prevent other views from becoming responder while - // the navigation view is the responder (mid-gesture) - false, - onPanResponderRelease: (event, gesture) => { - if (!this._isResponding) { - return; - } - this._isResponding = false; - - const immediateIndex = - this._immediateIndex == null ? index : this._immediateIndex; - - // Calculate animate duration according to gesture speed and moved distance - const axisDistance = isVertical - ? layout.height.__getValue() - : layout.width.__getValue(); - const movementDirection = gestureDirectionInverted ? -1 : 1; - const movedDistance = - movementDirection * gesture[isVertical ? 'dy' : 'dx']; - const gestureVelocity = - movementDirection * gesture[isVertical ? 'vy' : 'vx']; - const defaultVelocity = axisDistance / ANIMATION_DURATION; - const velocity = Math.max( - Math.abs(gestureVelocity), - defaultVelocity - ); - const resetDuration = gestureDirectionInverted - ? (axisDistance - movedDistance) / velocity - : movedDistance / velocity; - const goBackDuration = gestureDirectionInverted - ? movedDistance / velocity - : (axisDistance - movedDistance) / velocity; - - // To asyncronously get the current animated value, we need to run stopAnimation: - position.stopAnimation(value => { - // If the speed of the gesture release is significant, use that as the indication - // of intent - if (gestureVelocity < -0.5) { - this.props.onGestureCanceled && this.props.onGestureCanceled(); - this._reset(immediateIndex, resetDuration); - return; - } - if (gestureVelocity > 0.5) { - this.props.onGestureFinish && this.props.onGestureFinish(); - this._goBack(immediateIndex, goBackDuration); - return; - } - - // Then filter based on the distance the screen was moved. Over a third of the way swiped, - // and the back will happen. - if (value <= index - POSITION_THRESHOLD) { - this.props.onGestureFinish && this.props.onGestureFinish(); - this._goBack(immediateIndex, goBackDuration); - } else { - this.props.onGestureCanceled && this.props.onGestureCanceled(); - this._reset(immediateIndex, resetDuration); - } - }); - }, - }); + const responder = !gesturesEnabled ? null : this._panResponder; const handlers = gesturesEnabled ? responder.panHandlers : {}; const containerStyle = [ From 08e1b53f2e144a5354a485a327ba9dc6e89acd96 Mon Sep 17 00:00:00 2001 From: Eric Vicenti Date: Sat, 12 May 2018 10:48:45 -0700 Subject: [PATCH 36/40] Update playground yarn lockfile --- examples/NavigationPlayground/yarn.lock | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/examples/NavigationPlayground/yarn.lock b/examples/NavigationPlayground/yarn.lock index 209b983430..590a1b0011 100644 --- a/examples/NavigationPlayground/yarn.lock +++ b/examples/NavigationPlayground/yarn.lock @@ -5737,9 +5737,9 @@ react-native@^0.54.0: xmldoc "^0.4.0" yargs "^9.0.0" -react-navigation-deprecated-tab-navigator@1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/react-navigation-deprecated-tab-navigator/-/react-navigation-deprecated-tab-navigator-1.1.0.tgz#58945c1c4c7c21b54954e814e8721e98423df75d" +react-navigation-deprecated-tab-navigator@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/react-navigation-deprecated-tab-navigator/-/react-navigation-deprecated-tab-navigator-1.2.0.tgz#e0d969c196dcd3a4a440770a7bd97fa058eb4aaf" dependencies: react-native-tab-view "^0.0.74" @@ -5758,6 +5758,16 @@ react-navigation-material-bottom-tabs@0.1.3: react-native-paper "=1.4.0" react-navigation-tabs "0.2.0-rc.0" +react-navigation-tabs@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/react-navigation-tabs/-/react-navigation-tabs-0.2.0.tgz#d25be64e01a728c893a93cfeee6b176ab74d67de" + dependencies: + hoist-non-react-statics "^2.5.0" + prop-types "^15.6.0" + react-lifecycles-compat "^1.0.2" + react-native-safe-area-view "^0.7.0" + react-native-tab-view "~0.0.77" + react-navigation-tabs@0.2.0-rc.0: version "0.2.0-rc.0" resolved "https://registry.yarnpkg.com/react-navigation-tabs/-/react-navigation-tabs-0.2.0-rc.0.tgz#671e8c9914b915796879329752f7240147494038" From 99916328a1998bf97e96d3e8dce6dc4047c763e7 Mon Sep 17 00:00:00 2001 From: Brent Vatne Date: Mon, 21 May 2018 17:55:05 -0700 Subject: [PATCH 37/40] Don't warn about multiple navigation containers on Android This really is not ideal but it's an upstream bug on react-native Android that we can't work around. Users may experience other unexpected behavior as a result of this upstream bug. --- src/createNavigationContainer.js | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/createNavigationContainer.js b/src/createNavigationContainer.js index f29251d89c..91aebb72e9 100644 --- a/src/createNavigationContainer.js +++ b/src/createNavigationContainer.js @@ -1,5 +1,5 @@ import React from 'react'; -import { Linking, AsyncStorage } from 'react-native'; +import { AsyncStorage, Linking, Platform } from 'react-native'; import { polyfill } from 'react-lifecycles-compat'; import { BackHandler } from './PlatformHelpers'; @@ -199,11 +199,15 @@ export default function createNavigationContainer(Component) { if (__DEV__ && !this.props.detached) { if (_statefulContainerCount > 0) { - console.error( - `You should only render one navigator explicitly in your app, and other navigators should by rendered by including them in that navigator. Full details at: ${docsUrl( - 'common-mistakes.html#explicitly-rendering-more-than-one-navigator' - )}` - ); + // Temporarily only show this on iOS due to this issue: + // https://github.com/react-navigation/react-navigation/issues/4196#issuecomment-390827829 + if (Platform.OS === 'ios') { + console.warn( + `You should only render one navigator explicitly in your app, and other navigators should by rendered by including them in that navigator. Full details at: ${docsUrl( + 'common-mistakes.html#explicitly-rendering-more-than-one-navigator' + )}` + ); + } } } _statefulContainerCount++; From d168ab26f94bad03f76a63bb76aa176ca1b75340 Mon Sep 17 00:00:00 2001 From: Brent Vatne Date: Mon, 21 May 2018 17:56:24 -0700 Subject: [PATCH 38/40] Release 2.0.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 40f8b6eed4..1766744d68 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-navigation", - "version": "2.0.1", + "version": "2.0.2", "description": "Routing and navigation for your React Native apps", "main": "src/react-navigation.js", "repository": { From 2bb48b95e7e2acab5fdcf248d2558bba4d88e158 Mon Sep 17 00:00:00 2001 From: martin Date: Tue, 22 May 2018 12:19:10 +0100 Subject: [PATCH 39/40] Revert yarn.lock --- yarn.lock | 119 ++++++++++++------------------------------------------ 1 file changed, 25 insertions(+), 94 deletions(-) diff --git a/yarn.lock b/yarn.lock index 20660924a7..31331a9b2a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -108,7 +108,7 @@ ansi-gray@^0.1.1: dependencies: ansi-wrap "0.1.0" -ansi-regex@^2.0.0: +ansi-regex@^2.0.0, ansi-regex@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" @@ -120,7 +120,7 @@ ansi-styles@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" -ansi-styles@^3.2.0, ansi-styles@^3.2.1: +ansi-styles@^3.0.0, ansi-styles@^3.2.0, ansi-styles@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" dependencies: @@ -1915,7 +1915,7 @@ escodegen@^1.9.0: optionalDependencies: source-map "~0.6.1" -eslint-config-prettier@^2.9.0: +eslint-config-prettier@^2.3.0: version "2.9.0" resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-2.9.0.tgz#5ecd65174d486c22dff389fe036febf502d468a3" dependencies: @@ -1962,7 +1962,7 @@ eslint-plugin-jsx-a11y@^6.0.2: emoji-regex "^6.1.0" jsx-ast-utils "^2.0.0" -eslint-plugin-prettier@^2.6.0: +eslint-plugin-prettier@^2.1.2: version "2.6.0" resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-2.6.0.tgz#33e4e228bdb06142d03c560ce04ec23f6c767dd7" dependencies: @@ -1989,50 +1989,7 @@ eslint-visitor-keys@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#3f3180fb2e291017716acb4c9d6d5b5c34a6a81d" -eslint@^4.0.0: - version "4.19.1" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-4.19.1.tgz#32d1d653e1d90408854bfb296f076ec7e186a300" - dependencies: - ajv "^5.3.0" - babel-code-frame "^6.22.0" - chalk "^2.1.0" - concat-stream "^1.6.0" - cross-spawn "^5.1.0" - debug "^3.1.0" - doctrine "^2.1.0" - eslint-scope "^3.7.1" - eslint-visitor-keys "^1.0.0" - espree "^3.5.4" - esquery "^1.0.0" - esutils "^2.0.2" - file-entry-cache "^2.0.0" - functional-red-black-tree "^1.0.1" - glob "^7.1.2" - globals "^11.0.1" - ignore "^3.3.3" - imurmurhash "^0.1.4" - inquirer "^3.0.6" - is-resolvable "^1.0.0" - js-yaml "^3.9.1" - json-stable-stringify-without-jsonify "^1.0.1" - levn "^0.3.0" - lodash "^4.17.4" - minimatch "^3.0.2" - mkdirp "^0.5.1" - natural-compare "^1.4.0" - optionator "^0.8.2" - path-is-inside "^1.0.2" - pluralize "^7.0.0" - progress "^2.0.0" - regexpp "^1.0.1" - require-uncached "^1.0.3" - semver "^5.3.0" - strip-ansi "^4.0.0" - strip-json-comments "~2.0.1" - table "4.0.2" - text-table "~0.2.0" - -eslint@^4.2.0: +eslint@^4.2.0, eslint@^4.5.0: version "4.18.2" resolved "https://registry.yarnpkg.com/eslint/-/eslint-4.18.2.tgz#0f81267ad1012e7d2051e186a9004cc2267b8d45" dependencies: @@ -2074,7 +2031,7 @@ eslint@^4.2.0: table "4.0.2" text-table "~0.2.0" -espree@^3.5.2, espree@^3.5.4: +espree@^3.5.2: version "3.5.4" resolved "https://registry.yarnpkg.com/espree/-/espree-3.5.4.tgz#b0f447187c8a8bed944b815a660bddf5deb5d1a7" dependencies: @@ -3946,10 +3903,6 @@ lodash.throttle@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/lodash.throttle/-/lodash.throttle-4.1.1.tgz#c23e91b710242ac70c37f1e1cda9274cc39bf2f4" -lodash.unescape@4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/lodash.unescape/-/lodash.unescape-4.0.1.tgz#bf2249886ce514cda112fae9218cdc065211fc9c" - lodash@^3.5.0: version "3.10.1" resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6" @@ -4735,26 +4688,30 @@ preserve@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" -prettier-eslint@^8.8.1: - version "8.8.1" - resolved "https://registry.yarnpkg.com/prettier-eslint/-/prettier-eslint-8.8.1.tgz#38505163274742f2a0b31653c39e40f37ebd07da" +prettier-eslint@^6.4.2: + version "6.4.3" + resolved "https://registry.yarnpkg.com/prettier-eslint/-/prettier-eslint-6.4.3.tgz#8335b7a8bd50d01879a9d505bc0b9208caa9ecfc" dependencies: - babel-runtime "^6.26.0" common-tags "^1.4.0" dlv "^1.1.0" - eslint "^4.0.0" + eslint "^4.5.0" indent-string "^3.2.0" lodash.merge "^4.6.0" loglevel-colored-level-prefix "^1.0.0" - prettier "^1.7.0" - pretty-format "^22.0.3" + prettier "^1.6.0" + pretty-format "^20.0.3" require-relative "^0.8.7" - typescript "^2.5.1" - typescript-eslint-parser "^11.0.0" -prettier@^1.12.1, prettier@^1.7.0: - version "1.12.1" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.12.1.tgz#c1ad20e803e7749faf905a409d2367e06bbe7325" +prettier@^1.5.3, prettier@^1.6.0: + version "1.11.1" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.11.1.tgz#61e43fc4cd44e68f2b0dfc2c38cd4bb0fccdcc75" + +pretty-format@^20.0.3: + version "20.0.3" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-20.0.3.tgz#020e350a560a1fe1a98dc3beb6ccffb386de8b14" + dependencies: + ansi-regex "^2.1.1" + ansi-styles "^3.0.0" pretty-format@^21.2.1: version "21.2.1" @@ -4763,13 +4720,6 @@ pretty-format@^21.2.1: ansi-regex "^3.0.0" ansi-styles "^3.2.0" -pretty-format@^22.0.3: - version "22.4.3" - resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-22.4.3.tgz#f873d780839a9c02e9664c8a082e9ee79eaac16f" - dependencies: - ansi-regex "^3.0.0" - ansi-styles "^3.2.0" - pretty-format@^22.4.0: version "22.4.0" resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-22.4.0.tgz#237b1f7e1c50ed03bc65c03ccc29d7c8bb7beb94" @@ -5011,9 +4961,9 @@ react-navigation-deprecated-tab-navigator@1.1.0: dependencies: react-native-tab-view "^0.0.74" -react-navigation-tabs@0.1.0-alpha.8: - version "0.1.0-alpha.8" - resolved "https://registry.yarnpkg.com/react-navigation-tabs/-/react-navigation-tabs-0.1.0-alpha.8.tgz#bb18699f8496a00f9911c9c75cce243d299c2423" +react-navigation-tabs@0.1.0-alpha.7: + version "0.1.0-alpha.7" + resolved "https://registry.yarnpkg.com/react-navigation-tabs/-/react-navigation-tabs-0.1.0-alpha.7.tgz#bcea5b031a3db3b4230be63f17fed721bf78e198" dependencies: hoist-non-react-statics "^2.5.0" prop-types "^15.6.0" @@ -5156,10 +5106,6 @@ regex-not@^1.0.0, regex-not@^1.0.2: extend-shallow "^3.0.2" safe-regex "^1.1.0" -regexpp@^1.0.1: - version "1.1.0" - resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-1.1.0.tgz#0e3516dd0b7904f413d2d4193dce4618c3a689ab" - regexpu-core@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-2.0.0.tgz#49d038837b8dcf8bfa5b9a42139938e6ea2ae240" @@ -5451,10 +5397,6 @@ sax@~1.1.1: version "5.5.0" resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab" -semver@5.4.1: - version "5.4.1" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.4.1.tgz#e059c09d8571f0540823733433505d3a2f00b18e" - send@0.13.2: version "0.13.2" resolved "https://registry.yarnpkg.com/send/-/send-0.13.2.tgz#765e7607c8055452bba6f0b052595350986036de" @@ -6033,17 +5975,6 @@ typedarray@^0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" -typescript-eslint-parser@^11.0.0: - version "11.0.0" - resolved "https://registry.yarnpkg.com/typescript-eslint-parser/-/typescript-eslint-parser-11.0.0.tgz#37dba6a0130dd307504aa4b4b21b0d3dc7d4e9f2" - dependencies: - lodash.unescape "4.0.1" - semver "5.4.1" - -typescript@^2.5.1: - version "2.8.3" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.8.3.tgz#5d817f9b6f31bb871835f4edf0089f21abe6c170" - ua-parser-js@^0.7.9: version "0.7.17" resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.17.tgz#e9ec5f9498b9ec910e7ae3ac626a805c4d09ecac" From 638a79147fab18d1e8e02cb1a1c46be816458f86 Mon Sep 17 00:00:00 2001 From: martin Date: Tue, 22 May 2018 12:33:11 +0100 Subject: [PATCH 40/40] Resolve conflict --- src/views/StackView/StackView.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/views/StackView/StackView.js b/src/views/StackView/StackView.js index 13f401e979..4f4030e39f 100644 --- a/src/views/StackView/StackView.js +++ b/src/views/StackView/StackView.js @@ -26,10 +26,7 @@ class StackView extends React.Component { onTransitionStart={this.props.navigationConfig.onTransitionStart} onTransitionEnd={(transition, lastTransition) => { const { navigationConfig, navigation } = this.props; - if ( - transition.navigation.state.isTransitioning && - !lastTransition.navigation.state.isTransitioning - ) { + if (transition.navigation.state.isTransitioning) { navigation.dispatch( StackActions.completeTransition({ key: navigation.state.key,