Browse Source

Allow to update props for a specific component (#5612)

This commit adds support to update props of screen or custom button/title via the mergeOptions api.

```js
Navigation.mergeOptions('myComponentId', {
  passProps: {
    text: 'new value'
  }
});
```
Tal Magen 4 years ago
parent
commit
291f16177d

+ 1
- 0
.gitignore View File

@@ -1,6 +1,7 @@
1 1
 dist
2 2
 .vscode/
3 3
 package-lock.json
4
+.history/
4 5
 
5 6
 ############
6 7
 # Node

+ 2
- 2
docs/api/Store.md View File

@@ -32,9 +32,9 @@
32 32
 
33 33
 ---
34 34
 
35
-## cleanId
35
+## clearComponent
36 36
 
37
-`cleanId(id: string): void`
37
+`clearComponent(id: string): void`
38 38
 
39 39
 [source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/components/Store.ts#L23)
40 40
 

+ 48
- 0
e2e/Buttons.test.js View File

@@ -0,0 +1,48 @@
1
+const Utils = require('./Utils');
2
+const TestIDs = require('../playground/src/testIDs');
3
+
4
+const { elementById, elementByLabel } = Utils;
5
+
6
+describe('Buttons', () => {
7
+  beforeEach(async () => {
8
+    await device.relaunchApp();
9
+    await elementById(TestIDs.OPTIONS_TAB).tap();
10
+    await elementById(TestIDs.GOTO_BUTTONS_SCREEN).tap();
11
+  });
12
+
13
+  it('sets right buttons', async () => {
14
+    await expect(elementById(TestIDs.BUTTON_ONE)).toBeVisible();
15
+    await expect(elementById(TestIDs.ROUND_BUTTON)).toBeVisible();
16
+  });
17
+
18
+  it('set left buttons', async () => {
19
+    await expect(elementById(TestIDs.LEFT_BUTTON)).toBeVisible();
20
+  });
21
+
22
+  it('pass props to custom button component', async () => {
23
+    await expect(elementByLabel('Two')).toExist();
24
+  });
25
+
26
+  it('pass props to custom button component should exist after push pop', async () => {
27
+    await expect(elementByLabel('Two')).toExist();
28
+    await elementById(TestIDs.PUSH_BTN).tap();
29
+    await elementById(TestIDs.POP_BTN).tap();
30
+    await expect(elementByLabel('Two')).toExist();
31
+  });
32
+
33
+  it('custom button is clickable', async () => {
34
+    await elementByLabel('Two').tap();
35
+    await expect(elementByLabel('Thanks for that :)')).toExist();
36
+  });
37
+
38
+  it(':ios: Reseting buttons should unmount button react view', async () => {
39
+    await elementById(TestIDs.SHOW_LIFECYCLE_BTN).tap();
40
+    await elementById(TestIDs.RESET_BUTTONS).tap();
41
+    await expect(elementByLabel('Button component unmounted')).toBeVisible();
42
+  });
43
+
44
+  it('change button props without rendering all buttons', async () => {
45
+    await elementById(TestIDs.CHANGE_BUTTON_PROPS).tap();
46
+    await expect(elementByLabel('Three')).toBeVisible();
47
+  });
48
+});

+ 0
- 31
e2e/Options.test.js View File

@@ -27,31 +27,6 @@ describe('Options', () => {
27 27
     await expect(elementById(TestIDs.TOP_BAR)).toBeVisible();
28 28
   });
29 29
 
30
-  it('sets right buttons', async () => {
31
-    await expect(elementById(TestIDs.BUTTON_ONE)).toBeVisible();
32
-    await expect(elementById(TestIDs.ROUND_BUTTON)).toBeVisible();
33
-  });
34
-
35
-  it('set left buttons', async () => {
36
-    await expect(elementById(TestIDs.LEFT_BUTTON)).toBeVisible();
37
-  });
38
-
39
-  it('pass props to custom button component', async () => {
40
-    await expect(elementByLabel('Two')).toExist();
41
-  });
42
-
43
-  it('pass props to custom button component should exist after push pop', async () => {
44
-    await expect(elementByLabel('Two')).toExist();
45
-    await elementById(TestIDs.PUSH_BTN).tap();
46
-    await elementById(TestIDs.POP_BTN).tap();
47
-    await expect(elementByLabel('Two')).toExist();
48
-  });
49
-
50
-  it('custom button is clickable', async () => {
51
-    await elementByLabel('Two').tap();
52
-    await expect(elementByLabel('Thanks for that :)')).toExist();
53
-  });
54
-
55 30
   it('default options should apply to all screens in stack', async () => {
56 31
     await elementById(TestIDs.HIDE_TOPBAR_DEFAULT_OPTIONS).tap();
57 32
     await expect(elementById(TestIDs.TOP_BAR)).toBeVisible();
@@ -88,12 +63,6 @@ describe('Options', () => {
88 63
     await expect(elementByLabel('Styling Options')).toBeVisible();
89 64
   });
90 65
 
91
-  it(':ios: Reseting buttons should unmount button react view', async () => {
92
-    await elementById(TestIDs.SHOW_LIFECYCLE_BTN).tap();
93
-    await elementById(TestIDs.RESET_BUTTONS).tap();
94
-    await expect(elementByLabel('Button component unmounted')).toBeVisible();
95
-  });
96
-
97 66
   xit('hides topBar onScroll down and shows it on scroll up', async () => {
98 67
     await elementById(TestIDs.PUSH_OPTIONS_BUTTON).tap();
99 68
     await elementById(TestIDs.SCROLLVIEW_SCREEN_BUTTON).tap();

+ 2
- 2
lib/src/commands/Commands.ts View File

@@ -55,7 +55,7 @@ export class Commands {
55 55
 
56 56
   public mergeOptions(componentId: string, options: Options) {
57 57
     const input = _.cloneDeep(options);
58
-    this.optionsProcessor.processOptions(input);
58
+    this.optionsProcessor.processOptions(input, componentId);
59 59
 
60 60
     this.nativeCommandsSender.mergeOptions(componentId, input);
61 61
     this.commandsObserver.notify('mergeOptions', { componentId, options });
@@ -64,7 +64,7 @@ export class Commands {
64 64
   public showModal(layout: Layout) {
65 65
     const layoutCloned = _.cloneDeep(layout);
66 66
     const layoutNode = this.layoutTreeParser.parse(layoutCloned);
67
-    
67
+
68 68
     const commandId = this.uniqueIdProvider.generate('showModal');
69 69
     this.commandsObserver.notify('showModal', { commandId, layout: layoutNode });
70 70
     this.layoutTreeCrawler.crawl(layoutNode);

+ 10
- 0
lib/src/commands/OptionsProcessor.test.ts View File

@@ -135,4 +135,14 @@ describe('navigation options', () => {
135 135
     expect(options.topBar.title.component.passProps).toBeUndefined();
136 136
     expect(options.topBar.background.component.passProps).toBeUndefined();
137 137
   });
138
+
139
+  it('calls store when component has passProps component id and values', () => {
140
+    const props = { prop: 'updated prop' };
141
+    const options = { passProps: props };
142
+
143
+    uut.processOptions(options, 'component1');
144
+
145
+    verify(mockedStore.setPropsForId('component1', props)).called();
146
+    expect(options.passProps).toBeUndefined();
147
+  });
138 148
 });

+ 12
- 3
lib/src/commands/OptionsProcessor.ts View File

@@ -14,17 +14,19 @@ export class OptionsProcessor {
14 14
     private assetService: AssetService,
15 15
   ) {}
16 16
 
17
-  public processOptions(options: Options) {
18
-    this.processObject(options);
17
+  public processOptions(options: Options, componentId?: string) {
18
+    this.processObject(options, componentId);
19 19
   }
20 20
 
21
-  private processObject(objectToProcess: object) {
21
+  private processObject(objectToProcess: object, componentId?: string) {
22 22
     _.forEach(objectToProcess, (value, key) => {
23 23
       this.processColor(key, value, objectToProcess);
24
+
24 25
       if (!value) {
25 26
         return;
26 27
       }
27 28
 
29
+      this.processProps(key, value, objectToProcess, componentId);
28 30
       this.processComponent(key, value, objectToProcess);
29 31
       this.processImage(key, value, objectToProcess);
30 32
       this.processButtonsPassProps(key, value);
@@ -72,4 +74,11 @@ export class OptionsProcessor {
72 74
       options[key].passProps = undefined;
73 75
     }
74 76
   }
77
+
78
+  private processProps(key: string, value: any, options: Record<string, any>, componentId?: string) {
79
+    if (key === 'passProps' && componentId && value) {
80
+      this.store.setPropsForId(componentId, value);
81
+      options[key] = undefined;
82
+    }
83
+  }
75 84
 }

+ 15
- 4
lib/src/components/ComponentWrapper.test.tsx View File

@@ -96,13 +96,18 @@ describe('ComponentWrapper', () => {
96 96
 
97 97
   it('updates props from store into inner component', () => {
98 98
     const NavigationComponent = uut.wrap(componentName, () => MyComponent, store, componentEventsObserver);
99
-    const tree = renderer.create(<TestParent ChildClass={NavigationComponent} />);
99
+    renderer.create(<TestParent ChildClass={NavigationComponent} />);
100
+    expect(myComponentProps.myProp).toEqual(undefined);
100 101
     store.setPropsForId('component1', { myProp: 'hello' });
102
+    expect(myComponentProps.myProp).toEqual('hello');
103
+  });
104
+
105
+  it('updates props from state into inner component', () => {
106
+    const NavigationComponent = uut.wrap(componentName, () => MyComponent, store, componentEventsObserver);
107
+    const tree = renderer.create(<TestParent ChildClass={NavigationComponent} />);
101 108
     expect(myComponentProps.foo).toEqual(undefined);
102
-    expect(myComponentProps.myProp).toEqual(undefined);
103 109
     (tree.getInstance() as any).setState({ propsFromState: { foo: 'yo' } });
104 110
     expect(myComponentProps.foo).toEqual('yo');
105
-    expect(myComponentProps.myProp).toEqual('hello');
106 111
   });
107 112
 
108 113
   it('protects id from change', () => {
@@ -157,6 +162,12 @@ describe('ComponentWrapper', () => {
157 162
     expect(tree.root.findByType(MyComponent).props).toEqual({componentId: 'component123'});
158 163
   });
159 164
 
165
+  it('sets component instance in store when constructed', () => {
166
+    const NavigationComponent = uut.wrap(componentName, () => MyComponent, store, componentEventsObserver);
167
+    renderer.create(<NavigationComponent componentId={'component1'} />);
168
+    expect(store.getComponentInstance('component1')).toBeTruthy();
169
+  });
170
+
160 171
   describe(`register with redux store`, () => {
161 172
     class MyReduxComp extends React.Component<any> {
162 173
       static options() {
@@ -179,7 +190,7 @@ describe('ComponentWrapper', () => {
179 190
     const ConnectedComp = require('react-redux').connect(mapStateToProps)(MyReduxComp);
180 191
     const ReduxProvider = require('react-redux').Provider;
181 192
     const initialState: RootState = { txt: 'it just works' };
182
-    const reduxStore = require('redux').createStore((state = initialState) => state);
193
+    const reduxStore = require('redux').createStore((state: RootState = initialState) => state);
183 194
 
184 195
     it(`wraps the component with a react-redux provider with passed store`, () => {
185 196
       const NavigationComponent = uut.wrap(componentName, () => ConnectedComp, store, componentEventsObserver, undefined, ReduxProvider, reduxStore);

+ 10
- 1
lib/src/components/ComponentWrapper.tsx View File

@@ -10,6 +10,10 @@ import { ComponentEventsObserver } from '../events/ComponentEventsObserver';
10 10
 interface HocState { componentId: string; allProps: {}; }
11 11
 interface HocProps { componentId: string; }
12 12
 
13
+export interface IWrappedComponent extends React.Component {
14
+  setProps(newProps: Record<string, any>): void;
15
+}
16
+
13 17
 export class ComponentWrapper {
14 18
   wrap(
15 19
     componentName: string | number,
@@ -35,10 +39,15 @@ export class ComponentWrapper {
35 39
           componentId: props.componentId,
36 40
           allProps: {}
37 41
         };
42
+        store.setComponentInstance(props.componentId, this);
43
+      }
44
+
45
+      public setProps(newProps: any) {
46
+        this.setState({allProps: newProps});
38 47
       }
39 48
 
40 49
       componentWillUnmount() {
41
-        store.cleanId(this.state.componentId);
50
+        store.clearComponent(this.state.componentId);
42 51
         componentEventsObserver.unmounted(this.state.componentId);
43 52
       }
44 53
 

+ 27
- 3
lib/src/components/Store.test.ts View File

@@ -1,5 +1,6 @@
1 1
 import * as React from 'react';
2 2
 import { Store } from './Store';
3
+import { IWrappedComponent } from './ComponentWrapper';
3 4
 
4 5
 describe('Store', () => {
5 6
   let uut: Store;
@@ -28,11 +29,34 @@ describe('Store', () => {
28 29
     expect(uut.getComponentClassForName('example.mycomponent')).toEqual(MyWrappedComponent);
29 30
   });
30 31
 
31
-  it('clean by component id', () => {
32
+  it('clear props by component id when clear component', () => {
32 33
     uut.setPropsForId('refUniqueId', { foo: 'bar' });
34
+    uut.clearComponent('refUniqueId');
35
+    expect(uut.getPropsForId('refUniqueId')).toEqual({});
36
+  });
33 37
 
34
-    uut.cleanId('refUniqueId');
38
+  it('clear instance by component id when clear component', () => {
39
+    uut.setComponentInstance('refUniqueId', ({} as IWrappedComponent));
40
+    uut.clearComponent('refUniqueId');
41
+    expect(uut.getComponentInstance('refUniqueId')).toEqual(undefined);
42
+  });
35 43
 
36
-    expect(uut.getPropsForId('refUniqueId')).toEqual({});
44
+  it('holds component instance by id', () => {
45
+    uut.setComponentInstance('component1', ({} as IWrappedComponent));
46
+    expect(uut.getComponentInstance('component1')).toEqual({});
47
+  });
48
+
49
+  it('calls component setProps when set props by id', () => {
50
+    const instance: any = {setProps: jest.fn()};
51
+    const props = { foo: 'bar' };
52
+
53
+    uut.setComponentInstance('component1', instance);
54
+    uut.setPropsForId('component1', props);
55
+
56
+    expect(instance.setProps).toHaveBeenCalledWith(props);
57
+  });
58
+
59
+  it('not throw exeption when set props by id component not found', () => {
60
+    expect(() => uut.setPropsForId('component1', { foo: 'bar' })).not.toThrow();
37 61
   });
38 62
 });

+ 17
- 1
lib/src/components/Store.ts View File

@@ -1,19 +1,27 @@
1 1
 import { ComponentProvider } from 'react-native';
2
+import { IWrappedComponent } from './ComponentWrapper';
2 3
 
3 4
 export class Store {
4 5
   private componentsByName: Record<string, ComponentProvider> = {};
5 6
   private propsById: Record<string, any> = {};
7
+  private componentsInstancesById: Record<string, IWrappedComponent> = {};
6 8
 
7 9
   setPropsForId(componentId: string, props: any) {
8 10
     this.propsById[componentId] = props;
11
+    const component = this.componentsInstancesById[componentId];
12
+
13
+    if (component) {
14
+      this.componentsInstancesById[componentId].setProps(props);
15
+    }
9 16
   }
10 17
 
11 18
   getPropsForId(componentId: string) {
12 19
     return this.propsById[componentId] || {};
13 20
   }
14 21
 
15
-  cleanId(componentId: string) {
22
+  clearComponent(componentId: string) {
16 23
     delete this.propsById[componentId];
24
+    delete this.componentsInstancesById[componentId];
17 25
   }
18 26
 
19 27
   setComponentClassForName(componentName: string | number, ComponentClass: ComponentProvider) {
@@ -23,4 +31,12 @@ export class Store {
23 31
   getComponentClassForName(componentName: string | number): ComponentProvider | undefined {
24 32
     return this.componentsByName[componentName.toString()];
25 33
   }
34
+
35
+  setComponentInstance(id: string, component: IWrappedComponent): void {
36
+    this.componentsInstancesById[id] = component;
37
+  }
38
+
39
+  getComponentInstance(id: string): IWrappedComponent {
40
+    return this.componentsInstancesById[id];
41
+  }
26 42
 }

+ 8
- 4
lib/src/interfaces/Options.ts View File

@@ -536,15 +536,15 @@ export interface OptionsBottomTabs {
536 536
 
537 537
 export interface DotIndicatorOptions {
538 538
     // default red
539
-    color?: Color,
539
+    color?: Color;
540 540
     // default 6
541
-    size?: number,
541
+    size?: number;
542 542
     // default false
543
-    visible?: boolean,
543
+    visible?: boolean;
544 544
 }
545 545
 
546 546
 export interface OptionsBottomTab {
547
-    dotIndicator?: DotIndicatorOptions,
547
+    dotIndicator?: DotIndicatorOptions;
548 548
 
549 549
   /**
550 550
    * Set the text to display below the icon
@@ -1019,4 +1019,8 @@ setRoot: {
1019 1019
    * @default false
1020 1020
    */
1021 1021
   blurOnUnmount?: boolean;
1022
+  /**
1023
+   * Props to pass to a component
1024
+   */
1025
+  passProps?: Record<string, any>;
1022 1026
 }

+ 1
- 0
package.json View File

@@ -20,6 +20,7 @@
20 20
   "typings": "lib/dist/index.d.ts",
21 21
   "scripts": {
22 22
     "build": "rm -rf ./lib/dist && tsc",
23
+    "watch": "rm -rf ./lib/dist && tsc --watch",
23 24
     "xcode": "open playground/ios/playground.xcodeproj",
24 25
     "install-android": "node ./scripts/install-android",
25 26
     "uninstall-android": "cd playground/android && ./gradlew uninstallAll",

+ 105
- 0
playground/src/screens/ButtonsScreen.js View File

@@ -0,0 +1,105 @@
1
+const React = require('react');
2
+const {Component} = require('react');
3
+const Root = require('../components/Root');
4
+const Button = require('../components/Button')
5
+const Navigation = require('../services/Navigation');
6
+const Screens = require('./Screens');
7
+const Colors = require('../commons/Colors');
8
+const {
9
+  PUSH_BTN,
10
+  TOP_BAR,
11
+  ROUND_BUTTON,
12
+  BUTTON_ONE,
13
+  LEFT_BUTTON,
14
+  SHOW_LIFECYCLE_BTN,
15
+  RESET_BUTTONS,
16
+  CHANGE_BUTTON_PROPS
17
+} = require('../testIDs');
18
+
19
+class Options extends Component {
20
+  static options() {
21
+    return {
22
+      topBar: {
23
+        visible: true,
24
+        testID: TOP_BAR,
25
+        title: {
26
+          text: 'Styling Options'
27
+        },
28
+        rightButtons: [
29
+          {
30
+            id: 'ONE',
31
+            testID: BUTTON_ONE,
32
+            text: 'One',
33
+            color: Colors.primary
34
+          },
35
+          {
36
+            id: 'ROUND',
37
+            testID: ROUND_BUTTON,
38
+            component: {
39
+              id: 'ROUND_COMPONENT',
40
+              name: Screens.RoundButton,
41
+              passProps: {
42
+                title: 'Two'
43
+              }
44
+            }
45
+          }
46
+        ],
47
+        leftButtons: [
48
+          {
49
+            id: 'LEFT',
50
+            testID: LEFT_BUTTON,
51
+            icon: require('../../img/clear.png'),
52
+            color: Colors.primary
53
+          }
54
+        ]
55
+      }
56
+    };
57
+  }
58
+
59
+  render() {
60
+    return (
61
+      <Root componentId={this.props.componentId}>
62
+        <Button label='Push' testID={PUSH_BTN} onPress={this.push} />
63
+        <Button label='Show Lifecycle button' testID={SHOW_LIFECYCLE_BTN} onPress={this.showLifecycleButton} />
64
+        <Button label='Remove all buttons' testID={RESET_BUTTONS} onPress={this.resetButtons} />
65
+        <Button label='Change Button Props'  testID={CHANGE_BUTTON_PROPS} onPress={this.changeButtonProps} />
66
+      </Root>
67
+    );
68
+  }
69
+
70
+  push = () => Navigation.push(this, Screens.Pushed);
71
+
72
+  showLifecycleButton = () => Navigation.mergeOptions(this, {
73
+    topBar: {
74
+      rightButtons: [
75
+        {
76
+          id: 'ROUND',
77
+          testID: ROUND_BUTTON,
78
+          component: {
79
+            name: Screens.LifecycleButton,
80
+            passProps: {
81
+              title: 'Two'
82
+            }
83
+          }
84
+        }
85
+      ]
86
+    }
87
+  });
88
+
89
+  resetButtons = () => Navigation.mergeOptions(this, {
90
+    topBar: {
91
+      rightButtons: [],
92
+      leftButtons: []
93
+    }
94
+  });
95
+
96
+  changeButtonProps = () => {
97
+    Navigation.mergeOptions('ROUND_COMPONENT', {
98
+      passProps: {
99
+        title: 'Three'
100
+      }
101
+    });
102
+  }
103
+}
104
+
105
+module.exports = Options;

+ 5
- 59
playground/src/screens/OptionsScreen.js View File

@@ -4,21 +4,16 @@ const Root = require('../components/Root');
4 4
 const Button = require('../components/Button')
5 5
 const Navigation = require('../services/Navigation');
6 6
 const Screens = require('./Screens');
7
-const Colors = require('../commons/Colors');
8 7
 const {
9 8
   CHANGE_TITLE_BTN,
10 9
   HIDE_TOP_BAR_BTN,
11 10
   SHOW_TOP_BAR_BTN,
12 11
   TOP_BAR,
13
-  ROUND_BUTTON,
14
-  BUTTON_ONE,
15
-  LEFT_BUTTON,
16 12
   PUSH_BTN,
17 13
   HIDE_TOPBAR_DEFAULT_OPTIONS,
18 14
   SHOW_YELLOW_BOX_BTN,
19 15
   SET_REACT_TITLE_VIEW,
20
-  RESET_BUTTONS,
21
-  SHOW_LIFECYCLE_BTN
16
+  GOTO_BUTTONS_SCREEN
22 17
 } = require('../testIDs');
23 18
 
24 19
 class Options extends Component {
@@ -29,33 +24,7 @@ class Options extends Component {
29 24
         testID: TOP_BAR,
30 25
         title: {
31 26
           text: 'Styling Options'
32
-        },
33
-        rightButtons: [
34
-          {
35
-            id: 'ONE',
36
-            testID: BUTTON_ONE,
37
-            text: 'One',
38
-            color: Colors.primary
39
-          },
40
-          {
41
-            id: 'ROUND',
42
-            testID: ROUND_BUTTON,
43
-            component: {
44
-              name: Screens.RoundButton,
45
-              passProps: {
46
-                title: 'Two'
47
-              }
48
-            }
49
-          }
50
-        ],
51
-        leftButtons: [
52
-          {
53
-            id: 'LEFT',
54
-            testID: LEFT_BUTTON,
55
-            icon: require('../../img/clear.png'),
56
-            color: Colors.primary
57
-          }
58
-        ]
27
+        }
59 28
       }
60 29
     };
61 30
   }
@@ -71,36 +40,11 @@ class Options extends Component {
71 40
         <Button label='Set React Title View' testID={SET_REACT_TITLE_VIEW} onPress={this.setReactTitleView} />
72 41
         <Button label='Show Yellow Box' testID={SHOW_YELLOW_BOX_BTN} onPress={() => console.warn('Yellow Box')} />
73 42
         <Button label='StatusBar' onPress={this.statusBarScreen} />
74
-        <Button label='Show Lifecycle button' testID={SHOW_LIFECYCLE_BTN} onPress={this.showLifecycleButton} />
75
-        <Button label='Remove all buttons' testID={RESET_BUTTONS} onPress={this.resetButtons} />
43
+        <Button label='Buttons Screen' testID={GOTO_BUTTONS_SCREEN} onPress={this.goToButtonsScreen} />
76 44
       </Root>
77 45
     );
78 46
   }
79 47
 
80
-  showLifecycleButton = () => Navigation.mergeOptions(this, {
81
-    topBar: {
82
-      rightButtons: [
83
-        {
84
-          id: 'ROUND',
85
-          testID: ROUND_BUTTON,
86
-          component: {
87
-            name: Screens.LifecycleButton,
88
-            passProps: {
89
-              title: 'Two'
90
-            }
91
-          }
92
-        }
93
-      ]
94
-    }
95
-  });
96
-
97
-  resetButtons = () => Navigation.mergeOptions(this, {
98
-    topBar: {
99
-      rightButtons: [],
100
-      leftButtons: []
101
-    }
102
-  });
103
-
104 48
   changeTitle = () => Navigation.mergeOptions(this, {
105 49
     topBar: {
106 50
       title: {
@@ -149,6 +93,8 @@ class Options extends Component {
149 93
   });
150 94
 
151 95
   statusBarScreen = () => Navigation.showModal(Screens.StatusBar);
96
+
97
+  goToButtonsScreen = () => Navigation.push(this, Screens.Buttons);
152 98
 }
153 99
 
154 100
 module.exports = Options;

+ 1
- 0
playground/src/screens/Screens.js View File

@@ -11,6 +11,7 @@ module.exports = {
11 11
   Pushed: 'Pushed',
12 12
   Layouts: 'Layouts',
13 13
   Options: 'Options',
14
+  Buttons: 'Buttons',
14 15
   Stack: 'Stack',
15 16
   Modal: 'Modal',
16 17
   FullScreenModal: 'FullScreenModal',

+ 1
- 1
playground/src/screens/index.js View File

@@ -23,13 +23,13 @@ function registerScreens() {
23 23
   Navigation.registerComponent(Screens.FullScreenModal, () => require('./FullScreenModalScreen'))
24 24
   Navigation.registerComponent(Screens.Navigation, () => require('./NavigationScreen'));
25 25
   Navigation.registerComponent(Screens.Options, () => require('./OptionsScreen'));
26
+  Navigation.registerComponent(Screens.Buttons, () => require('./ButtonsScreen'));
26 27
   Navigation.registerComponent(Screens.Orientation, () => require('./OrientationScreen'));
27 28
   Navigation.registerComponent(Screens.OrientationDetect, () => require('./OrientationDetectScreen'));
28 29
   Navigation.registerComponent(Screens.Overlay, () => require('./OverlayScreen'));
29 30
   Navigation.registerComponent(Screens.OverlayAlert, () => require('./OverlayAlert'));
30 31
   Navigation.registerComponent(Screens.Pushed, () => require('./PushedScreen'));
31 32
   Navigation.registerComponent(Screens.ScrollViewOverlay, () => require('./ScrollViewOverlay'));
32
-  Navigation.registerComponent(Screens.RoundButton, () => require('./RoundedButton'));
33 33
   Navigation.registerComponent(Screens.LifecycleButton, () => require('./LifecycleButton'));
34 34
   Navigation.registerComponent(Screens.ReactTitleView, () => require('./CustomTopBar'));
35 35
   Navigation.registerComponent(Screens.RoundButton, () => require('./RoundedButton'));

+ 3
- 0
playground/src/testIDs.js View File

@@ -7,6 +7,7 @@ module.exports = {
7 7
   LAYOUTS_TAB: 'LAYOUTS_TAB',
8 8
   NAVIGATION_TAB: 'NAVIGATION_TAB',
9 9
   OPTIONS_TAB: 'OPTIONS_TAB',
10
+  BUTTONS_TAB: 'BUTTONS_TAB',
10 11
   SIDE_MENU_INSIDE_BOTTOM_TABS_BTN: 'SIDE_MENU_INSIDE_BOTTOM_TABS',
11 12
   OVERLAY_BTN: 'OVERLAY_BTN',
12 13
   SIDE_MENU_BTN: 'SIDE_MENU_BTN',
@@ -130,6 +131,8 @@ module.exports = {
130 131
   SET_ROOT:'SET_ROOT',
131 132
   RESET_BUTTONS: 'RESET_BUTTONS',
132 133
   SHOW_LIFECYCLE_BTN: 'SHOW_LIFECYCLE_BTN',
134
+  CHANGE_BUTTON_PROPS: 'CHANGE_BUTTON_PROPS',
135
+  GOTO_BUTTONS_SCREEN: 'GOTO_BUTTONS_SCREEN',
133 136
 
134 137
   // Elements
135 138
   SCROLLVIEW_ELEMENT: `SCROLLVIEW_ELEMENT`,