Преглед на файлове

Smarter set root (#3251)

* setRoot({root:{}})

* support setRoot with root, modals, overlays

* Update setRoot calls in playground app to new api

* Update setRoot on Android to new api

currently only supporting root node

* Update setRoot on iOS to new api

* fix unit tests
Yogev B преди 6 години
родител
ревизия
f3efebe8ca
No account linked to committer's email address

+ 1
- 1
lib/android/app/src/main/java/com/reactnativenavigation/react/NavigationModule.java Целия файл

55
 
55
 
56
 	@ReactMethod
56
 	@ReactMethod
57
 	public void setRoot(String commandId, ReadableMap rawLayoutTree, Promise promise) {
57
 	public void setRoot(String commandId, ReadableMap rawLayoutTree, Promise promise) {
58
-		final LayoutNode layoutTree = LayoutNodeParser.parse(new JSONObject(rawLayoutTree.toHashMap()));
58
+		final LayoutNode layoutTree = LayoutNodeParser.parse(new JSONObject(rawLayoutTree.getMap("root").toHashMap()));
59
 		handle(() -> {
59
 		handle(() -> {
60
             final ViewController viewController = newLayoutFactory().create(layoutTree);
60
             final ViewController viewController = newLayoutFactory().create(layoutTree);
61
             navigator().setRoot(viewController, new NativeCommandListener(commandId, promise, eventEmitter, now));
61
             navigator().setRoot(viewController, new NativeCommandListener(commandId, promise, eventEmitter, now));

+ 1
- 1
lib/ios/RNNCommandsHandler.m Целия файл

48
 	[_modalManager dismissAllModals];
48
 	[_modalManager dismissAllModals];
49
 	[_eventEmitter sendOnNavigationCommand:setRoot params:@{@"layout": layout}];
49
 	[_eventEmitter sendOnNavigationCommand:setRoot params:@{@"layout": layout}];
50
 	
50
 	
51
-	UIViewController *vc = [_controllerFactory createLayoutAndSaveToStore:layout];
51
+	UIViewController *vc = [_controllerFactory createLayoutAndSaveToStore:layout[@"root"]];
52
 	
52
 	
53
 	UIApplication.sharedApplication.delegate.window.rootViewController = vc;
53
 	UIApplication.sharedApplication.delegate.window.rootViewController = vc;
54
 	[UIApplication.sharedApplication.delegate.window makeKeyAndVisible];
54
 	[UIApplication.sharedApplication.delegate.window makeKeyAndVisible];

+ 8
- 0
lib/ios/ReactNativeNavigation.xcodeproj/project.pbxproj Целия файл

100
 		507F44201FFA8A8800D9425B /* RNNRootViewProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = 507F441F1FFA8A8800D9425B /* RNNRootViewProtocol.h */; };
100
 		507F44201FFA8A8800D9425B /* RNNRootViewProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = 507F441F1FFA8A8800D9425B /* RNNRootViewProtocol.h */; };
101
 		50A00C37200F84D6000F01A6 /* RNNOverlayOptions.h in Headers */ = {isa = PBXBuildFile; fileRef = 50A00C35200F84D6000F01A6 /* RNNOverlayOptions.h */; };
101
 		50A00C37200F84D6000F01A6 /* RNNOverlayOptions.h in Headers */ = {isa = PBXBuildFile; fileRef = 50A00C35200F84D6000F01A6 /* RNNOverlayOptions.h */; };
102
 		50A00C38200F84D6000F01A6 /* RNNOverlayOptions.m in Sources */ = {isa = PBXBuildFile; fileRef = 50A00C36200F84D6000F01A6 /* RNNOverlayOptions.m */; };
102
 		50A00C38200F84D6000F01A6 /* RNNOverlayOptions.m in Sources */ = {isa = PBXBuildFile; fileRef = 50A00C36200F84D6000F01A6 /* RNNOverlayOptions.m */; };
103
+		50BE951220B5A787004F5DF5 /* RNNStatusBarOptions.m in Sources */ = {isa = PBXBuildFile; fileRef = 50BE951020B5A787004F5DF5 /* RNNStatusBarOptions.m */; };
104
+		50BE951320B5A787004F5DF5 /* RNNStatusBarOptions.h in Headers */ = {isa = PBXBuildFile; fileRef = 50BE951120B5A787004F5DF5 /* RNNStatusBarOptions.h */; };
103
 		50C4A496206BDDBB00DB292E /* RNNSubtitleOptions.h in Headers */ = {isa = PBXBuildFile; fileRef = 50C4A494206BDDBB00DB292E /* RNNSubtitleOptions.h */; };
105
 		50C4A496206BDDBB00DB292E /* RNNSubtitleOptions.h in Headers */ = {isa = PBXBuildFile; fileRef = 50C4A494206BDDBB00DB292E /* RNNSubtitleOptions.h */; };
104
 		50C4A497206BDDBB00DB292E /* RNNSubtitleOptions.m in Sources */ = {isa = PBXBuildFile; fileRef = 50C4A495206BDDBB00DB292E /* RNNSubtitleOptions.m */; };
106
 		50C4A497206BDDBB00DB292E /* RNNSubtitleOptions.m in Sources */ = {isa = PBXBuildFile; fileRef = 50C4A495206BDDBB00DB292E /* RNNSubtitleOptions.m */; };
105
 		50CB3B691FDE911400AA153B /* RNNSideMenuOptions.h in Headers */ = {isa = PBXBuildFile; fileRef = 50CB3B671FDE911400AA153B /* RNNSideMenuOptions.h */; };
107
 		50CB3B691FDE911400AA153B /* RNNSideMenuOptions.h in Headers */ = {isa = PBXBuildFile; fileRef = 50CB3B671FDE911400AA153B /* RNNSideMenuOptions.h */; };
295
 		507F441F1FFA8A8800D9425B /* RNNRootViewProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNNRootViewProtocol.h; sourceTree = "<group>"; };
297
 		507F441F1FFA8A8800D9425B /* RNNRootViewProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNNRootViewProtocol.h; sourceTree = "<group>"; };
296
 		50A00C35200F84D6000F01A6 /* RNNOverlayOptions.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNNOverlayOptions.h; sourceTree = "<group>"; };
298
 		50A00C35200F84D6000F01A6 /* RNNOverlayOptions.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNNOverlayOptions.h; sourceTree = "<group>"; };
297
 		50A00C36200F84D6000F01A6 /* RNNOverlayOptions.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNNOverlayOptions.m; sourceTree = "<group>"; };
299
 		50A00C36200F84D6000F01A6 /* RNNOverlayOptions.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNNOverlayOptions.m; sourceTree = "<group>"; };
300
+		50BE951020B5A787004F5DF5 /* RNNStatusBarOptions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNNStatusBarOptions.m; sourceTree = "<group>"; };
301
+		50BE951120B5A787004F5DF5 /* RNNStatusBarOptions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNNStatusBarOptions.h; sourceTree = "<group>"; };
298
 		50C4A494206BDDBB00DB292E /* RNNSubtitleOptions.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNNSubtitleOptions.h; sourceTree = "<group>"; };
302
 		50C4A494206BDDBB00DB292E /* RNNSubtitleOptions.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNNSubtitleOptions.h; sourceTree = "<group>"; };
299
 		50C4A495206BDDBB00DB292E /* RNNSubtitleOptions.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNNSubtitleOptions.m; sourceTree = "<group>"; };
303
 		50C4A495206BDDBB00DB292E /* RNNSubtitleOptions.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNNSubtitleOptions.m; sourceTree = "<group>"; };
300
 		50CB3B671FDE911400AA153B /* RNNSideMenuOptions.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNNSideMenuOptions.h; sourceTree = "<group>"; };
304
 		50CB3B671FDE911400AA153B /* RNNSideMenuOptions.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNNSideMenuOptions.h; sourceTree = "<group>"; };
509
 				50570B252061473D006A1B5C /* RNNTitleOptions.m */,
513
 				50570B252061473D006A1B5C /* RNNTitleOptions.m */,
510
 				50C4A494206BDDBB00DB292E /* RNNSubtitleOptions.h */,
514
 				50C4A494206BDDBB00DB292E /* RNNSubtitleOptions.h */,
511
 				50C4A495206BDDBB00DB292E /* RNNSubtitleOptions.m */,
515
 				50C4A495206BDDBB00DB292E /* RNNSubtitleOptions.m */,
516
+				50BE951120B5A787004F5DF5 /* RNNStatusBarOptions.h */,
517
+				50BE951020B5A787004F5DF5 /* RNNStatusBarOptions.m */,
512
 				50EB4ED52068EBE000D6ED34 /* RNNBackgroundOptions.h */,
518
 				50EB4ED52068EBE000D6ED34 /* RNNBackgroundOptions.h */,
513
 				50EB4ED62068EBE000D6ED34 /* RNNBackgroundOptions.m */,
519
 				50EB4ED62068EBE000D6ED34 /* RNNBackgroundOptions.m */,
514
 				A7626BFF1FC578AB00492FB8 /* RNNBottomTabsOptions.h */,
520
 				A7626BFF1FC578AB00492FB8 /* RNNBottomTabsOptions.h */,
783
 				268692821E5054F800E2C612 /* RNNStore.h in Headers */,
789
 				268692821E5054F800E2C612 /* RNNStore.h in Headers */,
784
 				E8AEDB3C1F55A1C2000F5A6A /* RNNElementView.h in Headers */,
790
 				E8AEDB3C1F55A1C2000F5A6A /* RNNElementView.h in Headers */,
785
 				E8E518321F83B3E0000467AC /* RNNUtils.h in Headers */,
791
 				E8E518321F83B3E0000467AC /* RNNUtils.h in Headers */,
792
+				50BE951320B5A787004F5DF5 /* RNNStatusBarOptions.h in Headers */,
786
 				507F44201FFA8A8800D9425B /* RNNRootViewProtocol.h in Headers */,
793
 				507F44201FFA8A8800D9425B /* RNNRootViewProtocol.h in Headers */,
787
 				50570BEA2063E09B006A1B5C /* RNNTitleViewHelper.h in Headers */,
794
 				50570BEA2063E09B006A1B5C /* RNNTitleViewHelper.h in Headers */,
788
 				263905CA1E4C6F440023D7D3 /* SidebarLuvocracyAnimation.h in Headers */,
795
 				263905CA1E4C6F440023D7D3 /* SidebarLuvocracyAnimation.h in Headers */,
933
 				E8DA24411F97459B00CD552B /* RNNElementFinder.m in Sources */,
940
 				E8DA24411F97459B00CD552B /* RNNElementFinder.m in Sources */,
934
 				50570B272061473D006A1B5C /* RNNTitleOptions.m in Sources */,
941
 				50570B272061473D006A1B5C /* RNNTitleOptions.m in Sources */,
935
 				263905BF1E4C6F440023D7D3 /* RCCTheSideBarManagerViewController.m in Sources */,
942
 				263905BF1E4C6F440023D7D3 /* RCCTheSideBarManagerViewController.m in Sources */,
943
+				50BE951220B5A787004F5DF5 /* RNNStatusBarOptions.m in Sources */,
936
 				7B1126A01E2D263F00F9B03B /* RNNEventEmitter.m in Sources */,
944
 				7B1126A01E2D263F00F9B03B /* RNNEventEmitter.m in Sources */,
937
 				A7626BFD1FC2FB2C00492FB8 /* RNNTopBarOptions.m in Sources */,
945
 				A7626BFD1FC2FB2C00492FB8 /* RNNTopBarOptions.m in Sources */,
938
 				263905CB1E4C6F440023D7D3 /* SidebarLuvocracyAnimation.m in Sources */,
946
 				263905CB1E4C6F440023D7D3 /* SidebarLuvocracyAnimation.m in Sources */,

+ 6
- 6
lib/ios/ReactNativeNavigationTests/RNNRootViewControllerTest.m Целия файл

70
 }
70
 }
71
 
71
 
72
 - (void)testStatusBarHidden_true {
72
 - (void)testStatusBarHidden_true {
73
-	self.options.statusBarHidden = @(1);
73
+	self.options.statusBar.hidden = @(1);
74
 	__unused RNNNavigationController* nav = [[RNNNavigationController alloc] initWithRootViewController:self.uut];
74
 	__unused RNNNavigationController* nav = [[RNNNavigationController alloc] initWithRootViewController:self.uut];
75
 	[self.uut viewWillAppear:false];
75
 	[self.uut viewWillAppear:false];
76
 	
76
 	
78
 }
78
 }
79
 
79
 
80
 - (void)testStatusBarHideWithTopBar_false {
80
 - (void)testStatusBarHideWithTopBar_false {
81
-	self.options.statusBarHideWithTopBar = @(0);
81
+	self.options.statusBar.hideWithTopBar = @(0);
82
 	self.options.topBar.visible = @(0);
82
 	self.options.topBar.visible = @(0);
83
 	__unused UINavigationController* nav = [[UINavigationController alloc] initWithRootViewController:self.uut];
83
 	__unused UINavigationController* nav = [[UINavigationController alloc] initWithRootViewController:self.uut];
84
 	[self.uut viewWillAppear:false];
84
 	[self.uut viewWillAppear:false];
87
 }
87
 }
88
 
88
 
89
 - (void)testStatusBarHideWithTopBar_true {
89
 - (void)testStatusBarHideWithTopBar_true {
90
-	self.options.statusBarHideWithTopBar = @(1);
90
+	self.options.statusBar.hideWithTopBar = @(1);
91
 	self.options.topBar.visible = @(0);
91
 	self.options.topBar.visible = @(0);
92
 	__unused UINavigationController* nav = [[UINavigationController alloc] initWithRootViewController:self.uut];
92
 	__unused UINavigationController* nav = [[UINavigationController alloc] initWithRootViewController:self.uut];
93
 	[self.uut viewWillAppear:false];
93
 	[self.uut viewWillAppear:false];
97
 
97
 
98
 
98
 
99
 - (void)testStatusBarHidden_false {
99
 - (void)testStatusBarHidden_false {
100
-	self.options.statusBarHidden = @(0);
100
+	self.options.statusBar.hidden = @(0);
101
 	__unused RNNNavigationController* nav = [[RNNNavigationController alloc] initWithRootViewController:self.uut];
101
 	__unused RNNNavigationController* nav = [[RNNNavigationController alloc] initWithRootViewController:self.uut];
102
 	[self.uut viewWillAppear:false];
102
 	[self.uut viewWillAppear:false];
103
 	
103
 	
448
 
448
 
449
 -(void)testStatusBarBlurOn {
449
 -(void)testStatusBarBlurOn {
450
 	NSNumber* statusBarBlurInput = @(1);
450
 	NSNumber* statusBarBlurInput = @(1);
451
-	self.options.statusBarBlur = statusBarBlurInput;
451
+	self.options.statusBar.blur = statusBarBlurInput;
452
 	__unused UINavigationController* nav = [[UINavigationController alloc] initWithRootViewController:self.uut];
452
 	__unused UINavigationController* nav = [[UINavigationController alloc] initWithRootViewController:self.uut];
453
 	[self.uut viewWillAppear:false];
453
 	[self.uut viewWillAppear:false];
454
 	XCTAssertNotNil([self.uut.view viewWithTag:BLUR_STATUS_TAG]);
454
 	XCTAssertNotNil([self.uut.view viewWithTag:BLUR_STATUS_TAG]);
456
 
456
 
457
 -(void)testStatusBarBlurOff {
457
 -(void)testStatusBarBlurOff {
458
 	NSNumber* statusBarBlurInput = @(0);
458
 	NSNumber* statusBarBlurInput = @(0);
459
-	self.options.statusBarBlur = statusBarBlurInput;
459
+	self.options.statusBar.blur = statusBarBlurInput;
460
 	__unused UINavigationController* nav = [[UINavigationController alloc] initWithRootViewController:self.uut];
460
 	__unused UINavigationController* nav = [[UINavigationController alloc] initWithRootViewController:self.uut];
461
 	[self.uut viewWillAppear:false];
461
 	[self.uut viewWillAppear:false];
462
 	XCTAssertNil([self.uut.view viewWithTag:BLUR_STATUS_TAG]);
462
 	XCTAssertNil([self.uut.view viewWithTag:BLUR_STATUS_TAG]);

+ 2
- 2
lib/src/adapters/NativeCommandsSender.ts Целия файл

6
     this.nativeCommandsModule = NativeModules.RNNBridgeModule;
6
     this.nativeCommandsModule = NativeModules.RNNBridgeModule;
7
   }
7
   }
8
 
8
 
9
-  setRoot(commandId: string, layoutTree: object) {
10
-    return this.nativeCommandsModule.setRoot(commandId, layoutTree);
9
+  setRoot(commandId: string, layout: { root: any, modals: any[], overlays: any[] }) {
10
+    return this.nativeCommandsModule.setRoot(commandId, layout);
11
   }
11
   }
12
 
12
 
13
   setDefaultOptions(options: object) {
13
   setDefaultOptions(options: object) {

+ 81
- 16
lib/src/commands/Commands.test.ts Целия файл

30
   describe('setRoot', () => {
30
   describe('setRoot', () => {
31
     it('sends setRoot to native after parsing into a correct layout tree', () => {
31
     it('sends setRoot to native after parsing into a correct layout tree', () => {
32
       uut.setRoot({
32
       uut.setRoot({
33
-        component: {
34
-          name: 'com.example.MyScreen'
33
+        root: {
34
+          component: {
35
+            name: 'com.example.MyScreen'
36
+          }
35
         }
37
         }
36
       });
38
       });
37
       expect(mockCommandsSender.setRoot).toHaveBeenCalledTimes(1);
39
       expect(mockCommandsSender.setRoot).toHaveBeenCalledTimes(1);
38
       expect(mockCommandsSender.setRoot).toHaveBeenCalledWith('setRoot+UNIQUE_ID', {
40
       expect(mockCommandsSender.setRoot).toHaveBeenCalledWith('setRoot+UNIQUE_ID', {
39
-        type: 'Component',
40
-        id: 'Component+UNIQUE_ID',
41
-        children: [],
42
-        data: {
43
-          name: 'com.example.MyScreen',
44
-          options: {}
45
-        }
41
+        root: {
42
+          type: 'Component',
43
+          id: 'Component+UNIQUE_ID',
44
+          children: [],
45
+          data: {
46
+            name: 'com.example.MyScreen',
47
+            options: {}
48
+          }
49
+        },
50
+        modals: [],
51
+        overlays: []
46
       });
52
       });
47
     });
53
     });
48
 
54
 
49
     it('deep clones input to avoid mutation errors', () => {
55
     it('deep clones input to avoid mutation errors', () => {
50
       const obj = {};
56
       const obj = {};
51
-      uut.setRoot({ component: { name: 'bla', inner: obj } });
52
-      expect(mockCommandsSender.setRoot.mock.calls[0][1].data.inner).not.toBe(obj);
57
+      uut.setRoot({ root: { component: { name: 'bla', inner: obj } } });
58
+      expect(mockCommandsSender.setRoot.mock.calls[0][1].root.data.inner).not.toBe(obj);
53
     });
59
     });
54
 
60
 
55
     it('passProps into components', () => {
61
     it('passProps into components', () => {
57
         fn: () => 'Hello'
63
         fn: () => 'Hello'
58
       };
64
       };
59
       expect(store.getPropsForId('Component+UNIQUE_ID')).toEqual({});
65
       expect(store.getPropsForId('Component+UNIQUE_ID')).toEqual({});
60
-      uut.setRoot({ component: { name: 'asd', passProps } });
66
+      uut.setRoot({ root: { component: { name: 'asd', passProps } } });
61
       expect(store.getPropsForId('Component+UNIQUE_ID')).toEqual(passProps);
67
       expect(store.getPropsForId('Component+UNIQUE_ID')).toEqual(passProps);
62
       expect(store.getPropsForId('Component+UNIQUE_ID').fn()).toEqual('Hello');
68
       expect(store.getPropsForId('Component+UNIQUE_ID').fn()).toEqual('Hello');
63
     });
69
     });
64
 
70
 
65
     it('returns a promise with the resolved layout', async () => {
71
     it('returns a promise with the resolved layout', async () => {
66
       mockCommandsSender.setRoot.mockReturnValue(Promise.resolve('the resolved layout'));
72
       mockCommandsSender.setRoot.mockReturnValue(Promise.resolve('the resolved layout'));
67
-      const result = await uut.setRoot({ component: { name: 'com.example.MyScreen' } });
73
+      const result = await uut.setRoot({ root: { component: { name: 'com.example.MyScreen' } } });
68
       expect(result).toEqual('the resolved layout');
74
       expect(result).toEqual('the resolved layout');
69
     });
75
     });
76
+
77
+    it('inputs modals and overlays', () => {
78
+      uut.setRoot({
79
+        root: {
80
+          component: {
81
+            name: 'com.example.MyScreen'
82
+          }
83
+        },
84
+        modals: [
85
+          {
86
+            component: {
87
+              name: 'com.example.MyModal'
88
+            }
89
+          }
90
+        ],
91
+        overlays: [
92
+          {
93
+            component: {
94
+              name: 'com.example.MyOverlay'
95
+            }
96
+          }
97
+        ]
98
+      });
99
+      expect(mockCommandsSender.setRoot).toHaveBeenCalledTimes(1);
100
+      expect(mockCommandsSender.setRoot).toHaveBeenCalledWith('setRoot+UNIQUE_ID', {
101
+        root:
102
+          {
103
+            type: 'Component',
104
+            id: 'Component+UNIQUE_ID',
105
+            children: [],
106
+            data: {
107
+              name: 'com.example.MyScreen',
108
+              options: {}
109
+            }
110
+          },
111
+        modals: [
112
+          {
113
+            type: 'Component',
114
+            id: 'Component+UNIQUE_ID',
115
+            children: [],
116
+            data: {
117
+              name: 'com.example.MyModal',
118
+              options: {}
119
+            }
120
+          }
121
+        ],
122
+        overlays: [
123
+          {
124
+            type: 'Component',
125
+            id: 'Component+UNIQUE_ID',
126
+            children: [],
127
+            data: {
128
+              name: 'com.example.MyOverlay',
129
+              options: {}
130
+            }
131
+          }
132
+        ]
133
+      });
134
+    });
70
   });
135
   });
71
 
136
 
72
   describe('mergeOptions', () => {
137
   describe('mergeOptions', () => {
352
 
417
 
353
     it('notify on all commands', () => {
418
     it('notify on all commands', () => {
354
       _.forEach(getAllMethodsOfUut(), (m) => {
419
       _.forEach(getAllMethodsOfUut(), (m) => {
355
-        uut[m]();
420
+        uut[m]({});
356
       });
421
       });
357
       expect(cb).toHaveBeenCalledTimes(getAllMethodsOfUut().length);
422
       expect(cb).toHaveBeenCalledTimes(getAllMethodsOfUut().length);
358
     });
423
     });
374
         dismissOverlay: ['id'],
439
         dismissOverlay: ['id'],
375
       };
440
       };
376
       const paramsForMethodName = {
441
       const paramsForMethodName = {
377
-        setRoot: { commandId: 'setRoot+UNIQUE_ID', layout: 'parsed' },
442
+        setRoot: { commandId: 'setRoot+UNIQUE_ID', layout: { root: 'parsed', modals: [], overlays: [] } },
378
         setDefaultOptions: { options: {} },
443
         setDefaultOptions: { options: {} },
379
         mergeOptions: { componentId: 'id', options: {} },
444
         mergeOptions: { componentId: 'id', options: {} },
380
         showModal: { commandId: 'showModal+UNIQUE_ID', layout: 'parsed' },
445
         showModal: { commandId: 'showModal+UNIQUE_ID', layout: 'parsed' },
381
         dismissModal: { commandId: 'dismissModal+UNIQUE_ID', componentId: 'id' },
446
         dismissModal: { commandId: 'dismissModal+UNIQUE_ID', componentId: 'id' },
382
-        dismissAllModals: {commandId: 'dismissAllModals+UNIQUE_ID'},
447
+        dismissAllModals: { commandId: 'dismissAllModals+UNIQUE_ID' },
383
         push: { commandId: 'push+UNIQUE_ID', componentId: 'id', layout: 'parsed' },
448
         push: { commandId: 'push+UNIQUE_ID', componentId: 'id', layout: 'parsed' },
384
         pop: { commandId: 'pop+UNIQUE_ID', componentId: 'id', options: {} },
449
         pop: { commandId: 'pop+UNIQUE_ID', componentId: 'id', options: {} },
385
         popTo: { commandId: 'popTo+UNIQUE_ID', componentId: 'id' },
450
         popTo: { commandId: 'popTo+UNIQUE_ID', componentId: 'id' },

+ 16
- 4
lib/src/commands/Commands.ts Целия файл

14
 
14
 
15
   public setRoot(simpleApi) {
15
   public setRoot(simpleApi) {
16
     const input = _.cloneDeep(simpleApi);
16
     const input = _.cloneDeep(simpleApi);
17
-    const layout = this.layoutTreeParser.parse(input);
18
-    this.layoutTreeCrawler.crawl(layout);
17
+    const root = this.layoutTreeParser.parse(input.root);
18
+    this.layoutTreeCrawler.crawl(root);
19
+
20
+    const modals = _.map(input.modals, (modal) => {
21
+      const modalLayout = this.layoutTreeParser.parse(modal);
22
+      this.layoutTreeCrawler.crawl(modalLayout);
23
+      return modalLayout;
24
+    });
25
+
26
+    const overlays = _.map(input.overlays, (overlay) => {
27
+      const overlayLayout = this.layoutTreeParser.parse(overlay);
28
+      this.layoutTreeCrawler.crawl(overlayLayout);
29
+      return overlayLayout;
30
+    });
19
 
31
 
20
     const commandId = this.uniqueIdProvider.generate('setRoot');
32
     const commandId = this.uniqueIdProvider.generate('setRoot');
21
-    const result = this.nativeCommandsSender.setRoot(commandId, layout);
22
-    this.commandsObserver.notify('setRoot', { commandId, layout });
33
+    const result = this.nativeCommandsSender.setRoot(commandId, { root, modals, overlays });
34
+    this.commandsObserver.notify('setRoot', { commandId, layout: { root, modals, overlays } });
23
     return result;
35
     return result;
24
   }
36
   }
25
 
37
 

+ 10
- 8
playground/src/app.js Целия файл

149
     });
149
     });
150
 
150
 
151
     Navigation.setRoot({
151
     Navigation.setRoot({
152
-      stack: {
153
-        id: 'TEST',
154
-        children: [
155
-          {
156
-            component: {
157
-              name: 'navigation.playground.WelcomeScreen'
152
+      root: {
153
+        stack: {
154
+          id: 'TEST',
155
+          children: [
156
+            {
157
+              component: {
158
+                name: 'navigation.playground.WelcomeScreen'
159
+              }
158
             }
160
             }
159
-          }
160
-        ]
161
+          ]
162
+        }
161
       }
163
       }
162
     });
164
     });
163
   });
165
   });

+ 133
- 129
playground/src/screens/WelcomeScreen.js Целия файл

46
 
46
 
47
   onClickSwitchToTabs = () => {
47
   onClickSwitchToTabs = () => {
48
     Navigation.setRoot({
48
     Navigation.setRoot({
49
-      bottomTabs: {
50
-        children: [
51
-          {
52
-            stack: {
53
-              id: 'TAB1_ID',
54
-              children: [
55
-                {
56
-                  component: {
57
-                    name: 'navigation.playground.TextScreen',
58
-                    passProps: {
59
-                      text: 'This is tab 1',
60
-                      myFunction: () => 'Hello from a function!'
61
-                    },
62
-                    options: {
63
-                      topBar: {
64
-                        visible: true,
65
-                        title: {
66
-                          text: 'React Native Navigation!'
49
+      root: {
50
+        bottomTabs: {
51
+          children: [
52
+            {
53
+              stack: {
54
+                id: 'TAB1_ID',
55
+                children: [
56
+                  {
57
+                    component: {
58
+                      name: 'navigation.playground.TextScreen',
59
+                      passProps: {
60
+                        text: 'This is tab 1',
61
+                        myFunction: () => 'Hello from a function!'
62
+                      },
63
+                      options: {
64
+                        topBar: {
65
+                          visible: true,
66
+                          title: {
67
+                            text: 'React Native Navigation!'
68
+                          }
67
                         }
69
                         }
68
                       }
70
                       }
69
                     }
71
                     }
70
                   }
72
                   }
71
-                }
72
-              ],
73
-              options: {
74
-                bottomTab: {
75
-                  title: 'Tab 1',
76
-                  icon: require('../images/one.png'),
77
-                  testID: testIDs.FIRST_TAB_BAR_BUTTON
78
-                },
79
-                topBar: {
80
-                  visible: false
73
+                ],
74
+                options: {
75
+                  bottomTab: {
76
+                    title: 'Tab 1',
77
+                    icon: require('../images/one.png'),
78
+                    testID: testIDs.FIRST_TAB_BAR_BUTTON
79
+                  },
80
+                  topBar: {
81
+                    visible: false
82
+                  }
81
                 }
83
                 }
82
               }
84
               }
83
-            }
84
-          },
85
-          {
86
-            stack: {
87
-              children: [
88
-                {
89
-                  component: {
90
-                    name: 'navigation.playground.TextScreen',
91
-                    passProps: {
92
-                      text: 'This is tab 2'
85
+            },
86
+            {
87
+              stack: {
88
+                children: [
89
+                  {
90
+                    component: {
91
+                      name: 'navigation.playground.TextScreen',
92
+                      passProps: {
93
+                        text: 'This is tab 2'
94
+                      }
93
                     }
95
                     }
94
                   }
96
                   }
95
-                }
96
-              ],
97
-              options: {
98
-                bottomTab: {
99
-                  title: 'Tab 2',
100
-                  icon: require('../images/two.png'),
101
-                  testID: testIDs.SECOND_TAB_BAR_BUTTON
97
+                ],
98
+                options: {
99
+                  bottomTab: {
100
+                    title: 'Tab 2',
101
+                    icon: require('../images/two.png'),
102
+                    testID: testIDs.SECOND_TAB_BAR_BUTTON
103
+                  }
102
                 }
104
                 }
103
               }
105
               }
104
             }
106
             }
105
-          }
106
-        ],
107
-        options: {
108
-          bottomTabs: {
109
-            tabColor: 'red',
110
-            selectedTabColor: 'blue',
111
-            fontFamily: 'HelveticaNeue-Italic',
112
-            fontSize: 13,
113
-            testID: testIDs.BOTTOM_TABS_ELEMENT
107
+          ],
108
+          options: {
109
+            bottomTabs: {
110
+              tabColor: 'red',
111
+              selectedTabColor: 'blue',
112
+              fontFamily: 'HelveticaNeue-Italic',
113
+              fontSize: 13,
114
+              testID: testIDs.BOTTOM_TABS_ELEMENT
115
+            }
114
           }
116
           }
115
         }
117
         }
116
       }
118
       }
119
 
121
 
120
   onClickSwitchToSideMenus = () => {
122
   onClickSwitchToSideMenus = () => {
121
     Navigation.setRoot({
123
     Navigation.setRoot({
122
-      sideMenu: {
123
-        left: {
124
-          component: {
125
-            name: 'navigation.playground.SideMenuScreen',
126
-            passProps: {
127
-              side: 'left'
124
+      root: {
125
+        sideMenu: {
126
+          left: {
127
+            component: {
128
+              name: 'navigation.playground.SideMenuScreen',
129
+              passProps: {
130
+                side: 'left'
131
+              }
128
             }
132
             }
129
-          }
130
-        },
131
-        center: {
132
-          bottomTabs: {
133
-            children: [
134
-              {
135
-                stack: {
136
-                  children: [
137
-                    {
138
-                      component: {
139
-                        name: 'navigation.playground.TextScreen',
140
-                        passProps: {
141
-                          text: 'This is a side menu center screen tab 1'
133
+          },
134
+          center: {
135
+            bottomTabs: {
136
+              children: [
137
+                {
138
+                  stack: {
139
+                    children: [
140
+                      {
141
+                        component: {
142
+                          name: 'navigation.playground.TextScreen',
143
+                          passProps: {
144
+                            text: 'This is a side menu center screen tab 1'
145
+                          }
142
                         }
146
                         }
143
                       }
147
                       }
144
-                    }
145
-                  ],
146
-                  options: {
147
-                    bottomTab: {
148
-                      title: 'Tab 1',
149
-                      icon: require('../images/one.png'),
150
-                      testID: testIDs.FIRST_TAB_BAR_BUTTON
148
+                    ],
149
+                    options: {
150
+                      bottomTab: {
151
+                        title: 'Tab 1',
152
+                        icon: require('../images/one.png'),
153
+                        testID: testIDs.FIRST_TAB_BAR_BUTTON
154
+                      }
151
                     }
155
                     }
152
                   }
156
                   }
153
-                }
154
-              },
155
-              {
156
-                stack: {
157
-                  children: [
158
-                    {
159
-                      component: {
160
-                        name: 'navigation.playground.TextScreen',
161
-                        passProps: {
162
-                          text: 'This is a side menu center screen tab 2'
157
+                },
158
+                {
159
+                  stack: {
160
+                    children: [
161
+                      {
162
+                        component: {
163
+                          name: 'navigation.playground.TextScreen',
164
+                          passProps: {
165
+                            text: 'This is a side menu center screen tab 2'
166
+                          }
163
                         }
167
                         }
164
                       }
168
                       }
165
-                    }
166
-                  ],
167
-                  options: {
168
-                    bottomTab: {
169
-                      title: 'Tab 2',
170
-                      icon: require('../images/two.png'),
171
-                      testID: testIDs.SECOND_TAB_BAR_BUTTON
169
+                    ],
170
+                    options: {
171
+                      bottomTab: {
172
+                        title: 'Tab 2',
173
+                        icon: require('../images/two.png'),
174
+                        testID: testIDs.SECOND_TAB_BAR_BUTTON
175
+                      }
172
                     }
176
                     }
173
                   }
177
                   }
174
-                }
175
-              },
176
-              {
177
-                stack: {
178
-                  children: [
179
-                    {
180
-                      component: {
181
-                        name: 'navigation.playground.TextScreen',
182
-                        passProps: {
183
-                          text: 'This is a side menu center screen tab 3'
178
+                },
179
+                {
180
+                  stack: {
181
+                    children: [
182
+                      {
183
+                        component: {
184
+                          name: 'navigation.playground.TextScreen',
185
+                          passProps: {
186
+                            text: 'This is a side menu center screen tab 3'
187
+                          }
184
                         }
188
                         }
185
                       }
189
                       }
186
-                    }
187
-                  ],
188
-                  options: {
189
-                    bottomTab: {
190
-                      title: 'Tab 3',
191
-                      icon: require('../images/three.png'),
192
-                      testID: testIDs.SECOND_TAB_BAR_BUTTON
190
+                    ],
191
+                    options: {
192
+                      bottomTab: {
193
+                        title: 'Tab 3',
194
+                        icon: require('../images/three.png'),
195
+                        testID: testIDs.SECOND_TAB_BAR_BUTTON
196
+                      }
193
                     }
197
                     }
194
                   }
198
                   }
195
                 }
199
                 }
196
-              }
197
-            ],
198
-            options: {
199
-              bottomTabs: {
200
-                tabColor: 'red',
201
-                selectedTabColor: 'blue',
202
-                fontFamily: 'HelveticaNeue-Italic',
203
-                fontSize: 13
200
+              ],
201
+              options: {
202
+                bottomTabs: {
203
+                  tabColor: 'red',
204
+                  selectedTabColor: 'blue',
205
+                  fontFamily: 'HelveticaNeue-Italic',
206
+                  fontSize: 13
207
+                }
204
               }
208
               }
205
             }
209
             }
206
-          }
207
-        },
208
-        right: {
209
-          component: {
210
-            name: 'navigation.playground.SideMenuScreen',
211
-            passProps: {
212
-              side: 'right'
210
+          },
211
+          right: {
212
+            component: {
213
+              name: 'navigation.playground.SideMenuScreen',
214
+              passProps: {
215
+                side: 'right'
216
+              }
213
             }
217
             }
214
           }
218
           }
215
         }
219
         }