Explorar el Código

[BREAKING] Event registry rework (#3497)

[BREAKING] Call Navigation.events().bindComponent(this) to listen to lifecycle events

This commit introduces breaking changes to the way components listen to RNN events.


Background

Up until now, components could handle navigation events by implemented a set of callbacks:
* componentDidAppear
* componentDidDisappear
* onNavigationButtonPressed
* onSearchBarUpdated
* onSearchBarCancelPressed

While this worked fine for the most part, this was completely broken for HOCs as RNN invoked these methods only on the registered component (top most HOC), leaving it to the user to propagate these events down the HOC chain. See the discussion in #1642 for more details.


Solution

In order to support HOC use case, we're introducing a new api which will let any Component bind itself to receive navigation events:

```js
class LifecycleScreen extends Component {
  constructor(props) {
    super(props);
    this.subscription = Navigation.events().bindComponent(this);
  }

  componentWillUnmount() {
    // The subscription is removed automatically when components unmount, but they can be explicitly removed as well by calling `this.subscription.remove(); `
  }
}
```

It's still the users responsibility to propagate the `componentId` down the HOC chain, but by binding a component to RNN, it will be able to handle events as expected. Multiple components can be bound for the same `componentId`.


Consolidate event names

* onNavigationButtonPressed -> navigationButtonPressed
* onSearchBarUpdated -> searchBarUpdated
* onSearchBarCancelPressed -> searchBarCancelPressed
Daniel Zlotin hace 6 años
padre
commit
b5a3b54fa6
Se han modificado 47 ficheros con 944 adiciones y 888 borrados
  1. 21
    13
      docs/api/Commands.md
  2. 51
    3
      docs/api/ComponentEventsObserver.md
  3. 2
    2
      docs/api/ComponentRegistry.md
  4. 32
    0
      docs/api/Constants.md
  5. 0
    146
      docs/api/Element.md
  6. 44
    12
      docs/api/EventsRegistry.md
  7. 15
    7
      docs/api/LayoutTreeParser.md
  8. 1
    0
      docs/api/LayoutType.md
  9. 19
    11
      docs/api/NativeCommandsSender.md
  10. 31
    7
      docs/api/NativeEventsReceiver.md
  11. 27
    2
      docs/api/Navigation.md
  12. 1
    0
      docs/api/README.md
  13. 5
    21
      docs/api/Store.md
  14. 1
    0
      docs/api/_sidebar.md
  15. 2
    2
      docs/docs/events.md
  16. 30
    36
      lib/android/app/src/main/java/com/reactnativenavigation/react/EventEmitter.java
  17. 0
    3
      lib/ios/RNNCommandsHandler.m
  18. 1
    3
      lib/ios/RNNEventEmitter.h
  19. 53
    31
      lib/ios/RNNEventEmitter.m
  20. 11
    11
      lib/ios/RNNRootViewController.m
  21. 1
    2
      lib/ios/RNNTabBarController.m
  22. 5
    6
      lib/src/Navigation.ts
  23. 29
    9
      lib/src/adapters/NativeEventsReceiver.ts
  24. 1
    1
      lib/src/components/ComponentRegistry.test.tsx
  25. 4
    6
      lib/src/components/ComponentRegistry.ts
  26. 51
    147
      lib/src/components/ComponentWrapper.test.tsx
  27. 6
    43
      lib/src/components/ComponentWrapper.tsx
  28. 1
    10
      lib/src/components/Store.test.ts
  29. 0
    10
      lib/src/components/Store.ts
  30. 1
    1
      lib/src/events/CommandsObserver.ts
  31. 0
    139
      lib/src/events/ComponentEventsObserver.test.ts
  32. 181
    0
      lib/src/events/ComponentEventsObserver.test.tsx
  33. 66
    41
      lib/src/events/ComponentEventsObserver.ts
  34. 0
    99
      lib/src/events/EventsRegistry.test.ts
  35. 100
    0
      lib/src/events/EventsRegistry.test.tsx
  36. 36
    11
      lib/src/events/EventsRegistry.ts
  37. 24
    0
      lib/src/interfaces/ComponentEvents.ts
  38. 10
    0
      lib/src/interfaces/Events.ts
  39. 3
    0
      playground/src/screens/CustomRoundedButton.js
  40. 3
    0
      playground/src/screens/CustomTopBar.js
  41. 4
    2
      playground/src/screens/LifecycleScreen.js
  42. 9
    4
      playground/src/screens/OptionsScreen.js
  43. 19
    22
      playground/src/screens/PushedScreen.js
  44. 3
    2
      playground/src/screens/SearchScreen.js
  45. 15
    13
      playground/src/screens/StaticLifecycleOverlay.js
  46. 3
    0
      playground/src/screens/TopBarBackground.js
  47. 22
    10
      scripts/gen-docs/ClassParser.ts

+ 21
- 13
docs/api/Commands.md Ver fichero

4
 
4
 
5
 `setRoot(simpleApi: any): any`
5
 `setRoot(simpleApi: any): any`
6
 
6
 
7
-[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/commands/Commands.ts#L13)
7
+[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/commands/Commands.ts#L15)
8
 
8
 
9
 ---
9
 ---
10
 
10
 
12
 
12
 
13
 `setDefaultOptions(options: any): void`
13
 `setDefaultOptions(options: any): void`
14
 
14
 
15
-[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/commands/Commands.ts#L23)
15
+[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/commands/Commands.ts#L38)
16
 
16
 
17
 ---
17
 ---
18
 
18
 
20
 
20
 
21
 `mergeOptions(componentId: any, options: any): void`
21
 `mergeOptions(componentId: any, options: any): void`
22
 
22
 
23
-[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/commands/Commands.ts#L31)
23
+[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/commands/Commands.ts#L46)
24
 
24
 
25
 ---
25
 ---
26
 
26
 
28
 
28
 
29
 `showModal(simpleApi: any): any`
29
 `showModal(simpleApi: any): any`
30
 
30
 
31
-[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/commands/Commands.ts#L39)
31
+[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/commands/Commands.ts#L54)
32
 
32
 
33
 ---
33
 ---
34
 
34
 
36
 
36
 
37
 `dismissModal(componentId: any): any`
37
 `dismissModal(componentId: any): any`
38
 
38
 
39
-[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/commands/Commands.ts#L49)
39
+[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/commands/Commands.ts#L65)
40
 
40
 
41
 ---
41
 ---
42
 
42
 
44
 
44
 
45
 `dismissAllModals(): any`
45
 `dismissAllModals(): any`
46
 
46
 
47
-[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/commands/Commands.ts#L55)
47
+[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/commands/Commands.ts#L72)
48
 
48
 
49
 ---
49
 ---
50
 
50
 
52
 
52
 
53
 `push(componentId: any, simpleApi: any): any`
53
 `push(componentId: any, simpleApi: any): any`
54
 
54
 
55
-[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/commands/Commands.ts#L61)
55
+[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/commands/Commands.ts#L79)
56
 
56
 
57
 ---
57
 ---
58
 
58
 
60
 
60
 
61
 `pop(componentId: any, options: any): any`
61
 `pop(componentId: any, options: any): any`
62
 
62
 
63
-[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/commands/Commands.ts#L72)
63
+[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/commands/Commands.ts#L91)
64
 
64
 
65
 ---
65
 ---
66
 
66
 
68
 
68
 
69
 `popTo(componentId: any): any`
69
 `popTo(componentId: any): any`
70
 
70
 
71
-[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/commands/Commands.ts#L78)
71
+[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/commands/Commands.ts#L98)
72
 
72
 
73
 ---
73
 ---
74
 
74
 
76
 
76
 
77
 `popToRoot(componentId: any): any`
77
 `popToRoot(componentId: any): any`
78
 
78
 
79
-[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/commands/Commands.ts#L84)
79
+[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/commands/Commands.ts#L105)
80
 
80
 
81
 ---
81
 ---
82
 
82
 
84
 
84
 
85
 `setStackRoot(componentId: any, simpleApi: any): any`
85
 `setStackRoot(componentId: any, simpleApi: any): any`
86
 
86
 
87
-[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/commands/Commands.ts#L90)
87
+[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/commands/Commands.ts#L112)
88
 
88
 
89
 ---
89
 ---
90
 
90
 
92
 
92
 
93
 `showOverlay(simpleApi: any): any`
93
 `showOverlay(simpleApi: any): any`
94
 
94
 
95
-[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/commands/Commands.ts#L101)
95
+[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/commands/Commands.ts#L124)
96
 
96
 
97
 ---
97
 ---
98
 
98
 
100
 
100
 
101
 `dismissOverlay(componentId: any): any`
101
 `dismissOverlay(componentId: any): any`
102
 
102
 
103
-[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/commands/Commands.ts#L112)
103
+[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/commands/Commands.ts#L136)
104
+
105
+---
106
+
107
+## getLaunchArgs
108
+
109
+`getLaunchArgs(): any`
110
+
111
+[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/commands/Commands.ts#L143)
104
 
112
 
105
 ---
113
 ---
106
 
114
 

+ 51
- 3
docs/api/ComponentEventsObserver.md Ver fichero

1
 # ComponentEventsObserver
1
 # ComponentEventsObserver
2
 
2
 
3
-## registerForAllComponents
3
+## registerOnceForAllComponentEvents
4
 
4
 
5
-`registerForAllComponents(): void`
5
+`registerOnceForAllComponentEvents(): void`
6
 
6
 
7
-[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/events/ComponentEventsObserver.ts#L13)
7
+[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/events/ComponentEventsObserver.ts#L25)
8
+
9
+---
10
+
11
+## bindComponent
12
+
13
+`bindComponent(component: Component<any>): EventSubscription`
14
+
15
+[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/events/ComponentEventsObserver.ts#L35)
16
+
17
+---
18
+
19
+## notifyComponentDidAppear
20
+
21
+`notifyComponentDidAppear(event: ComponentDidAppearEvent): void`
22
+
23
+[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/events/ComponentEventsObserver.ts#L46)
24
+
25
+---
26
+
27
+## notifyComponentDidDisappear
28
+
29
+`notifyComponentDidDisappear(event: ComponentDidDisappearEvent): void`
30
+
31
+[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/events/ComponentEventsObserver.ts#L50)
32
+
33
+---
34
+
35
+## notifyNavigationButtonPressed
36
+
37
+`notifyNavigationButtonPressed(event: NavigationButtonPressedEvent): void`
38
+
39
+[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/events/ComponentEventsObserver.ts#L54)
40
+
41
+---
42
+
43
+## notifySearchBarUpdated
44
+
45
+`notifySearchBarUpdated(event: SearchBarUpdatedEvent): void`
46
+
47
+[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/events/ComponentEventsObserver.ts#L58)
48
+
49
+---
50
+
51
+## notifySearchBarCancelPressed
52
+
53
+`notifySearchBarCancelPressed(event: SearchBarCancelPressedEvent): void`
54
+
55
+[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/events/ComponentEventsObserver.ts#L62)
8
 
56
 
9
 ---
57
 ---
10
 
58
 

+ 2
- 2
docs/api/ComponentRegistry.md Ver fichero

2
 
2
 
3
 ## registerComponent
3
 ## registerComponent
4
 
4
 
5
-`registerComponent(componentName: string, getComponentClassFunc: ComponentProvider): void`
5
+`registerComponent(componentName: string, getComponentClassFunc: ComponentProvider): ComponentType<any>`
6
 
6
 
7
-[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/components/ComponentRegistry.ts#L11)
7
+[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/components/ComponentRegistry.ts#L12)
8
 
8
 
9
 ---
9
 ---
10
 
10
 

+ 32
- 0
docs/api/Constants.md Ver fichero

1
+# Constants
2
+
3
+## backButtonId
4
+
5
+`backButtonId (string)`
6
+
7
+---
8
+## bottomTabsHeight
9
+
10
+`bottomTabsHeight (number)`
11
+
12
+---
13
+## statusBarHeight
14
+
15
+`statusBarHeight (number)`
16
+
17
+---
18
+## topBarHeight
19
+
20
+`topBarHeight (number)`
21
+
22
+---
23
+
24
+## get
25
+
26
+`get(): Promise<any>`
27
+
28
+[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/adapters/Constants.ts#L4)
29
+
30
+---
31
+
32
+

+ 0
- 146
docs/api/Element.md Ver fichero

29
 
29
 
30
 ---
30
 ---
31
 
31
 
32
-## setState
33
-
34
-`setState(state: function | S | object, callback: function): void`
35
-
36
-[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src//Users/danielzlotin/dev/react-native-navigation/node_modules/@types/react/index.d.ts#L287)
37
-
38
----
39
-
40
-## forceUpdate
41
-
42
-`forceUpdate(callBack: function): void`
43
-
44
-[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src//Users/danielzlotin/dev/react-native-navigation/node_modules/@types/react/index.d.ts#L292)
45
-
46
----
47
-
48
-## componentDidMount
49
-
50
-`componentDidMount(): void`
51
-
52
-[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src//Users/danielzlotin/dev/react-native-navigation/node_modules/@types/react/index.d.ts#L376)
53
-
54
-Called immediately after a compoment is mounted. Setting state here will trigger re-rendering.
55
-
56
----
57
-
58
-## shouldComponentUpdate
59
-
60
-`shouldComponentUpdate(nextProps: Readonly<object>, nextState: Readonly<any>, nextContext: any): boolean`
61
-
62
-[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src//Users/danielzlotin/dev/react-native-navigation/node_modules/@types/react/index.d.ts#L387)
63
-
64
-Called to determine whether the change in props and state should trigger a re-render.
65
-
66
----
67
-
68
-## componentWillUnmount
69
-
70
-`componentWillUnmount(): void`
71
-
72
-[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src//Users/danielzlotin/dev/react-native-navigation/node_modules/@types/react/index.d.ts#L392)
73
-
74
-Called immediately before a component is destroyed. Perform any necessary cleanup in this method, such as
75
-cancelled network requests, or cleaning up any DOM elements created in `componentDidMount`.
76
-
77
----
78
-
79
-## componentDidCatch
80
-
81
-`componentDidCatch(error: Error, errorInfo: ErrorInfo): void`
82
-
83
-[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src//Users/danielzlotin/dev/react-native-navigation/node_modules/@types/react/index.d.ts#L397)
84
-
85
-Catches exceptions generated in descendant components. Unhandled exceptions will cause
86
-the entire component tree to unmount.
87
-
88
----
89
-
90
-## getSnapshotBeforeUpdate
91
-
92
-`getSnapshotBeforeUpdate(prevProps: Readonly<object>, prevState: Readonly<any>): SS | null`
93
-
94
-[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src//Users/danielzlotin/dev/react-native-navigation/node_modules/@types/react/index.d.ts#L423)
95
-
96
-Runs before React applies the result of `render` to the document, and
97
-returns an object to be given to componentDidUpdate. Useful for saving
98
-things such as scroll position before `render` causes changes to it.
99
-
100
----
101
-
102
-## componentDidUpdate
103
-
104
-`componentDidUpdate(prevProps: Readonly<object>, prevState: Readonly<any>, snapshot: SS): void`
105
-
106
-[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src//Users/danielzlotin/dev/react-native-navigation/node_modules/@types/react/index.d.ts#L429)
107
-
108
-Called immediately after updating occurs. Not called for the initial render.
109
-
110
----
111
-
112
-## componentWillMount
113
-
114
-`componentWillMount(): void`
115
-
116
-[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src//Users/danielzlotin/dev/react-native-navigation/node_modules/@types/react/index.d.ts#L444)
117
-
118
-Called immediately before mounting occurs, and before `Component#render`.
119
-Avoid introducing any side-effects or subscriptions in this method.
120
-
121
----
122
-
123
-## UNSAFE_componentWillMount
124
-
125
-`UNSAFE_componentWillMount(): void`
126
-
127
-[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src//Users/danielzlotin/dev/react-native-navigation/node_modules/@types/react/index.d.ts#L458)
128
-
129
-Called immediately before mounting occurs, and before `Component#render`.
130
-Avoid introducing any side-effects or subscriptions in this method.
131
-
132
----
133
-
134
-## componentWillReceiveProps
135
-
136
-`componentWillReceiveProps(nextProps: Readonly<object>, nextContext: any): void`
137
-
138
-[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src//Users/danielzlotin/dev/react-native-navigation/node_modules/@types/react/index.d.ts#L473)
139
-
140
-Called when the component may be receiving new props.
141
-React may call this even if props have not changed, so be sure to compare new and existing
142
-props if you only want to handle changes.
143
-
144
----
145
-
146
-## UNSAFE_componentWillReceiveProps
147
-
148
-`UNSAFE_componentWillReceiveProps(nextProps: Readonly<object>, nextContext: any): void`
149
-
150
-[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src//Users/danielzlotin/dev/react-native-navigation/node_modules/@types/react/index.d.ts#L490)
151
-
152
-Called when the component may be receiving new props.
153
-React may call this even if props have not changed, so be sure to compare new and existing
154
-props if you only want to handle changes.
155
-
156
----
157
-
158
-## componentWillUpdate
159
-
160
-`componentWillUpdate(nextProps: Readonly<object>, nextState: Readonly<any>, nextContext: any): void`
161
-
162
-[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src//Users/danielzlotin/dev/react-native-navigation/node_modules/@types/react/index.d.ts#L503)
163
-
164
-Called immediately before rendering when new props or state is received. Not called for the initial render.
165
-
166
----
167
-
168
-## UNSAFE_componentWillUpdate
169
-
170
-`UNSAFE_componentWillUpdate(nextProps: Readonly<object>, nextState: Readonly<any>, nextContext: any): void`
171
-
172
-[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src//Users/danielzlotin/dev/react-native-navigation/node_modules/@types/react/index.d.ts#L518)
173
-
174
-Called immediately before rendering when new props or state is received. Not called for the initial render.
175
-
176
----
177
-
178
 
32
 

+ 44
- 12
docs/api/EventsRegistry.md Ver fichero

4
 
4
 
5
 `registerAppLaunchedListener(callback: function): EventSubscription`
5
 `registerAppLaunchedListener(callback: function): EventSubscription`
6
 
6
 
7
-[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/events/EventsRegistry.ts#L8)
7
+[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/events/EventsRegistry.ts#L17)
8
 
8
 
9
 ---
9
 ---
10
 
10
 
12
 
12
 
13
 `registerComponentDidAppearListener(callback: function): EventSubscription`
13
 `registerComponentDidAppearListener(callback: function): EventSubscription`
14
 
14
 
15
-[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/events/EventsRegistry.ts#L12)
15
+[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/events/EventsRegistry.ts#L21)
16
 
16
 
17
 ---
17
 ---
18
 
18
 
20
 
20
 
21
 `registerComponentDidDisappearListener(callback: function): EventSubscription`
21
 `registerComponentDidDisappearListener(callback: function): EventSubscription`
22
 
22
 
23
-[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/events/EventsRegistry.ts#L16)
23
+[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/events/EventsRegistry.ts#L25)
24
 
24
 
25
 ---
25
 ---
26
 
26
 
27
-## registerCommandListener
27
+## registerCommandCompletedListener
28
 
28
 
29
-`registerCommandListener(callback: function): EventSubscription`
29
+`registerCommandCompletedListener(callback: function): EventSubscription`
30
 
30
 
31
-[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/events/EventsRegistry.ts#L20)
31
+[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/events/EventsRegistry.ts#L29)
32
 
32
 
33
 ---
33
 ---
34
 
34
 
35
-## registerCommandCompletedListener
35
+## registerBottomTabSelectedListener
36
 
36
 
37
-`registerCommandCompletedListener(callback: function): EventSubscription`
37
+`registerBottomTabSelectedListener(callback: function): EventSubscription`
38
+
39
+[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/events/EventsRegistry.ts#L33)
40
+
41
+---
42
+
43
+## registerNavigationButtonPressedListener
44
+
45
+`registerNavigationButtonPressedListener(callback: function): EventSubscription`
46
+
47
+[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/events/EventsRegistry.ts#L37)
48
+
49
+---
50
+
51
+## registerSearchBarUpdatedListener
52
+
53
+`registerSearchBarUpdatedListener(callback: function): EventSubscription`
54
+
55
+[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/events/EventsRegistry.ts#L41)
56
+
57
+---
58
+
59
+## registerSearchBarCancelPressedListener
60
+
61
+`registerSearchBarCancelPressedListener(callback: function): EventSubscription`
62
+
63
+[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/events/EventsRegistry.ts#L45)
64
+
65
+---
66
+
67
+## registerCommandListener
68
+
69
+`registerCommandListener(callback: function): EventSubscription`
38
 
70
 
39
-[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/events/EventsRegistry.ts#L24)
71
+[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/events/EventsRegistry.ts#L49)
40
 
72
 
41
 ---
73
 ---
42
 
74
 
43
-## registerNativeEventListener
75
+## bindComponent
44
 
76
 
45
-`registerNativeEventListener(callback: function): EventSubscription`
77
+`bindComponent(component: Component<any>): EventSubscription`
46
 
78
 
47
-[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/events/EventsRegistry.ts#L28)
79
+[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/events/EventsRegistry.ts#L53)
48
 
80
 
49
 ---
81
 ---
50
 
82
 

+ 15
- 7
docs/api/LayoutTreeParser.md Ver fichero

12
 
12
 
13
 `_topTabs(api: any): LayoutNode`
13
 `_topTabs(api: any): LayoutNode`
14
 
14
 
15
-[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/commands/LayoutTreeParser.ts#L27)
15
+[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/commands/LayoutTreeParser.ts#L29)
16
 
16
 
17
 ---
17
 ---
18
 
18
 
20
 
20
 
21
 `_sideMenu(api: any): LayoutNode`
21
 `_sideMenu(api: any): LayoutNode`
22
 
22
 
23
-[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/commands/LayoutTreeParser.ts#L36)
23
+[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/commands/LayoutTreeParser.ts#L38)
24
 
24
 
25
 ---
25
 ---
26
 
26
 
28
 
28
 
29
 `_sideMenuChildren(api: any): LayoutNode[]`
29
 `_sideMenuChildren(api: any): LayoutNode[]`
30
 
30
 
31
-[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/commands/LayoutTreeParser.ts#L45)
31
+[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/commands/LayoutTreeParser.ts#L47)
32
 
32
 
33
 ---
33
 ---
34
 
34
 
36
 
36
 
37
 `_bottomTabs(api: any): LayoutNode`
37
 `_bottomTabs(api: any): LayoutNode`
38
 
38
 
39
-[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/commands/LayoutTreeParser.ts#L75)
39
+[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/commands/LayoutTreeParser.ts#L77)
40
 
40
 
41
 ---
41
 ---
42
 
42
 
44
 
44
 
45
 `_stack(api: any): LayoutNode`
45
 `_stack(api: any): LayoutNode`
46
 
46
 
47
-[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/commands/LayoutTreeParser.ts#L84)
47
+[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/commands/LayoutTreeParser.ts#L86)
48
 
48
 
49
 ---
49
 ---
50
 
50
 
52
 
52
 
53
 `_component(api: any): LayoutNode`
53
 `_component(api: any): LayoutNode`
54
 
54
 
55
-[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/commands/LayoutTreeParser.ts#L93)
55
+[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/commands/LayoutTreeParser.ts#L95)
56
 
56
 
57
 ---
57
 ---
58
 
58
 
60
 
60
 
61
 `_externalComponent(api: any): LayoutNode`
61
 `_externalComponent(api: any): LayoutNode`
62
 
62
 
63
-[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/commands/LayoutTreeParser.ts#L102)
63
+[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/commands/LayoutTreeParser.ts#L104)
64
+
65
+---
66
+
67
+## _splitView
68
+
69
+`_splitView(api: any): LayoutNode`
70
+
71
+[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/commands/LayoutTreeParser.ts#L113)
64
 
72
 
65
 ---
73
 ---
66
 
74
 

+ 1
- 0
docs/api/LayoutType.md Ver fichero

7
 - SideMenuLeft
7
 - SideMenuLeft
8
 - SideMenuRight
8
 - SideMenuRight
9
 - SideMenuRoot
9
 - SideMenuRoot
10
+- SplitView
10
 - Stack
11
 - Stack
11
 - TopTabs
12
 - TopTabs

+ 19
- 11
docs/api/NativeCommandsSender.md Ver fichero

2
 
2
 
3
 ## setRoot
3
 ## setRoot
4
 
4
 
5
-`setRoot(layoutTree: object): any`
5
+`setRoot(commandId: string, layout: object): any`
6
 
6
 
7
 [source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/adapters/NativeCommandsSender.ts#L9)
7
 [source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/adapters/NativeCommandsSender.ts#L9)
8
 
8
 
26
 
26
 
27
 ## push
27
 ## push
28
 
28
 
29
-`push(onComponentId: string, layout: object): any`
29
+`push(commandId: string, onComponentId: string, layout: object): any`
30
 
30
 
31
 [source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/adapters/NativeCommandsSender.ts#L21)
31
 [source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/adapters/NativeCommandsSender.ts#L21)
32
 
32
 
34
 
34
 
35
 ## pop
35
 ## pop
36
 
36
 
37
-`pop(componentId: string, options: object): any`
37
+`pop(commandId: string, componentId: string, options: object): any`
38
 
38
 
39
 [source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/adapters/NativeCommandsSender.ts#L25)
39
 [source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/adapters/NativeCommandsSender.ts#L25)
40
 
40
 
42
 
42
 
43
 ## popTo
43
 ## popTo
44
 
44
 
45
-`popTo(componentId: string): any`
45
+`popTo(commandId: string, componentId: string): any`
46
 
46
 
47
 [source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/adapters/NativeCommandsSender.ts#L29)
47
 [source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/adapters/NativeCommandsSender.ts#L29)
48
 
48
 
50
 
50
 
51
 ## popToRoot
51
 ## popToRoot
52
 
52
 
53
-`popToRoot(componentId: string): any`
53
+`popToRoot(commandId: string, componentId: string): any`
54
 
54
 
55
 [source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/adapters/NativeCommandsSender.ts#L33)
55
 [source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/adapters/NativeCommandsSender.ts#L33)
56
 
56
 
58
 
58
 
59
 ## setStackRoot
59
 ## setStackRoot
60
 
60
 
61
-`setStackRoot(onComponentId: string, layout: object): any`
61
+`setStackRoot(commandId: string, onComponentId: string, layout: object): any`
62
 
62
 
63
 [source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/adapters/NativeCommandsSender.ts#L37)
63
 [source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/adapters/NativeCommandsSender.ts#L37)
64
 
64
 
66
 
66
 
67
 ## showModal
67
 ## showModal
68
 
68
 
69
-`showModal(layout: object): any`
69
+`showModal(commandId: string, layout: object): any`
70
 
70
 
71
 [source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/adapters/NativeCommandsSender.ts#L41)
71
 [source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/adapters/NativeCommandsSender.ts#L41)
72
 
72
 
74
 
74
 
75
 ## dismissModal
75
 ## dismissModal
76
 
76
 
77
-`dismissModal(componentId: string): any`
77
+`dismissModal(commandId: string, componentId: string): any`
78
 
78
 
79
 [source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/adapters/NativeCommandsSender.ts#L45)
79
 [source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/adapters/NativeCommandsSender.ts#L45)
80
 
80
 
82
 
82
 
83
 ## dismissAllModals
83
 ## dismissAllModals
84
 
84
 
85
-`dismissAllModals(): any`
85
+`dismissAllModals(commandId: string): any`
86
 
86
 
87
 [source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/adapters/NativeCommandsSender.ts#L49)
87
 [source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/adapters/NativeCommandsSender.ts#L49)
88
 
88
 
90
 
90
 
91
 ## showOverlay
91
 ## showOverlay
92
 
92
 
93
-`showOverlay(layout: object): any`
93
+`showOverlay(commandId: string, layout: object): any`
94
 
94
 
95
 [source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/adapters/NativeCommandsSender.ts#L53)
95
 [source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/adapters/NativeCommandsSender.ts#L53)
96
 
96
 
98
 
98
 
99
 ## dismissOverlay
99
 ## dismissOverlay
100
 
100
 
101
-`dismissOverlay(componentId: string): any`
101
+`dismissOverlay(commandId: string, componentId: string): any`
102
 
102
 
103
 [source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/adapters/NativeCommandsSender.ts#L57)
103
 [source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/adapters/NativeCommandsSender.ts#L57)
104
 
104
 
105
 ---
105
 ---
106
 
106
 
107
+## getLaunchArgs
108
+
109
+`getLaunchArgs(commandId: string): any`
110
+
111
+[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/adapters/NativeCommandsSender.ts#L61)
112
+
113
+---
114
+
107
 
115
 

+ 31
- 7
docs/api/NativeEventsReceiver.md Ver fichero

4
 
4
 
5
 `registerAppLaunchedListener(callback: function): EventSubscription`
5
 `registerAppLaunchedListener(callback: function): EventSubscription`
6
 
6
 
7
-[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/adapters/NativeEventsReceiver.ts#L10)
7
+[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/adapters/NativeEventsReceiver.ts#L28)
8
 
8
 
9
 ---
9
 ---
10
 
10
 
12
 
12
 
13
 `registerComponentDidAppearListener(callback: function): EventSubscription`
13
 `registerComponentDidAppearListener(callback: function): EventSubscription`
14
 
14
 
15
-[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/adapters/NativeEventsReceiver.ts#L14)
15
+[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/adapters/NativeEventsReceiver.ts#L32)
16
 
16
 
17
 ---
17
 ---
18
 
18
 
20
 
20
 
21
 `registerComponentDidDisappearListener(callback: function): EventSubscription`
21
 `registerComponentDidDisappearListener(callback: function): EventSubscription`
22
 
22
 
23
-[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/adapters/NativeEventsReceiver.ts#L18)
23
+[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/adapters/NativeEventsReceiver.ts#L36)
24
+
25
+---
26
+
27
+## registerNavigationButtonPressedListener
28
+
29
+`registerNavigationButtonPressedListener(callback: function): EventSubscription`
30
+
31
+[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/adapters/NativeEventsReceiver.ts#L40)
32
+
33
+---
34
+
35
+## registerSearchBarUpdatedListener
36
+
37
+`registerSearchBarUpdatedListener(callback: function): EventSubscription`
38
+
39
+[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/adapters/NativeEventsReceiver.ts#L44)
40
+
41
+---
42
+
43
+## registerSearchBarCancelPressedListener
44
+
45
+`registerSearchBarCancelPressedListener(callback: function): EventSubscription`
46
+
47
+[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/adapters/NativeEventsReceiver.ts#L48)
24
 
48
 
25
 ---
49
 ---
26
 
50
 
28
 
52
 
29
 `registerCommandCompletedListener(callback: function): EventSubscription`
53
 `registerCommandCompletedListener(callback: function): EventSubscription`
30
 
54
 
31
-[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/adapters/NativeEventsReceiver.ts#L22)
55
+[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/adapters/NativeEventsReceiver.ts#L52)
32
 
56
 
33
 ---
57
 ---
34
 
58
 
35
-## registerNativeEventListener
59
+## registerBottomTabSelectedListener
36
 
60
 
37
-`registerNativeEventListener(callback: function): EventSubscription`
61
+`registerBottomTabSelectedListener(callback: function): EventSubscription`
38
 
62
 
39
-[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/adapters/NativeEventsReceiver.ts#L26)
63
+[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/adapters/NativeEventsReceiver.ts#L56)
40
 
64
 
41
 ---
65
 ---
42
 
66
 

+ 27
- 2
docs/api/Navigation.md Ver fichero

4
 
4
 
5
 `Element (React.ComponentType<object>)`
5
 `Element (React.ComponentType<object>)`
6
 
6
 
7
+---
8
+## store
9
+
10
+`store (Store)`
11
+
7
 ---
12
 ---
8
 
13
 
9
 ## registerComponent
14
 ## registerComponent
10
 
15
 
11
-`registerComponent(componentName: string, getComponentClassFunc: ComponentProvider): React.ComponentType<any>`
16
+`registerComponent(componentName: string, getComponentClassFunc: ComponentProvider): ComponentType<any>`
12
 
17
 
13
 [source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/Navigation.ts#L52)
18
 [source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/Navigation.ts#L52)
14
 
19
 
147
 
152
 
148
 ---
153
 ---
149
 
154
 
155
+## getLaunchArgs
156
+
157
+`getLaunchArgs(): Promise<any>`
158
+
159
+[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/Navigation.ts#L150)
160
+
161
+Resolves arguments passed on launch
162
+
163
+---
164
+
150
 ## events
165
 ## events
151
 
166
 
152
 `events(): EventsRegistry`
167
 `events(): EventsRegistry`
153
 
168
 
154
-[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/Navigation.ts#L150)
169
+[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/Navigation.ts#L157)
155
 
170
 
156
 Obtain the events registry instance
171
 Obtain the events registry instance
157
 
172
 
158
 ---
173
 ---
159
 
174
 
175
+## constants
176
+
177
+`constants(): Promise<any>`
178
+
179
+[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/Navigation.ts#L164)
180
+
181
+Constants coming from native
182
+
183
+---
184
+
160
 
185
 

+ 1
- 0
docs/api/README.md Ver fichero

1
 - [Home](/)
1
 - [Home](/)
2
 - [Navigation](/api/Navigation)
2
 - [Navigation](/api/Navigation)
3
+- [Constants](/api/Constants)
3
 - [Element](/api/Element)
4
 - [Element](/api/Element)
4
 - [NativeCommandsSender](/api/NativeCommandsSender)
5
 - [NativeCommandsSender](/api/NativeCommandsSender)
5
 - [NativeEventsReceiver](/api/NativeEventsReceiver)
6
 - [NativeEventsReceiver](/api/NativeEventsReceiver)

+ 5
- 21
docs/api/Store.md Ver fichero

4
 
4
 
5
 `setPropsForId(componentId: string, props: any): void`
5
 `setPropsForId(componentId: string, props: any): void`
6
 
6
 
7
-[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/components/Store.ts#L8)
7
+[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/components/Store.ts#L7)
8
 
8
 
9
 ---
9
 ---
10
 
10
 
12
 
12
 
13
 `getPropsForId(componentId: string): any`
13
 `getPropsForId(componentId: string): any`
14
 
14
 
15
-[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/components/Store.ts#L12)
15
+[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/components/Store.ts#L11)
16
 
16
 
17
 ---
17
 ---
18
 
18
 
20
 
20
 
21
 `setOriginalComponentClassForName(componentName: string, ComponentClass: any): void`
21
 `setOriginalComponentClassForName(componentName: string, ComponentClass: any): void`
22
 
22
 
23
-[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/components/Store.ts#L16)
23
+[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/components/Store.ts#L15)
24
 
24
 
25
 ---
25
 ---
26
 
26
 
28
 
28
 
29
 `getOriginalComponentClassForName(componentName: string): any`
29
 `getOriginalComponentClassForName(componentName: string): any`
30
 
30
 
31
-[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/components/Store.ts#L20)
32
-
33
----
34
-
35
-## setRefForId
36
-
37
-`setRefForId(id: string, ref: any): void`
38
-
39
-[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/components/Store.ts#L24)
40
-
41
----
42
-
43
-## getRefForId
44
-
45
-`getRefForId(id: string): any`
46
-
47
-[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/components/Store.ts#L28)
31
+[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/components/Store.ts#L19)
48
 
32
 
49
 ---
33
 ---
50
 
34
 
52
 
36
 
53
 `cleanId(id: string): void`
37
 `cleanId(id: string): void`
54
 
38
 
55
-[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/components/Store.ts#L32)
39
+[source](https://github.com/wix/react-native-navigation/blob/v2/lib/src/components/Store.ts#L23)
56
 
40
 
57
 ---
41
 ---
58
 
42
 

+ 1
- 0
docs/api/_sidebar.md Ver fichero

1
 - [Home](/)
1
 - [Home](/)
2
 - [Navigation](/api/Navigation)
2
 - [Navigation](/api/Navigation)
3
+- [Constants](/api/Constants)
3
 - [Element](/api/Element)
4
 - [Element](/api/Element)
4
 - [NativeCommandsSender](/api/NativeCommandsSender)
5
 - [NativeCommandsSender](/api/NativeCommandsSender)
5
 - [NativeEventsReceiver](/api/NativeEventsReceiver)
6
 - [NativeEventsReceiver](/api/NativeEventsReceiver)

+ 2
- 2
docs/docs/events.md Ver fichero

103
 |**name**|`buttonPressed`|
103
 |**name**|`buttonPressed`|
104
 |**params**|`componentId`: `componentId` of the layout element the pressed button is bound to<br>`buttonId`: `id` of the pressed button|
104
 |**params**|`componentId`: `componentId` of the layout element the pressed button is bound to<br>`buttonId`: `id` of the pressed button|
105
 
105
 
106
-## onNavigationButtonPressed
106
+## navigationButtonPressed
107
 Called when a TopBar button is pressed.
107
 Called when a TopBar button is pressed.
108
 
108
 
109
 ```js
109
 ```js
110
 class MyComponent extends Component {
110
 class MyComponent extends Component {
111
-  onNavigationButtonPressed(buttonId) {
111
+  navigationButtonPressed(buttonId) {
112
 
112
 
113
   }
113
   }
114
 }
114
 }

+ 30
- 36
lib/android/app/src/main/java/com/reactnativenavigation/react/EventEmitter.java Ver fichero

8
 import static com.facebook.react.modules.core.DeviceEventManagerModule.RCTDeviceEventEmitter;
8
 import static com.facebook.react.modules.core.DeviceEventManagerModule.RCTDeviceEventEmitter;
9
 
9
 
10
 public class EventEmitter {
10
 public class EventEmitter {
11
-	private static final String onAppLaunched = "RNN.appLaunched";
12
-	private static final String componentDidAppear = "RNN.componentDidAppear";
13
-	private static final String componentDidDisappear = "RNN.componentDidDisappear";
14
-	private static final String nativeEvent = "RNN.nativeEvent";
15
-    private static final String commandCompleted = "RNN.commandCompleted";
16
-    private static final String buttonPressedEvent = "buttonPressed";
11
+	private static final String AppLaunched             = "RNN.AppLaunched";
12
+	private static final String CommandCompleted        = "RNN.CommandCompleted";
13
+	private static final String BottomTabSelected       = "RNN.BottomTabSelected";
14
+	private static final String ComponentDidAppear      = "RNN.ComponentDidAppear";
15
+	private static final String ComponentDidDisappear   = "RNN.ComponentDidDisappear";
16
+	private static final String NavigationButtonPressed = "RNN.NavigationButtonPressed";
17
+	private static final String SearchBarUpdated        = "RNN.SearchBarUpdated";
18
+	private static final String SearchBarCancelPressed  = "RNN.SearchBarCancelPressed";
17
 
19
 
18
-    private final RCTDeviceEventEmitter emitter;
20
+	private final RCTDeviceEventEmitter emitter;
19
 
21
 
20
-    EventEmitter(ReactContext reactContext) {
22
+	EventEmitter(ReactContext reactContext) {
21
 		this.emitter = reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class);
23
 		this.emitter = reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class);
22
 	}
24
 	}
23
 
25
 
24
 	public void appLaunched() {
26
 	public void appLaunched() {
25
-		emit(onAppLaunched);
27
+		emit(AppLaunched);
26
 	}
28
 	}
27
 
29
 
28
 	public void componentDidDisappear(String id, String componentName) {
30
 	public void componentDidDisappear(String id, String componentName) {
29
 		WritableMap event = Arguments.createMap();
31
 		WritableMap event = Arguments.createMap();
30
 		event.putString("componentId", id);
32
 		event.putString("componentId", id);
31
 		event.putString("componentName", componentName);
33
 		event.putString("componentName", componentName);
32
-		emit(componentDidDisappear, event);
34
+		emit(ComponentDidDisappear, event);
33
 	}
35
 	}
34
 
36
 
35
 	public void componentDidAppear(String id, String componentName) {
37
 	public void componentDidAppear(String id, String componentName) {
36
 		WritableMap event = Arguments.createMap();
38
 		WritableMap event = Arguments.createMap();
37
 		event.putString("componentId", id);
39
 		event.putString("componentId", id);
38
 		event.putString("componentName", componentName);
40
 		event.putString("componentName", componentName);
39
-		emit(componentDidAppear, event);
41
+		emit(ComponentDidAppear, event);
40
 	}
42
 	}
41
 
43
 
42
-    public void emitOnNavigationButtonPressed(String id, String buttonId) {
43
-		WritableMap params = Arguments.createMap();
44
-		params.putString("componentId", id);
45
-		params.putString("buttonId", buttonId);
46
-
47
-        WritableMap event = Arguments.createMap();
48
-        event.putString("name", buttonPressedEvent);
49
-        event.putMap("params", params);
50
-		emit(nativeEvent, event);
44
+	public void emitOnNavigationButtonPressed(String id, String buttonId) {
45
+		WritableMap event = Arguments.createMap();
46
+		event.putString("componentId", id);
47
+		event.putString("buttonId", buttonId);
48
+		emit(NavigationButtonPressed, event);
51
 	}
49
 	}
52
 
50
 
53
-    public void emitBottomTabSelected(int unselectedTabIndex, int selectedTabIndex) {
54
-        WritableMap params = Arguments.createMap();
55
-        params.putInt("unselectedTabIndex", unselectedTabIndex);
56
-        params.putInt("selectedTabIndex", selectedTabIndex);
57
-
58
-        WritableMap event = Arguments.createMap();
59
-        event.putString("name", "bottomTabSelected");
60
-        event.putMap("params", params);
61
-        emitter.emit(nativeEvent, event);
62
-    }
51
+	public void emitBottomTabSelected(int unselectedTabIndex, int selectedTabIndex) {
52
+		WritableMap event = Arguments.createMap();
53
+		event.putInt("unselectedTabIndex", unselectedTabIndex);
54
+		event.putInt("selectedTabIndex", selectedTabIndex);
55
+		emit(BottomTabSelected, event);
56
+	}
63
 
57
 
64
-    public void emitCommandCompletedEvent(String commandId, long completionTime) {
65
-        WritableMap event = Arguments.createMap();
66
-        event.putString("commandId", commandId);
67
-        event.putDouble("completionTime", completionTime);
68
-        emitter.emit(commandCompleted, event);
69
-    }
58
+	public void emitCommandCompletedEvent(String commandId, long completionTime) {
59
+		WritableMap event = Arguments.createMap();
60
+		event.putString("commandId", commandId);
61
+		event.putDouble("completionTime", completionTime);
62
+		emit(CommandCompleted, event);
63
+	}
70
 
64
 
71
 	private void emit(String eventName) {
65
 	private void emit(String eventName) {
72
 		emit(eventName, Arguments.createMap());
66
 		emit(eventName, Arguments.createMap());

+ 0
- 3
lib/ios/RNNCommandsHandler.m Ver fichero

50
 	[self assertReady];
50
 	[self assertReady];
51
 	
51
 	
52
 	[_modalManager dismissAllModals];
52
 	[_modalManager dismissAllModals];
53
-	[_eventEmitter sendOnNavigationCommand:setRoot params:@{@"layout": layout}];
54
 	
53
 	
55
 	UIViewController *vc = [_controllerFactory createLayoutAndSaveToStore:layout[@"root"]];
54
 	UIViewController *vc = [_controllerFactory createLayoutAndSaveToStore:layout[@"root"]];
56
 	
55
 	
62
 
61
 
63
 -(void) mergeOptions:(NSString*)componentId options:(NSDictionary*)options completion:(RNNTransitionCompletionBlock)completion {
62
 -(void) mergeOptions:(NSString*)componentId options:(NSDictionary*)options completion:(RNNTransitionCompletionBlock)completion {
64
 	[self assertReady];
63
 	[self assertReady];
65
-	[_eventEmitter sendOnNavigationCommand:mergeOptions params:@{@"componentId": componentId, @"options": options}];
66
 	
64
 	
67
 	UIViewController* vc = [_store findComponentForId:componentId];
65
 	UIViewController* vc = [_store findComponentForId:componentId];
68
 	if([vc isKindOfClass:[RNNRootViewController class]]) {
66
 	if([vc isKindOfClass:[RNNRootViewController class]]) {
91
 
89
 
92
 -(void) setDefaultOptions:(NSDictionary*)optionsDict completion:(RNNTransitionCompletionBlock)completion {
90
 -(void) setDefaultOptions:(NSDictionary*)optionsDict completion:(RNNTransitionCompletionBlock)completion {
93
 	[self assertReady];
91
 	[self assertReady];
94
-	[_eventEmitter sendOnNavigationCommand:setDefaultOptions params:@{@"options": optionsDict}];
95
 	[_controllerFactory setDefaultOptionsDict:optionsDict];
92
 	[_controllerFactory setDefaultOptionsDict:optionsDict];
96
 }
93
 }
97
 
94
 

+ 1
- 3
lib/ios/RNNEventEmitter.h Ver fichero

14
 
14
 
15
 -(void)sendOnNavigationButtonPressed:(NSString*)componentId buttonId:(NSString*)buttonId;
15
 -(void)sendOnNavigationButtonPressed:(NSString*)componentId buttonId:(NSString*)buttonId;
16
 
16
 
17
--(void)sendOnNavigationEvent:(NSString *)commandName params:(NSDictionary*)params;
18
-
19
--(void)sendOnNavigationCommand:(NSString *)commandName params:(NSDictionary*)params;
17
+-(void)sendBottomTabSelected:(NSNumber *)selectedTabIndex unselected:(NSNumber*)unselectedTabIndex;
20
 
18
 
21
 -(void)sendOnNavigationCommandCompletion:(NSString *)commandName params:(NSDictionary*)params;
19
 -(void)sendOnNavigationCommandCompletion:(NSString *)commandName params:(NSDictionary*)params;
22
 
20
 

+ 53
- 31
lib/ios/RNNEventEmitter.m Ver fichero

2
 #import "RNNUtils.h"
2
 #import "RNNUtils.h"
3
 
3
 
4
 @implementation RNNEventEmitter {
4
 @implementation RNNEventEmitter {
5
-  NSInteger _appLaunchedListenerCount;
6
-  BOOL _appLaunchedEventDeferred;
5
+	NSInteger _appLaunchedListenerCount;
6
+	BOOL _appLaunchedEventDeferred;
7
 }
7
 }
8
 
8
 
9
 RCT_EXPORT_MODULE();
9
 RCT_EXPORT_MODULE();
10
 
10
 
11
-static NSString* const onAppLaunched	= @"RNN.appLaunched";
12
-static NSString* const componentDidAppear	= @"RNN.componentDidAppear";
13
-static NSString* const componentDidDisappear	= @"RNN.componentDidDisappear";
14
-static NSString* const commandComplete	= @"RNN.commandCompleted";
15
-static NSString* const navigationEvent	= @"RNN.nativeEvent";
11
+static NSString* const AppLaunched				= @"RNN.AppLaunched";
12
+static NSString* const CommandCompleted			= @"RNN.CommandCompleted";
13
+static NSString* const BottomTabSelected		= @"RNN.BottomTabSelected";
14
+static NSString* const ComponentDidAppear		= @"RNN.ComponentDidAppear";
15
+static NSString* const ComponentDidDisappear	= @"RNN.ComponentDidDisappear";
16
+static NSString* const NavigationButtonPressed	= @"RNN.NavigationButtonPressed";
17
+static NSString* const SearchBarUpdated 		= @"RNN.SearchBarUpdated";
18
+static NSString* const SearchBarCancelPressed 	= @"RNN.SearchBarCancelPressed";
16
 
19
 
17
 -(NSArray<NSString *> *)supportedEvents {
20
 -(NSArray<NSString *> *)supportedEvents {
18
-	return @[onAppLaunched, componentDidAppear, componentDidDisappear, commandComplete, navigationEvent];
21
+	return @[AppLaunched,
22
+			 CommandCompleted,
23
+			 BottomTabSelected,
24
+			 ComponentDidAppear,
25
+			 ComponentDidDisappear,
26
+			 NavigationButtonPressed,
27
+			 SearchBarUpdated,
28
+			 SearchBarCancelPressed];
19
 }
29
 }
20
 
30
 
21
 # pragma mark public
31
 # pragma mark public
22
 
32
 
23
 -(void)sendOnAppLaunched {
33
 -(void)sendOnAppLaunched {
24
 	if (_appLaunchedListenerCount > 0) {
34
 	if (_appLaunchedListenerCount > 0) {
25
-		[self send:onAppLaunched body:nil];
35
+		[self send:AppLaunched body:nil];
26
 	} else {
36
 	} else {
27
 		_appLaunchedEventDeferred = TRUE;
37
 		_appLaunchedEventDeferred = TRUE;
28
 	}
38
 	}
29
 }
39
 }
30
 
40
 
31
 -(void)sendComponentDidAppear:(NSString *)componentId componentName:(NSString *)componentName {
41
 -(void)sendComponentDidAppear:(NSString *)componentId componentName:(NSString *)componentName {
32
-	[self send:componentDidAppear body:@{@"componentId":componentId, @"componentName": componentName}];
42
+	[self send:ComponentDidAppear body:@{
43
+										 @"componentId":componentId,
44
+										 @"componentName": componentName
45
+										 }];
33
 }
46
 }
34
 
47
 
35
 -(void)sendComponentDidDisappear:(NSString *)componentId componentName:(NSString *)componentName{
48
 -(void)sendComponentDidDisappear:(NSString *)componentId componentName:(NSString *)componentName{
36
-	[self send:componentDidDisappear body:@{@"componentId":componentId, @"componentName": componentName}];
49
+	[self send:ComponentDidDisappear body:@{
50
+											@"componentId":componentId,
51
+											@"componentName": componentName
52
+											}];
37
 }
53
 }
38
 
54
 
39
 -(void)sendOnNavigationButtonPressed:(NSString *)componentId buttonId:(NSString*)buttonId {
55
 -(void)sendOnNavigationButtonPressed:(NSString *)componentId buttonId:(NSString*)buttonId {
40
-	[self send:navigationEvent body:@{@"name": @"buttonPressed", @"params": @{@"componentId": componentId , @"buttonId": buttonId}}];
56
+	[self send:NavigationButtonPressed body:@{
57
+											  @"componentId": componentId,
58
+											  @"buttonId": buttonId
59
+											  }];
41
 }
60
 }
42
 
61
 
43
--(void)sendOnNavigationCommand:(NSString *)commandName params:(NSDictionary*)params {
44
-	[self send:navigationEvent body:@{@"name":commandName , @"params": params}];
62
+-(void)sendBottomTabSelected:(NSNumber *)selectedTabIndex unselected:(NSNumber*)unselectedTabIndex {
63
+	[self send:BottomTabSelected body:@{
64
+									  @"selectedTabIndex": selectedTabIndex,
65
+									  @"unselectedTabIndex": unselectedTabIndex
66
+									  }];
45
 }
67
 }
46
 
68
 
47
 -(void)sendOnNavigationCommandCompletion:(NSString *)commandName params:(NSDictionary*)params {
69
 -(void)sendOnNavigationCommandCompletion:(NSString *)commandName params:(NSDictionary*)params {
48
-	[self send:commandComplete body:@{@"commandId":commandName , @"params": params, @"completionTime": [RNNUtils getCurrentTimestamp] }];
49
-}
50
-
51
--(void)sendOnNavigationEvent:(NSString *)commandName params:(NSDictionary*)params {
52
-	[self send:navigationEvent body:@{@"name":commandName , @"params": params}];
70
+	[self send:CommandCompleted body:@{
71
+									   @"commandId":commandName,
72
+									   @"params": params,
73
+									   @"completionTime": [RNNUtils getCurrentTimestamp]
74
+									   }];
53
 }
75
 }
54
 
76
 
55
 -(void)sendOnSearchBarUpdated:(NSString *)componentId
77
 -(void)sendOnSearchBarUpdated:(NSString *)componentId
56
 						 text:(NSString*)text
78
 						 text:(NSString*)text
57
 					isFocused:(BOOL)isFocused {
79
 					isFocused:(BOOL)isFocused {
58
-	[self send:navigationEvent body:@{@"name": @"searchBarUpdated",
59
-									  @"params": @{
60
-												  @"componentId": componentId,
61
-												  @"text": text,
62
-												  @"isFocused": @(isFocused)}}];
80
+	[self send:SearchBarUpdated body:@{
81
+									   @"componentId": componentId,
82
+									   @"text": text,
83
+									   @"isFocused": @(isFocused)
84
+									   }];
63
 }
85
 }
64
 
86
 
65
 - (void)sendOnSearchBarCancelPressed:(NSString *)componentId {
87
 - (void)sendOnSearchBarCancelPressed:(NSString *)componentId {
66
-	[self send:navigationEvent body:@{@"name": @"searchBarCancelPressed",
67
-									  @"params": @{
68
-											  @"componentId": componentId}}];
88
+	[self send:SearchBarCancelPressed body:@{
89
+											@"componentId": componentId
90
+											}];
69
 }
91
 }
70
 
92
 
71
 - (void)addListener:(NSString *)eventName {
93
 - (void)addListener:(NSString *)eventName {
72
 	[super addListener:eventName];
94
 	[super addListener:eventName];
73
-	if ([eventName isEqualToString:onAppLaunched]) {
95
+	if ([eventName isEqualToString:AppLaunched]) {
74
 		_appLaunchedListenerCount++;
96
 		_appLaunchedListenerCount++;
75
 		if (_appLaunchedEventDeferred) {
97
 		if (_appLaunchedEventDeferred) {
76
 			_appLaunchedEventDeferred = FALSE;
98
 			_appLaunchedEventDeferred = FALSE;
82
 # pragma mark private
104
 # pragma mark private
83
 
105
 
84
 -(void)send:(NSString *)eventName body:(id)body {
106
 -(void)send:(NSString *)eventName body:(id)body {
85
-    if ([eventName isEqualToString:componentDidDisappear] && self.bridge == nil) {
86
-        return;
87
-    }
107
+	if (self.bridge == nil) {
108
+		return;
109
+	}
88
 	[self sendEventWithName:eventName body:body];
110
 	[self sendEventWithName:eventName body:body];
89
 }
111
 }
90
 
112
 

+ 11
- 11
lib/ios/RNNRootViewController.m Ver fichero

292
 
292
 
293
 - (UIViewController *)previewingContext:(id<UIViewControllerPreviewing>)previewingContext viewControllerForLocation:(CGPoint)location{
293
 - (UIViewController *)previewingContext:(id<UIViewControllerPreviewing>)previewingContext viewControllerForLocation:(CGPoint)location{
294
 	if (self.previewController) {
294
 	if (self.previewController) {
295
-		RNNRootViewController * vc = (RNNRootViewController*) self.previewController;
296
-		[_eventEmitter sendOnNavigationEvent:@"previewContext" params:@{
297
-																		@"previewComponentId": vc.componentId,
298
-																		@"componentId": self.componentId
299
-																		}];
295
+//		RNNRootViewController * vc = (RNNRootViewController*) self.previewController;
296
+//		[_eventEmitter sendOnNavigationEvent:@"previewContext" params:@{
297
+//																		@"previewComponentId": vc.componentId,
298
+//																		@"componentId": self.componentId
299
+//																		}];
300
 	}
300
 	}
301
 	return self.previewController;
301
 	return self.previewController;
302
 }
302
 }
304
 
304
 
305
 - (void)previewingContext:(id<UIViewControllerPreviewing>)previewingContext commitViewController:(UIViewController *)viewControllerToCommit {
305
 - (void)previewingContext:(id<UIViewControllerPreviewing>)previewingContext commitViewController:(UIViewController *)viewControllerToCommit {
306
 	RNNRootViewController * vc = (RNNRootViewController*) self.previewController;
306
 	RNNRootViewController * vc = (RNNRootViewController*) self.previewController;
307
-	NSDictionary * params = @{
308
-							  @"previewComponentId": vc.componentId,
309
-							  @"componentId": self.componentId
310
-							  };
307
+//	NSDictionary * params = @{
308
+//							  @"previewComponentId": vc.componentId,
309
+//							  @"componentId": self.componentId
310
+//							  };
311
 	if (vc.options.preview.commit) {
311
 	if (vc.options.preview.commit) {
312
-		[_eventEmitter sendOnNavigationEvent:@"previewCommit" params:params];
312
+//		[_eventEmitter sendOnNavigationEvent:@"previewCommit" params:params];
313
 		[self.navigationController pushViewController:vc animated:false];
313
 		[self.navigationController pushViewController:vc animated:false];
314
 	} else {
314
 	} else {
315
-		[_eventEmitter sendOnNavigationEvent:@"previewDismissed" params:params];
315
+//		[_eventEmitter sendOnNavigationEvent:@"previewDismissed" params:params];
316
 	}
316
 	}
317
 }
317
 }
318
 
318
 

+ 1
- 2
lib/ios/RNNTabBarController.m Ver fichero

56
 #pragma mark UITabBarControllerDelegate
56
 #pragma mark UITabBarControllerDelegate
57
 
57
 
58
 - (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController {
58
 - (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController {
59
-	[_eventEmitter sendOnNavigationEvent:@"bottomTabSelected" params:@{@"selectedTabIndex": @(tabBarController.selectedIndex), @"unselectedTabIndex": @(_currentTabIndex)}];
60
-	
59
+	[_eventEmitter sendBottomTabSelected:@(tabBarController.selectedIndex) unselected:@(_currentTabIndex)];
61
 	_currentTabIndex = tabBarController.selectedIndex;
60
 	_currentTabIndex = tabBarController.selectedIndex;
62
 }
61
 }
63
 
62
 

+ 5
- 6
lib/src/Navigation.ts Ver fichero

9
 import { EventsRegistry } from './events/EventsRegistry';
9
 import { EventsRegistry } from './events/EventsRegistry';
10
 import { ComponentProvider } from 'react-native';
10
 import { ComponentProvider } from 'react-native';
11
 import { Element } from './adapters/Element';
11
 import { Element } from './adapters/Element';
12
-import { ComponentEventsObserver } from './events/ComponentEventsObserver';
13
 import { CommandsObserver } from './events/CommandsObserver';
12
 import { CommandsObserver } from './events/CommandsObserver';
14
 import { Constants } from './adapters/Constants';
13
 import { Constants } from './adapters/Constants';
15
 import { ComponentType } from 'react';
14
 import { ComponentType } from 'react';
15
+import { ComponentEventsObserver } from './events/ComponentEventsObserver';
16
 
16
 
17
 export class Navigation {
17
 export class Navigation {
18
   public readonly Element: React.ComponentType<{ elementId: any; resizeMode?: any; }>;
18
   public readonly Element: React.ComponentType<{ elementId: any; resizeMode?: any; }>;
33
     this.store = new Store();
33
     this.store = new Store();
34
     this.nativeEventsReceiver = new NativeEventsReceiver();
34
     this.nativeEventsReceiver = new NativeEventsReceiver();
35
     this.uniqueIdProvider = new UniqueIdProvider();
35
     this.uniqueIdProvider = new UniqueIdProvider();
36
-    this.componentRegistry = new ComponentRegistry(this.store);
36
+    this.componentEventsObserver = new ComponentEventsObserver(this.nativeEventsReceiver);
37
+    this.componentRegistry = new ComponentRegistry(this.store, this.componentEventsObserver);
37
     this.layoutTreeParser = new LayoutTreeParser();
38
     this.layoutTreeParser = new LayoutTreeParser();
38
     this.layoutTreeCrawler = new LayoutTreeCrawler(this.uniqueIdProvider, this.store);
39
     this.layoutTreeCrawler = new LayoutTreeCrawler(this.uniqueIdProvider, this.store);
39
     this.nativeCommandsSender = new NativeCommandsSender();
40
     this.nativeCommandsSender = new NativeCommandsSender();
40
     this.commandsObserver = new CommandsObserver();
41
     this.commandsObserver = new CommandsObserver();
41
     this.commands = new Commands(this.nativeCommandsSender, this.layoutTreeParser, this.layoutTreeCrawler, this.commandsObserver, this.uniqueIdProvider);
42
     this.commands = new Commands(this.nativeCommandsSender, this.layoutTreeParser, this.layoutTreeCrawler, this.commandsObserver, this.uniqueIdProvider);
42
-    this.eventsRegistry = new EventsRegistry(this.nativeEventsReceiver, this.commandsObserver);
43
-    this.componentEventsObserver = new ComponentEventsObserver(this.eventsRegistry, this.store);
43
+    this.eventsRegistry = new EventsRegistry(this.nativeEventsReceiver, this.commandsObserver, this.componentEventsObserver);
44
 
44
 
45
-    this.componentEventsObserver.registerForAllComponents();
45
+    this.componentEventsObserver.registerOnceForAllComponentEvents();
46
   }
46
   }
47
 
47
 
48
   /**
48
   /**
145
   }
145
   }
146
 
146
 
147
   /**
147
   /**
148
-   * 
149
    * Resolves arguments passed on launch
148
    * Resolves arguments passed on launch
150
    */
149
    */
151
   public getLaunchArgs(): Promise<any> {
150
   public getLaunchArgs(): Promise<any> {

+ 29
- 9
lib/src/adapters/NativeEventsReceiver.ts Ver fichero

1
 import { NativeModules, NativeEventEmitter } from 'react-native';
1
 import { NativeModules, NativeEventEmitter } from 'react-native';
2
 import { EventSubscription } from '../interfaces/EventSubscription';
2
 import { EventSubscription } from '../interfaces/EventSubscription';
3
+import {
4
+  ComponentDidAppearEvent,
5
+  ComponentDidDisappearEvent,
6
+  NavigationButtonPressedEvent,
7
+  SearchBarUpdatedEvent,
8
+  SearchBarCancelPressedEvent
9
+} from '../interfaces/ComponentEvents';
10
+import { CommandCompletedEvent, BottomTabSelectedEvent } from '../interfaces/Events';
3
 
11
 
4
 export class NativeEventsReceiver {
12
 export class NativeEventsReceiver {
5
   private emitter;
13
   private emitter;
18
   }
26
   }
19
 
27
 
20
   public registerAppLaunchedListener(callback: () => void): EventSubscription {
28
   public registerAppLaunchedListener(callback: () => void): EventSubscription {
21
-    return this.emitter.addListener('RNN.appLaunched', callback);
29
+    return this.emitter.addListener('RNN.AppLaunched', callback);
22
   }
30
   }
23
 
31
 
24
-  public registerComponentDidAppearListener(callback: (data) => void): EventSubscription {
25
-    return this.emitter.addListener('RNN.componentDidAppear', callback);
32
+  public registerComponentDidAppearListener(callback: (event: ComponentDidAppearEvent) => void): EventSubscription {
33
+    return this.emitter.addListener('RNN.ComponentDidAppear', callback);
26
   }
34
   }
27
 
35
 
28
-  public registerComponentDidDisappearListener(callback: (data) => void): EventSubscription {
29
-    return this.emitter.addListener('RNN.componentDidDisappear', callback);
36
+  public registerComponentDidDisappearListener(callback: (event: ComponentDidDisappearEvent) => void): EventSubscription {
37
+    return this.emitter.addListener('RNN.ComponentDidDisappear', callback);
30
   }
38
   }
31
 
39
 
32
-  public registerCommandCompletedListener(callback: (data) => void): EventSubscription {
33
-    return this.emitter.addListener('RNN.commandCompleted', callback);
40
+  public registerNavigationButtonPressedListener(callback: (event: NavigationButtonPressedEvent) => void): EventSubscription {
41
+    return this.emitter.addListener('RNN.NavigationButtonPressed', callback);
34
   }
42
   }
35
 
43
 
36
-  public registerNativeEventListener(callback: (data) => void): EventSubscription {
37
-    return this.emitter.addListener('RNN.nativeEvent', callback);
44
+  public registerSearchBarUpdatedListener(callback: (event: SearchBarUpdatedEvent) => void): EventSubscription {
45
+    return this.emitter.addListener('RNN.SearchBarUpdated', callback);
46
+  }
47
+
48
+  public registerSearchBarCancelPressedListener(callback: (event: SearchBarCancelPressedEvent) => void): EventSubscription {
49
+    return this.emitter.addListener('RNN.SearchBarCancelPressed', callback);
50
+  }
51
+
52
+  public registerCommandCompletedListener(callback: (data: CommandCompletedEvent) => void): EventSubscription {
53
+    return this.emitter.addListener('RNN.CommandCompleted', callback);
54
+  }
55
+
56
+  public registerBottomTabSelectedListener(callback: (data: BottomTabSelectedEvent) => void): EventSubscription {
57
+    return this.emitter.addListener('RNN.BottomTabSelected', callback);
38
   }
58
   }
39
 }
59
 }

+ 1
- 1
lib/src/components/ComponentRegistry.test.tsx Ver fichero

23
   beforeEach(() => {
23
   beforeEach(() => {
24
     store = new Store();
24
     store = new Store();
25
     mockRegistry = AppRegistry.registerComponent = jest.fn(AppRegistry.registerComponent);
25
     mockRegistry = AppRegistry.registerComponent = jest.fn(AppRegistry.registerComponent);
26
-    uut = new ComponentRegistry(store);
26
+    uut = new ComponentRegistry(store, {} as any);
27
   });
27
   });
28
 
28
 
29
   it('registers component component by componentName into AppRegistry', () => {
29
   it('registers component component by componentName into AppRegistry', () => {

+ 4
- 6
lib/src/components/ComponentRegistry.ts Ver fichero

1
 import { AppRegistry, ComponentProvider } from 'react-native';
1
 import { AppRegistry, ComponentProvider } from 'react-native';
2
 import { ComponentWrapper } from './ComponentWrapper';
2
 import { ComponentWrapper } from './ComponentWrapper';
3
 import { ComponentType } from 'react';
3
 import { ComponentType } from 'react';
4
+import { Store } from './Store';
5
+import { ComponentEventsObserver } from '../events/ComponentEventsObserver';
4
 
6
 
5
 export class ComponentRegistry {
7
 export class ComponentRegistry {
6
-  private store;
7
-
8
-  constructor(store) {
9
-    this.store = store;
10
-  }
8
+  constructor(private readonly store: Store, private readonly componentEventsObserver: ComponentEventsObserver) { }
11
 
9
 
12
   registerComponent(componentName: string, getComponentClassFunc: ComponentProvider): ComponentType<any> {
10
   registerComponent(componentName: string, getComponentClassFunc: ComponentProvider): ComponentType<any> {
13
     const OriginalComponentClass = getComponentClassFunc();
11
     const OriginalComponentClass = getComponentClassFunc();
14
-    const NavigationComponent = ComponentWrapper.wrap(componentName, OriginalComponentClass, this.store);
12
+    const NavigationComponent = ComponentWrapper.wrap(componentName, OriginalComponentClass, this.store, this.componentEventsObserver);
15
     this.store.setOriginalComponentClassForName(componentName, OriginalComponentClass);
13
     this.store.setOriginalComponentClassForName(componentName, OriginalComponentClass);
16
     AppRegistry.registerComponent(componentName, () => NavigationComponent);
14
     AppRegistry.registerComponent(componentName, () => NavigationComponent);
17
     return NavigationComponent;
15
     return NavigationComponent;

+ 51
- 147
lib/src/components/ComponentWrapper.test.tsx Ver fichero

4
 import { ComponentWrapper } from './ComponentWrapper';
4
 import { ComponentWrapper } from './ComponentWrapper';
5
 import { Store } from './Store';
5
 import { Store } from './Store';
6
 
6
 
7
-declare module 'react-test-renderer' {
8
-  interface ReactTestInstance {
9
-    [P: string]: any;
10
-  }
11
-}
12
-
13
 describe('ComponentWrapper', () => {
7
 describe('ComponentWrapper', () => {
14
-  let store;
15
   const componentName = 'example.MyComponent';
8
   const componentName = 'example.MyComponent';
16
-  let childRef;
9
+  let store;
10
+  let myComponentProps;
11
+  const componentEventsObserver = { unmounted: jest.fn() };
17
 
12
 
18
-  class MyComponent extends React.Component {
13
+  class MyComponent extends React.Component<any, any> {
19
     static options = {
14
     static options = {
20
       title: 'MyComponentTitle'
15
       title: 'MyComponentTitle'
21
     };
16
     };
22
 
17
 
23
     render() {
18
     render() {
24
-      return <Text>{'Hello, World!'}</Text>;
19
+      myComponentProps = this.props;
20
+      if (this.props.renderCount) {
21
+        this.props.renderCount();
22
+      }
23
+      return <Text>{this.props.text || 'Hello, World!'}</Text>;
25
     }
24
     }
26
   }
25
   }
27
 
26
 
28
-  class TestParent extends React.Component<any, { propsFromState: {} }> {
27
+  class TestParent extends React.Component<any, any> {
29
     private ChildClass;
28
     private ChildClass;
30
 
29
 
31
     constructor(props) {
30
     constructor(props) {
37
     render() {
36
     render() {
38
       return (
37
       return (
39
         <this.ChildClass
38
         <this.ChildClass
40
-          ref={(r) => childRef = r}
41
           componentId='component1'
39
           componentId='component1'
42
           {...this.state.propsFromState}
40
           {...this.state.propsFromState}
43
         />
41
         />
50
   });
48
   });
51
 
49
 
52
   it('must have componentId as prop', () => {
50
   it('must have componentId as prop', () => {
53
-    const NavigationComponent = ComponentWrapper.wrap(componentName, MyComponent, store);
51
+    const NavigationComponent = ComponentWrapper.wrap(componentName, MyComponent, store, componentEventsObserver);
54
     const orig = console.error;
52
     const orig = console.error;
55
     console.error = (a) => a;
53
     console.error = (a) => a;
56
     expect(() => {
54
     expect(() => {
60
   });
58
   });
61
 
59
 
62
   it('wraps the component', () => {
60
   it('wraps the component', () => {
63
-    const NavigationComponent = ComponentWrapper.wrap(componentName, MyComponent, store);
61
+    const NavigationComponent = ComponentWrapper.wrap(componentName, MyComponent, store, componentEventsObserver);
64
     expect(NavigationComponent).not.toBeInstanceOf(MyComponent);
62
     expect(NavigationComponent).not.toBeInstanceOf(MyComponent);
65
     const tree = renderer.create(<NavigationComponent componentId={'component1'} />);
63
     const tree = renderer.create(<NavigationComponent componentId={'component1'} />);
66
     expect(tree.toJSON()!.children).toEqual(['Hello, World!']);
64
     expect(tree.toJSON()!.children).toEqual(['Hello, World!']);
67
-    expect(tree.getInstance()!.originalComponentRef).toBeInstanceOf(MyComponent);
68
   });
65
   });
69
 
66
 
70
   it('injects props from wrapper into original component', () => {
67
   it('injects props from wrapper into original component', () => {
71
-    const NavigationComponent = ComponentWrapper.wrap(componentName, MyComponent, store);
72
-    const tree = renderer.create(<NavigationComponent componentId={'component1'} myProp={'yo'} />);
73
-    expect(tree.getInstance()!.originalComponentRef.props.myProp).toEqual('yo');
68
+    const renderCount = jest.fn();
69
+    const NavigationComponent = ComponentWrapper.wrap(componentName, MyComponent, store, componentEventsObserver);
70
+    const tree = renderer.create(<NavigationComponent componentId={'component1'} text={'yo'} renderCount={renderCount} />);
71
+    expect(tree.toJSON()!.children).toEqual(['yo']);
72
+    expect(renderCount).toHaveBeenCalledTimes(1);
74
   });
73
   });
75
 
74
 
76
-  it('updates props from wrapper into original component', () => {
77
-    const NavigationComponent = ComponentWrapper.wrap(componentName, MyComponent, store);
75
+  it('updates props from wrapper into original component on state change', () => {
76
+    const NavigationComponent = ComponentWrapper.wrap(componentName, MyComponent, store, componentEventsObserver);
78
     const tree = renderer.create(<TestParent ChildClass={NavigationComponent} />);
77
     const tree = renderer.create(<TestParent ChildClass={NavigationComponent} />);
79
-    expect(childRef.props.foo).toEqual(undefined);
80
-    tree.getInstance()!.setState({ propsFromState: { foo: 'yo' } });
81
-    expect(childRef.props.foo).toEqual('yo');
78
+    expect(myComponentProps.foo).toEqual(undefined);
79
+    (tree.getInstance() as any).setState({ propsFromState: { foo: 'yo' } });
80
+    expect(myComponentProps.foo).toEqual('yo');
82
   });
81
   });
83
 
82
 
84
   it('pulls props from the store and injects them into the inner component', () => {
83
   it('pulls props from the store and injects them into the inner component', () => {
85
     store.setPropsForId('component123', { numberProp: 1, stringProp: 'hello', objectProp: { a: 2 } });
84
     store.setPropsForId('component123', { numberProp: 1, stringProp: 'hello', objectProp: { a: 2 } });
86
-    const NavigationComponent = ComponentWrapper.wrap(componentName, MyComponent, store);
87
-    const tree = renderer.create(<NavigationComponent componentId={'component123'} />);
88
-    const originalComponentProps = tree.getInstance()!.originalComponentRef.props;
89
-    expect(originalComponentProps).toEqual({ componentId: 'component123', numberProp: 1, stringProp: 'hello', objectProp: { a: 2 } });
85
+    const NavigationComponent = ComponentWrapper.wrap(componentName, MyComponent, store, componentEventsObserver);
86
+    renderer.create(<NavigationComponent componentId={'component123'} />);
87
+    expect(myComponentProps).toEqual({ componentId: 'component123', numberProp: 1, stringProp: 'hello', objectProp: { a: 2 } });
90
   });
88
   });
91
 
89
 
92
   it('updates props from store into inner component', () => {
90
   it('updates props from store into inner component', () => {
93
-    const NavigationComponent = ComponentWrapper.wrap(componentName, MyComponent, store);
91
+    const NavigationComponent = ComponentWrapper.wrap(componentName, MyComponent, store, componentEventsObserver);
94
     const tree = renderer.create(<TestParent ChildClass={NavigationComponent} />);
92
     const tree = renderer.create(<TestParent ChildClass={NavigationComponent} />);
95
     store.setPropsForId('component1', { myProp: 'hello' });
93
     store.setPropsForId('component1', { myProp: 'hello' });
96
-    expect(childRef.originalComponentRef.props.foo).toEqual(undefined);
97
-    expect(childRef.originalComponentRef.props.myProp).toEqual(undefined);
98
-    tree.getInstance()!.setState({ propsFromState: { foo: 'yo' } });
99
-    expect(childRef.originalComponentRef.props.foo).toEqual('yo');
100
-    expect(childRef.originalComponentRef.props.myProp).toEqual('hello');
94
+    expect(myComponentProps.foo).toEqual(undefined);
95
+    expect(myComponentProps.myProp).toEqual(undefined);
96
+    (tree.getInstance() as any).setState({ propsFromState: { foo: 'yo' } });
97
+    expect(myComponentProps.foo).toEqual('yo');
98
+    expect(myComponentProps.myProp).toEqual('hello');
101
   });
99
   });
102
 
100
 
103
   it('protects id from change', () => {
101
   it('protects id from change', () => {
104
-    const NavigationComponent = ComponentWrapper.wrap(componentName, MyComponent, store);
102
+    const NavigationComponent = ComponentWrapper.wrap(componentName, MyComponent, store, componentEventsObserver);
105
     const tree = renderer.create(<TestParent ChildClass={NavigationComponent} />);
103
     const tree = renderer.create(<TestParent ChildClass={NavigationComponent} />);
106
-    expect(childRef.originalComponentRef.props.componentId).toEqual('component1');
107
-    tree.getInstance()!.setState({ propsFromState: { id: 'ERROR' } });
108
-    expect(childRef.originalComponentRef.props.componentId).toEqual('component1');
104
+    expect(myComponentProps.componentId).toEqual('component1');
105
+    (tree.getInstance() as any).setState({ propsFromState: { id: 'ERROR' } });
106
+    expect(myComponentProps.componentId).toEqual('component1');
109
   });
107
   });
110
 
108
 
111
   it('assignes key by id', () => {
109
   it('assignes key by id', () => {
112
-    const NavigationComponent = ComponentWrapper.wrap(componentName, MyComponent, store);
113
-    const tree = renderer.create(<NavigationComponent componentId={'component1'} />);
114
-    expect(tree.getInstance()!.originalComponentRef.props.componentId).toEqual('component1');
115
-    expect(tree.getInstance()!.originalComponentRef._reactInternalInstance.key).toEqual('component1');
116
-  });
117
-
118
-  it('saves self ref into store', () => {
119
-    const NavigationComponent = ComponentWrapper.wrap(componentName, MyComponent, store);
120
-    const tree = renderer.create(<NavigationComponent componentId={'component1'} />);
121
-    expect(store.getRefForId('component1')).toBeDefined();
122
-    expect(store.getRefForId('component1')).toBe(tree.getInstance());
123
-  });
124
-
125
-  it('cleans ref from store on unMount', () => {
126
-    const NavigationComponent = ComponentWrapper.wrap(componentName, MyComponent, store);
127
-    const tree = renderer.create(<NavigationComponent componentId={'component1'} />);
128
-    expect(store.getRefForId('component1')).toBeDefined();
129
-    tree.unmount();
130
-    expect(store.getRefForId('component1')).toBeUndefined();
131
-  });
132
-
133
-  it('holds ref to OriginalComponent', () => {
134
-    const NavigationComponent = ComponentWrapper.wrap(componentName, MyComponent, store);
110
+    const NavigationComponent = ComponentWrapper.wrap(componentName, MyComponent, store, componentEventsObserver);
135
     const tree = renderer.create(<NavigationComponent componentId={'component1'} />);
111
     const tree = renderer.create(<NavigationComponent componentId={'component1'} />);
136
-    expect(tree.getInstance()!.originalComponentRef).toBeDefined();
137
-    expect(tree.getInstance()!.originalComponentRef).toBeInstanceOf(MyComponent);
112
+    expect(myComponentProps.componentId).toEqual('component1');
113
+    expect((tree.getInstance() as any)._reactInternalInstance.child.key).toEqual('component1');
138
   });
114
   });
139
 
115
 
140
-  it('cleans ref to internal component on unount', () => {
141
-    const NavigationComponent = ComponentWrapper.wrap(componentName, MyComponent, store);
142
-    const tree = renderer.create(<NavigationComponent componentId={'component1'} />);
143
-    const instance = tree.getInstance()!;
144
-    expect(instance.originalComponentRef).toBeInstanceOf(React.Component);
116
+  it('cleans props from store on unMount', () => {
117
+    store.setPropsForId('component123', { foo: 'bar' });
118
+    const NavigationComponent = ComponentWrapper.wrap(componentName, MyComponent, store, componentEventsObserver);
119
+    const tree = renderer.create(<NavigationComponent componentId={'component123'} />);
120
+    expect(store.getPropsForId('component123')).toEqual({ foo: 'bar' });
145
     tree.unmount();
121
     tree.unmount();
146
-    expect(instance.originalComponentRef).toBeFalsy();
122
+    expect(store.getPropsForId('component123')).toEqual({});
147
   });
123
   });
148
 
124
 
149
   it(`merges static members from wrapped component`, () => {
125
   it(`merges static members from wrapped component`, () => {
150
-    const NavigationComponent = ComponentWrapper.wrap(componentName, MyComponent, store) as any;
126
+    const NavigationComponent = ComponentWrapper.wrap(componentName, MyComponent, store, componentEventsObserver) as any;
151
     expect(NavigationComponent.options).toEqual({ title: 'MyComponentTitle' });
127
     expect(NavigationComponent.options).toEqual({ title: 'MyComponentTitle' });
152
   });
128
   });
153
 
129
 
154
-  describe('component lifecycle', () => {
155
-    const componentDidAppearCallback = jest.fn();
156
-    const componentDidDisappearCallback = jest.fn();
157
-    const onNavigationButtonPressedCallback = jest.fn();
158
-    const onSearchBarCallback = jest.fn();
159
-    const onSearchBarCancelCallback = jest.fn();
160
-
161
-    class MyLifecycleComponent extends MyComponent {
162
-      componentDidAppear() {
163
-        componentDidAppearCallback();
164
-      }
165
-
166
-      componentDidDisappear() {
167
-        componentDidDisappearCallback();
168
-      }
169
-
170
-      onNavigationButtonPressed() {
171
-        onNavigationButtonPressedCallback();
172
-      }
173
-
174
-      onSearchBarUpdated() {
175
-        onSearchBarCallback();
176
-      }
177
-
178
-      onSearchBarCancelPressed() {
179
-        onSearchBarCancelCallback();
180
-      }
181
-    }
182
-
183
-    it('componentDidAppear, componentDidDisappear and onNavigationButtonPressed are optional', () => {
184
-      const NavigationComponent = ComponentWrapper.wrap(componentName, MyComponent, store);
185
-      const tree = renderer.create(<NavigationComponent componentId={'component1'} />);
186
-      expect(() => tree.getInstance()!.componentDidAppear()).not.toThrow();
187
-      expect(() => tree.getInstance()!.componentDidDisappear()).not.toThrow();
188
-      expect(() => tree.getInstance()!.onNavigationButtonPressed()).not.toThrow();
189
-      expect(() => tree.getInstance()!.onSearchBarUpdated()).not.toThrow();
190
-      expect(() => tree.getInstance()!.onSearchBarCancelPressed()).not.toThrow();
191
-    });
192
-
193
-    it('calls componentDidAppear on OriginalComponent', () => {
194
-      const NavigationComponent = ComponentWrapper.wrap(componentName, MyLifecycleComponent, store);
195
-      const tree = renderer.create(<NavigationComponent componentId={'component1'} />);
196
-      expect(componentDidAppearCallback).toHaveBeenCalledTimes(0);
197
-      tree.getInstance()!.componentDidAppear();
198
-      expect(componentDidAppearCallback).toHaveBeenCalledTimes(1);
199
-    });
200
-
201
-    it('calls componentDidDisappear on OriginalComponent', () => {
202
-      const NavigationComponent = ComponentWrapper.wrap(componentName, MyLifecycleComponent, store);
203
-      const tree = renderer.create(<NavigationComponent componentId={'component1'} />);
204
-      expect(componentDidDisappearCallback).toHaveBeenCalledTimes(0);
205
-      tree.getInstance()!.componentDidDisappear();
206
-      expect(componentDidDisappearCallback).toHaveBeenCalledTimes(1);
207
-    });
208
-
209
-    it('calls onNavigationButtonPressed on OriginalComponent', () => {
210
-      const NavigationComponent = ComponentWrapper.wrap(componentName, MyLifecycleComponent, store);
211
-      const tree = renderer.create(<NavigationComponent componentId={'component1'} />);
212
-      expect(onNavigationButtonPressedCallback).toHaveBeenCalledTimes(0);
213
-      tree.getInstance()!.onNavigationButtonPressed();
214
-      expect(onNavigationButtonPressedCallback).toHaveBeenCalledTimes(1);
215
-    });
216
-
217
-    it('calls onSearchBarUpdated on OriginalComponent', () => {
218
-      const NavigationComponent = ComponentWrapper.wrap(componentName, MyLifecycleComponent, store);
219
-      const tree = renderer.create(<NavigationComponent componentId={'component1'} />);
220
-      expect(onSearchBarCallback).toHaveBeenCalledTimes(0);
221
-      tree.getInstance()!.onSearchBarUpdated();
222
-      expect(onSearchBarCallback).toHaveBeenCalledTimes(1);
223
-    });
224
-
225
-    it('calls onSearchBarCancelPressed on OriginalComponent', () => {
226
-      const NavigationComponent = ComponentWrapper.wrap(componentName, MyLifecycleComponent, store);
227
-      const tree = renderer.create(<NavigationComponent componentId={'component1'} />);
228
-      expect(onSearchBarCancelCallback).toHaveBeenCalledTimes(0);
229
-      tree.getInstance()!.onSearchBarCancelPressed();
230
-      expect(onSearchBarCancelCallback).toHaveBeenCalledTimes(1);
231
-    });
130
+  it(`calls unmounted on componentEventsObserver`, () => {
131
+    const NavigationComponent = ComponentWrapper.wrap(componentName, MyComponent, store, componentEventsObserver);
132
+    const tree = renderer.create(<NavigationComponent componentId={'component123'} />);
133
+    expect(componentEventsObserver.unmounted).not.toHaveBeenCalled();
134
+    tree.unmount();
135
+    expect(componentEventsObserver.unmounted).toHaveBeenCalledTimes(1);
232
   });
136
   });
233
 });
137
 });

+ 6
- 43
lib/src/components/ComponentWrapper.tsx Ver fichero

4
 
4
 
5
 export class ComponentWrapper {
5
 export class ComponentWrapper {
6
 
6
 
7
-  static wrap(componentName: string, OriginalComponentClass: React.ComponentType<any>, store): React.ComponentType<any> {
7
+  static wrap(
8
+    componentName: string,
9
+    OriginalComponentClass: React.ComponentType<any>,
10
+    store,
11
+    componentEventsObserver): React.ComponentType<any> {
8
 
12
 
9
     class WrappedComponent extends React.Component<any, { componentId: string; allProps: {}; }> {
13
     class WrappedComponent extends React.Component<any, { componentId: string; allProps: {}; }> {
10
 
14
 
14
         };
18
         };
15
       }
19
       }
16
 
20
 
17
-      private originalComponentRef;
18
-
19
       constructor(props) {
21
       constructor(props) {
20
         super(props);
22
         super(props);
21
         this._assertComponentId();
23
         this._assertComponentId();
22
-        this._saveComponentRef = this._saveComponentRef.bind(this);
23
         this.state = {
24
         this.state = {
24
           componentId: props.componentId,
25
           componentId: props.componentId,
25
           allProps: {}
26
           allProps: {}
26
         };
27
         };
27
       }
28
       }
28
 
29
 
29
-      componentDidMount() {
30
-        store.setRefForId(this.state.componentId, this);
31
-      }
32
-
33
       componentWillUnmount() {
30
       componentWillUnmount() {
34
         store.cleanId(this.state.componentId);
31
         store.cleanId(this.state.componentId);
35
-      }
36
-
37
-      componentDidAppear() {
38
-        if (this.originalComponentRef.componentDidAppear) {
39
-          this.originalComponentRef.componentDidAppear();
40
-        }
41
-      }
42
-
43
-      componentDidDisappear() {
44
-        if (this.originalComponentRef.componentDidDisappear) {
45
-          this.originalComponentRef.componentDidDisappear();
46
-        }
47
-      }
48
-
49
-      onNavigationButtonPressed(buttonId) {
50
-        if (this.originalComponentRef.onNavigationButtonPressed) {
51
-          this.originalComponentRef.onNavigationButtonPressed(buttonId);
52
-        }
53
-      }
54
-
55
-      onSearchBarUpdated(text, isFocused) {
56
-        if (this.originalComponentRef.onSearchBarUpdated) {
57
-          this.originalComponentRef.onSearchBarUpdated(text, isFocused);
58
-        }
59
-      }
60
-
61
-      onSearchBarCancelPressed() {
62
-        if (this.originalComponentRef.onSearchBarCancelPressed) {
63
-          this.originalComponentRef.onSearchBarCancelPressed();
64
-        }
32
+        componentEventsObserver.unmounted(this.state.componentId);
65
       }
33
       }
66
 
34
 
67
       render() {
35
       render() {
68
         return (
36
         return (
69
           <OriginalComponentClass
37
           <OriginalComponentClass
70
-            ref={this._saveComponentRef}
71
             {...this.state.allProps}
38
             {...this.state.allProps}
72
             componentId={this.state.componentId}
39
             componentId={this.state.componentId}
73
             key={this.state.componentId}
40
             key={this.state.componentId}
80
           throw new Error(`Component ${componentName} does not have a componentId!`);
47
           throw new Error(`Component ${componentName} does not have a componentId!`);
81
         }
48
         }
82
       }
49
       }
83
-
84
-      private _saveComponentRef(r) {
85
-        this.originalComponentRef = r;
86
-      }
87
     }
50
     }
88
 
51
 
89
     ReactLifecyclesCompat.polyfill(WrappedComponent);
52
     ReactLifecyclesCompat.polyfill(WrappedComponent);

+ 1
- 10
lib/src/components/Store.test.ts Ver fichero

30
     expect(uut.getOriginalComponentClassForName('example.mycomponent')).toEqual(MyComponent);
30
     expect(uut.getOriginalComponentClassForName('example.mycomponent')).toEqual(MyComponent);
31
   });
31
   });
32
 
32
 
33
-  it('holds component refs by id', () => {
34
-    const ref = {};
35
-    uut.setRefForId('refUniqueId', ref);
36
-    expect(uut.getRefForId('other')).toBeUndefined();
37
-    expect(uut.getRefForId('refUniqueId')).toBe(ref);
38
-  });
39
-
40
-  it('clean by id', () => {
41
-    uut.setRefForId('refUniqueId', {});
33
+  it('clean by component id', () => {
42
     uut.setPropsForId('refUniqueId', { foo: 'bar' });
34
     uut.setPropsForId('refUniqueId', { foo: 'bar' });
43
 
35
 
44
     uut.cleanId('refUniqueId');
36
     uut.cleanId('refUniqueId');
45
 
37
 
46
-    expect(uut.getRefForId('refUniqueId')).toBeUndefined();
47
     expect(uut.getPropsForId('refUniqueId')).toEqual({});
38
     expect(uut.getPropsForId('refUniqueId')).toEqual({});
48
   });
39
   });
49
 });
40
 });

+ 0
- 10
lib/src/components/Store.ts Ver fichero

3
 export class Store {
3
 export class Store {
4
   private componentsByName = {};
4
   private componentsByName = {};
5
   private propsById = {};
5
   private propsById = {};
6
-  private refsById = {};
7
 
6
 
8
   setPropsForId(componentId: string, props) {
7
   setPropsForId(componentId: string, props) {
9
     _.set(this.propsById, componentId, props);
8
     _.set(this.propsById, componentId, props);
21
     return _.get(this.componentsByName, componentName);
20
     return _.get(this.componentsByName, componentName);
22
   }
21
   }
23
 
22
 
24
-  setRefForId(id: string, ref) {
25
-    _.set(this.refsById, id, ref);
26
-  }
27
-
28
-  getRefForId(id: string) {
29
-    return _.get(this.refsById, id);
30
-  }
31
-
32
   cleanId(id: string) {
23
   cleanId(id: string) {
33
-    _.unset(this.refsById, id);
34
     _.unset(this.propsById, id);
24
     _.unset(this.propsById, id);
35
   }
25
   }
36
 }
26
 }

+ 1
- 1
lib/src/events/CommandsObserver.ts Ver fichero

15
   }
15
   }
16
 
16
 
17
   public notify(commandName: string, params: {}): void {
17
   public notify(commandName: string, params: {}): void {
18
-    _.forEach(this.listeners, (listener) => listener(commandName, params));
18
+    _.forEach(this.listeners, (listener: CommandsListener) => listener(commandName, params));
19
   }
19
   }
20
 }
20
 }

+ 0
- 139
lib/src/events/ComponentEventsObserver.test.ts Ver fichero

1
-import { ComponentEventsObserver } from './ComponentEventsObserver';
2
-import { Store } from '../components/Store';
3
-
4
-describe(`ComponentEventsObserver`, () => {
5
-  let uut: ComponentEventsObserver;
6
-  let eventRegistry;
7
-  let store: Store;
8
-  let mockComponentRef;
9
-  const refId = 'myUniqueId';
10
-
11
-  beforeEach(() => {
12
-    eventRegistry = {
13
-      registerComponentDidAppearListener: jest.fn(),
14
-      registerComponentDidDisappearListener: jest.fn(),
15
-      registerNativeEventListener: jest.fn()
16
-    };
17
-
18
-    mockComponentRef = {
19
-      componentDidAppear: jest.fn(),
20
-      componentDidDisappear: jest.fn(),
21
-      onNavigationButtonPressed: jest.fn(),
22
-      onSearchBarUpdated: jest.fn(),
23
-      onSearchBarCancelPressed: jest.fn()
24
-    };
25
-
26
-    store = new Store();
27
-    store.setRefForId(refId, mockComponentRef);
28
-
29
-    uut = new ComponentEventsObserver(eventRegistry, store);
30
-  });
31
-
32
-  it('register for lifecycle events on eventRegistry', () => {
33
-    expect(eventRegistry.registerComponentDidAppearListener).toHaveBeenCalledTimes(0);
34
-    expect(eventRegistry.registerComponentDidDisappearListener).toHaveBeenCalledTimes(0);
35
-    expect(eventRegistry.registerNativeEventListener).toHaveBeenCalledTimes(0);
36
-    uut.registerForAllComponents();
37
-    expect(eventRegistry.registerComponentDidAppearListener).toHaveBeenCalledTimes(1);
38
-    expect(eventRegistry.registerComponentDidDisappearListener).toHaveBeenCalledTimes(1);
39
-    expect(eventRegistry.registerNativeEventListener).toHaveBeenCalledTimes(1);
40
-  });
41
-
42
-  it('bubbles lifecycle to component from store', () => {
43
-    const params = {};
44
-    expect(mockComponentRef.componentDidAppear).toHaveBeenCalledTimes(0);
45
-    expect(mockComponentRef.componentDidDisappear).toHaveBeenCalledTimes(0);
46
-    expect(mockComponentRef.onNavigationButtonPressed).toHaveBeenCalledTimes(0);
47
-    expect(mockComponentRef.onSearchBarUpdated).toHaveBeenCalledTimes(0);
48
-    expect(mockComponentRef.onSearchBarCancelPressed).toHaveBeenCalledTimes(0);
49
-    uut.registerForAllComponents();
50
-    eventRegistry.registerComponentDidAppearListener.mock.calls[0][0](refId);
51
-    eventRegistry.registerComponentDidDisappearListener.mock.calls[0][0](refId);
52
-    eventRegistry.registerNativeEventListener.mock.calls[0][0](refId, params);
53
-    expect(mockComponentRef.componentDidAppear).toHaveBeenCalledTimes(1);
54
-    expect(mockComponentRef.componentDidDisappear).toHaveBeenCalledTimes(1);
55
-    expect(mockComponentRef.onNavigationButtonPressed).toHaveBeenCalledTimes(0);
56
-    expect(mockComponentRef.onSearchBarUpdated).toHaveBeenCalledTimes(0);
57
-    expect(mockComponentRef.onSearchBarCancelPressed).toHaveBeenCalledTimes(0);
58
-  });
59
-
60
-  it('bubbles onNavigationButtonPressed to component by id', () => {
61
-    const params = {
62
-      componentId: refId,
63
-      buttonId: 'theButtonId'
64
-    };
65
-    expect(mockComponentRef.onNavigationButtonPressed).toHaveBeenCalledTimes(0);
66
-    uut.registerForAllComponents();
67
-
68
-    eventRegistry.registerNativeEventListener.mock.calls[0][0]('some other event name', params);
69
-    expect(mockComponentRef.onNavigationButtonPressed).toHaveBeenCalledTimes(0);
70
-
71
-    eventRegistry.registerNativeEventListener.mock.calls[0][0]('buttonPressed', params);
72
-    expect(mockComponentRef.onNavigationButtonPressed).toHaveBeenCalledTimes(1);
73
-    expect(mockComponentRef.onNavigationButtonPressed).toHaveBeenCalledWith('theButtonId');
74
-  });
75
-
76
-  it('bubbles onSearchUpdated to component by id', () => {
77
-    const params = {
78
-      componentId: refId,
79
-      text: 'query',
80
-      isFocused: true,
81
-    };
82
-    expect(mockComponentRef.onSearchBarUpdated).toHaveBeenCalledTimes(0);
83
-    uut.registerForAllComponents();
84
-
85
-    eventRegistry.registerNativeEventListener.mock.calls[0][0]('buttonPressed', params);
86
-    expect(mockComponentRef.onSearchBarUpdated).toHaveBeenCalledTimes(0);
87
-
88
-    eventRegistry.registerNativeEventListener.mock.calls[0][0]('searchBarUpdated', params);
89
-    expect(mockComponentRef.onSearchBarUpdated).toHaveBeenCalledTimes(1);
90
-    expect(mockComponentRef.onSearchBarUpdated).toHaveBeenCalledWith('query', true);
91
-    const paramsForUnexisted = {
92
-      componentId: 'NOT_EXISTED',
93
-      text: 'query',
94
-      isFocused: true,
95
-    };
96
-    eventRegistry.registerNativeEventListener.mock.calls[0][0]('searchBarUpdated', paramsForUnexisted);
97
-    expect(mockComponentRef.onSearchBarUpdated).toHaveBeenCalledTimes(1);
98
-    expect(mockComponentRef.onSearchBarUpdated).toHaveBeenCalledWith('query', true);
99
-  });
100
-
101
-  it('bubbles onSearchBarCancelPressed to component by id', () => {
102
-    const params = {
103
-      componentId: refId,
104
-    };
105
-    expect(mockComponentRef.onSearchBarCancelPressed).toHaveBeenCalledTimes(0);
106
-    uut.registerForAllComponents();
107
-
108
-    eventRegistry.registerNativeEventListener.mock.calls[0][0]('buttonPressed', params);
109
-    expect(mockComponentRef.onSearchBarCancelPressed).toHaveBeenCalledTimes(0);
110
-
111
-    eventRegistry.registerNativeEventListener.mock.calls[0][0]('searchBarCancelPressed', params);
112
-    expect(mockComponentRef.onSearchBarCancelPressed).toHaveBeenCalledTimes(1);
113
-
114
-    const paramsForUnexisted = {
115
-      componentId: 'NOT_EXISTED',
116
-    };
117
-    eventRegistry.registerNativeEventListener.mock.calls[0][0]('searchBarCancelPressed', paramsForUnexisted);
118
-    expect(mockComponentRef.onSearchBarCancelPressed).toHaveBeenCalledTimes(1);
119
-  });
120
-
121
-  it('defensive unknown id', () => {
122
-    uut.registerForAllComponents();
123
-    expect(() => {
124
-      eventRegistry.registerComponentDidAppearListener.mock.calls[0][0]('bad id');
125
-      eventRegistry.registerComponentDidDisappearListener.mock.calls[0][0]('bad id');
126
-      eventRegistry.registerNativeEventListener.mock.calls[0][0]('buttonPressed', { componentId: 'bad id' });
127
-    }).not.toThrow();
128
-  });
129
-
130
-  it('defensive method impl', () => {
131
-    store.setRefForId('myId', {});
132
-    uut.registerForAllComponents();
133
-    expect(() => {
134
-      eventRegistry.registerComponentDidAppearListener.mock.calls[0][0]('myId');
135
-      eventRegistry.registerComponentDidDisappearListener.mock.calls[0][0]('myId');
136
-      eventRegistry.registerNativeEventListener.mock.calls[0][0]('bad event name', {});
137
-    }).not.toThrow();
138
-  });
139
-});

+ 181
- 0
lib/src/events/ComponentEventsObserver.test.tsx Ver fichero

1
+import * as React from 'react';
2
+import * as renderer from 'react-test-renderer';
3
+import { ComponentEventsObserver } from './ComponentEventsObserver';
4
+import { NativeEventsReceiver } from '../adapters/NativeEventsReceiver.mock';
5
+
6
+describe('ComponentEventsObserver', () => {
7
+  const mockEventsReceiver = new NativeEventsReceiver();
8
+  const uut = new ComponentEventsObserver(mockEventsReceiver);
9
+  const didAppearFn = jest.fn();
10
+  const didDisappearFn = jest.fn();
11
+  const didMountFn = jest.fn();
12
+  const willUnmountFn = jest.fn();
13
+  const navigationButtonPressedFn = jest.fn();
14
+  const searchBarUpdatedFn = jest.fn();
15
+  const searchBarCancelPressedFn = jest.fn();
16
+  let subscription;
17
+
18
+  class SimpleScreen extends React.Component<any, any> {
19
+    render() {
20
+      return 'Hello';
21
+    }
22
+  }
23
+
24
+  class BoundScreen extends React.Component<any, any> {
25
+    constructor(props) {
26
+      super(props);
27
+      subscription = uut.bindComponent(this);
28
+    }
29
+
30
+    componentDidMount() {
31
+      didMountFn();
32
+    }
33
+
34
+    componentWillUnmount() {
35
+      willUnmountFn();
36
+    }
37
+
38
+    componentDidAppear() {
39
+      didAppearFn();
40
+    }
41
+
42
+    componentDidDisappear() {
43
+      didDisappearFn();
44
+    }
45
+
46
+    navigationButtonPressed(event) {
47
+      navigationButtonPressedFn(event);
48
+    }
49
+
50
+    searchBarUpdated(event) {
51
+      searchBarUpdatedFn(event);
52
+    }
53
+
54
+    searchBarCancelPressed(event) {
55
+      searchBarCancelPressedFn(event);
56
+    }
57
+
58
+    render() {
59
+      return 'Hello';
60
+    }
61
+  }
62
+
63
+  it(`bindComponent expects a component with componentId`, () => {
64
+    const tree = renderer.create(<SimpleScreen />);
65
+    expect(() => uut.bindComponent(tree.getInstance() as any)).toThrow('');
66
+    const tree2 = renderer.create(<SimpleScreen componentId={123} />);
67
+    expect(() => uut.bindComponent(tree2.getInstance() as any)).toThrow('');
68
+  });
69
+
70
+  it(`bindComponent notifies listeners by componentId on events`, () => {
71
+    const tree = renderer.create(<BoundScreen componentId={'myCompId'} />);
72
+    expect(tree.toJSON()).toBeDefined();
73
+    expect(didMountFn).toHaveBeenCalledTimes(1);
74
+    expect(didAppearFn).not.toHaveBeenCalled();
75
+    expect(didDisappearFn).not.toHaveBeenCalled();
76
+    expect(willUnmountFn).not.toHaveBeenCalled();
77
+
78
+    uut.notifyComponentDidAppear({ componentId: 'myCompId', componentName: 'doesnt matter' });
79
+    expect(didAppearFn).toHaveBeenCalledTimes(1);
80
+
81
+    uut.notifyComponentDidDisappear({ componentId: 'myCompId', componentName: 'doesnt matter' });
82
+    expect(didDisappearFn).toHaveBeenCalledTimes(1);
83
+
84
+    uut.notifyNavigationButtonPressed({ componentId: 'myCompId', buttonId: 'myButtonId' });
85
+    expect(navigationButtonPressedFn).toHaveBeenCalledTimes(1);
86
+    expect(navigationButtonPressedFn).toHaveBeenCalledWith({ buttonId: 'myButtonId', componentId: 'myCompId' });
87
+
88
+    uut.notifySearchBarUpdated({ componentId: 'myCompId', text: 'theText', isFocused: true });
89
+    expect(searchBarUpdatedFn).toHaveBeenCalledTimes(1);
90
+    expect(searchBarUpdatedFn).toHaveBeenCalledWith({ componentId: 'myCompId', text: 'theText', isFocused: true });
91
+
92
+    uut.notifySearchBarCancelPressed({ componentId: 'myCompId' });
93
+    expect(searchBarCancelPressedFn).toHaveBeenCalledTimes(1);
94
+    expect(searchBarCancelPressedFn).toHaveBeenCalledWith({ componentId: 'myCompId' });
95
+
96
+    tree.unmount();
97
+    expect(willUnmountFn).toHaveBeenCalledTimes(1);
98
+  });
99
+
100
+  it(`doesnt call other componentIds`, () => {
101
+    renderer.create(<BoundScreen componentId={'myCompId'} />);
102
+    uut.notifyComponentDidAppear({ componentId: 'other', componentName: 'doesnt matter' });
103
+    expect(didAppearFn).not.toHaveBeenCalled();
104
+  });
105
+
106
+  it(`doesnt call unimplemented methods`, () => {
107
+    const tree = renderer.create(<SimpleScreen componentId={'myCompId'} />);
108
+    expect((tree.getInstance() as any).componentDidAppear).toBeUndefined();
109
+    uut.bindComponent(tree.getInstance() as any);
110
+    uut.notifyComponentDidAppear({ componentId: 'myCompId', componentName: 'doesnt matter' });
111
+  });
112
+
113
+  it(`returns unregister fn`, () => {
114
+    renderer.create(<BoundScreen componentId={'123'} />);
115
+
116
+    uut.notifyComponentDidAppear({ componentId: '123', componentName: 'doesnt matter' });
117
+    expect(didAppearFn).toHaveBeenCalledTimes(1);
118
+
119
+    subscription.remove();
120
+
121
+    uut.notifyComponentDidAppear({ componentId: '123', componentName: 'doesnt matter' });
122
+    expect(didAppearFn).toHaveBeenCalledTimes(1);
123
+  });
124
+
125
+  it(`removeAllListenersForComponentId`, () => {
126
+    renderer.create(<BoundScreen componentId={'123'} />);
127
+    renderer.create(<BoundScreen componentId={'123'} />);
128
+
129
+    uut.unmounted('123');
130
+
131
+    uut.notifyComponentDidAppear({ componentId: '123', componentName: 'doesnt matter' });
132
+    expect(didAppearFn).not.toHaveBeenCalled();
133
+  });
134
+
135
+  it(`supports multiple listeners with same componentId`, () => {
136
+    const tree1 = renderer.create(<SimpleScreen componentId={'myCompId'} />);
137
+    const tree2 = renderer.create(<SimpleScreen componentId={'myCompId'} />);
138
+    const instance1 = tree1.getInstance() as any;
139
+    const instance2 = tree2.getInstance() as any;
140
+    instance1.componentDidAppear = jest.fn();
141
+    instance2.componentDidAppear = jest.fn();
142
+
143
+    const result1 = uut.bindComponent(instance1);
144
+    const result2 = uut.bindComponent(instance2);
145
+    expect(result1).not.toEqual(result2);
146
+
147
+    uut.notifyComponentDidAppear({ componentId: 'myCompId', componentName: 'doesnt matter' });
148
+
149
+    expect(instance1.componentDidAppear).toHaveBeenCalledTimes(1);
150
+    expect(instance2.componentDidAppear).toHaveBeenCalledTimes(1);
151
+
152
+    result2.remove();
153
+
154
+    uut.notifyComponentDidAppear({ componentId: 'myCompId', componentName: 'doesnt matter' });
155
+    expect(instance1.componentDidAppear).toHaveBeenCalledTimes(2);
156
+    expect(instance2.componentDidAppear).toHaveBeenCalledTimes(1);
157
+
158
+    result1.remove();
159
+
160
+    uut.notifyComponentDidAppear({ componentId: 'myCompId', componentName: 'doesnt matter' });
161
+    expect(instance1.componentDidAppear).toHaveBeenCalledTimes(2);
162
+    expect(instance2.componentDidAppear).toHaveBeenCalledTimes(1);
163
+  });
164
+
165
+  it(`register for all native component events notifies self on events, once`, () => {
166
+    expect(mockEventsReceiver.registerComponentDidAppearListener).not.toHaveBeenCalled();
167
+    expect(mockEventsReceiver.registerComponentDidDisappearListener).not.toHaveBeenCalled();
168
+    expect(mockEventsReceiver.registerNavigationButtonPressedListener).not.toHaveBeenCalled();
169
+    expect(mockEventsReceiver.registerSearchBarUpdatedListener).not.toHaveBeenCalled();
170
+    expect(mockEventsReceiver.registerSearchBarCancelPressedListener).not.toHaveBeenCalled();
171
+    uut.registerOnceForAllComponentEvents();
172
+    uut.registerOnceForAllComponentEvents();
173
+    uut.registerOnceForAllComponentEvents();
174
+    uut.registerOnceForAllComponentEvents();
175
+    expect(mockEventsReceiver.registerComponentDidAppearListener).toHaveBeenCalledTimes(1);
176
+    expect(mockEventsReceiver.registerComponentDidDisappearListener).toHaveBeenCalledTimes(1);
177
+    expect(mockEventsReceiver.registerNavigationButtonPressedListener).toHaveBeenCalledTimes(1);
178
+    expect(mockEventsReceiver.registerSearchBarUpdatedListener).toHaveBeenCalledTimes(1);
179
+    expect(mockEventsReceiver.registerSearchBarCancelPressedListener).toHaveBeenCalledTimes(1);
180
+  });
181
+});

+ 66
- 41
lib/src/events/ComponentEventsObserver.ts Ver fichero

1
-import { EventsRegistry } from './EventsRegistry';
2
-import { Store } from '../components/Store';
3
-
4
-const BUTTON_PRESSED_EVENT_NAME = 'buttonPressed';
5
-const ON_SEARCH_BAR_UPDATED = 'searchBarUpdated';
6
-const ON_SEARCH_BAR_CANCEL_PRESSED = 'searchBarCancelPressed';
1
+import * as _ from 'lodash';
2
+import { EventSubscription } from '../interfaces/EventSubscription';
3
+import {
4
+  ComponentDidAppearEvent,
5
+  ComponentDidDisappearEvent,
6
+  NavigationButtonPressedEvent,
7
+  SearchBarUpdatedEvent,
8
+  SearchBarCancelPressedEvent,
9
+  ComponentEvent
10
+} from '../interfaces/ComponentEvents';
11
+import { NativeEventsReceiver } from '../adapters/NativeEventsReceiver';
7
 
12
 
8
 export class ComponentEventsObserver {
13
 export class ComponentEventsObserver {
9
-  constructor(private eventsRegistry: EventsRegistry, private store: Store) {
10
-    this.componentDidAppear = this.componentDidAppear.bind(this);
11
-    this.componentDidDisappear = this.componentDidDisappear.bind(this);
12
-    this.onNativeEvent = this.onNativeEvent.bind(this);
14
+  private readonly listeners = {};
15
+  private alreadyRegistered = false;
16
+
17
+  constructor(private readonly nativeEventsReceiver: NativeEventsReceiver) {
18
+    this.notifyComponentDidAppear = this.notifyComponentDidAppear.bind(this);
19
+    this.notifyComponentDidDisappear = this.notifyComponentDidDisappear.bind(this);
20
+    this.notifyNavigationButtonPressed = this.notifyNavigationButtonPressed.bind(this);
21
+    this.notifySearchBarUpdated = this.notifySearchBarUpdated.bind(this);
22
+    this.notifySearchBarCancelPressed = this.notifySearchBarCancelPressed.bind(this);
13
   }
23
   }
14
 
24
 
15
-  public registerForAllComponents(): void {
16
-    this.eventsRegistry.registerComponentDidAppearListener(this.componentDidAppear);
17
-    this.eventsRegistry.registerComponentDidDisappearListener(this.componentDidDisappear);
18
-    this.eventsRegistry.registerNativeEventListener(this.onNativeEvent);
25
+  public registerOnceForAllComponentEvents() {
26
+    if (this.alreadyRegistered) { return; }
27
+    this.alreadyRegistered = true;
28
+    this.nativeEventsReceiver.registerComponentDidAppearListener(this.notifyComponentDidAppear);
29
+    this.nativeEventsReceiver.registerComponentDidDisappearListener(this.notifyComponentDidDisappear);
30
+    this.nativeEventsReceiver.registerNavigationButtonPressedListener(this.notifyNavigationButtonPressed);
31
+    this.nativeEventsReceiver.registerSearchBarUpdatedListener(this.notifySearchBarUpdated);
32
+    this.nativeEventsReceiver.registerSearchBarCancelPressedListener(this.notifySearchBarCancelPressed);
19
   }
33
   }
20
 
34
 
21
-  private componentDidAppear(componentId: string) {
22
-    const componentRef = this.store.getRefForId(componentId);
23
-    if (componentRef && componentRef.componentDidAppear) {
24
-      componentRef.componentDidAppear();
35
+  public bindComponent(component: React.Component<any>): EventSubscription {
36
+    const componentId = component.props.componentId;
37
+    if (!_.isString(componentId)) {
38
+      throw new Error(`bindComponent expects a component with a componentId in props`);
39
+    }
40
+    if (_.isNil(this.listeners[componentId])) {
41
+      this.listeners[componentId] = {};
25
     }
42
     }
43
+    const key = _.uniqueId();
44
+    this.listeners[componentId][key] = component;
45
+
46
+    return { remove: () => _.unset(this.listeners[componentId], key) };
26
   }
47
   }
27
 
48
 
28
-  private componentDidDisappear(componentId: string) {
29
-    const componentRef = this.store.getRefForId(componentId);
30
-    if (componentRef && componentRef.componentDidDisappear) {
31
-      componentRef.componentDidDisappear();
32
-    }
49
+  public unmounted(componentId: string) {
50
+    _.unset(this.listeners, componentId);
33
   }
51
   }
34
 
52
 
35
-  private onNativeEvent(name: string, params: any) {
36
-    if (name === BUTTON_PRESSED_EVENT_NAME) {
37
-      const componentRef = this.store.getRefForId(params.componentId);
38
-      if (componentRef && componentRef.onNavigationButtonPressed) {
39
-        componentRef.onNavigationButtonPressed(params.buttonId);
40
-      }
41
-    }
42
-    if (name === ON_SEARCH_BAR_UPDATED) {
43
-      const componentRef = this.store.getRefForId(params.componentId);
44
-      if (componentRef && componentRef.onSearchBarUpdated) {
45
-        componentRef.onSearchBarUpdated(params.text, params.isFocused);
46
-      }
47
-    }
48
-    if (name === ON_SEARCH_BAR_CANCEL_PRESSED) {
49
-      const componentRef = this.store.getRefForId(params.componentId);
50
-      if (componentRef && componentRef.onSearchBarCancelPressed) {
51
-        componentRef.onSearchBarCancelPressed();
53
+  notifyComponentDidAppear(event: ComponentDidAppearEvent) {
54
+    this.triggerOnAllListenersByComponentId(event, 'componentDidAppear');
55
+  }
56
+
57
+  notifyComponentDidDisappear(event: ComponentDidDisappearEvent) {
58
+    this.triggerOnAllListenersByComponentId(event, 'componentDidDisappear');
59
+  }
60
+
61
+  notifyNavigationButtonPressed(event: NavigationButtonPressedEvent) {
62
+    this.triggerOnAllListenersByComponentId(event, 'navigationButtonPressed');
63
+  }
64
+
65
+  notifySearchBarUpdated(event: SearchBarUpdatedEvent) {
66
+    this.triggerOnAllListenersByComponentId(event, 'searchBarUpdated');
67
+  }
68
+
69
+  notifySearchBarCancelPressed(event: SearchBarCancelPressedEvent) {
70
+    this.triggerOnAllListenersByComponentId(event, 'searchBarCancelPressed');
71
+  }
72
+
73
+  private triggerOnAllListenersByComponentId(event: ComponentEvent, method: string) {
74
+    _.forEach(this.listeners[event.componentId], (component) => {
75
+      if (_.isObject(component) && _.isFunction(component[method])) {
76
+        component[method](event);
52
       }
77
       }
53
-    }
78
+    });
54
   }
79
   }
55
 }
80
 }

+ 0
- 99
lib/src/events/EventsRegistry.test.ts Ver fichero

1
-import { EventsRegistry } from './EventsRegistry';
2
-import { NativeEventsReceiver } from '../adapters/NativeEventsReceiver.mock';
3
-import { CommandsObserver } from './CommandsObserver';
4
-
5
-describe('EventsRegistry', () => {
6
-  let uut: EventsRegistry;
7
-  const mockNativeEventsReceiver = new NativeEventsReceiver();
8
-  let commandsObserver: CommandsObserver;
9
-
10
-  beforeEach(() => {
11
-    commandsObserver = new CommandsObserver();
12
-    uut = new EventsRegistry(mockNativeEventsReceiver, commandsObserver);
13
-  });
14
-
15
-  it('exposes appLaunched event', () => {
16
-    const subscription = {};
17
-    const cb = jest.fn();
18
-    mockNativeEventsReceiver.registerAppLaunchedListener.mockReturnValueOnce(subscription);
19
-
20
-    const result = uut.registerAppLaunchedListener(cb);
21
-
22
-    expect(result).toBe(subscription);
23
-    expect(mockNativeEventsReceiver.registerAppLaunchedListener).toHaveBeenCalledTimes(1);
24
-    expect(mockNativeEventsReceiver.registerAppLaunchedListener).toHaveBeenCalledWith(cb);
25
-  });
26
-
27
-  it('exposes componentDidAppear event', () => {
28
-    const subscription = {};
29
-    const cb = jest.fn();
30
-    mockNativeEventsReceiver.registerComponentDidAppearListener.mockReturnValueOnce(subscription);
31
-
32
-    const result = uut.registerComponentDidAppearListener(cb);
33
-
34
-    expect(result).toBe(subscription);
35
-    expect(mockNativeEventsReceiver.registerComponentDidAppearListener).toHaveBeenCalledTimes(1);
36
-
37
-    mockNativeEventsReceiver.registerComponentDidAppearListener.mock.calls[0][0]({ componentId: 'theId', componentName: 'theName' });
38
-    expect(cb).toHaveBeenCalledWith('theId', 'theName');
39
-  });
40
-
41
-  it('exposes componentDidDisappear event', () => {
42
-    const subscription = {};
43
-    const cb = jest.fn();
44
-    mockNativeEventsReceiver.registerComponentDidDisappearListener.mockReturnValueOnce(subscription);
45
-
46
-    const result = uut.registerComponentDidDisappearListener(cb);
47
-
48
-    expect(result).toBe(subscription);
49
-    expect(mockNativeEventsReceiver.registerComponentDidDisappearListener).toHaveBeenCalledTimes(1);
50
-
51
-    mockNativeEventsReceiver.registerComponentDidDisappearListener.mock.calls[0][0]({ componentId: 'theId', componentName: 'theName' });
52
-    expect(cb).toHaveBeenCalledWith('theId', 'theName');
53
-  });
54
-
55
-  it('exposes registerCommandListener registers listener to commandObserver', () => {
56
-    const cb = jest.fn();
57
-    const result = uut.registerCommandListener(cb);
58
-    expect(result).toBeDefined();
59
-    commandsObserver.notify('theCommandName', { x: 1 });
60
-    expect(cb).toHaveBeenCalledTimes(1);
61
-    expect(cb).toHaveBeenCalledWith('theCommandName', { x: 1 });
62
-  });
63
-
64
-  it('registerCommandListener unregister', () => {
65
-    const cb = jest.fn();
66
-    const result = uut.registerCommandListener(cb);
67
-    result.remove();
68
-    commandsObserver.notify('theCommandName', { x: 1 });
69
-    expect(cb).not.toHaveBeenCalled();
70
-  });
71
-
72
-  it('registerCommandCompletedListener', () => {
73
-    const subscription = {};
74
-    const cb = jest.fn();
75
-    mockNativeEventsReceiver.registerCommandCompletedListener.mockReturnValueOnce(subscription);
76
-
77
-    const result = uut.registerCommandCompletedListener(cb);
78
-
79
-    expect(result).toBe(subscription);
80
-    expect(mockNativeEventsReceiver.registerCommandCompletedListener).toHaveBeenCalledTimes(1);
81
-
82
-    mockNativeEventsReceiver.registerCommandCompletedListener.mock.calls[0][0]({ commandId: 'theCommandId', completionTime: 12345, params: { a: 1 } });
83
-    expect(cb).toHaveBeenCalledWith('theCommandId', 12345, { a: 1 });
84
-  });
85
-
86
-  it('registerNativeEventListener', () => {
87
-    const subscription = {};
88
-    const cb = jest.fn();
89
-    mockNativeEventsReceiver.registerNativeEventListener.mockReturnValueOnce(subscription);
90
-
91
-    const result = uut.registerNativeEventListener(cb);
92
-
93
-    expect(result).toBe(subscription);
94
-    expect(mockNativeEventsReceiver.registerNativeEventListener).toHaveBeenCalledTimes(1);
95
-
96
-    mockNativeEventsReceiver.registerNativeEventListener.mock.calls[0][0]({ name: 'the event name', params: { a: 1 } });
97
-    expect(cb).toHaveBeenCalledWith('the event name', { a: 1 });
98
-  });
99
-});

+ 100
- 0
lib/src/events/EventsRegistry.test.tsx Ver fichero

1
+import { EventsRegistry } from './EventsRegistry';
2
+import { NativeEventsReceiver } from '../adapters/NativeEventsReceiver.mock';
3
+import { CommandsObserver } from './CommandsObserver';
4
+
5
+describe('EventsRegistry', () => {
6
+  let uut: EventsRegistry;
7
+  const mockNativeEventsReceiver = new NativeEventsReceiver();
8
+  let commandsObserver: CommandsObserver;
9
+  const mockScreenEventsRegistry = {} as any;
10
+
11
+  beforeEach(() => {
12
+    commandsObserver = new CommandsObserver();
13
+    uut = new EventsRegistry(mockNativeEventsReceiver, commandsObserver, mockScreenEventsRegistry);
14
+  });
15
+
16
+  it('exposes appLaunched event', () => {
17
+    const subscription = {};
18
+    const cb = jest.fn();
19
+    mockNativeEventsReceiver.registerAppLaunchedListener.mockReturnValueOnce(subscription);
20
+
21
+    const result = uut.registerAppLaunchedListener(cb);
22
+
23
+    expect(result).toBe(subscription);
24
+    expect(mockNativeEventsReceiver.registerAppLaunchedListener).toHaveBeenCalledTimes(1);
25
+    expect(mockNativeEventsReceiver.registerAppLaunchedListener).toHaveBeenCalledWith(cb);
26
+  });
27
+
28
+  it('delegates didAppear to nativeEventsReceiver', () => {
29
+    const cb = jest.fn();
30
+    uut.registerComponentDidAppearListener(cb);
31
+    expect(mockNativeEventsReceiver.registerComponentDidAppearListener).toHaveBeenCalledTimes(1);
32
+    expect(mockNativeEventsReceiver.registerComponentDidAppearListener).toHaveBeenCalledWith(cb);
33
+  });
34
+
35
+  it('delegates didDisappear to nativeEventsReceiver', () => {
36
+    const cb = jest.fn();
37
+    uut.registerComponentDidDisappearListener(cb);
38
+    expect(mockNativeEventsReceiver.registerComponentDidDisappearListener).toHaveBeenCalledTimes(1);
39
+    expect(mockNativeEventsReceiver.registerComponentDidDisappearListener).toHaveBeenCalledWith(cb);
40
+  });
41
+
42
+  it('delegates commandCompleted to nativeEventsReceiver', () => {
43
+    const cb = jest.fn();
44
+    uut.registerCommandCompletedListener(cb);
45
+    expect(mockNativeEventsReceiver.registerCommandCompletedListener).toHaveBeenCalledTimes(1);
46
+    expect(mockNativeEventsReceiver.registerCommandCompletedListener).toHaveBeenCalledWith(cb);
47
+  });
48
+
49
+  it('delegates BottomTabsSelected to nativeEventsReceiver', () => {
50
+    const cb = jest.fn();
51
+    uut.registerBottomTabSelectedListener(cb);
52
+    expect(mockNativeEventsReceiver.registerBottomTabSelectedListener).toHaveBeenCalledTimes(1);
53
+    expect(mockNativeEventsReceiver.registerBottomTabSelectedListener).toHaveBeenCalledWith(cb);
54
+  });
55
+
56
+  it('delegates navigationButtonPressed to nativeEventsReceiver', () => {
57
+    const cb = jest.fn();
58
+    uut.registerNavigationButtonPressedListener(cb);
59
+    expect(mockNativeEventsReceiver.registerNavigationButtonPressedListener).toHaveBeenCalledTimes(1);
60
+    expect(mockNativeEventsReceiver.registerNavigationButtonPressedListener).toHaveBeenCalledWith(cb);
61
+  });
62
+
63
+  it('delegates searchBarUpdated to nativeEventsReceiver', () => {
64
+    const cb = jest.fn();
65
+    uut.registerSearchBarUpdatedListener(cb);
66
+    expect(mockNativeEventsReceiver.registerSearchBarUpdatedListener).toHaveBeenCalledTimes(1);
67
+    expect(mockNativeEventsReceiver.registerSearchBarUpdatedListener).toHaveBeenCalledWith(cb);
68
+  });
69
+
70
+  it('delegates searchBarCancelPressed to nativeEventsReceiver', () => {
71
+    const cb = jest.fn();
72
+    uut.registerSearchBarCancelPressedListener(cb);
73
+    expect(mockNativeEventsReceiver.registerSearchBarCancelPressedListener).toHaveBeenCalledTimes(1);
74
+    expect(mockNativeEventsReceiver.registerSearchBarCancelPressedListener).toHaveBeenCalledWith(cb);
75
+  });
76
+
77
+  it('delegates registerCommandListener to commandObserver', () => {
78
+    const cb = jest.fn();
79
+    const result = uut.registerCommandListener(cb);
80
+    expect(result).toBeDefined();
81
+    commandsObserver.notify('theCommandName', { x: 1 });
82
+    expect(cb).toHaveBeenCalledTimes(1);
83
+    expect(cb).toHaveBeenCalledWith('theCommandName', { x: 1 });
84
+  });
85
+
86
+  it('registerCommandListener unregister', () => {
87
+    const cb = jest.fn();
88
+    const result = uut.registerCommandListener(cb);
89
+    result.remove();
90
+    commandsObserver.notify('theCommandName', { x: 1 });
91
+    expect(cb).not.toHaveBeenCalled();
92
+  });
93
+
94
+  it(`delegates bindComponent to ComponentObserver`, () => {
95
+    const subscription = {};
96
+    mockScreenEventsRegistry.bindComponent = jest.fn();
97
+    mockScreenEventsRegistry.bindComponent.mockReturnValueOnce(subscription);
98
+    expect(uut.bindComponent({} as React.Component<any>)).toEqual(subscription);
99
+  });
100
+});

+ 36
- 11
lib/src/events/EventsRegistry.ts Ver fichero

1
 import { NativeEventsReceiver } from '../adapters/NativeEventsReceiver';
1
 import { NativeEventsReceiver } from '../adapters/NativeEventsReceiver';
2
 import { CommandsObserver } from './CommandsObserver';
2
 import { CommandsObserver } from './CommandsObserver';
3
 import { EventSubscription } from '../interfaces/EventSubscription';
3
 import { EventSubscription } from '../interfaces/EventSubscription';
4
+import { ComponentEventsObserver } from './ComponentEventsObserver';
5
+import {
6
+  ComponentDidAppearEvent,
7
+  ComponentDidDisappearEvent,
8
+  NavigationButtonPressedEvent,
9
+  SearchBarUpdatedEvent,
10
+  SearchBarCancelPressedEvent
11
+} from '../interfaces/ComponentEvents';
12
+import { CommandCompletedEvent, BottomTabSelectedEvent } from '../interfaces/Events';
4
 
13
 
5
 export class EventsRegistry {
14
 export class EventsRegistry {
6
-  constructor(private nativeEventsReceiver: NativeEventsReceiver, private commandsObserver: CommandsObserver) { }
15
+  constructor(private nativeEventsReceiver: NativeEventsReceiver, private commandsObserver: CommandsObserver, private componentEventsObserver: ComponentEventsObserver) { }
7
 
16
 
8
   public registerAppLaunchedListener(callback: () => void): EventSubscription {
17
   public registerAppLaunchedListener(callback: () => void): EventSubscription {
9
     return this.nativeEventsReceiver.registerAppLaunchedListener(callback);
18
     return this.nativeEventsReceiver.registerAppLaunchedListener(callback);
10
   }
19
   }
11
 
20
 
12
-  public registerComponentDidAppearListener(callback: (componentId: string, componentName: string) => void): EventSubscription {
13
-    return this.nativeEventsReceiver.registerComponentDidAppearListener(({ componentId, componentName }) => callback(componentId, componentName));
21
+  public registerComponentDidAppearListener(callback: (event: ComponentDidAppearEvent) => void): EventSubscription {
22
+    return this.nativeEventsReceiver.registerComponentDidAppearListener(callback);
14
   }
23
   }
15
 
24
 
16
-  public registerComponentDidDisappearListener(callback: (componentId: string, componentName: string) => void): EventSubscription {
17
-    return this.nativeEventsReceiver.registerComponentDidDisappearListener(({ componentId, componentName }) => callback(componentId, componentName));
25
+  public registerComponentDidDisappearListener(callback: (event: ComponentDidDisappearEvent) => void): EventSubscription {
26
+    return this.nativeEventsReceiver.registerComponentDidDisappearListener(callback);
18
   }
27
   }
19
 
28
 
20
-  public registerCommandListener(callback: (name: string, params: any) => void): EventSubscription {
21
-    return this.commandsObserver.register(callback);
29
+  public registerCommandCompletedListener(callback: (event: CommandCompletedEvent) => void): EventSubscription {
30
+    return this.nativeEventsReceiver.registerCommandCompletedListener(callback);
31
+  }
32
+
33
+  public registerBottomTabSelectedListener(callback: (event: BottomTabSelectedEvent) => void): EventSubscription {
34
+    return this.nativeEventsReceiver.registerBottomTabSelectedListener(callback);
35
+  }
36
+
37
+  public registerNavigationButtonPressedListener(callback: (event: NavigationButtonPressedEvent) => void): EventSubscription {
38
+    return this.nativeEventsReceiver.registerNavigationButtonPressedListener(callback);
22
   }
39
   }
23
 
40
 
24
-  public registerCommandCompletedListener(callback: (commandId: string, completionTime: number, params: any) => void): EventSubscription {
25
-    return this.nativeEventsReceiver.registerCommandCompletedListener(({ commandId, completionTime, params }) => callback(commandId, completionTime, params));
41
+  public registerSearchBarUpdatedListener(callback: (event: SearchBarUpdatedEvent) => void): EventSubscription {
42
+    return this.nativeEventsReceiver.registerSearchBarUpdatedListener(callback);
43
+  }
44
+
45
+  public registerSearchBarCancelPressedListener(callback: (event: SearchBarCancelPressedEvent) => void): EventSubscription {
46
+    return this.nativeEventsReceiver.registerSearchBarCancelPressedListener(callback);
47
+  }
48
+
49
+  public registerCommandListener(callback: (name: string, params: any) => void): EventSubscription {
50
+    return this.commandsObserver.register(callback);
26
   }
51
   }
27
 
52
 
28
-  public registerNativeEventListener(callback: (name: string, params: any) => void): EventSubscription {
29
-    return this.nativeEventsReceiver.registerNativeEventListener(({ name, params }) => callback(name, params));
53
+  public bindComponent(component: React.Component<any>): EventSubscription {
54
+    return this.componentEventsObserver.bindComponent(component);
30
   }
55
   }
31
 }
56
 }

+ 24
- 0
lib/src/interfaces/ComponentEvents.ts Ver fichero

1
+export interface ComponentEvent {
2
+  componentId: string;
3
+}
4
+
5
+export interface ComponentDidAppearEvent extends ComponentEvent {
6
+  componentName: string;
7
+}
8
+
9
+export interface ComponentDidDisappearEvent extends ComponentEvent {
10
+  componentName: string;
11
+}
12
+
13
+export interface NavigationButtonPressedEvent extends ComponentEvent {
14
+  buttonId: string;
15
+}
16
+
17
+export interface SearchBarUpdatedEvent extends ComponentEvent {
18
+  text: string;
19
+  isFocused: boolean;
20
+}
21
+
22
+export interface SearchBarCancelPressedEvent extends ComponentEvent {
23
+  componentName?: string;
24
+}

+ 10
- 0
lib/src/interfaces/Events.ts Ver fichero

1
+export interface CommandCompletedEvent {
2
+  commandId: string;
3
+  completionTime: number;
4
+  params: any;
5
+}
6
+
7
+export interface BottomTabSelectedEvent {
8
+  selectedTabIndex: number;
9
+  unselectedTabIndex: number;
10
+}

+ 3
- 0
playground/src/screens/CustomRoundedButton.js Ver fichero

8
   Alert,
8
   Alert,
9
   Platform
9
   Platform
10
 } = require('react-native');
10
 } = require('react-native');
11
+const { Navigation } = require('react-native-navigation');
11
 
12
 
12
 class CustomRoundedButton extends Component {
13
 class CustomRoundedButton extends Component {
13
 
14
 
14
   constructor(props) {
15
   constructor(props) {
15
     super(props);
16
     super(props);
17
+    this.subscription = Navigation.events().bindComponent(this);
16
     this.state = {};
18
     this.state = {};
17
   }
19
   }
18
 
20
 
29
   }
31
   }
30
 
32
 
31
   componentWillUnmount() {
33
   componentWillUnmount() {
34
+    this.subscription.remove();
32
     console.log('RNN', `CRB.componentWillUnmount`);
35
     console.log('RNN', `CRB.componentWillUnmount`);
33
   }
36
   }
34
 
37
 

+ 3
- 0
playground/src/screens/CustomTopBar.js Ver fichero

8
   Alert,
8
   Alert,
9
   Platform
9
   Platform
10
 } = require('react-native');
10
 } = require('react-native');
11
+const { Navigation } = require('react-native-navigation');
11
 
12
 
12
 class CustomTopBar extends Component {
13
 class CustomTopBar extends Component {
13
 
14
 
14
   constructor(props) {
15
   constructor(props) {
15
     super(props);
16
     super(props);
16
     this.state = {};
17
     this.state = {};
18
+    this.subscription = Navigation.events().bindComponent(this);
17
   }
19
   }
18
 
20
 
19
   componentDidAppear() {
21
   componentDidAppear() {
30
 
32
 
31
   componentWillUnmount() {
33
   componentWillUnmount() {
32
     console.log('RNN', `CTB.componentWillUnmount`);
34
     console.log('RNN', `CTB.componentWillUnmount`);
35
+    this.subscription.remove();
33
   }
36
   }
34
 
37
 
35
   render() {
38
   render() {

+ 4
- 2
playground/src/screens/LifecycleScreen.js Ver fichero

13
     this.state = {
13
     this.state = {
14
       text: 'nothing yet'
14
       text: 'nothing yet'
15
     };
15
     };
16
+    this.subscription = Navigation.events().bindComponent(this);
16
   }
17
   }
17
 
18
 
18
   componentDidAppear() {
19
   componentDidAppear() {
24
   }
25
   }
25
 
26
 
26
   componentWillUnmount() {
27
   componentWillUnmount() {
28
+    this.subscription.remove();
27
     alert('componentWillUnmount'); // eslint-disable-line no-alert
29
     alert('componentWillUnmount'); // eslint-disable-line no-alert
28
   }
30
   }
29
 
31
 
30
-  onNavigationButtonPressed(id) {
31
-    alert(`onNavigationButtonPressed: ${id}`); // eslint-disable-line no-alert
32
+  navigationButtonPressed(id) {
33
+    alert(`navigationButtonPressed: ${id}`); // eslint-disable-line no-alert
32
   }
34
   }
33
 
35
 
34
   render() {
36
   render() {

+ 9
- 4
playground/src/screens/OptionsScreen.js Ver fichero

15
 const TOPBAR_HEIGHT = 67;
15
 const TOPBAR_HEIGHT = 67;
16
 
16
 
17
 class OptionsScreen extends Component {
17
 class OptionsScreen extends Component {
18
+  constructor(props) {
19
+    super(props);
20
+    Navigation.events().bindComponent(this);
21
+  }
22
+
18
   static get options() {
23
   static get options() {
19
     return {
24
     return {
20
       statusBar: {
25
       statusBar: {
137
     );
142
     );
138
   }
143
   }
139
 
144
 
140
-  onNavigationButtonPressed(id) {
141
-    if (id === BUTTON_ONE) {
145
+  navigationButtonPressed({buttonId}) {
146
+    if (buttonId === BUTTON_ONE) {
142
       Navigation.mergeOptions(this.props.componentId, {
147
       Navigation.mergeOptions(this.props.componentId, {
143
         topBar: {
148
         topBar: {
144
           rightButtons: [{
149
           rightButtons: [{
155
           leftButtons: []
160
           leftButtons: []
156
         }
161
         }
157
       });
162
       });
158
-    } else if (id === BUTTON_TWO) {
163
+    } else if (buttonId === BUTTON_TWO) {
159
       Navigation.mergeOptions(this.props.componentId, {
164
       Navigation.mergeOptions(this.props.componentId, {
160
         topBar: {
165
         topBar: {
161
           rightButtons: [{
166
           rightButtons: [{
173
           }]
178
           }]
174
         }
179
         }
175
       });
180
       });
176
-    } else if (id === BUTTON_LEFT) {
181
+    } else if (buttonId === BUTTON_LEFT) {
177
       Navigation.pop(this.props.componentId);
182
       Navigation.pop(this.props.componentId);
178
     }
183
     }
179
   }
184
   }

+ 19
- 22
playground/src/screens/PushedScreen.js Ver fichero

1
 const _ = require('lodash');
1
 const _ = require('lodash');
2
-
3
 const React = require('react');
2
 const React = require('react');
4
 const { Component } = require('react');
3
 const { Component } = require('react');
5
-
6
 const { View, Text, Platform } = require('react-native');
4
 const { View, Text, Platform } = require('react-native');
7
-
8
 const { Navigation } = require('react-native-navigation');
5
 const { Navigation } = require('react-native-navigation');
9
 const Button = require('./Button');
6
 const Button = require('./Button');
10
 const testIDs = require('../testIDs');
7
 const testIDs = require('../testIDs');
53
 
50
 
54
   componentDidMount() {
51
   componentDidMount() {
55
     this.listeners.push(
52
     this.listeners.push(
56
-      Navigation.events().registerNativeEventListener((name, params) => {
57
-        if (name === 'previewContext') {
58
-          const { previewComponentId } = params;
59
-          this.setState({ previewComponentId });
60
-        }
61
-      }),
62
-      Navigation.events().registerComponentDidAppearListener((componentId, componentName) => {
63
-        if (this.state.previewComponentId === componentId) {
64
-          this.setState({ disabled: true });
65
-        }
66
-      }),
67
-      Navigation.events().registerComponentDidDisappearListener((componentId, componentName) => {
68
-        if (this.state.previewComponentId === componentId) {
69
-          this.setState({ disabled: false });
53
+      this.subscription = Navigation.events().registerComponentDidAppearListener((event) => {
54
+        if (this.state.previewComponentId === event.componentId) {
55
+          this.setState({ disabled: event.type === 'ComponentDidAppear' });
70
         }
56
         }
71
       })
57
       })
72
     );
58
     );
59
+    if (Platform.OS === 'ios') {
60
+      // this.listeners.push(
61
+      //   Navigation.events().registerNativeEventListener((name, params) => {
62
+      //     if (name === 'previewContext') {
63
+      //       const { previewComponentId } = params;
64
+      //       this.setState({ previewComponentId });
65
+      //     }
66
+      //   })
67
+      // );
68
+    }
73
   }
69
   }
74
 
70
 
75
   componentWillUnmount() {
71
   componentWillUnmount() {
72
+    this.subscription.remove();
76
     this.listeners.forEach(listener => listener.remove && listener.remove());
73
     this.listeners.forEach(listener => listener.remove && listener.remove());
77
   }
74
   }
78
 
75
 
83
         <Text testID={testIDs.PUSHED_SCREEN_HEADER} style={styles.h1}>{`Pushed Screen`}</Text>
80
         <Text testID={testIDs.PUSHED_SCREEN_HEADER} style={styles.h1}>{`Pushed Screen`}</Text>
84
         <Text style={styles.h2}>{`Stack Position: ${stackPosition}`}</Text>
81
         <Text style={styles.h2}>{`Stack Position: ${stackPosition}`}</Text>
85
         <Button title='Push' testID={testIDs.PUSH_BUTTON} onPress={this.onClickPush} />
82
         <Button title='Push' testID={testIDs.PUSH_BUTTON} onPress={this.onClickPush} />
86
-          {Platform.OS === 'ios' && (
87
-            <Navigation.Element elementId='PreviewElement'>
88
-              <Button testID={testIDs.SHOW_PREVIEW_BUTTON} onPress={this.onClickPush} onPressIn={this.onClickShowPreview} title='Push Preview' />
89
-            </Navigation.Element>
90
-          )}
83
+        {Platform.OS === 'ios' && (
84
+          <Navigation.Element elementId='PreviewElement'>
85
+            <Button testID={testIDs.SHOW_PREVIEW_BUTTON} onPress={this.onClickPush} onPressIn={this.onClickShowPreview} title='Push Preview' />
86
+          </Navigation.Element>
87
+        )}
91
         <Button title='Pop' testID={testIDs.POP_BUTTON} onPress={this.onClickPop} />
88
         <Button title='Pop' testID={testIDs.POP_BUTTON} onPress={this.onClickPop} />
92
         <Button title='Pop Previous' testID={testIDs.POP_PREVIOUS_BUTTON} onPress={this.onClickPopPrevious} />
89
         <Button title='Pop Previous' testID={testIDs.POP_PREVIOUS_BUTTON} onPress={this.onClickPopPrevious} />
93
         <Button title='Pop To Root' testID={testIDs.POP_TO_ROOT} onPress={this.onClickPopToRoot} />
90
         <Button title='Pop To Root' testID={testIDs.POP_TO_ROOT} onPress={this.onClickPopToRoot} />

+ 3
- 2
playground/src/screens/SearchScreen.js Ver fichero

38
     this.state = {
38
     this.state = {
39
       query: ''
39
       query: ''
40
     };
40
     };
41
+    Navigation.events().bindComponent(this);
41
   }
42
   }
42
 
43
 
43
   filteredData() {
44
   filteredData() {
79
     );
80
     );
80
   }
81
   }
81
 
82
 
82
-  onSearchBarUpdated(query, isFocused) {
83
-    this.setState({ query, isFocused });
83
+  searchBarUpdated({text, isFocused}) {
84
+    this.setState({ query: text, isFocused });
84
   }
85
   }
85
 }
86
 }
86
 
87
 

+ 15
- 13
playground/src/screens/StaticLifecycleOverlay.js Ver fichero

12
       events: []
12
       events: []
13
     };
13
     };
14
     this.listeners = [];
14
     this.listeners = [];
15
-    this.listeners.push(Navigation.events().registerComponentDidAppearListener((componentId, componentName) => {
15
+    this.listeners.push(Navigation.events().registerComponentDidAppearListener((event) => {
16
+      event.event = 'componentDidAppear';
16
       this.setState({
17
       this.setState({
17
-        events: [...this.state.events, { event: 'componentDidAppear', componentId, componentName }]
18
+        events: [...this.state.events, { ...event }]
18
       });
19
       });
19
     }));
20
     }));
20
-    this.listeners.push(Navigation.events().registerComponentDidDisappearListener((componentId, componentName) => {
21
+    this.listeners.push(Navigation.events().registerComponentDidDisappearListener((event) => {
22
+      event.event = 'componentDidDisappear';
21
       this.setState({
23
       this.setState({
22
-        events: [...this.state.events, { event: 'componentDidDisappear', componentId, componentName }]
24
+        events: [...this.state.events, { ...event }]
23
       });
25
       });
24
     }));
26
     }));
25
-    this.listeners.push(Navigation.events().registerCommandCompletedListener((commandId, completionTime, params) => {
27
+    this.listeners.push(Navigation.events().registerCommandCompletedListener(({commandId}) => {
26
       this.setState({
28
       this.setState({
27
         events: [...this.state.events, { event: 'commandCompleted', commandId }]
29
         events: [...this.state.events, { event: 'commandCompleted', commandId }]
28
       });
30
       });
62
   }
64
   }
63
 
65
 
64
   renderDismissButton = () => {
66
   renderDismissButton = () => {
65
-  return (
66
-    <TouchableOpacity
67
-      style={styles.dismissBtn}
68
-      onPress={() => Navigation.dismissOverlay(this.props.componentId)}
69
-    >
70
-      <Text testID={testIDs.DISMISS_BUTTON} style={{ color: 'red', alignSelf: 'center' }}>X</Text>
71
-    </TouchableOpacity>
72
-  );
67
+    return (
68
+      <TouchableOpacity
69
+        style={styles.dismissBtn}
70
+        onPress={() => Navigation.dismissOverlay(this.props.componentId)}
71
+      >
72
+        <Text testID={testIDs.DISMISS_BUTTON} style={{ color: 'red', alignSelf: 'center' }}>X</Text>
73
+      </TouchableOpacity>
74
+    );
73
   }
75
   }
74
 }
76
 }
75
 module.exports = StaticLifecycleOverlay;
77
 module.exports = StaticLifecycleOverlay;

+ 3
- 0
playground/src/screens/TopBarBackground.js Ver fichero

4
   StyleSheet,
4
   StyleSheet,
5
   View
5
   View
6
 } = require('react-native');
6
 } = require('react-native');
7
+const { Navigation } = require('react-native-navigation');
7
 
8
 
8
 class TopBarBackground extends Component {
9
 class TopBarBackground extends Component {
9
 
10
 
10
   constructor(props) {
11
   constructor(props) {
11
     super(props);
12
     super(props);
13
+    this.subscription = Navigation.events().bindComponent(this);
12
     this.state = {};
14
     this.state = {};
13
     this.dots = new Array(55).fill('').map((ignored, i) => <View key={'dot' + i} style={[styles.dot, {backgroundColor: this.props.color}]}/>);
15
     this.dots = new Array(55).fill('').map((ignored, i) => <View key={'dot' + i} style={[styles.dot, {backgroundColor: this.props.color}]}/>);
14
   }
16
   }
27
 
29
 
28
   componentWillUnmount() {
30
   componentWillUnmount() {
29
     console.log('RNN', `TBB.componentWillUnmount`);
31
     console.log('RNN', `TBB.componentWillUnmount`);
32
+    this.subscription.remove();
30
   }
33
   }
31
 
34
 
32
   render() {
35
   render() {

+ 22
- 10
scripts/gen-docs/ClassParser.ts Ver fichero

1
-import * as Handlebars from 'handlebars';
2
 import * as Typedoc from 'typedoc';
1
 import * as Typedoc from 'typedoc';
3
 
2
 
4
 export interface PropertyContext {
3
 export interface PropertyContext {
16
   arguments: ArgumentContext[];
15
   arguments: ArgumentContext[];
17
   returnType: string;
16
   returnType: string;
18
   source: string;
17
   source: string;
18
+  line: number;
19
   comment?: string;
19
   comment?: string;
20
 }
20
 }
21
 
21
 
42
 
42
 
43
   private parseMethods(reflection: Typedoc.DeclarationReflection): MethodContext[] {
43
   private parseMethods(reflection: Typedoc.DeclarationReflection): MethodContext[] {
44
     const methodReflections = reflection.getChildrenByKind(Typedoc.ReflectionKind.Method);
44
     const methodReflections = reflection.getChildrenByKind(Typedoc.ReflectionKind.Method);
45
+    const methods = methodReflections.map((m) => this.parseMethod(m))
46
+      .filter((m) => !m.source.includes('/node_modules/'))
47
+      .sort((a, b) => a.line - b.line);
48
+    return methods;
49
+  }
45
 
50
 
46
-    methodReflections.sort((a, b) => a.sources[0].line - b.sources[0].line);
47
-
48
-    return methodReflections.map((methodReflection) => ({
49
-      name: methodReflection.name,
50
-      arguments: this.parseArguments(methodReflection.signatures[0].parameters || []),
51
-      returnType: methodReflection.signatures[0].type.toString(),
52
-      source: `${this.sourceLinkPrefix}/${methodReflection.sources[0].fileName}#L${methodReflection.sources[0].line}`,
53
-      comment: methodReflection.signatures[0].comment ? methodReflection.signatures[0].comment.shortText : ''
54
-    }));
51
+  private parseMethod(methodReflection: Typedoc.DeclarationReflection) {
52
+    const name = methodReflection.name;
53
+    const line = methodReflection.sources[0].line;
54
+    const fileName = methodReflection.sources[0].fileName;
55
+    const source = `${this.sourceLinkPrefix}/${fileName}#L${line}`;
56
+    const comment = methodReflection.signatures[0].comment ? methodReflection.signatures[0].comment.shortText : '';
57
+    const args = this.parseArguments(methodReflection.signatures[0].parameters || []);
58
+    const returnType = methodReflection.signatures[0].type.toString();
59
+    return {
60
+      name,
61
+      arguments: args,
62
+      returnType,
63
+      source,
64
+      line,
65
+      comment
66
+    };
55
   }
67
   }
56
 
68
 
57
   private parseArguments(parameters: Typedoc.ParameterReflection[]): ArgumentContext[] {
69
   private parseArguments(parameters: Typedoc.ParameterReflection[]): ArgumentContext[] {