Browse Source

Add missing typescript interfaces (#6203)

* Add missing typescript interfaces

* Fix tsconfig

* Fix ts imports

* Remove NavigationListener

* Add Navigation.events().registerComponentListener()

* Avoid breaking changes in typescript

* Export NavigationComponentProps
Yogev Ben David 3 years ago
parent
commit
ec7f32404d
No account linked to committer's email address

+ 14
- 0
lib/src/events/ComponentEventsObserver.test.tsx View File

@@ -221,6 +221,20 @@ describe('ComponentEventsObserver', () => {
221 221
     expect(willUnmountFn).toHaveBeenCalledTimes(1);
222 222
   });
223 223
 
224
+  it(`registerComponentListener accepts listener object`, () => {
225
+    const tree = renderer.create(<UnboundScreen />);
226
+    const didAppearListenerFn = jest.fn();
227
+    uut.registerComponentListener({
228
+      componentDidAppear: didAppearListenerFn
229
+    }, 'myCompId')
230
+
231
+    expect(tree.toJSON()).toBeDefined();
232
+    expect(didAppearListenerFn).not.toHaveBeenCalled();
233
+
234
+    uut.notifyComponentDidAppear({ componentId: 'myCompId', componentName: 'doesnt matter', componentType: 'Component' });
235
+    expect(didAppearListenerFn).toHaveBeenCalledTimes(1);
236
+  });
237
+
224 238
   it(`componentDidAppear should receive component props from store`, () => {
225 239
     const event = {
226 240
       componentId: 'myCompId',

+ 14
- 5
lib/src/events/ComponentEventsObserver.ts View File

@@ -18,8 +18,9 @@ import {
18 18
 } from '../interfaces/ComponentEvents';
19 19
 import { NativeEventsReceiver } from '../adapters/NativeEventsReceiver';
20 20
 import { Store } from '../components/Store';
21
+import { NavigationComponentListener } from 'react-native-navigation/interfaces/NavigationComponentListener'
21 22
 
22
-type ReactComponentWithIndexing = React.Component<any> & Record<string, any>;
23
+type ReactComponentWithIndexing = NavigationComponentListener & Record<string, any>;
23 24
 
24 25
 export class ComponentEventsObserver {
25 26
   private listeners: Record<string, Record<string, ReactComponentWithIndexing>> = {};
@@ -60,13 +61,21 @@ export class ComponentEventsObserver {
60 61
     if (!isString(computedComponentId)) {
61 62
       throw new Error(`bindComponent expects a component with a componentId in props or a componentId as the second argument`);
62 63
     }
63
-    if (isNil(this.listeners[computedComponentId])) {
64
-      this.listeners[computedComponentId] = {};
64
+    
65
+    return this.registerComponentListener(component as NavigationComponentListener, computedComponentId);
66
+  }
67
+
68
+  public registerComponentListener(listener: NavigationComponentListener, componentId: string): EventSubscription {
69
+    if (!isString(componentId)) {
70
+      throw new Error(`registerComponentListener expects a componentId as the second argument`);
71
+    }
72
+    if (isNil(this.listeners[componentId])) {
73
+      this.listeners[componentId] = {};
65 74
     }
66 75
     const key = uniqueId();
67
-    this.listeners[computedComponentId][key] = component;
76
+    this.listeners[componentId][key] = listener;
68 77
 
69
-    return { remove: () => unset(this.listeners[computedComponentId], key) };
78
+    return { remove: () => unset(this.listeners[componentId], key) };
70 79
   }
71 80
 
72 81
   public unmounted(componentId: string) {

+ 10
- 1
lib/src/events/EventsRegistry.test.tsx View File

@@ -2,6 +2,8 @@ import { EventsRegistry } from './EventsRegistry';
2 2
 import { NativeEventsReceiver } from '../adapters/NativeEventsReceiver.mock';
3 3
 import { CommandsObserver } from './CommandsObserver';
4 4
 import { UniqueIdProvider } from '../adapters/UniqueIdProvider';
5
+import { NavigationComponent } from '../interfaces/NavigationComponent';
6
+import { NavigationComponentListener } from 'react-native-navigation/interfaces/NavigationComponentListener';
5 7
 
6 8
 describe('EventsRegistry', () => {
7 9
   let uut: EventsRegistry;
@@ -117,7 +119,14 @@ describe('EventsRegistry', () => {
117 119
     const subscription = {};
118 120
     mockScreenEventsRegistry.bindComponent = jest.fn();
119 121
     mockScreenEventsRegistry.bindComponent.mockReturnValueOnce(subscription);
120
-    expect(uut.bindComponent({} as React.Component<any>)).toEqual(subscription);
122
+    expect(uut.bindComponent({} as NavigationComponent<any>)).toEqual(subscription);
123
+  });
124
+
125
+  it(`delegates registerComponentListener to ComponentObserver`, () => {
126
+    const subscription = {};
127
+    mockScreenEventsRegistry.registerComponentListener = jest.fn();
128
+    mockScreenEventsRegistry.registerComponentListener.mockReturnValueOnce(subscription);
129
+    expect(uut.registerComponentListener({} as NavigationComponentListener, 'componentId')).toEqual(subscription);
121 130
   });
122 131
 
123 132
   it('delegates screenPopped to nativeEventsReceiver', () => {

+ 8
- 0
lib/src/events/EventsRegistry.ts View File

@@ -21,6 +21,7 @@ import {
21 21
   BottomTabLongPressedEvent,
22 22
   BottomTabPressedEvent
23 23
 } from '../interfaces/Events';
24
+import { NavigationComponentListener } from 'react-native-navigation/interfaces/NavigationComponentListener';
24 25
 
25 26
 export class EventsRegistry {
26 27
   constructor(
@@ -134,6 +135,13 @@ export class EventsRegistry {
134 135
     return this.componentEventsObserver.bindComponent(component, componentId);
135 136
   }
136 137
 
138
+  public registerComponentListener(
139
+    listener: NavigationComponentListener,
140
+    componentId: string
141
+  ): EventSubscription {
142
+    return this.componentEventsObserver.registerComponentListener(listener, componentId);
143
+  }
144
+
137 145
   public registerScreenPoppedListener(
138 146
     callback: (event: ScreenPoppedEvent) => void
139 147
   ): EmitterSubscription {

+ 2
- 0
lib/src/index.ts View File

@@ -9,3 +9,5 @@ export * from './interfaces/Events';
9 9
 export * from './interfaces/EventSubscription';
10 10
 export * from './interfaces/Layout';
11 11
 export * from './interfaces/Options';
12
+export * from './interfaces/NavigationComponent';
13
+export * from './interfaces/NavigationComponentProps';

+ 26
- 0
lib/src/interfaces/NavigationComponent.ts View File

@@ -0,0 +1,26 @@
1
+import React from 'react';
2
+import {
3
+  NavigationButtonPressedEvent,
4
+  ModalDismissedEvent,
5
+  ModalAttemptedToDismissEvent,
6
+  SearchBarUpdatedEvent,
7
+  SearchBarCancelPressedEvent,
8
+  PreviewCompletedEvent,
9
+  ScreenPoppedEvent,
10
+  ComponentDidAppearEvent,
11
+  ComponentDidDisappearEvent,
12
+} from './ComponentEvents';
13
+import { NavigationComponentProps } from './NavigationComponentProps';
14
+
15
+export class NavigationComponent<Props = {}, State = {}, Snapshot = any>
16
+  extends React.Component<Props & NavigationComponentProps, State, Snapshot> {
17
+    componentDidAppear(_event: ComponentDidAppearEvent) {}
18
+    componentDidDisappear(_event: ComponentDidDisappearEvent) {}
19
+    navigationButtonPressed(_event: NavigationButtonPressedEvent) {}
20
+    modalDismissed(_event: ModalDismissedEvent) {}
21
+    modalAttemptedToDismiss(_event: ModalAttemptedToDismissEvent) {}
22
+    searchBarUpdated(_event: SearchBarUpdatedEvent) {}
23
+    searchBarCancelPressed(_event: SearchBarCancelPressedEvent) {}
24
+    previewCompleted(_event: PreviewCompletedEvent) {}
25
+    screenPopped(_event: ScreenPoppedEvent) {}
26
+  }

+ 23
- 0
lib/src/interfaces/NavigationComponentListener.ts View File

@@ -0,0 +1,23 @@
1
+import {
2
+  NavigationButtonPressedEvent,
3
+  ModalDismissedEvent,
4
+  ModalAttemptedToDismissEvent,
5
+  SearchBarUpdatedEvent,
6
+  SearchBarCancelPressedEvent,
7
+  PreviewCompletedEvent,
8
+  ScreenPoppedEvent,
9
+  ComponentDidAppearEvent,
10
+  ComponentDidDisappearEvent,
11
+} from './ComponentEvents';
12
+
13
+export interface NavigationComponentListener {
14
+    componentDidAppear? : (_event: ComponentDidAppearEvent) => void
15
+    componentDidDisappear? : (_event: ComponentDidDisappearEvent) => void
16
+    navigationButtonPressed? : (_event: NavigationButtonPressedEvent) => void
17
+    modalDismissed? : (_event: ModalDismissedEvent) => void
18
+    modalAttemptedToDismiss? : (_event: ModalAttemptedToDismissEvent) => void
19
+    searchBarUpdated? : (_event: SearchBarUpdatedEvent) => void
20
+    searchBarCancelPressed? : (_event: SearchBarCancelPressedEvent) => void
21
+    previewCompleted? : (_event: PreviewCompletedEvent) => void
22
+    screenPopped? : (_event: ScreenPoppedEvent) => void
23
+  }

+ 3
- 0
lib/src/interfaces/NavigationComponentProps.ts View File

@@ -0,0 +1,3 @@
1
+export interface NavigationComponentProps {
2
+  componentId: string;
3
+}

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

@@ -11,8 +11,8 @@ const Screens = require('./Screens');
11 11
 function registerScreens() {
12 12
   Navigation.registerComponent(Screens.Alert, () => require('./Alert'));
13 13
   Navigation.registerComponent(Screens.CocktailDetailsScreen, () => require('./sharedElementTransition/CocktailDetailsScreen'));
14
-  Navigation.registerComponent(Screens.CocktailsListScreen, () => require('./sharedElementTransition/CocktailsListScreen'));
15
-  Navigation.registerComponent(Screens.CocktailsListMasterScreen, () => require('./splitView/CocktailsListMasterScreen'));
14
+  Navigation.registerComponent(Screens.CocktailsListScreen, () => require('./sharedElementTransition/CocktailsListScreen').default);
15
+  Navigation.registerComponent(Screens.CocktailsListMasterScreen, () => require('./splitView/CocktailsListMasterScreen').default);
16 16
   Navigation.registerComponent(Screens.EventsOverlay, () => require('./StaticLifecycleOverlay').StaticLifecycleOverlay);
17 17
   Navigation.registerComponent(Screens.EventsScreen, () => require('./StaticEventsScreen'));
18 18
   Navigation.registerComponent(Screens.ExternalComponent, () => require('./ExternalComponentScreen'));

playground/src/screens/sharedElementTransition/CocktailsListScreen.js → playground/src/screens/sharedElementTransition/CocktailsListScreen.tsx View File

@@ -1,5 +1,5 @@
1 1
 const React = require('react');
2
-const { Component } = require('react');
2
+import { NavigationComponent } from 'react-native-navigation';
3 3
 const CocktailsView = require('./CocktailsView')
4 4
 const { Platform } = require('react-native');
5 5
 const Navigation = require('../../services/Navigation');
@@ -8,7 +8,7 @@ const MULTIPLIER = 1.15
8 8
 const LONG_DURATION = 350 * MULTIPLIER
9 9
 const SHORT_DURATION = 190 * MULTIPLIER
10 10
 
11
-class CocktailsListScreen extends Component {
11
+export default class CocktailsListScreen extends NavigationComponent {
12 12
   static options() {
13 13
     return {
14 14
       ...Platform.select({
@@ -35,11 +35,11 @@ class CocktailsListScreen extends Component {
35 35
     );
36 36
   }
37 37
 
38
-  update = (item) => {
38
+  update = (item: any) => {
39 39
     Navigation.updateProps('DETAILS_COMPONENT_ID', item);
40 40
   }
41 41
 
42
-  pushCocktailDetails = (item) => {
42
+  pushCocktailDetails = (item: any) => {
43 43
     Navigation.push(
44 44
       this,
45 45
       {
@@ -94,4 +94,4 @@ class CocktailsListScreen extends Component {
94 94
     )
95 95
   }
96 96
 }
97
-module.exports = CocktailsListScreen;
97
+

playground/src/screens/splitView/CocktailsListMasterScreen.js → playground/src/screens/splitView/CocktailsListMasterScreen.tsx View File

@@ -3,12 +3,14 @@ const CocktailsView = require('../sharedElementTransition/CocktailsView')
3 3
 const { Platform } = require('react-native');
4 4
 const Navigation = require('../../services/Navigation');
5 5
 const Screens = require('../Screens');
6
-const CocktailsListScreen = require('../sharedElementTransition/CocktailsListScreen');
6
+import CocktailsListScreen from '../sharedElementTransition/CocktailsListScreen';
7
+import { NavigationButtonPressedEvent } from 'react-native-navigation';
8
+
7 9
 const {
8 10
   PUSH_MASTER_BTN
9 11
 } = require('../../testIDs');
10 12
 
11
-class CocktailsListMasterScreen extends CocktailsListScreen {
13
+export default class CocktailsListMasterScreen extends CocktailsListScreen {
12 14
   static options() {
13 15
     return {
14 16
       ...Platform.select({
@@ -32,13 +34,13 @@ class CocktailsListMasterScreen extends CocktailsListScreen {
32 34
     }
33 35
   }
34 36
 
35
-  constructor(props) {
37
+  constructor(props: any) {
36 38
     super(props);
37 39
     Navigation.events().bindComponent(this);
38 40
   }
39 41
 
40
-  navigationButtonPressed({buttonId}) {
41
-    if (buttonId === 'pushMaster') {
42
+  navigationButtonPressed(event: NavigationButtonPressedEvent) {
43
+    if (event.buttonId === 'pushMaster') {
42 44
       Navigation.push(this, Screens.Pushed)
43 45
     }
44 46
   }
@@ -52,9 +54,7 @@ class CocktailsListMasterScreen extends CocktailsListScreen {
52 54
     );
53 55
   }
54 56
 
55
-  updateDetailsScreen = (item) => {
57
+  updateDetailsScreen = (item: any) => {
56 58
     Navigation.updateProps('DETAILS_COMPONENT_ID', item);
57 59
   }
58 60
 }
59
-
60
-module.exports = CocktailsListMasterScreen;

+ 2
- 2
scripts/build.js View File

@@ -7,8 +7,8 @@ run();
7 7
 function run() {
8 8
     if (isWindows) {
9 9
         exec.execSync(`del /F /S /Q lib\\dist`);
10
-        exec.execSync(`tsc`);
10
+        exec.execSync(`tsc --project tsconfig.build.json`);
11 11
     } else {
12
-        exec.execSync(`rm -rf ./lib/dist && tsc`);
12
+        exec.execSync(`rm -rf ./lib/dist && tsc --project tsconfig.build.json`);
13 13
     }
14 14
 }

+ 1
- 1
scripts/start-windows.js View File

@@ -5,7 +5,7 @@ run();
5 5
 function run() {
6 6
   // exec.killPort(8081);
7 7
   // exec.execSync(`rd "./lib/dist" /Q/S`);
8
-  exec.execSync(`"./node_modules/.bin/tsc"`);
8
+  exec.execSync(`"./node_modules/.bin/tsc --project tsconfig.build.json"`);
9 9
   exec.execSync(`adb reverse tcp:8081 tcp:8081`);
10 10
   exec.execSync(`node ./node_modules/react-native/local-cli/cli.js start`);
11 11
 }

+ 2
- 2
scripts/watch.js View File

@@ -7,8 +7,8 @@ run();
7 7
 function run() {
8 8
     if (isWindows) {
9 9
         exec.execSync(`del /F /S /Q lib\\dist`);
10
-        exec.execSync(`tsc --watch`);
10
+        exec.execSync(`tsc --project tsconfig.build.json --watch`);
11 11
     } else {
12
-        exec.execSync(`rm -rf ./lib/dist && tsc --watch`);
12
+        exec.execSync(`rm -rf ./lib/dist && tsc --project tsconfig.build.json --watch`);
13 13
     }
14 14
 }

+ 6
- 0
tsconfig.build.json View File

@@ -0,0 +1,6 @@
1
+{
2
+  "extends": "./tsconfig.json",
3
+  "exclude": [
4
+    "./playground/**/*"
5
+  ]
6
+}

+ 8
- 2
tsconfig.json View File

@@ -15,9 +15,15 @@
15 15
       "react",
16 16
       "react-native",
17 17
       "react-test-renderer"
18
-    ]
18
+    ],
19
+    "baseUrl": ".",
20
+    "paths": {
21
+      "react-native-navigation": ["lib/src/"],
22
+      "react-native-navigation/*": ["lib/src/*"]
23
+    }
19 24
   },
20 25
   "include": [
21
-    "./lib/src/**/*"
26
+    "./lib/src/**/*",
27
+    "./playground/**/*"
22 28
   ]
23 29
 }