Просмотр исходного кода

Tab bar items (#2345)

* tabBarItem support

* apply tab items on tabController initialization

* e2e test

* refactored bottomTab item

* tests fix

* tabItem testID fix

* renamed tabBadge to badge

* fix merge

* BottomTab fix

* removed BottomTabs
yogevbd 6 лет назад
Родитель
Сommit
2885c8d767
No account linked to committer's email address
32 измененных файлов: 196 добавлений и 86 удалений
  1. 1
    1
      docs/_sidebar.md
  2. 0
    8
      docs/docs/BottomTabs.md
  3. 1
    0
      docs/docs/Container.md
  4. 1
    1
      docs/docs/Root.md
  5. 12
    0
      docs/docs/options/BottomTab.md
  6. 0
    1
      docs/docs/options/BottomTabs.md
  7. 1
    0
      docs/docs/options/NavigationOptions.md
  8. 6
    0
      e2e/ScreenStyle.test.js
  9. 2
    2
      lib/ios/RNNControllerFactory.m
  10. 5
    0
      lib/ios/RNNNavigationOptions.h
  11. 31
    9
      lib/ios/RNNNavigationOptions.m
  12. 1
    0
      lib/ios/RNNRootViewController.h
  13. 5
    1
      lib/ios/RNNRootViewController.m
  14. 0
    1
      lib/ios/RNNTabBarOptions.h
  15. 0
    1
      lib/ios/RNNTabBarOptions.m
  16. 18
    0
      lib/ios/RNNTabItemOptions.h
  17. 32
    0
      lib/ios/RNNTabItemOptions.m
  18. 8
    0
      lib/ios/ReactNativeNavigation.xcodeproj/project.pbxproj
  19. 1
    1
      lib/ios/ReactNativeNavigationTests/RNNRootViewControllerTest.m
  20. 0
    17
      lib/src/params/containers/BottomTabs.js
  21. 0
    34
      lib/src/params/containers/BottomTabs.test.js
  22. 2
    0
      lib/src/params/containers/Container.js
  23. 5
    3
      lib/src/params/containers/Root.js
  24. 23
    0
      lib/src/params/options/BottomTab.js
  25. 18
    0
      lib/src/params/options/BottomTab.test.js
  26. 0
    2
      lib/src/params/options/BottomTabs.js
  27. 0
    2
      lib/src/params/options/BottomTabs.test.js
  28. 3
    0
      lib/src/params/options/NavigationOptions.js
  29. 4
    0
      lib/src/params/options/NavigationOptions.test.js
  30. 2
    2
      playground/src/containers/TextScreen.js
  31. 12
    0
      playground/src/containers/WelcomeScreen.js
  32. 2
    0
      playground/src/testIDs.js

+ 1
- 1
docs/_sidebar.md Просмотреть файл

@@ -8,9 +8,9 @@
8 8
  - [Root](/docs/Root)
9 9
  - [Container](/docs/Container)
10 10
  - [SideMenu](/docs/SideMenu)
11
- - [BottomTabs](/docs/BottomTabs)
12 11
 - Options
13 12
  - [NavigationOptions](/docs/options/NavigationOptions)
14 13
  - [TopBar](/docs/options/TopBar)
15 14
  - [Button](/docs/options/Button)
16 15
  - [BottomTabs](/docs/options/BottomTabs)
16
+ - [BottomTab](/docs/options/BottomTab)

+ 0
- 8
docs/docs/BottomTabs.md Просмотреть файл

@@ -1,8 +0,0 @@
1
-<h1>BottomTabs</h1>
2
-
3
-**Properties**
4
-
5
-| Name | Type |
6
-| --- | --- |
7
-| tabs | <a href="https://wix.github.io/react-native-navigation/v2/#/docs/Container">Container[]</a> | 
8
-

+ 1
- 0
docs/docs/Container.md Просмотреть файл

@@ -6,4 +6,5 @@
6 6
 | --- | --- | --- |
7 7
 | name | <code>string</code> | The container's registered name |
8 8
 | passProps | <code>object</code> | props |
9
+| navigationOptions | <a href="https://wix.github.io/react-native-navigation/v2/#/docs/NavigationOptions">NavigationOptions</a> |  |
9 10
 

+ 1
- 1
docs/docs/Root.md Просмотреть файл

@@ -6,5 +6,5 @@
6 6
 | --- | --- |
7 7
 | container | <a href="https://wix.github.io/react-native-navigation/v2/#/docs/Container">Container</a> | 
8 8
 | sideMenu | <a href="https://wix.github.io/react-native-navigation/v2/#/docs/SideMenu">SideMenu</a> | 
9
-| bottomTabs | <a href="https://wix.github.io/react-native-navigation/v2/#/docs/BottomTabs">BottomTabs</a> | 
9
+| bottomTabs | <a href="https://wix.github.io/react-native-navigation/v2/#/docs/Container">Container[]</a> | 
10 10
 

+ 12
- 0
docs/docs/options/BottomTab.md Просмотреть файл

@@ -0,0 +1,12 @@
1
+<h1>BottomTab</h1>
2
+
3
+**Properties**
4
+
5
+| Name | Type |
6
+| --- | --- |
7
+| title | <code>string</code> | 
8
+| tag | <code>number</code> | 
9
+| icon | <code>object</code> | 
10
+| visible | <code>boolean</code> | 
11
+| badge | <code>string</code> | 
12
+

+ 0
- 1
docs/docs/options/BottomTabs.md Просмотреть файл

@@ -6,7 +6,6 @@
6 6
 | --- | --- |
7 7
 | currentTabId | <code>string</code> | 
8 8
 | currentTabIndex | <code>number</code> | 
9
-| tabBadge | <code>number</code> | 
10 9
 | hidden | <code>boolean</code> | 
11 10
 | animateHide | <code>boolean</code> | 
12 11
 

+ 1
- 0
docs/docs/options/NavigationOptions.md Просмотреть файл

@@ -6,6 +6,7 @@
6 6
 | --- | --- |
7 7
 | topBar | <a href="https://wix.github.io/react-native-navigation/v2/#/docs/options/TopBar">TopBar</a> | 
8 8
 | bottomTabs | <a href="https://wix.github.io/react-native-navigation/v2/#/docs/options/BottomTabs">BottomTabs</a> | 
9
+| bottomTab | <a href="https://wix.github.io/react-native-navigation/v2/#/docs/options/BottomTab">BottomTab</a> | 
9 10
 | orientation | <code>string</code> | 
10 11
 | rightButtons | <a href="https://wix.github.io/react-native-navigation/v2/#/docs/options/Button">Button[]</a> | 
11 12
 | leftButtons | <a href="https://wix.github.io/react-native-navigation/v2/#/docs/options/Button">Button[]</a> | 

+ 6
- 0
e2e/ScreenStyle.test.js Просмотреть файл

@@ -104,4 +104,10 @@ describe('screen style', () => {
104 104
     await elementById(testIDs.PUSH_OPTIONS_BUTTON).tap();
105 105
     await expect(elementById('buttonLeft')).toBeVisible();
106 106
   });
107
+
108
+  it('tab bar items visibility', async () => {
109
+    await elementById(testIDs.TAB_BASED_APP_BUTTON).tap();
110
+    await expect(elementById(testIDs.FIRST_TAB_BAR_BUTTON)).toBeVisible();
111
+    await expect(elementById(testIDs.SECOND_TAB_BAR_BUTTON)).toBeVisible();
112
+  });
107 113
 });

+ 2
- 2
lib/ios/RNNControllerFactory.m Просмотреть файл

@@ -103,9 +103,9 @@
103 103
 	NSMutableArray* controllers = [NSMutableArray new];
104 104
 	for (NSDictionary *child in node.children) {
105 105
 		UIViewController* childVc = [self fromTree:child];
106
+		RNNRootViewController* rootView = (RNNRootViewController *)childVc.childViewControllers.firstObject;
107
+		[rootView applyTabBarItem];
106 108
 		
107
-		UITabBarItem* item = [[UITabBarItem alloc] initWithTitle:@"A Tab" image:nil tag:1];
108
-		[childVc setTabBarItem:item];
109 109
 		[controllers addObject:childVc];
110 110
 	}
111 111
 	[vc setViewControllers:controllers];

+ 5
- 0
lib/ios/RNNNavigationOptions.h Просмотреть файл

@@ -3,6 +3,7 @@
3 3
 #import "RNNTopBarOptions.h"
4 4
 #import "RNNTabBarOptions.h"
5 5
 #import "RNNSideMenuOptions.h"
6
+#import "RNNTabItemOptions.h"
6 7
 
7 8
 extern const NSInteger BLUR_STATUS_TAG;
8 9
 extern const NSInteger BLUR_TOPBAR_TAG;
@@ -25,6 +26,8 @@ extern const NSInteger TOP_BAR_TRANSPARENT_TAG;
25 26
 @property (nonatomic, strong) RNNSideMenuOptions* sideMenu;
26 27
 @property (nonatomic, strong) UIImage* backgroundImage;
27 28
 @property (nonatomic, strong) UIImage* rootBackgroundImage;
29
+@property (nonatomic, strong) RNNTabItemOptions* tabItem;
30
+
28 31
 
29 32
 - (UIInterfaceOrientationMask)supportedOrientations;
30 33
 
@@ -35,4 +38,6 @@ extern const NSInteger TOP_BAR_TRANSPARENT_TAG;
35 38
 -(void)mergeWith:(NSDictionary*)otherOptions;
36 39
 -(void)storeOriginalTopBarImages:(UIViewController*)viewController;
37 40
 
41
+- (void)applyTabBarItemOptions:(UIViewController*)viewController;
42
+
38 43
 @end

+ 31
- 9
lib/ios/RNNNavigationOptions.m Просмотреть файл

@@ -30,7 +30,8 @@ const NSInteger TOP_BAR_TRANSPARENT_TAG = 78264803;
30 30
 	self.sideMenu = [[RNNSideMenuOptions alloc] initWithDict:[navigationOptions objectForKey:@"sideMenu"]];
31 31
 	self.backgroundImage = [RCTConvert UIImage:[navigationOptions objectForKey:@"backgroundImage"]];
32 32
 	self.rootBackgroundImage = [RCTConvert UIImage:[navigationOptions objectForKey:@"rootBackgroundImage"]];
33
-
33
+	self.tabItem = [[RNNTabItemOptions alloc] initWithDict:[navigationOptions objectForKey:@"bottomTab"]];
34
+    
34 35
 	return self;
35 36
 }
36 37
 
@@ -42,6 +43,8 @@ const NSInteger TOP_BAR_TRANSPARENT_TAG = 78264803;
42 43
 			[self.bottomTabs mergeWith:[otherOptions objectForKey:key]];
43 44
 		} else if ([key isEqualToString:@"sideMenu"]) {
44 45
 			[self.sideMenu mergeWith:[otherOptions objectForKey:@"sideMenu"]];
46
+		} else if ([key isEqualToString:@"bottomTab"]) {
47
+			[self.tabItem mergeWith:[otherOptions objectForKey:key]];
45 48
 		} else {
46 49
 			[self setValue:[otherOptions objectForKey:key] forKey:key];
47 50
 		}
@@ -195,14 +198,6 @@ const NSInteger TOP_BAR_TRANSPARENT_TAG = 78264803;
195 198
 	}
196 199
 	
197 200
 	if (self.bottomTabs) {
198
-		if (self.bottomTabs.tabBadge) {
199
-			NSString *badge = [RCTConvert NSString:self.bottomTabs.tabBadge];
200
-			if (viewController.navigationController) {
201
-				viewController.navigationController.tabBarItem.badgeValue = badge;
202
-			} else {
203
-				viewController.tabBarItem.badgeValue = badge;
204
-			}
205
-		}
206 201
 		if (self.bottomTabs.currentTabIndex) {
207 202
 			[viewController.tabBarController setSelectedIndex:[self.bottomTabs.currentTabIndex unsignedIntegerValue]];
208 203
 		}
@@ -283,6 +278,33 @@ const NSInteger TOP_BAR_TRANSPARENT_TAG = 78264803;
283 278
 		backgroundImageView.image = self.rootBackgroundImage;
284 279
 		[backgroundImageView setContentMode:UIViewContentModeScaleAspectFill];
285 280
 	}
281
+	
282
+	[self applyTabBarItemOptions:viewController];
283
+}
284
+
285
+- (void)applyTabBarItemOptions:(UIViewController*)viewController {
286
+	if (self.tabItem) {
287
+		if (self.tabItem.title || self.tabItem.icon) {
288
+			UITabBarItem* tabItem = [[UITabBarItem alloc] initWithTitle:self.tabItem.title image:[RCTConvert UIImage:self.tabItem.icon] tag:self.tabItem.tag];
289
+			tabItem.accessibilityIdentifier = self.tabItem.testID;
290
+			[viewController.navigationController setTabBarItem:tabItem];
291
+		}
292
+		
293
+		if (self.tabItem.badge) {
294
+			NSString *badge = [RCTConvert NSString:self.tabItem.badge];
295
+			if (viewController.navigationController) {
296
+				viewController.navigationController.tabBarItem.badgeValue = badge;
297
+			} else {
298
+				viewController.tabBarItem.badgeValue = badge;
299
+			}
300
+		}
301
+		
302
+		if (self.tabItem.visible) {
303
+			[viewController.tabBarController setSelectedIndex:[viewController.tabBarController.viewControllers indexOfObject:viewController]];
304
+		}
305
+		
306
+		[self.tabItem resetOptions];
307
+	}
286 308
 }
287 309
 
288 310
 - (UIInterfaceOrientationMask)supportedOrientations {

+ 1
- 0
lib/ios/RNNRootViewController.h Просмотреть файл

@@ -23,5 +23,6 @@
23 23
 
24 24
 -(void)applyNavigationButtons;
25 25
 -(BOOL)isAnimated;
26
+-(void)applyTabBarItem;
26 27
 
27 28
 @end

+ 5
- 1
lib/ios/RNNRootViewController.m Просмотреть файл

@@ -108,10 +108,14 @@
108 108
 
109 109
 
110 110
 
111
--(void) applyNavigationButtons{
111
+-(void)applyNavigationButtons{
112 112
 	[self.navigationButtons applyLeftButtons:self.navigationOptions.leftButtons rightButtons:self.navigationOptions.rightButtons];
113 113
 }
114 114
 
115
+-(void)applyTabBarItem {
116
+	[self.navigationOptions applyTabBarItemOptions:self];
117
+}
118
+
115 119
 /**
116 120
  *	fix for #877, #878
117 121
  */

+ 0
- 1
lib/ios/RNNTabBarOptions.h Просмотреть файл

@@ -6,7 +6,6 @@ extern const NSInteger BLUR_TOPBAR_TAG;
6 6
 
7 7
 @property (nonatomic, strong) NSNumber* hidden;
8 8
 @property (nonatomic, strong) NSNumber* animateHide;
9
-@property (nonatomic, strong) NSString* tabBadge;
10 9
 @property (nonatomic, strong) NSNumber* currentTabIndex;
11 10
 @property (nonatomic, strong) NSString* testID;
12 11
 @property (nonatomic, strong) NSNumber* drawUnder;

+ 0
- 1
lib/ios/RNNTabBarOptions.m Просмотреть файл

@@ -11,7 +11,6 @@
11 11
 	
12 12
 	self.hidden = [tabBarOptions valueForKey:@"hidden"];
13 13
 	self.animateHide = [tabBarOptions valueForKey:@"animateHide"];
14
-	self.tabBadge = [tabBarOptions valueForKey:@"tabBadge"];
15 14
 	self.currentTabIndex = [tabBarOptions valueForKey:@"currentTabIndex"];
16 15
 	self.testID = [tabBarOptions valueForKey:@"testID"];
17 16
 	

+ 18
- 0
lib/ios/RNNTabItemOptions.h Просмотреть файл

@@ -0,0 +1,18 @@
1
+#import <Foundation/Foundation.h>
2
+
3
+@interface RNNTabItemOptions : NSObject
4
+
5
+@property (nonatomic) NSUInteger tag;
6
+@property (nonatomic, strong) NSString* title;
7
+@property (nonatomic, strong) NSString* badge;
8
+@property (nonatomic, strong) NSString* testID;
9
+@property (nonatomic, strong) NSNumber* visible;
10
+@property (nonatomic, strong) NSDictionary* icon;
11
+
12
+-(instancetype)initWithDict:(NSDictionary*)tabItemDict;
13
+
14
+-(void)mergeWith:(NSDictionary *)otherOptions;
15
+
16
+-(void)resetOptions;
17
+
18
+@end

+ 32
- 0
lib/ios/RNNTabItemOptions.m Просмотреть файл

@@ -0,0 +1,32 @@
1
+#import "RNNTabItemOptions.h"
2
+
3
+@implementation RNNTabItemOptions
4
+
5
+-(instancetype)initWithDict:(NSDictionary *)tabItemDict {
6
+	self = [super init];
7
+	
8
+	self.title = tabItemDict[@"title"];
9
+	self.tag = [tabItemDict[@"tag"] integerValue];
10
+	self.badge = tabItemDict[@"badge"];
11
+	self.testID = tabItemDict[@"testID"];
12
+	self.visible = tabItemDict[@"visible"];
13
+	self.icon = tabItemDict[@"icon"];
14
+	
15
+	return self;
16
+}
17
+
18
+-(void)mergeWith:(NSDictionary *)otherOptions {
19
+	for (id key in otherOptions) {
20
+		[self setValue:[otherOptions objectForKey:key] forKey:key];
21
+	}
22
+}
23
+
24
+-(void)resetOptions {
25
+	self.title = nil;
26
+	self.badge = nil;
27
+	self.visible = nil;
28
+	self.icon = nil;
29
+	self.testID = nil;
30
+}
31
+
32
+@end

+ 8
- 0
lib/ios/ReactNativeNavigation.xcodeproj/project.pbxproj Просмотреть файл

@@ -59,6 +59,8 @@
59 59
 		26916C991E4B9E7700D13680 /* RNNReactRootViewCreator.m in Sources */ = {isa = PBXBuildFile; fileRef = 26916C971E4B9E7700D13680 /* RNNReactRootViewCreator.m */; };
60 60
 		50CB3B691FDE911400AA153B /* RNNSideMenuOptions.h in Headers */ = {isa = PBXBuildFile; fileRef = 50CB3B671FDE911400AA153B /* RNNSideMenuOptions.h */; };
61 61
 		50CB3B6A1FDE911400AA153B /* RNNSideMenuOptions.m in Sources */ = {isa = PBXBuildFile; fileRef = 50CB3B681FDE911400AA153B /* RNNSideMenuOptions.m */; };
62
+		50EB93411FE14A3E00BD8EEE /* RNNTabItemOptions.h in Headers */ = {isa = PBXBuildFile; fileRef = 50EB933F1FE14A3E00BD8EEE /* RNNTabItemOptions.h */; };
63
+		50EB93421FE14A3E00BD8EEE /* RNNTabItemOptions.m in Sources */ = {isa = PBXBuildFile; fileRef = 50EB93401FE14A3E00BD8EEE /* RNNTabItemOptions.m */; };
62 64
 		50F5DFC11F407A8C001A00BC /* RNNTabBarController.h in Headers */ = {isa = PBXBuildFile; fileRef = 50F5DFBF1F407A8C001A00BC /* RNNTabBarController.h */; };
63 65
 		50F5DFC21F407A8C001A00BC /* RNNTabBarController.m in Sources */ = {isa = PBXBuildFile; fileRef = 50F5DFC01F407A8C001A00BC /* RNNTabBarController.m */; };
64 66
 		50F5DFC51F407AA0001A00BC /* RNNNavigationController.h in Headers */ = {isa = PBXBuildFile; fileRef = 50F5DFC31F407AA0001A00BC /* RNNNavigationController.h */; };
@@ -207,6 +209,8 @@
207 209
 		26916C971E4B9E7700D13680 /* RNNReactRootViewCreator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNNReactRootViewCreator.m; sourceTree = "<group>"; };
208 210
 		50CB3B671FDE911400AA153B /* RNNSideMenuOptions.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNNSideMenuOptions.h; sourceTree = "<group>"; };
209 211
 		50CB3B681FDE911400AA153B /* RNNSideMenuOptions.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNNSideMenuOptions.m; sourceTree = "<group>"; };
212
+		50EB933F1FE14A3E00BD8EEE /* RNNTabItemOptions.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNNTabItemOptions.h; sourceTree = "<group>"; };
213
+		50EB93401FE14A3E00BD8EEE /* RNNTabItemOptions.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNNTabItemOptions.m; sourceTree = "<group>"; };
210 214
 		50F5DFBF1F407A8C001A00BC /* RNNTabBarController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNNTabBarController.h; sourceTree = "<group>"; };
211 215
 		50F5DFC01F407A8C001A00BC /* RNNTabBarController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNNTabBarController.m; sourceTree = "<group>"; };
212 216
 		50F5DFC31F407AA0001A00BC /* RNNNavigationController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNNNavigationController.h; sourceTree = "<group>"; };
@@ -426,6 +430,8 @@
426 430
 				21B85E5C1F44480200B314B5 /* RNNNavigationButtons.m */,
427 431
 				214545261F4DC164006E8DA1 /* RNNUIBarButtonItem.h */,
428 432
 				214545241F4DC125006E8DA1 /* RNNUIBarButtonItem.m */,
433
+				50EB933F1FE14A3E00BD8EEE /* RNNTabItemOptions.h */,
434
+				50EB93401FE14A3E00BD8EEE /* RNNTabItemOptions.m */,
429 435
 				A7626BFE1FC2FB6700492FB8 /* RNNTopBarOptions.h */,
430 436
 				A7626BFC1FC2FB2C00492FB8 /* RNNTopBarOptions.m */,
431 437
 				A7626BFF1FC578AB00492FB8 /* RNNTabBarOptions.h */,
@@ -603,6 +609,7 @@
603 609
 				E8E518321F83B3E0000467AC /* RNNUtils.h in Headers */,
604 610
 				263905CA1E4C6F440023D7D3 /* SidebarLuvocracyAnimation.h in Headers */,
605 611
 				263905B11E4C6F440023D7D3 /* MMDrawerController.h in Headers */,
612
+				50EB93411FE14A3E00BD8EEE /* RNNTabItemOptions.h in Headers */,
606 613
 				263905B91E4C6F440023D7D3 /* RCCDrawerController.h in Headers */,
607 614
 				263905B31E4C6F440023D7D3 /* MMDrawerVisualState.h in Headers */,
608 615
 				E8A5CD621F49114F00E89D0D /* RNNElement.h in Headers */,
@@ -757,6 +764,7 @@
757 764
 				263905CD1E4C6F440023D7D3 /* SidebarWunderlistAnimation.m in Sources */,
758 765
 				263905CF1E4C6F440023D7D3 /* TheSidebarController.m in Sources */,
759 766
 				E8A430121F9CB87B00B61A20 /* RNNAnimatedView.m in Sources */,
767
+				50EB93421FE14A3E00BD8EEE /* RNNTabItemOptions.m in Sources */,
760 768
 				E8367B811F7A8A4700675C05 /* VICMAImageView.m in Sources */,
761 769
 				A7626C011FC5796200492FB8 /* RNNTabBarOptions.m in Sources */,
762 770
 				263905AF1E4C6F440023D7D3 /* MMDrawerBarButtonItem.m in Sources */,

+ 1
- 1
lib/ios/ReactNativeNavigationTests/RNNRootViewControllerTest.m Просмотреть файл

@@ -174,7 +174,7 @@
174 174
 
175 175
 -(void)testTabBadge {
176 176
 	NSString* tabBadgeInput = @"5";
177
-	self.options.bottomTabs.tabBadge = tabBadgeInput;
177
+	self.options.tabItem.badge = tabBadgeInput;
178 178
 	__unused RNNTabBarController* vc = [[RNNTabBarController alloc] init];
179 179
 	NSMutableArray* controllers = [NSMutableArray new];
180 180
 	UITabBarItem* item = [[UITabBarItem alloc] initWithTitle:@"A Tab" image:nil tag:1];

+ 0
- 17
lib/src/params/containers/BottomTabs.js Просмотреть файл

@@ -1,17 +0,0 @@
1
-const { forEach } = require('lodash');
2
-const Container = require('./Container');
3
-
4
-class BottomTabs {
5
-  /**
6
-   * @property {Container[]} tabs
7
-   */
8
-  constructor(tabs) {
9
-    if (!tabs || tabs.length === 0) {
10
-      throw new Error('BottomTabs undefined');
11
-    }
12
-    this.tabs = [];
13
-    forEach(tabs, (tab) => this.tabs.push({ container: new Container(tab.container) }));
14
-  }
15
-}
16
-
17
-module.exports = BottomTabs;

+ 0
- 34
lib/src/params/containers/BottomTabs.test.js Просмотреть файл

@@ -1,34 +0,0 @@
1
-const BottomTabs = require('./BottomTabs');
2
-
3
-const TAB1 = {
4
-  container: {
5
-    name: 'navigation.playground.TextScreen',
6
-    passProps: {
7
-      text: 'This is a side menu center screen tab 2'
8
-    }
9
-  }
10
-};
11
-const TAB2 = {
12
-  container: {
13
-    name: 'navigation.playground.TextScreen',
14
-    passProps: {
15
-      text: 'This is a side menu center screen tab 1'
16
-    }
17
-  }
18
-};
19
-const TABS = [TAB1, TAB2];
20
-
21
-describe('ContainerRegistry', () => {
22
-  it('parses tabs correctly', () => {
23
-    const uut = new BottomTabs(TABS);
24
-    expect(uut.tabs.length).toBe(2);
25
-  });
26
-
27
-  it('throws if tabs are undefined', () => {
28
-    expect(() => new BottomTabs()).toThrowError('BottomTabs undefined');
29
-  });
30
-
31
-  it('throws if zero tabs', () => {
32
-    expect(() => new BottomTabs([])).toThrowError('BottomTabs undefined');
33
-  });
34
-});

+ 2
- 0
lib/src/params/containers/Container.js Просмотреть файл

@@ -2,6 +2,7 @@ class Container {
2 2
   /**
3 3
    * @property {string} name The container's registered name
4 4
    * @property {object} [passProps] props
5
+   * @property {NavigationOptions} navigationOptions
5 6
    */
6 7
   constructor(params) {
7 8
     if (!params || !params.name) {
@@ -9,6 +10,7 @@ class Container {
9 10
     }
10 11
     this.name = params.name;
11 12
     this.passProps = params.passProps;
13
+    this.navigationOptions = params.navigationOptions;
12 14
   }
13 15
 }
14 16
 

+ 5
- 3
lib/src/params/containers/Root.js Просмотреть файл

@@ -1,17 +1,19 @@
1 1
 const Container = require('./Container');
2 2
 const SideMenu = require('./SideMenu');
3
-const BottomTabs = require('./BottomTabs');
4 3
 
5 4
 class Root {
6 5
   /**
7 6
    * @property {Container} container
8 7
    * @property {SideMenu} [sideMenu]
9
-   * @property {BottomTabs} [bottomTabs]
8
+   * @property {Container[]} [bottomTabs]
10 9
    */
11 10
   constructor(root) {
12 11
     this.container = root.container && new Container(root.container);
13 12
     this.sideMenu = root.sideMenu && new SideMenu(root.sideMenu);
14
-    this.bottomTabs = root.bottomTabs && new BottomTabs(root.bottomTabs).tabs;
13
+    if (root.bottomTabs) {
14
+      root.bottomTabs.map((t) => new Container(t.container));
15
+      this.bottomTabs = root.bottomTabs;
16
+    }
15 17
   }
16 18
 }
17 19
 

+ 23
- 0
lib/src/params/options/BottomTab.js Просмотреть файл

@@ -0,0 +1,23 @@
1
+const { isEmpty } = require('lodash');
2
+
3
+class BottomTab {
4
+  /**
5
+   * @property {string} [title]
6
+   * @property {number} [tag]
7
+   * @property {object} [icon]
8
+   * @property {boolean} [visible]
9
+   * @property {string} [badge]
10
+   */
11
+  constructor(params) {
12
+    if (isEmpty(params)) {
13
+      return;
14
+    }
15
+
16
+    this.badge = params.badge;
17
+    this.title = params.title;
18
+    this.icon = params.icon;
19
+    this.visible = params.visible;
20
+  }
21
+}
22
+
23
+module.exports = BottomTab;

+ 18
- 0
lib/src/params/options/BottomTab.test.js Просмотреть файл

@@ -0,0 +1,18 @@
1
+const BottomTab = require('./BottomTab');
2
+
3
+const BOTTOM_TAB = {
4
+  title: 'title',
5
+  badge: 3,
6
+  visible: true,
7
+  icon: { uri: '' }
8
+};
9
+
10
+describe('BottomTab', () => {
11
+  it('parses BottomTab options', () => {
12
+    const uut = new BottomTab(BOTTOM_TAB);
13
+    expect(uut.title).toEqual('title');
14
+    expect(uut.badge).toEqual(3);
15
+    expect(uut.visible).toEqual(true);
16
+    expect(uut.icon).toEqual({ uri: '' });
17
+  });
18
+});

+ 0
- 2
lib/src/params/options/BottomTabs.js Просмотреть файл

@@ -4,7 +4,6 @@ class BottomTabs {
4 4
   /**
5 5
    * @property {string} [currentTabId]
6 6
    * @property {number} [currentTabIndex]
7
-   * @property {number} [tabBadge]
8 7
    * @property {boolean} [hidden]
9 8
    * @property {boolean} [animateHide]
10 9
    */
@@ -14,7 +13,6 @@ class BottomTabs {
14 13
     }
15 14
     this.currentTabId = params.currentTabId;
16 15
     this.currentTabIndex = params.currentTabIndex;
17
-    this.tabBadge = params.tabBadge;
18 16
     this.hidden = params.hidden;
19 17
     this.animateHide = params.animateHide;
20 18
   }

+ 0
- 2
lib/src/params/options/BottomTabs.test.js Просмотреть файл

@@ -3,7 +3,6 @@ const BottomTabs = require('./BottomTabs');
3 3
 const BOTTOM_TABS = {
4 4
   currentTabId: 1,
5 5
   currentTabIndex: 2,
6
-  tabBadge: 3,
7 6
   hidden: true,
8 7
   animateHide: true
9 8
 };
@@ -13,7 +12,6 @@ describe('BottomTabs', () => {
13 12
     const uut = new BottomTabs(BOTTOM_TABS);
14 13
     expect(uut.currentTabId).toEqual(1);
15 14
     expect(uut.currentTabIndex).toEqual(2);
16
-    expect(uut.tabBadge).toEqual(3);
17 15
     expect(uut.hidden).toEqual(true);
18 16
     expect(uut.animateHide).toEqual(true);
19 17
   });

+ 3
- 0
lib/src/params/options/NavigationOptions.js Просмотреть файл

@@ -1,11 +1,13 @@
1 1
 const TopBar = require('./TopBar');
2 2
 const BottomTabs = require('./BottomTabs');
3 3
 const Button = require('./Button');
4
+const BottomTab = require('./BottomTab');
4 5
 
5 6
 class NavigationOptions {
6 7
   /**
7 8
    * @property {options:TopBar} [topBar]
8 9
    * @property {options:BottomTabs} [bottomTabs]
10
+   * @property {options:BottomTab} [bottomTab]
9 11
    * @property {string} [orientation]
10 12
    * @property {options:Button[]} [rightButtons]
11 13
    * @property {options:Button[]} [leftButtons]
@@ -13,6 +15,7 @@ class NavigationOptions {
13 15
   constructor(options) {
14 16
     this.topBar = options.topBar && new TopBar(options.topBar);
15 17
     this.bottomTabs = options.bottomTabs && new BottomTabs(options.bottomTabs);
18
+    this.bottomTab = options.bottomTab && new BottomTab(options.bottomTab);
16 19
     this.orientation = options.orientation;
17 20
     this.rightButtons = options.rightButtons && options.rightButtons.map((button) => new Button(button));
18 21
     this.leftButtons = options.leftButtons && options.leftButtons.map((button) => new Button(button));

+ 4
- 0
lib/src/params/options/NavigationOptions.test.js Просмотреть файл

@@ -1,9 +1,11 @@
1 1
 const NavigationOptions = require('./NavigationOptions');
2 2
 const BottomTabs = require('./BottomTabs');
3 3
 const TopBar = require('./TopBar');
4
+const BottomTab = require('./BottomTab');
4 5
 
5 6
 const TAB_BAR = {};
6 7
 const TOP_BAR = {};
8
+const TAB_ITEM = {};
7 9
 const RIGHT_BUTTONS = [
8 10
   {
9 11
     id: 'myBtn',
@@ -23,6 +25,7 @@ const LEFT_BUTTONS = [
23 25
 const NAVIGATION_OPTIONS = {
24 26
   topBar: TOP_BAR,
25 27
   bottomTabs: TAB_BAR,
28
+  bottomTab: TAB_ITEM,
26 29
   orientation: 'portrait',
27 30
   rightButtons: RIGHT_BUTTONS,
28 31
   leftButtons: LEFT_BUTTONS
@@ -33,6 +36,7 @@ describe('NavigationOptions', () => {
33 36
     const uut = new NavigationOptions(NAVIGATION_OPTIONS);
34 37
     expect(uut.bottomTabs).toBeInstanceOf(BottomTabs);
35 38
     expect(uut.topBar).toBeInstanceOf(TopBar);
39
+    expect(uut.bottomTab).toBeInstanceOf(BottomTab);
36 40
     expect(uut.orientation).toEqual('portrait');
37 41
     expect(uut.rightButtons).toEqual(RIGHT_BUTTONS);
38 42
     expect(uut.leftButtons).toEqual(LEFT_BUTTONS);

+ 2
- 2
playground/src/containers/TextScreen.js Просмотреть файл

@@ -42,8 +42,8 @@ class TextScreen extends Component {
42 42
 
43 43
   onButtonPress() {
44 44
     Navigation.setOptions(this.props.containerId, {
45
-      bottomTabs: {
46
-        tabBadge: `TeSt`
45
+      bottomTab: {
46
+        badge: `TeSt`
47 47
       }
48 48
     });
49 49
   }

+ 12
- 0
playground/src/containers/WelcomeScreen.js Просмотреть файл

@@ -53,6 +53,12 @@ class WelcomeScreen extends Component {
53 53
             passProps: {
54 54
               text: 'This is tab 1',
55 55
               myFunction: () => 'Hello from a function!'
56
+            },
57
+            navigationOptions: {
58
+              bottomTab: {
59
+                title: 'Tab 1',
60
+                testID: testIDs.FIRST_TAB_BAR_BUTTON
61
+              }
56 62
             }
57 63
           }
58 64
         },
@@ -61,6 +67,12 @@ class WelcomeScreen extends Component {
61 67
             name: 'navigation.playground.TextScreen',
62 68
             passProps: {
63 69
               text: 'This is tab 2'
70
+            },
71
+            navigationOptions: {
72
+              bottomTab: {
73
+                title: 'Tab 2',
74
+                testID: testIDs.SECOND_TAB_BAR_BUTTON
75
+              }
64 76
             }
65 77
           }
66 78
         }

+ 2
- 0
playground/src/testIDs.js Просмотреть файл

@@ -42,6 +42,8 @@ module.exports = {
42 42
   HIDE_RIGHT_SIDE_MENU_BUTTON: `HIDE_RIGHT_SIDE_MENU_BUTTON`,
43 43
   HIDE_BOTTOM_TABS_BUTTON: `HIDE_BOTTOM_TABS_BUTTON`,
44 44
   SHOW_BOTTOM_TABS_BUTTON: `SHOW_BOTTOM_TABS_BUTTON`,
45
+  FIRST_TAB_BAR_BUTTON: `FIRST_TAB_BAR_BUTTON`,
46
+  SECOND_TAB_BAR_BUTTON: `SECOND_TAB_BAR_BUTTON`,
45 47
 
46 48
   // Elements
47 49
   SCROLLVIEW_ELEMENT: `SCROLLVIEW_ELEMENT`,