react-native-navigation 8.1.0-alpha-snapshot.1648 → 8.1.0-rc01

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/lib/Mock/Components/ComponentScreen.tsx +2 -1
  2. package/lib/Mock/Components/LayoutComponent.tsx +9 -0
  3. package/lib/Mock/Components/SideMenu.tsx +27 -0
  4. package/lib/Mock/Layouts/BottomTabsNode.ts +4 -2
  5. package/lib/Mock/Layouts/LayoutNodeFactory.ts +14 -1
  6. package/lib/Mock/Layouts/ParentNode.ts +4 -0
  7. package/lib/Mock/Layouts/SideMenu.ts +87 -0
  8. package/lib/Mock/Stores/LayoutStore.ts +42 -10
  9. package/lib/Mock/actions/layoutActions.ts +11 -0
  10. package/lib/Mock/mocks/NativeCommandsSender.tsx +1 -0
  11. package/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/bottomtabs/BottomTabsController.java +16 -4
  12. package/lib/dist/Mock/Components/ComponentScreen.js +2 -1
  13. package/lib/dist/Mock/Components/LayoutComponent.js +9 -0
  14. package/lib/dist/Mock/Components/SideMenu.d.ts +58 -0
  15. package/lib/dist/Mock/Components/SideMenu.js +25 -0
  16. package/lib/dist/Mock/Layouts/BottomTabsNode.d.ts +1 -1
  17. package/lib/dist/Mock/Layouts/BottomTabsNode.js +3 -2
  18. package/lib/dist/Mock/Layouts/LayoutNodeFactory.d.ts +2 -1
  19. package/lib/dist/Mock/Layouts/LayoutNodeFactory.js +10 -1
  20. package/lib/dist/Mock/Layouts/ParentNode.d.ts +1 -0
  21. package/lib/dist/Mock/Layouts/ParentNode.js +3 -0
  22. package/lib/dist/Mock/Layouts/SideMenu.d.ts +31 -0
  23. package/lib/dist/Mock/Layouts/SideMenu.js +80 -0
  24. package/lib/dist/Mock/Stores/LayoutStore.js +38 -9
  25. package/lib/dist/Mock/actions/layoutActions.d.ts +3 -0
  26. package/lib/dist/Mock/actions/layoutActions.js +11 -1
  27. package/lib/dist/Mock/mocks/NativeCommandsSender.js +1 -0
  28. package/lib/ios/AnimatedTextView.mm +1 -0
  29. package/lib/ios/RNNCommandsHandler.mm +1 -0
  30. package/lib/ios/RNNCustomTitleView.h +1 -0
  31. package/lib/ios/RNNCustomTitleView.mm +8 -1
  32. package/lib/ios/RNNEventEmitter.mm +3 -0
  33. package/lib/ios/RNNReactButtonView.mm +1 -1
  34. package/lib/ios/RNNReactView.h +3 -1
  35. package/lib/ios/RNNReactView.mm +45 -20
  36. package/lib/ios/TopBarTitlePresenter.mm +2 -0
  37. package/lib/ios/TurboModules/RNNTurboEventEmitter.mm +7 -0
  38. package/lib/ios/UINavigationController+RNNCommands.mm +4 -0
  39. package/package.json +1 -1
@@ -25,7 +25,8 @@ export const ComponentScreen = connect(
25
25
  }
26
26
 
27
27
  isVisible(): boolean {
28
- return LayoutStore.isVisibleLayout(this.props.layoutNode);
28
+ const isVisible = LayoutStore.isVisibleLayout(this.props.layoutNode);
29
+ return isVisible;
29
30
  }
30
31
 
31
32
  renderTabBar() {
@@ -4,6 +4,7 @@ import { BottomTabs } from './BottomTabs';
4
4
  import { ComponentProps } from '../ComponentProps';
5
5
  import { ComponentScreen } from './ComponentScreen';
6
6
  import { Stack } from './Stack';
7
+ import { SideMenuRoot, SideMenuCenter, SideMenuLeft, SideMenuRight } from './SideMenu';
7
8
 
8
9
  export const LayoutComponent = class extends Component<ComponentProps> {
9
10
  render() {
@@ -14,6 +15,14 @@ export const LayoutComponent = class extends Component<ComponentProps> {
14
15
  return <Stack layoutNode={this.props.layoutNode} />;
15
16
  case 'Component':
16
17
  return <ComponentScreen layoutNode={this.props.layoutNode} />;
18
+ case 'SideMenuRoot':
19
+ return <SideMenuRoot layoutNode={this.props.layoutNode} />;
20
+ case 'SideMenuLeft':
21
+ return <SideMenuLeft layoutNode={this.props.layoutNode} />;
22
+ case 'SideMenuCenter':
23
+ return <SideMenuCenter layoutNode={this.props.layoutNode} />;
24
+ case 'SideMenuRight':
25
+ return <SideMenuRight layoutNode={this.props.layoutNode} />;
17
26
  }
18
27
 
19
28
  return <View />;
@@ -0,0 +1,27 @@
1
+ import React, { Component } from 'react';
2
+ import { connect } from '../connect';
3
+ import { ComponentProps } from '../ComponentProps';
4
+ import { LayoutComponent } from './LayoutComponent';
5
+ import ParentNode from '../Layouts/ParentNode';
6
+
7
+ export const SideMenuRoot = connect(
8
+ class extends Component<ComponentProps> {
9
+ render() {
10
+ const children = this.props.layoutNode.children;
11
+ return children.map((child: ParentNode) => {
12
+ return <LayoutComponent key={child.nodeId} layoutNode={child} />;
13
+ });
14
+ }
15
+ }
16
+ );
17
+
18
+ class SideMenuComponent extends Component<ComponentProps> {
19
+ render() {
20
+ const children = this.props.layoutNode.children;
21
+ const component = children[0];
22
+ return <LayoutComponent key={component.nodeId} layoutNode={component} />;
23
+ }
24
+ }
25
+ export const SideMenuLeft = connect(SideMenuComponent);
26
+ export const SideMenuCenter = connect(SideMenuComponent);
27
+ export const SideMenuRight = connect(SideMenuComponent);
@@ -10,8 +10,10 @@ export default class BottomTabsNode extends ParentNode {
10
10
  this.selectedIndex = layout.data?.options?.bottomTabs?.currentTabIndex || 0;
11
11
  }
12
12
 
13
- mergeOptions(options: Options) {
14
- super.mergeOptions(options);
13
+ mergeOptions(_options: Options) {
14
+ super.mergeOptions(_options);
15
+
16
+ const { options } = this.data;
15
17
  if (options.bottomTabs?.currentTabIndex) {
16
18
  this.selectedIndex = options.bottomTabs?.currentTabIndex;
17
19
  switchTabByIndex(this, this.selectedIndex);
@@ -2,6 +2,11 @@ import BottomTabs from './BottomTabsNode';
2
2
  import ComponentNode from './ComponentNode';
3
3
  import Stack from './StackNode';
4
4
  import ParentNode from './ParentNode';
5
+ import SideMenuRootNode, {
6
+ SideMenuLeftNode,
7
+ SideMenuRightNode,
8
+ SideMenuCenterNode,
9
+ } from './SideMenu';
5
10
 
6
11
  export default class LayoutNodeFactory {
7
12
  static create(layout: any, parentNode?: ParentNode) {
@@ -10,7 +15,15 @@ export default class LayoutNodeFactory {
10
15
  return new ComponentNode(layout, parentNode);
11
16
  case 'Stack':
12
17
  return new Stack(layout, parentNode);
13
- default:
18
+ case 'SideMenuRoot':
19
+ return new SideMenuRootNode(layout, parentNode);
20
+ case 'SideMenuLeft':
21
+ return new SideMenuLeftNode(layout, parentNode);
22
+ case 'SideMenuCenter':
23
+ return new SideMenuCenterNode(layout, parentNode);
24
+ case 'SideMenuRight':
25
+ return new SideMenuRightNode(layout, parentNode);
26
+ default: // TODO Undo
14
27
  case 'BottomTabs':
15
28
  return new BottomTabs(layout, parentNode);
16
29
  }
@@ -35,6 +35,10 @@ export default class ParentNode extends Node {
35
35
  return this;
36
36
  }
37
37
 
38
+ applyOptions(_options: Options) {
39
+ this.parentNode?.applyOptions(_options);
40
+ }
41
+
38
42
  mergeOptions(options: Options) {
39
43
  this.data.options = _.mergeWith(this.data.options, options, (objValue, srcValue, key) => {
40
44
  if (_.isArray(objValue)) {
@@ -0,0 +1,87 @@
1
+ import ParentNode from './ParentNode';
2
+ import ComponentNode from './ComponentNode';
3
+ import { Options } from '../../src/index';
4
+ import * as layoutActions from '../actions/layoutActions';
5
+ import { NodeType } from './Node';
6
+
7
+ const isCenterChild = (child: ParentNode) => child.type === 'SideMenuCenter';
8
+ const isLeftChild = (child: ParentNode) => child.type === 'SideMenuLeft';
9
+ const isRightChild = (child: ParentNode) => child.type === 'SideMenuRight';
10
+
11
+ export default class SideMenuRootNode extends ParentNode {
12
+ visibleChild: ParentNode;
13
+
14
+ constructor(layout: any, parentNode?: ParentNode) {
15
+ super(layout, 'SideMenuRoot', parentNode);
16
+
17
+ this.visibleChild = this._getCenterChild();
18
+ if (!this.visibleChild) {
19
+ throw new Error('SideMenuRootNode must have a SideMenuCenter child');
20
+ }
21
+ }
22
+
23
+ applyOptions(_options: Options) {
24
+ super.applyOptions(_options);
25
+
26
+ this._updateVisibility(_options);
27
+ }
28
+
29
+ mergeOptions(options: Options) {
30
+ super.mergeOptions(options);
31
+
32
+ this._updateVisibility(options);
33
+ }
34
+
35
+ /**
36
+ * @override
37
+ */
38
+ getVisibleLayout(): ComponentNode {
39
+ return this.visibleChild.getVisibleLayout();
40
+ }
41
+
42
+ _updateVisibility(options: Options) {
43
+ if (options.sideMenu) {
44
+ if (options.sideMenu.left?.visible) {
45
+ this.visibleChild = this._getLeftChild();
46
+ layoutActions.openSideMenu(this.visibleChild);
47
+ } else if (options.sideMenu.right?.visible) {
48
+ this.visibleChild = this._getRightChild();
49
+ layoutActions.openSideMenu(this.visibleChild);
50
+ } else {
51
+ this.visibleChild = this._getCenterChild();
52
+ layoutActions.closeSideMenu(this.visibleChild);
53
+ }
54
+ }
55
+ }
56
+
57
+ _getCenterChild = () => this.children.find(isCenterChild) as ParentNode;
58
+ _getLeftChild = () => this.children.find(isLeftChild) as ParentNode;
59
+ _getRightChild = () => this.children.find(isRightChild) as ParentNode;
60
+ }
61
+
62
+ export class SideMenuNode extends ParentNode {
63
+ constructor(layout: any, type: NodeType, parentNode?: ParentNode) {
64
+ super(layout, type, parentNode);
65
+ }
66
+
67
+ getVisibleLayout() {
68
+ return this.children[0].getVisibleLayout();
69
+ }
70
+ }
71
+
72
+ export class SideMenuLeftNode extends SideMenuNode {
73
+ constructor(layout: any, parentNode?: ParentNode) {
74
+ super(layout, 'SideMenuLeft', parentNode);
75
+ }
76
+ }
77
+ export class SideMenuRightNode extends SideMenuNode {
78
+ constructor(layout: any, parentNode?: ParentNode) {
79
+ super(layout, 'SideMenuRight', parentNode);
80
+ }
81
+ }
82
+
83
+ export class SideMenuCenterNode extends SideMenuNode {
84
+ constructor(layout: any, parentNode?: ParentNode) {
85
+ super(layout, 'SideMenuCenter', parentNode);
86
+ }
87
+ }
@@ -2,8 +2,9 @@ import _ from 'lodash';
2
2
  import BottomTabsNode from '../Layouts/BottomTabsNode';
3
3
  import ParentNode from '../Layouts/ParentNode';
4
4
  import LayoutNodeFactory from '../Layouts/LayoutNodeFactory';
5
- import { Options } from '../../src/interfaces/Options';
5
+ import { SideMenuNode } from '../Layouts/SideMenu';
6
6
  import StackNode from '../Layouts/StackNode';
7
+ import { Options } from '../../src/interfaces/Options';
7
8
 
8
9
  const remx = require('remx');
9
10
 
@@ -11,6 +12,7 @@ const state = remx.state({
11
12
  root: {},
12
13
  modals: [],
13
14
  overlays: [],
15
+ sideMenu: undefined,
14
16
  });
15
17
 
16
18
  const setters = remx.setters({
@@ -75,6 +77,23 @@ const setters = remx.setters({
75
77
  selectTabIndex(layout: BottomTabsNode, index: number) {
76
78
  getters.getLayoutById(layout.nodeId).selectedIndex = index;
77
79
  },
80
+ openSideMenu(layout: SideMenuNode) {
81
+ if (state.sideMenu) {
82
+ throw new Error(
83
+ 'A side-menu is already open; Mocked-testing of multiple side-menu scenarios is not supported yet.' +
84
+ ' You can submit a request in https://github.com/wix/react-native-navigation/issues/new/choose.'
85
+ );
86
+ }
87
+ state.sideMenu = layout;
88
+ },
89
+ closeSideMenu(_layout: SideMenuNode) {
90
+ state.sideMenu = undefined;
91
+ },
92
+ applyOptions(componentId: string, options: Options) {
93
+ const layout = getters.getLayoutById(componentId);
94
+ if (layout) layout.applyOptions(options);
95
+ else console.warn(`[RNN error] Merge options failure: cannot find layout for: ${componentId}`);
96
+ },
78
97
  mergeOptions(componentId: string, options: Options) {
79
98
  const layout = getters.getLayoutById(componentId);
80
99
  if (layout) layout.mergeOptions(options);
@@ -87,12 +106,26 @@ const getters = remx.getters({
87
106
  return state.root;
88
107
  },
89
108
  getVisibleLayout() {
109
+ let layout: ParentNode | undefined;
90
110
  if (state.modals.length > 0) {
91
- return _.last<ParentNode>(state.modals)!.getVisibleLayout();
92
- } else if (!_.isEqual(state.root, {})) return state.root.getVisibleLayout();
111
+ layout = _.last<ParentNode>(state.modals)!;
112
+ } else if (!_.isEqual(state.root, {})) {
113
+ layout = state.root;
114
+ }
115
+
116
+ // Note: While this logic should be fair for all use cases (i.e. even multiple side-menus across tabs),
117
+ // there is no current test case that justifies it. Nevertheless, it's required to pass the tests,
118
+ // because otherwise getVisibleLayout() would not be revisited whenever side-menus are opened/closed.
119
+ if (layout && state.sideMenu && findNode(state.sideMenu.nodeId, layout!)) {
120
+ layout = state.sideMenu.parentNode;
121
+ }
122
+
123
+ return layout?.getVisibleLayout();
93
124
  },
94
125
  isVisibleLayout(layout: ParentNode) {
95
- return getters.getVisibleLayout() && getters.getVisibleLayout().nodeId === layout.nodeId;
126
+ const nodeId = layout.nodeId;
127
+ const visibleLayout = getters.getVisibleLayout();
128
+ return visibleLayout?.nodeId === nodeId;
96
129
  },
97
130
  getModals() {
98
131
  return state.modals;
@@ -101,13 +134,12 @@ const getters = remx.getters({
101
134
  return state.overlays;
102
135
  },
103
136
  getLayoutById(layoutId: string) {
104
- if (getters.getModalById(layoutId))
105
- return findParentNode(layoutId, getters.getModalById(layoutId));
137
+ if (getters.getModalById(layoutId)) return findNode(layoutId, getters.getModalById(layoutId));
106
138
 
107
- return findParentNode(layoutId, state.root);
139
+ return findNode(layoutId, state.root);
108
140
  },
109
141
  getModalById(layoutId: string) {
110
- return _.find(state.modals, (layout) => findParentNode(layoutId, layout));
142
+ return _.find(state.modals, (layout) => findNode(layoutId, layout));
111
143
  },
112
144
  getLayoutChildren(layoutId: string) {
113
145
  return getters.getLayoutById(layoutId).children;
@@ -120,13 +152,13 @@ const getters = remx.getters({
120
152
  },
121
153
  });
122
154
 
123
- function findParentNode(layoutId: string, layout: ParentNode): any | ParentNode {
155
+ function findNode(layoutId: string, layout: ParentNode): any | ParentNode {
124
156
  if (layoutId === layout.nodeId) {
125
157
  return layout;
126
158
  } else if (layout.children) {
127
159
  for (let i = 0; i < layout.children.length; i += 1) {
128
160
  const child = layout.children[i];
129
- const result = findParentNode(layoutId, child);
161
+ const result = findNode(layoutId, child);
130
162
 
131
163
  if (result !== false) {
132
164
  return result;
@@ -1,4 +1,5 @@
1
1
  import ParentNode from '../Layouts/ParentNode';
2
+ import { SideMenuNode } from '../Layouts/SideMenu';
2
3
  import { LayoutStore } from '../Stores/LayoutStore';
3
4
 
4
5
  export const switchTabByIndex = (bottomTabs: ParentNode | undefined, index: number) => {
@@ -8,3 +9,13 @@ export const switchTabByIndex = (bottomTabs: ParentNode | undefined, index: numb
8
9
  LayoutStore.getVisibleLayout().componentDidAppear();
9
10
  }
10
11
  };
12
+
13
+ export const openSideMenu = (sideMenu: SideMenuNode) => {
14
+ LayoutStore.openSideMenu(sideMenu);
15
+ LayoutStore.getVisibleLayout().componentDidAppear();
16
+ };
17
+
18
+ export const closeSideMenu = (layout: SideMenuNode) => {
19
+ LayoutStore.getVisibleLayout().componentDidDisappear();
20
+ LayoutStore.closeSideMenu(layout);
21
+ };
@@ -39,6 +39,7 @@ export class NativeCommandsSender {
39
39
  const layoutNode = LayoutNodeFactory.create(layout, stack);
40
40
  stack.getVisibleLayout().componentDidDisappear();
41
41
  LayoutStore.push(layoutNode, stack);
42
+ LayoutStore.applyOptions(layoutNode.nodeId, layoutNode.data.options);
42
43
  stack.getVisibleLayout().componentDidAppear();
43
44
  resolve(stack.getVisibleLayout().nodeId);
44
45
  this.reportCommandCompletion(CommandName.Push, commandId);
@@ -1,5 +1,9 @@
1
1
  package com.reactnativenavigation.viewcontrollers.bottomtabs;
2
2
 
3
+ import static com.reactnativenavigation.utils.CollectionUtils.forEach;
4
+ import static com.reactnativenavigation.utils.CollectionUtils.map;
5
+ import static com.reactnativenavigation.utils.ObjectUtils.perform;
6
+
3
7
  import android.animation.Animator;
4
8
  import android.app.Activity;
5
9
  import android.content.res.Configuration;
@@ -9,6 +13,8 @@ import android.view.ViewGroup;
9
13
  import androidx.annotation.NonNull;
10
14
  import androidx.annotation.RestrictTo;
11
15
  import androidx.coordinatorlayout.widget.CoordinatorLayout;
16
+ import androidx.core.graphics.Insets;
17
+ import androidx.core.view.WindowInsetsCompat;
12
18
 
13
19
  import com.aurelhubert.ahbottomnavigation.AHBottomNavigation;
14
20
  import com.aurelhubert.ahbottomnavigation.AHBottomNavigationItem;
@@ -34,10 +40,6 @@ import java.util.Deque;
34
40
  import java.util.LinkedList;
35
41
  import java.util.List;
36
42
 
37
- import static com.reactnativenavigation.utils.CollectionUtils.forEach;
38
- import static com.reactnativenavigation.utils.CollectionUtils.map;
39
- import static com.reactnativenavigation.utils.ObjectUtils.perform;
40
-
41
43
  public class BottomTabsController extends ParentController<BottomTabsLayout> implements AHBottomNavigation.OnTabSelectedListener, TabSelector {
42
44
 
43
45
  private BottomTabsContainer bottomTabsContainer;
@@ -84,6 +86,7 @@ public class BottomTabsController extends ParentController<BottomTabsLayout> imp
84
86
  @Override
85
87
  public BottomTabsLayout createView() {
86
88
  BottomTabsLayout root = new BottomTabsLayout(getActivity());
89
+
87
90
  this.bottomTabsContainer = createBottomTabsContainer();
88
91
  this.bottomTabs = bottomTabsContainer.getBottomTabs();
89
92
  Options resolveCurrentOptions = resolveCurrentOptions();
@@ -95,6 +98,7 @@ public class BottomTabsController extends ParentController<BottomTabsLayout> imp
95
98
  bottomTabs.addItems(createTabs());
96
99
  setInitialTab(resolveCurrentOptions);
97
100
  tabsAttacher.attach();
101
+
98
102
  return root;
99
103
  }
100
104
 
@@ -299,6 +303,14 @@ public class BottomTabsController extends ParentController<BottomTabsLayout> imp
299
303
  return presenter.getPopAnimation(appearingOptions, disappearingOptions);
300
304
  }
301
305
 
306
+ @Override
307
+ protected WindowInsetsCompat onApplyWindowInsets(View view, WindowInsetsCompat insets) {
308
+ Insets sysInsets = insets.getInsets(WindowInsetsCompat.Type.systemBars());
309
+ view.setPaddingRelative(0, 0, 0, sysInsets.bottom);
310
+ return WindowInsetsCompat.CONSUMED;
311
+ }
312
+
313
+
302
314
  @RestrictTo(RestrictTo.Scope.TESTS)
303
315
  public BottomTabs getBottomTabs() {
304
316
  return bottomTabs;
@@ -23,7 +23,8 @@ exports.ComponentScreen = (0, connect_1.connect)(class extends react_1.Component
23
23
  this.props.layoutNode.componentDidMount();
24
24
  }
25
25
  isVisible() {
26
- return LayoutStore_1.LayoutStore.isVisibleLayout(this.props.layoutNode);
26
+ const isVisible = LayoutStore_1.LayoutStore.isVisibleLayout(this.props.layoutNode);
27
+ return isVisible;
27
28
  }
28
29
  renderTabBar() {
29
30
  const bottomTabs = this.props.layoutNode.getBottomTabs();
@@ -7,6 +7,7 @@ const react_native_1 = require("react-native");
7
7
  const BottomTabs_1 = require("./BottomTabs");
8
8
  const ComponentScreen_1 = require("./ComponentScreen");
9
9
  const Stack_1 = require("./Stack");
10
+ const SideMenu_1 = require("./SideMenu");
10
11
  const LayoutComponent = class extends react_1.Component {
11
12
  render() {
12
13
  switch (this.props.layoutNode.type) {
@@ -16,6 +17,14 @@ const LayoutComponent = class extends react_1.Component {
16
17
  return react_1.default.createElement(Stack_1.Stack, { layoutNode: this.props.layoutNode });
17
18
  case 'Component':
18
19
  return react_1.default.createElement(ComponentScreen_1.ComponentScreen, { layoutNode: this.props.layoutNode });
20
+ case 'SideMenuRoot':
21
+ return react_1.default.createElement(SideMenu_1.SideMenuRoot, { layoutNode: this.props.layoutNode });
22
+ case 'SideMenuLeft':
23
+ return react_1.default.createElement(SideMenu_1.SideMenuLeft, { layoutNode: this.props.layoutNode });
24
+ case 'SideMenuCenter':
25
+ return react_1.default.createElement(SideMenu_1.SideMenuCenter, { layoutNode: this.props.layoutNode });
26
+ case 'SideMenuRight':
27
+ return react_1.default.createElement(SideMenu_1.SideMenuRight, { layoutNode: this.props.layoutNode });
19
28
  }
20
29
  return react_1.default.createElement(react_native_1.View, null);
21
30
  }
@@ -0,0 +1,58 @@
1
+ import React, { Component } from 'react';
2
+ import { ComponentProps } from '../ComponentProps';
3
+ export declare const SideMenuRoot: {
4
+ new (props: ComponentProps): {
5
+ render(): React.JSX.Element[];
6
+ context: unknown;
7
+ setState<K extends never>(state: {} | ((prevState: Readonly<{}>, props: Readonly<ComponentProps>) => {} | Pick<{}, K> | null) | Pick<{}, K> | null, callback?: (() => void) | undefined): void;
8
+ forceUpdate(callback?: (() => void) | undefined): void;
9
+ readonly props: Readonly<ComponentProps>;
10
+ state: Readonly<{}>;
11
+ refs: {
12
+ [key: string]: React.ReactInstance;
13
+ };
14
+ componentDidMount?(): void;
15
+ shouldComponentUpdate?(nextProps: Readonly<ComponentProps>, nextState: Readonly<{}>, nextContext: any): boolean;
16
+ componentWillUnmount?(): void;
17
+ componentDidCatch?(error: Error, errorInfo: React.ErrorInfo): void;
18
+ getSnapshotBeforeUpdate?(prevProps: Readonly<ComponentProps>, prevState: Readonly<{}>): any;
19
+ componentDidUpdate?(prevProps: Readonly<ComponentProps>, prevState: Readonly<{}>, snapshot?: any): void;
20
+ componentWillMount?(): void;
21
+ UNSAFE_componentWillMount?(): void;
22
+ componentWillReceiveProps?(nextProps: Readonly<ComponentProps>, nextContext: any): void;
23
+ UNSAFE_componentWillReceiveProps?(nextProps: Readonly<ComponentProps>, nextContext: any): void;
24
+ componentWillUpdate?(nextProps: Readonly<ComponentProps>, nextState: Readonly<{}>, nextContext: any): void;
25
+ UNSAFE_componentWillUpdate?(nextProps: Readonly<ComponentProps>, nextState: Readonly<{}>, nextContext: any): void;
26
+ };
27
+ new (props: ComponentProps, context: any): {
28
+ render(): React.JSX.Element[];
29
+ context: unknown;
30
+ setState<K extends never>(state: {} | ((prevState: Readonly<{}>, props: Readonly<ComponentProps>) => {} | Pick<{}, K> | null) | Pick<{}, K> | null, callback?: (() => void) | undefined): void;
31
+ forceUpdate(callback?: (() => void) | undefined): void;
32
+ readonly props: Readonly<ComponentProps>;
33
+ state: Readonly<{}>;
34
+ refs: {
35
+ [key: string]: React.ReactInstance;
36
+ };
37
+ componentDidMount?(): void;
38
+ shouldComponentUpdate?(nextProps: Readonly<ComponentProps>, nextState: Readonly<{}>, nextContext: any): boolean;
39
+ componentWillUnmount?(): void;
40
+ componentDidCatch?(error: Error, errorInfo: React.ErrorInfo): void;
41
+ getSnapshotBeforeUpdate?(prevProps: Readonly<ComponentProps>, prevState: Readonly<{}>): any;
42
+ componentDidUpdate?(prevProps: Readonly<ComponentProps>, prevState: Readonly<{}>, snapshot?: any): void;
43
+ componentWillMount?(): void;
44
+ UNSAFE_componentWillMount?(): void;
45
+ componentWillReceiveProps?(nextProps: Readonly<ComponentProps>, nextContext: any): void;
46
+ UNSAFE_componentWillReceiveProps?(nextProps: Readonly<ComponentProps>, nextContext: any): void;
47
+ componentWillUpdate?(nextProps: Readonly<ComponentProps>, nextState: Readonly<{}>, nextContext: any): void;
48
+ UNSAFE_componentWillUpdate?(nextProps: Readonly<ComponentProps>, nextState: Readonly<{}>, nextContext: any): void;
49
+ };
50
+ contextType?: React.Context<any> | undefined;
51
+ };
52
+ declare class SideMenuComponent extends Component<ComponentProps> {
53
+ render(): React.JSX.Element;
54
+ }
55
+ export declare const SideMenuLeft: typeof SideMenuComponent;
56
+ export declare const SideMenuCenter: typeof SideMenuComponent;
57
+ export declare const SideMenuRight: typeof SideMenuComponent;
58
+ export {};
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SideMenuRight = exports.SideMenuCenter = exports.SideMenuLeft = exports.SideMenuRoot = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const react_1 = tslib_1.__importStar(require("react"));
6
+ const connect_1 = require("../connect");
7
+ const LayoutComponent_1 = require("./LayoutComponent");
8
+ exports.SideMenuRoot = (0, connect_1.connect)(class extends react_1.Component {
9
+ render() {
10
+ const children = this.props.layoutNode.children;
11
+ return children.map((child) => {
12
+ return react_1.default.createElement(LayoutComponent_1.LayoutComponent, { key: child.nodeId, layoutNode: child });
13
+ });
14
+ }
15
+ });
16
+ class SideMenuComponent extends react_1.Component {
17
+ render() {
18
+ const children = this.props.layoutNode.children;
19
+ const component = children[0];
20
+ return react_1.default.createElement(LayoutComponent_1.LayoutComponent, { key: component.nodeId, layoutNode: component });
21
+ }
22
+ }
23
+ exports.SideMenuLeft = (0, connect_1.connect)(SideMenuComponent);
24
+ exports.SideMenuCenter = (0, connect_1.connect)(SideMenuComponent);
25
+ exports.SideMenuRight = (0, connect_1.connect)(SideMenuComponent);
@@ -3,6 +3,6 @@ import ParentNode from './ParentNode';
3
3
  export default class BottomTabsNode extends ParentNode {
4
4
  selectedIndex: number;
5
5
  constructor(layout: any, parentNode?: ParentNode);
6
- mergeOptions(options: Options): void;
6
+ mergeOptions(_options: Options): void;
7
7
  getVisibleLayout(): import("./ComponentNode").default;
8
8
  }
@@ -10,8 +10,9 @@ class BottomTabsNode extends ParentNode_1.default {
10
10
  super(layout, 'BottomTabs', parentNode);
11
11
  this.selectedIndex = layout.data?.options?.bottomTabs?.currentTabIndex || 0;
12
12
  }
13
- mergeOptions(options) {
14
- super.mergeOptions(options);
13
+ mergeOptions(_options) {
14
+ super.mergeOptions(_options);
15
+ const { options } = this.data;
15
16
  if (options.bottomTabs?.currentTabIndex) {
16
17
  this.selectedIndex = options.bottomTabs?.currentTabIndex;
17
18
  (0, layoutActions_1.switchTabByIndex)(this, this.selectedIndex);
@@ -2,6 +2,7 @@ import BottomTabs from './BottomTabsNode';
2
2
  import ComponentNode from './ComponentNode';
3
3
  import Stack from './StackNode';
4
4
  import ParentNode from './ParentNode';
5
+ import SideMenuRootNode, { SideMenuLeftNode, SideMenuRightNode, SideMenuCenterNode } from './SideMenu';
5
6
  export default class LayoutNodeFactory {
6
- static create(layout: any, parentNode?: ParentNode): Stack | BottomTabs | ComponentNode;
7
+ static create(layout: any, parentNode?: ParentNode): ComponentNode | SideMenuRootNode | SideMenuLeftNode | SideMenuRightNode | SideMenuCenterNode | Stack | BottomTabs;
7
8
  }
@@ -4,6 +4,7 @@ const tslib_1 = require("tslib");
4
4
  const BottomTabsNode_1 = tslib_1.__importDefault(require("./BottomTabsNode"));
5
5
  const ComponentNode_1 = tslib_1.__importDefault(require("./ComponentNode"));
6
6
  const StackNode_1 = tslib_1.__importDefault(require("./StackNode"));
7
+ const SideMenu_1 = tslib_1.__importStar(require("./SideMenu"));
7
8
  class LayoutNodeFactory {
8
9
  static create(layout, parentNode) {
9
10
  switch (layout.type) {
@@ -11,7 +12,15 @@ class LayoutNodeFactory {
11
12
  return new ComponentNode_1.default(layout, parentNode);
12
13
  case 'Stack':
13
14
  return new StackNode_1.default(layout, parentNode);
14
- default:
15
+ case 'SideMenuRoot':
16
+ return new SideMenu_1.default(layout, parentNode);
17
+ case 'SideMenuLeft':
18
+ return new SideMenu_1.SideMenuLeftNode(layout, parentNode);
19
+ case 'SideMenuCenter':
20
+ return new SideMenu_1.SideMenuCenterNode(layout, parentNode);
21
+ case 'SideMenuRight':
22
+ return new SideMenu_1.SideMenuRightNode(layout, parentNode);
23
+ default: // TODO Undo
15
24
  case 'BottomTabs':
16
25
  return new BottomTabsNode_1.default(layout, parentNode);
17
26
  }
@@ -10,6 +10,7 @@ export default class ParentNode extends Node {
10
10
  componentDidDisappear(): void;
11
11
  getVisibleLayout(): ComponentNode;
12
12
  getTopParent(): Node;
13
+ applyOptions(_options: Options): void;
13
14
  mergeOptions(options: Options): void;
14
15
  buttonsChanged(_oldButtons: OptionsTopBarButton[], _newButtons: OptionsTopBarButton[]): void;
15
16
  titleChanged(_oldComponent: any, _newComponent: any): void;
@@ -26,6 +26,9 @@ class ParentNode extends Node_1.default {
26
26
  return this.parentNode.getTopParent();
27
27
  return this;
28
28
  }
29
+ applyOptions(_options) {
30
+ this.parentNode?.applyOptions(_options);
31
+ }
29
32
  mergeOptions(options) {
30
33
  this.data.options = lodash_1.default.mergeWith(this.data.options, options, (objValue, srcValue, key) => {
31
34
  if (lodash_1.default.isArray(objValue)) {
@@ -0,0 +1,31 @@
1
+ import ParentNode from './ParentNode';
2
+ import ComponentNode from './ComponentNode';
3
+ import { Options } from '../../src/index';
4
+ import { NodeType } from './Node';
5
+ export default class SideMenuRootNode extends ParentNode {
6
+ visibleChild: ParentNode;
7
+ constructor(layout: any, parentNode?: ParentNode);
8
+ applyOptions(_options: Options): void;
9
+ mergeOptions(options: Options): void;
10
+ /**
11
+ * @override
12
+ */
13
+ getVisibleLayout(): ComponentNode;
14
+ _updateVisibility(options: Options): void;
15
+ _getCenterChild: () => ParentNode;
16
+ _getLeftChild: () => ParentNode;
17
+ _getRightChild: () => ParentNode;
18
+ }
19
+ export declare class SideMenuNode extends ParentNode {
20
+ constructor(layout: any, type: NodeType, parentNode?: ParentNode);
21
+ getVisibleLayout(): ComponentNode;
22
+ }
23
+ export declare class SideMenuLeftNode extends SideMenuNode {
24
+ constructor(layout: any, parentNode?: ParentNode);
25
+ }
26
+ export declare class SideMenuRightNode extends SideMenuNode {
27
+ constructor(layout: any, parentNode?: ParentNode);
28
+ }
29
+ export declare class SideMenuCenterNode extends SideMenuNode {
30
+ constructor(layout: any, parentNode?: ParentNode);
31
+ }
@@ -0,0 +1,80 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SideMenuCenterNode = exports.SideMenuRightNode = exports.SideMenuLeftNode = exports.SideMenuNode = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const ParentNode_1 = tslib_1.__importDefault(require("./ParentNode"));
6
+ const layoutActions = tslib_1.__importStar(require("../actions/layoutActions"));
7
+ const isCenterChild = (child) => child.type === 'SideMenuCenter';
8
+ const isLeftChild = (child) => child.type === 'SideMenuLeft';
9
+ const isRightChild = (child) => child.type === 'SideMenuRight';
10
+ class SideMenuRootNode extends ParentNode_1.default {
11
+ visibleChild;
12
+ constructor(layout, parentNode) {
13
+ super(layout, 'SideMenuRoot', parentNode);
14
+ this.visibleChild = this._getCenterChild();
15
+ if (!this.visibleChild) {
16
+ throw new Error('SideMenuRootNode must have a SideMenuCenter child');
17
+ }
18
+ }
19
+ applyOptions(_options) {
20
+ super.applyOptions(_options);
21
+ this._updateVisibility(_options);
22
+ }
23
+ mergeOptions(options) {
24
+ super.mergeOptions(options);
25
+ this._updateVisibility(options);
26
+ }
27
+ /**
28
+ * @override
29
+ */
30
+ getVisibleLayout() {
31
+ return this.visibleChild.getVisibleLayout();
32
+ }
33
+ _updateVisibility(options) {
34
+ if (options.sideMenu) {
35
+ if (options.sideMenu.left?.visible) {
36
+ this.visibleChild = this._getLeftChild();
37
+ layoutActions.openSideMenu(this.visibleChild);
38
+ }
39
+ else if (options.sideMenu.right?.visible) {
40
+ this.visibleChild = this._getRightChild();
41
+ layoutActions.openSideMenu(this.visibleChild);
42
+ }
43
+ else {
44
+ this.visibleChild = this._getCenterChild();
45
+ layoutActions.closeSideMenu(this.visibleChild);
46
+ }
47
+ }
48
+ }
49
+ _getCenterChild = () => this.children.find(isCenterChild);
50
+ _getLeftChild = () => this.children.find(isLeftChild);
51
+ _getRightChild = () => this.children.find(isRightChild);
52
+ }
53
+ exports.default = SideMenuRootNode;
54
+ class SideMenuNode extends ParentNode_1.default {
55
+ constructor(layout, type, parentNode) {
56
+ super(layout, type, parentNode);
57
+ }
58
+ getVisibleLayout() {
59
+ return this.children[0].getVisibleLayout();
60
+ }
61
+ }
62
+ exports.SideMenuNode = SideMenuNode;
63
+ class SideMenuLeftNode extends SideMenuNode {
64
+ constructor(layout, parentNode) {
65
+ super(layout, 'SideMenuLeft', parentNode);
66
+ }
67
+ }
68
+ exports.SideMenuLeftNode = SideMenuLeftNode;
69
+ class SideMenuRightNode extends SideMenuNode {
70
+ constructor(layout, parentNode) {
71
+ super(layout, 'SideMenuRight', parentNode);
72
+ }
73
+ }
74
+ exports.SideMenuRightNode = SideMenuRightNode;
75
+ class SideMenuCenterNode extends SideMenuNode {
76
+ constructor(layout, parentNode) {
77
+ super(layout, 'SideMenuCenter', parentNode);
78
+ }
79
+ }
80
+ exports.SideMenuCenterNode = SideMenuCenterNode;
@@ -9,6 +9,7 @@ const state = remx.state({
9
9
  root: {},
10
10
  modals: [],
11
11
  overlays: [],
12
+ sideMenu: undefined,
12
13
  });
13
14
  const setters = remx.setters({
14
15
  setRoot(layout) {
@@ -73,6 +74,23 @@ const setters = remx.setters({
73
74
  selectTabIndex(layout, index) {
74
75
  getters.getLayoutById(layout.nodeId).selectedIndex = index;
75
76
  },
77
+ openSideMenu(layout) {
78
+ if (state.sideMenu) {
79
+ throw new Error('A side-menu is already open; Mocked-testing of multiple side-menu scenarios is not supported yet.' +
80
+ ' You can submit a request in https://github.com/wix/react-native-navigation/issues/new/choose.');
81
+ }
82
+ state.sideMenu = layout;
83
+ },
84
+ closeSideMenu(_layout) {
85
+ state.sideMenu = undefined;
86
+ },
87
+ applyOptions(componentId, options) {
88
+ const layout = getters.getLayoutById(componentId);
89
+ if (layout)
90
+ layout.applyOptions(options);
91
+ else
92
+ console.warn(`[RNN error] Merge options failure: cannot find layout for: ${componentId}`);
93
+ },
76
94
  mergeOptions(componentId, options) {
77
95
  const layout = getters.getLayoutById(componentId);
78
96
  if (layout)
@@ -86,14 +104,25 @@ const getters = remx.getters({
86
104
  return state.root;
87
105
  },
88
106
  getVisibleLayout() {
107
+ let layout;
89
108
  if (state.modals.length > 0) {
90
- return lodash_1.default.last(state.modals).getVisibleLayout();
109
+ layout = lodash_1.default.last(state.modals);
110
+ }
111
+ else if (!lodash_1.default.isEqual(state.root, {})) {
112
+ layout = state.root;
113
+ }
114
+ // Note: While this logic should be fair for all use cases (i.e. even multiple side-menus across tabs),
115
+ // there is no current test case that justifies it. Nevertheless, it's required to pass the tests,
116
+ // because otherwise getVisibleLayout() would not be revisited whenever side-menus are opened/closed.
117
+ if (layout && state.sideMenu && findNode(state.sideMenu.nodeId, layout)) {
118
+ layout = state.sideMenu.parentNode;
91
119
  }
92
- else if (!lodash_1.default.isEqual(state.root, {}))
93
- return state.root.getVisibleLayout();
120
+ return layout?.getVisibleLayout();
94
121
  },
95
122
  isVisibleLayout(layout) {
96
- return getters.getVisibleLayout() && getters.getVisibleLayout().nodeId === layout.nodeId;
123
+ const nodeId = layout.nodeId;
124
+ const visibleLayout = getters.getVisibleLayout();
125
+ return visibleLayout?.nodeId === nodeId;
97
126
  },
98
127
  getModals() {
99
128
  return state.modals;
@@ -103,11 +132,11 @@ const getters = remx.getters({
103
132
  },
104
133
  getLayoutById(layoutId) {
105
134
  if (getters.getModalById(layoutId))
106
- return findParentNode(layoutId, getters.getModalById(layoutId));
107
- return findParentNode(layoutId, state.root);
135
+ return findNode(layoutId, getters.getModalById(layoutId));
136
+ return findNode(layoutId, state.root);
108
137
  },
109
138
  getModalById(layoutId) {
110
- return lodash_1.default.find(state.modals, (layout) => findParentNode(layoutId, layout));
139
+ return lodash_1.default.find(state.modals, (layout) => findNode(layoutId, layout));
111
140
  },
112
141
  getLayoutChildren(layoutId) {
113
142
  return getters.getLayoutById(layoutId).children;
@@ -117,14 +146,14 @@ const getters = remx.getters({
117
146
  lodash_1.default.find(state.modals, (layout) => findStack(layoutId, layout)));
118
147
  },
119
148
  });
120
- function findParentNode(layoutId, layout) {
149
+ function findNode(layoutId, layout) {
121
150
  if (layoutId === layout.nodeId) {
122
151
  return layout;
123
152
  }
124
153
  else if (layout.children) {
125
154
  for (let i = 0; i < layout.children.length; i += 1) {
126
155
  const child = layout.children[i];
127
- const result = findParentNode(layoutId, child);
156
+ const result = findNode(layoutId, child);
128
157
  if (result !== false) {
129
158
  return result;
130
159
  }
@@ -1,2 +1,5 @@
1
1
  import ParentNode from '../Layouts/ParentNode';
2
+ import { SideMenuNode } from '../Layouts/SideMenu';
2
3
  export declare const switchTabByIndex: (bottomTabs: ParentNode | undefined, index: number) => void;
4
+ export declare const openSideMenu: (sideMenu: SideMenuNode) => void;
5
+ export declare const closeSideMenu: (layout: SideMenuNode) => void;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.switchTabByIndex = void 0;
3
+ exports.closeSideMenu = exports.openSideMenu = exports.switchTabByIndex = void 0;
4
4
  const LayoutStore_1 = require("../Stores/LayoutStore");
5
5
  const switchTabByIndex = (bottomTabs, index) => {
6
6
  if (bottomTabs) {
@@ -10,3 +10,13 @@ const switchTabByIndex = (bottomTabs, index) => {
10
10
  }
11
11
  };
12
12
  exports.switchTabByIndex = switchTabByIndex;
13
+ const openSideMenu = (sideMenu) => {
14
+ LayoutStore_1.LayoutStore.openSideMenu(sideMenu);
15
+ LayoutStore_1.LayoutStore.getVisibleLayout().componentDidAppear();
16
+ };
17
+ exports.openSideMenu = openSideMenu;
18
+ const closeSideMenu = (layout) => {
19
+ LayoutStore_1.LayoutStore.getVisibleLayout().componentDidDisappear();
20
+ LayoutStore_1.LayoutStore.closeSideMenu(layout);
21
+ };
22
+ exports.closeSideMenu = closeSideMenu;
@@ -34,6 +34,7 @@ class NativeCommandsSender {
34
34
  const layoutNode = LayoutNodeFactory_1.default.create(layout, stack);
35
35
  stack.getVisibleLayout().componentDidDisappear();
36
36
  LayoutStore_1.LayoutStore.push(layoutNode, stack);
37
+ LayoutStore_1.LayoutStore.applyOptions(layoutNode.nodeId, layoutNode.data.options);
37
38
  stack.getVisibleLayout().componentDidAppear();
38
39
  resolve(stack.getVisibleLayout().nodeId);
39
40
  this.reportCommandCompletion(CommandName_1.CommandName.Push, commandId);
@@ -45,6 +45,7 @@
45
45
 
46
46
  - (void)reset {
47
47
  [super reset];
48
+ _fromTextContainer.size = _fromSize;
48
49
  }
49
50
 
50
51
  - (NSTextContainer *)container:(NSTextStorage *)fromTextStorage {
@@ -300,6 +300,7 @@ static NSString *const setDefaultOptions = @"setDefaultOptions";
300
300
  completion:^{
301
301
  [self->_eventEmitter sendOnNavigationCommandCompletion:pop
302
302
  commandId:commandId];
303
+ NSLog(@"Pop commandshandler completed");
303
304
  completion();
304
305
  }
305
306
  rejection:rejection];
@@ -4,6 +4,7 @@
4
4
 
5
5
  #ifdef RCT_NEW_ARCH_ENABLED
6
6
  #import <React/RCTSurfaceDelegate.h>
7
+ #import <React/RCTSurface.h>
7
8
  #endif
8
9
 
9
10
  @interface RNNCustomTitleView : UIView <
@@ -55,8 +55,15 @@
55
55
 
56
56
  #ifdef RCT_NEW_ARCH_ENABLED
57
57
  - (void)surface:(RCTSurface *)surface didChangeIntrinsicSize:(CGSize)intrinsicSize {
58
- // TODO: FILL WITH DATA
58
+ if ([self.alignment isEqualToString:@"center"]) {
59
+ [self setFrame:CGRectMake(self.frame.origin.x, self.frame.origin.y,
60
+ self.subView.intrinsicContentSize.width,
61
+ self.subView.intrinsicContentSize.height)];
62
+ [self.subView setFrame:CGRectMake(0, 0, surface.intrinsicSize.width,
63
+ surface.intrinsicSize.height)];
64
+ }
59
65
  }
66
+
60
67
  #else
61
68
  - (void)rootViewDidChangeIntrinsicSize:(RCTRootView *)rootView {
62
69
  if ([self.alignment isEqualToString:@"center"]) {
@@ -154,6 +154,9 @@ static NSString *const BottomTabPressed = @"RNN.BottomTabPressed";
154
154
  #pragma mark private
155
155
 
156
156
  - (void)send:(NSString *)eventName body:(id)body {
157
+ if (self.bridge == nil) {
158
+ return;
159
+ }
157
160
  [self sendEventWithName:eventName body:body];
158
161
  }
159
162
 
@@ -5,7 +5,7 @@
5
5
  - (instancetype)initWithHost:(RCTHost *)host
6
6
  moduleName:(NSString *)moduleName
7
7
  initialProperties:(NSDictionary *)initialProperties
8
- eventEmitter:(RNNEventEmitter *)eventEmitter
8
+ eventEmitter:(RNNTurboEventEmitter *)eventEmitter
9
9
  sizeMeasureMode:(RCTSurfaceSizeMeasureMode)sizeMeasureMode
10
10
  reactViewReadyBlock:(RNNReactViewReadyCompletionBlock)reactViewReadyBlock {
11
11
  self = [super initWithHost:host moduleName:moduleName initialProperties:initialProperties eventEmitter:eventEmitter sizeMeasureMode:convertToSurfaceSizeMeasureMode(RCTRootViewSizeFlexibilityWidthAndHeight) reactViewReadyBlock:reactViewReadyBlock];
@@ -15,6 +15,8 @@
15
15
  #define ComponentTypeButton @"TopBarButton"
16
16
  #define ComponentTypeBackground @"TopBarBackground"
17
17
 
18
+ #import "RNNTurboEventEmitter.h"
19
+
18
20
  #ifdef RCT_NEW_ARCH_ENABLED
19
21
  static RCTSurfaceSizeMeasureMode convertToSurfaceSizeMeasureMode(RCTRootViewSizeFlexibility sizeFlexibility)
20
22
  {
@@ -92,7 +94,7 @@ typedef void (^RNNReactViewReadyCompletionBlock)(void);
92
94
  - (instancetype)initWithHost:(RCTHost *)host
93
95
  moduleName:(NSString *)moduleName
94
96
  initialProperties:(NSDictionary *)initialProperties
95
- eventEmitter:(RNNEventEmitter *)eventEmitter
97
+ eventEmitter:(RNNTurboEventEmitter *)eventEmitter
96
98
  sizeMeasureMode:(RCTSurfaceSizeMeasureMode)sizeMeasureMode
97
99
  reactViewReadyBlock:(RNNReactViewReadyCompletionBlock)reactViewReadyBlock;
98
100
 
@@ -11,6 +11,7 @@
11
11
 
12
12
  @implementation RNNReactView {
13
13
  BOOL _isMounted;
14
+ BOOL _pendingWillAppear;
14
15
  BOOL _pendingDidAppear;
15
16
  BOOL _didAppear;
16
17
  BOOL _willAppear;
@@ -56,17 +57,18 @@
56
57
  - (instancetype)initWithHost:(RCTHost *)host
57
58
  moduleName:(NSString *)moduleName
58
59
  initialProperties:(NSDictionary *)initialProperties
59
- eventEmitter:(RNNEventEmitter *)eventEmitter
60
+ eventEmitter:(RNNTurboEventEmitter *)eventEmitter
60
61
  sizeMeasureMode:(RCTSurfaceSizeMeasureMode)sizeMeasureMode
61
62
  reactViewReadyBlock:(RNNReactViewReadyCompletionBlock)reactViewReadyBlock {
63
+
62
64
  RCTFabricSurface *surface = [host createSurfaceWithModuleName:moduleName
63
65
  initialProperties:initialProperties];
64
- [host.surfacePresenter addObserver:self];
66
+ [host.surfacePresenter addObserver:self];
65
67
  self = [super initWithSurface:surface sizeMeasureMode:sizeMeasureMode];
66
-
68
+
67
69
  _reactViewReadyBlock = reactViewReadyBlock;
68
70
  _eventEmitter = eventEmitter;
69
-
71
+
70
72
  return self;
71
73
  }
72
74
  #endif
@@ -88,7 +90,7 @@
88
90
  }
89
91
  }
90
92
  #endif
91
-
93
+
92
94
  - (void)reactViewReady {
93
95
  if (_reactViewReadyBlock) {
94
96
  _reactViewReadyBlock();
@@ -99,12 +101,19 @@
99
101
  #endif
100
102
  }
101
103
 
104
+ #pragma mark - RNNComponentProtocol
102
105
  - (void)componentWillAppear {
106
+ if (!_isMounted) {
107
+ _pendingWillAppear = YES;
108
+ return;
109
+ }
110
+
111
+ _pendingWillAppear = NO;
112
+
103
113
  if (!_willAppear) {
104
114
  [_eventEmitter sendComponentWillAppear:self.componentId
105
115
  componentName:self.moduleName
106
116
  componentType:self.componentType];
107
-
108
117
  _willAppear = YES;
109
118
  }
110
119
  }
@@ -116,6 +125,7 @@
116
125
  }
117
126
 
118
127
  _pendingDidAppear = NO;
128
+
119
129
  if (!_didAppear) {
120
130
  [_eventEmitter sendComponentDidAppear:self.componentId
121
131
  componentName:self.moduleName
@@ -131,18 +141,43 @@
131
141
  _willAppear = NO;
132
142
  _didAppear = NO;
133
143
  }
144
+
145
+ - (NSString *)componentId {
146
+ return self.appProperties[@"componentId"];
147
+ }
134
148
 
149
+ - (NSString *)componentType {
150
+ @throw [NSException exceptionWithName:@"componentType not implemented"
151
+ reason:@"Should always subclass RNNReactView"
152
+ userInfo:nil];
153
+ }
154
+ #pragma mark -
155
+
156
+
135
157
  #ifdef RCT_NEW_ARCH_ENABLED
158
+
159
+ #pragma mark - RCTSurfacePresenterObserver
160
+ - (void)willMountComponentsWithRootTag:(NSInteger)rootTag {
161
+ if (self.surface.rootTag == rootTag) {
162
+ _isMounted = YES;
163
+
164
+ if (_pendingWillAppear) {
165
+ [self componentWillAppear];
166
+ }
167
+ }
168
+ }
136
169
 
137
170
  - (void)didMountComponentsWithRootTag:(NSInteger)rootTag {
138
171
  if (self.surface.rootTag == rootTag) {
139
172
  _isMounted = YES;
173
+
140
174
  if (_pendingDidAppear) {
141
175
  [self componentDidAppear];
142
176
  }
143
177
  }
144
178
  }
145
-
179
+ #pragma mark -
180
+
146
181
  - (NSDictionary *)appProperties {
147
182
  @synchronized(self) {
148
183
  return self.surface.properties;
@@ -175,7 +210,7 @@
175
210
  }
176
211
 
177
212
  - (UIView *)contentView {
178
- return self;
213
+ return self;
179
214
  }
180
215
 
181
216
  - (RCTRootViewSizeFlexibility)sizeFlexibility {
@@ -185,17 +220,7 @@
185
220
  - (void)setSizeFlexibility:(RCTRootViewSizeFlexibility)sizeFlexibility {
186
221
  super.sizeMeasureMode = convertToSurfaceSizeMeasureMode(sizeFlexibility);
187
222
  }
188
-
223
+
189
224
  #endif
190
-
191
- - (NSString *)componentId {
192
- return self.appProperties[@"componentId"];
193
- }
194
-
195
- - (NSString *)componentType {
196
- @throw [NSException exceptionWithName:@"componentType not implemented"
197
- reason:@"Should always subclass RNNReactView"
198
- userInfo:nil];
199
- }
200
-
225
+
201
226
  @end
@@ -89,6 +89,8 @@
89
89
 
90
90
  viewController.navigationItem.titleView = nil;
91
91
  viewController.navigationItem.titleView = _customTitleView;
92
+ [_customTitleView componentWillAppear];
93
+ [_customTitleView componentDidAppear];
92
94
  } else {
93
95
  [_customTitleView removeFromSuperview];
94
96
  if (readyBlock) {
@@ -18,5 +18,12 @@ RCT_EXPORT_MODULE()
18
18
  _host = host;
19
19
  }
20
20
 
21
+ - (void)send:(NSString *)eventName body:(id)body {
22
+ if (_host == nil) {
23
+ return;
24
+ }
25
+ [self sendEventWithName:eventName body:body];
26
+ }
27
+
21
28
  @end
22
29
  #endif
@@ -21,6 +21,7 @@ typedef void (^RNNAnimationBlock)(void);
21
21
 
22
22
  [self
23
23
  performBlock:^{
24
+ NSLog(@"About to push a controller %@", newTop);
24
25
  [self pushViewController:newTop animated:animated];
25
26
  }
26
27
  animated:animated
@@ -38,9 +39,12 @@ typedef void (^RNNAnimationBlock)(void);
38
39
  }
39
40
  animated:animated
40
41
  completion:^{
42
+ NSLog(@"Pop popAnimated completed");
41
43
  if (poppedVC) {
44
+ NSLog(@"Pop popAnimated completion invokation");
42
45
  completion();
43
46
  } else {
47
+ NSLog(@"Pop rejection");
44
48
  [RNNErrorHandler reject:rejection
45
49
  withErrorCode:1012
46
50
  errorDescription:@"popping component failed"];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-navigation",
3
- "version": "8.1.0-alpha-snapshot.1648",
3
+ "version": "8.1.0-rc01",
4
4
  "description": "React Native Navigation - truly native navigation for iOS and Android",
5
5
  "license": "MIT",
6
6
  "nativePackage": true,