@applicaster/zapp-react-native-ui-components 12.0.0-alpha.4462655310 → 12.0.0-alpha.4484269996

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 (66) hide show
  1. package/Components/BaseFocusable/index.tsx +2 -2
  2. package/Components/Cell/Cell.tsx +26 -5
  3. package/Components/Cell/CellWithFocusable.tsx +6 -4
  4. package/Components/Cell/TvOSCellComponent.tsx +3 -7
  5. package/Components/Focusable/Focusable.tsx +6 -1
  6. package/Components/FocusableGroup/index.tsx +10 -2
  7. package/Components/FreezeWithCallback/Freeze.tsx +31 -0
  8. package/Components/FreezeWithCallback/LICENSE +21 -0
  9. package/Components/FreezeWithCallback/Suspender.tsx +17 -0
  10. package/Components/FreezeWithCallback/__tests__/index.test.tsx +170 -0
  11. package/Components/FreezeWithCallback/index.tsx +3 -0
  12. package/Components/Layout/TV/ScreenContainer.tsx +79 -5
  13. package/Components/Layout/TV/__tests__/ScreenContainer.test.tsx +38 -28
  14. package/Components/Layout/TV/__tests__/__snapshots__/ScreenContainer.test.tsx.snap +25 -13
  15. package/Components/Layout/TV/__tests__/index.test.tsx +2 -1
  16. package/Components/Layout/TV/index.tsx +11 -65
  17. package/Components/MasterCell/DefaultComponents/ActionButton.tsx +2 -1
  18. package/Components/MasterCell/DefaultComponents/BorderContainerView/index.tsx +1 -7
  19. package/Components/MasterCell/DefaultComponents/FocusableView/index.tsx +4 -1
  20. package/Components/MasterCell/DefaultComponents/ImageBorderContainer/index.ts +71 -0
  21. package/Components/MasterCell/DefaultComponents/LiveImage/index.tsx +20 -0
  22. package/Components/MasterCell/DefaultComponents/index.ts +2 -0
  23. package/Components/MasterCell/DefaultComponents/tv/ButtonContainerView/index.tsx +6 -1
  24. package/Components/MasterCell/SharedUI/ProgressBar/hooks/useFillInPercent.ts +7 -1
  25. package/Components/MasterCell/dataAdapter.ts +21 -7
  26. package/Components/MasterCell/index.tsx +5 -3
  27. package/Components/MasterCell/utils/__tests__/insertBetween.test.js +9 -0
  28. package/Components/Navigator/StackNavigator.tsx +14 -5
  29. package/Components/PlayerContainer/PlayerContainer.tsx +2 -5
  30. package/Components/Screen/TV/hooks/index.ts +0 -2
  31. package/Components/Screen/TV/index.web.tsx +40 -41
  32. package/Components/Screen/__tests__/Screen.test.tsx +0 -49
  33. package/Components/Screen/index.tsx +28 -77
  34. package/Components/Screen/navigationHandler.ts +6 -3
  35. package/Components/Screen/orientationHandler.ts +18 -7
  36. package/Components/Screen/utils.ts +16 -0
  37. package/Components/ScreenResolver/index.tsx +6 -11
  38. package/Components/Transitioner/Scene.tsx +20 -12
  39. package/Components/Transitioner/Transitioner.tsx +26 -21
  40. package/Components/Transitioner/__tests__/Scene.test.js +7 -0
  41. package/Components/Transitioner/__tests__/__snapshots__/Scene.test.js.snap +8 -4
  42. package/Components/Transitioner/__tests__/__snapshots__/transitioner.test.js.snap +1 -0
  43. package/Components/VideoLive/LiveImageManager.ts +10 -0
  44. package/Components/VideoLive/PlayerLiveImageComponent.tsx +52 -24
  45. package/Components/VideoLive/__tests__/__snapshots__/PlayerLiveImageComponent.test.tsx.snap +26 -24
  46. package/Components/VideoModal/ModalAnimation/AnimatedPlayerModalWrapper.tsx +2 -14
  47. package/Components/VideoModal/ModalAnimation/AnimatedScrollModal.tsx +31 -7
  48. package/Components/VideoModal/ModalAnimation/AnimatedVideoPlayerComponent.tsx +9 -2
  49. package/Components/VideoModal/ModalAnimation/AnimationComponent.tsx +27 -15
  50. package/Components/VideoModal/ModalAnimation/ModalAnimationContext.tsx +32 -4
  51. package/Components/VideoModal/ModalAnimation/utils.ts +7 -4
  52. package/Components/VideoModal/PlayerWrapper.tsx +2 -2
  53. package/Components/VideoModal/__tests__/__snapshots__/PlayerWrapper.test.tsx.snap +80 -14
  54. package/Components/VideoModal/hooks/useModalSize.ts +10 -12
  55. package/Components/ZappFrameworkComponents/BarView/BarView.tsx +4 -3
  56. package/Components/default-cell-renderer/__tests__/__snapshots__/defaultCellRenderer.test.tsx.snap +4 -4
  57. package/Contexts/FocusableGroupContext/FocusableGroupContext.ts +3 -0
  58. package/Contexts/FocusableGroupContext/FocusableGroupContextProvider.tsx +16 -0
  59. package/Contexts/FocusableGroupContext/__tests__/FocusableGroupContextProvider.test.tsx +22 -0
  60. package/Contexts/FocusableGroupContext/__tests__/withFocusableContext.test.tsx +26 -0
  61. package/Contexts/FocusableGroupContext/index.ts +7 -0
  62. package/Contexts/FocusableGroupContext/withFocusableContext.tsx +17 -0
  63. package/package.json +5 -5
  64. package/Components/Screen/TV/hooks/useRestoreFocus.ts +0 -22
  65. /package/Components/FocusableGroup/{index.android.js → index.android.ts} +0 -0
  66. /package/Components/FocusableGroup/{index.ios.js → index.ios.ts} +0 -0
@@ -1,3 +1 @@
1
1
  export { useInitialFocus } from "./useInitialFocus";
2
-
3
- export { useRestoreFocus } from "./useRestoreFocus";
@@ -1,20 +1,29 @@
1
- import * as React from "react";
2
- import { last, pathOr } from "ramda";
3
- import { View, StyleSheet } from "react-native";
1
+ import React from "react";
2
+ import { last } from "ramda";
3
+ import { StyleSheet, View } from "react-native";
4
4
  import {
5
+ findMenuPlugin,
5
6
  getNavigationProps,
6
7
  getPathAttributes,
7
- resolveNavigationPlugin,
8
8
  } from "@applicaster/zapp-react-native-utils/navigationUtils";
9
- import { useNavigation } from "@applicaster/zapp-react-native-utils/reactHooks";
9
+ import {
10
+ useIsScreenActive,
11
+ useNavigation,
12
+ } from "@applicaster/zapp-react-native-utils/reactHooks";
10
13
  import { noop } from "@applicaster/zapp-react-native-utils/functionUtils";
11
14
  import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
12
- import { useScreenBackgroundColor } from "@applicaster/zapp-react-native-utils/reactHooks/screen";
15
+ import {
16
+ useNavbarState,
17
+ useScreenBackgroundColor,
18
+ } from "@applicaster/zapp-react-native-utils/reactHooks/screen";
13
19
  import { isNilOrEmpty } from "@applicaster/zapp-react-native-utils/reactUtils/helpers";
14
20
 
15
21
  import { NavBarContainer } from "../../Layout/TV/NavBarContainer";
16
22
  import { ScreenResolver } from "../../ScreenResolver";
17
- import { useInitialFocus, useRestoreFocus } from "./hooks";
23
+ import { useInitialFocus } from "./hooks";
24
+ import { isPlayerPlugin } from "@applicaster/zapp-react-native-utils/pluginUtils";
25
+ import { focusManager } from "@applicaster/zapp-react-native-utils/appUtils";
26
+ import { FreezeWithCallback } from "../../FreezeWithCallback";
18
27
 
19
28
  const styles = StyleSheet.create({
20
29
  container: {
@@ -36,18 +45,6 @@ type Props = {
36
45
  Components: Components;
37
46
  };
38
47
 
39
- const getPluginType = pathOr("unknown_plugin_type", [
40
- "state",
41
- "screen",
42
- "plugin_type",
43
- ]);
44
-
45
- const isPlayerPlugin = (routeState): boolean =>
46
- getPluginType(routeState) === "player";
47
-
48
- const isLoginPlugin = (routeState): boolean =>
49
- getPluginType(routeState) === "login";
50
-
51
48
  const getActiveRiver = ({
52
49
  screenId,
53
50
  screenType,
@@ -111,7 +108,6 @@ export const Screen = ({ route, Components }: Props) => {
111
108
  const backgroundColor = useScreenBackgroundColor(screenId);
112
109
 
113
110
  useInitialFocus();
114
- useRestoreFocus();
115
111
 
116
112
  const activeRiver = getActiveRiver({
117
113
  screenId,
@@ -139,41 +135,44 @@ export const Screen = ({ route, Components }: Props) => {
139
135
  fallbackNavigations: navigator.activeRiver.navigations,
140
136
  });
141
137
 
142
- const menuPlugin = resolveNavigationPlugin({
143
- category: "menu",
144
- navigations,
145
- plugins,
146
- }) as QuickBrickPlugin;
138
+ const menuPlugin = findMenuPlugin(navigations, plugins);
147
139
 
148
140
  const NavBar = (Components.NavBar ||
149
141
  menuPlugin.module) as React.ComponentType<any>;
150
142
 
151
143
  const isPlayer = isPlayerPlugin(routeState);
152
- const isLogin = isLoginPlugin(routeState);
153
144
 
154
- const isNavBarVisible = !isPlayer && !isLogin;
145
+ const { visible: isNavBarVisible } = useNavbarState();
155
146
 
156
147
  const screenData =
157
148
  screenType === "hooks" || isPlayer
158
149
  ? routeState?.state?.entry
159
150
  : routeState?.state?.screen;
160
151
 
152
+ const isScreenActive = useIsScreenActive();
153
+
161
154
  return (
162
- <View style={[styles.container, { backgroundColor }]}>
163
- <NavBarContainer isVisible={isNavBarVisible} onReady={noop}>
164
- <NavBar
155
+ <FreezeWithCallback
156
+ freeze={!isScreenActive}
157
+ onRelease={() => {
158
+ focusManager.setInitialFocus();
159
+ }}
160
+ >
161
+ <View style={[styles.container, { backgroundColor }]}>
162
+ <NavBarContainer isVisible={isNavBarVisible} onReady={noop}>
163
+ <NavBar
164
+ isVisible={isNavBarVisible}
165
+ menuPlugin={menuPlugin}
166
+ navigationProps={navigationProps}
167
+ />
168
+ </NavBarContainer>
169
+ <ScreenResolver
170
+ screenType={screenType}
171
+ screenId={screenId}
172
+ screenData={screenData}
165
173
  groupId={route}
166
- isVisible={isNavBarVisible}
167
- menuPlugin={menuPlugin}
168
- navigationProps={navigationProps}
169
174
  />
170
- </NavBarContainer>
171
- <ScreenResolver
172
- screenType={screenType}
173
- screenId={screenId}
174
- screenData={screenData}
175
- groupId={route}
176
- />
177
- </View>
175
+ </View>
176
+ </FreezeWithCallback>
178
177
  );
179
178
  };
@@ -99,14 +99,6 @@ jest.mock("@applicaster/zapp-react-native-redux/hooks", () => ({
99
99
  }),
100
100
  }));
101
101
 
102
- const {
103
- ORIENTATIONS,
104
- } = require("@applicaster/zapp-react-native-utils/appUtils/orientationHelper");
105
-
106
- const {
107
- useCurrentScreenData,
108
- } = require("@applicaster/zapp-react-native-utils/reactHooks/screen");
109
-
110
102
  const {
111
103
  allowedOrientationsForScreen,
112
104
  getOrientation,
@@ -158,45 +150,4 @@ describe("<Screen Component />", () => {
158
150
  expect(wrapper.toJSON()).toMatchSnapshot();
159
151
  });
160
152
  });
161
-
162
- it("invokes the orientation hook when the route changes", () => {
163
- act(() => {
164
- wrapper = create(<Screen {...screenProps} />);
165
- });
166
-
167
- // @ts-ignore
168
- useCurrentScreenData.mockReturnValue({
169
- id: "player-testId",
170
- general: { screen_orientation: ORIENTATIONS.landscapeSensor },
171
- plugin_type: "player",
172
- });
173
-
174
- act(() => {
175
- wrapper.update(
176
- <Screen
177
- {...screenProps}
178
- pathname="/playable"
179
- screenData={{
180
- id: "player-testId",
181
- general: { screen_orientation: ORIENTATIONS.landscapeSensor },
182
- plugin_type: "player",
183
- }}
184
- />
185
- );
186
- });
187
-
188
- useCurrentScreenData.mockReturnValue({
189
- id: "player-testId",
190
- general: { screen_orientation: ORIENTATIONS.landscapeSensor },
191
- });
192
-
193
- act(() => {
194
- wrapper.update(<Screen {...screenProps} />);
195
- });
196
-
197
- expect(allowedOrientationsForScreen).toHaveBeenNthCalledWith(
198
- 1,
199
- ORIENTATIONS.landscapeSensor
200
- );
201
- });
202
153
  });
@@ -1,6 +1,5 @@
1
1
  /// <reference types="@applicaster/applicaster-types" />
2
2
  import React from "react";
3
- import * as R from "ramda";
4
3
  import { View } from "react-native";
5
4
  import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
6
5
  import {
@@ -11,10 +10,10 @@ import {
11
10
  import { useTheme } from "@applicaster/zapp-react-native-utils/theme";
12
11
  import { getComponentModule } from "@applicaster/zapp-react-native-utils/pluginUtils";
13
12
  import {
14
- getNavigationPropsV2,
15
- resolveNavigationPlugin,
13
+ shouldNavBarDisplayMenu,
14
+ getNavBarProps,
15
+ getScreenId,
16
16
  } from "@applicaster/zapp-react-native-utils/navigationUtils";
17
- import { useSafeAreaInsets } from "react-native-safe-area-context";
18
17
  import {
19
18
  useDimensions,
20
19
  useRoute,
@@ -25,39 +24,18 @@ import {
25
24
  } from "@applicaster/zapp-react-native-utils/reactHooks";
26
25
  import { getNavigationPluginModule } from "@applicaster/zapp-react-native-app/App/Layout/layoutHelpers";
27
26
 
28
- import { ScreenContextProvider } from "../../Contexts/ScreenContext";
29
27
  import { RouteManager } from "../RouteManager";
30
28
  import { useScreenConfiguration } from "../River/useScreenConfiguration";
31
- import { useScreenOrientationHandler } from "./orientationHandler";
32
-
33
- const getScreenId = (
34
- screenData: LegacyNavigationScreenData,
35
- fallbackRiver: ZappRiver
36
- ) => {
37
- return screenData?.targetScreen
38
- ? screenData?.targetScreen?.id ?? fallbackRiver.id
39
- : "screen_id" in screenData
40
- ? screenData.screen_id
41
- : fallbackRiver.id;
29
+ import { isValidColor } from "./utils";
30
+
31
+ const screenStyles = {
32
+ flex: 1,
33
+ paddingTop: 0,
34
+ // paddingBottom: insets.bottom, // Should be applied directly by UI plugin
35
+ // paddingLeft: insets.left, // Should be applied directly by UI plugin
36
+ // paddingRight: insets.right, // Should be applied directly by UI plugin
42
37
  };
43
38
 
44
- function colorIsNotTransparent(color) {
45
- const layers = R.compose(
46
- R.map(R.trim),
47
- R.split(","),
48
- R.replace(")", ""),
49
- R.replace("rgba(", "")
50
- )(color);
51
-
52
- const alpha = Number(layers?.[3]);
53
-
54
- return alpha > 0;
55
- }
56
-
57
- function isValidColor(string) {
58
- return string && string !== "transparent" && colorIsNotTransparent(string);
59
- }
60
-
61
39
  type Props = {
62
40
  pathname: unknown;
63
41
  screenData: unknown;
@@ -71,7 +49,6 @@ export function Screen(_props: Props) {
71
49
  // Gets the data for the current screen configuration
72
50
  const currentScreenData = useCurrentScreenData();
73
51
  const { backgroundColor } = useScreenConfiguration(currentScreenData.id);
74
- const insets = useSafeAreaInsets();
75
52
 
76
53
  const {
77
54
  width: screenWidth,
@@ -96,30 +73,12 @@ export function Screen(_props: Props) {
96
73
 
97
74
  const layoutData = { isTablet, isTabletPortrait, width: screenWidth, height };
98
75
 
99
- const hasMenu =
100
- resolveNavigationPlugin({
101
- category: "menu",
102
- navigations: currentRiver.navigations,
103
- plugins,
104
- })?.identifier === "quick_brick_side_menu";
105
-
106
- const navBarProps = React.useMemo<MobileNavBarPluginProps | null>(() => {
107
- const props = getNavigationPropsV2({
108
- currentRiver,
109
- title,
110
- category: "nav_bar",
111
- });
112
-
113
- if (props) {
114
- return {
115
- ...props,
116
- id: pathname,
117
- pathname: pathname,
118
- };
119
- }
120
-
121
- return null;
122
- }, [currentRiver, pathname]);
76
+ const hasMenu = shouldNavBarDisplayMenu(currentRiver, plugins);
77
+
78
+ const navBarProps = React.useMemo<MobileNavBarPluginProps | null>(
79
+ getNavBarProps(currentRiver, pathname, title),
80
+ [currentRiver, pathname]
81
+ );
123
82
 
124
83
  const NavBar = React.useMemo(
125
84
  () =>
@@ -141,23 +100,17 @@ export function Screen(_props: Props) {
141
100
 
142
101
  const style = React.useMemo(
143
102
  () => ({
144
- flex: 1,
103
+ ...screenStyles,
145
104
  backgroundColor: isValidColor(backgroundColor)
146
105
  ? backgroundColor
147
106
  : theme.app_background_color,
148
- paddingTop: 0,
149
- // paddingBottom: insets.bottom, // Should be applied directly by UI plugin
150
- // paddingLeft: insets.left, // Should be applied directly by UI plugin
151
- // paddingRight: insets.right, // Should be applied directly by UI plugin
152
107
  }),
153
- [insets, screenWidth, theme.app_background_color, backgroundColor]
108
+ [theme.app_background_color, backgroundColor]
154
109
  );
155
110
 
156
111
  const targetScreenData =
157
112
  currentScreenData || (screenData as any)?.targetScreen || screenData;
158
113
 
159
- useScreenOrientationHandler({ screenData: targetScreenData });
160
-
161
114
  const orientation = useGetScreenOrientation(targetScreenData);
162
115
 
163
116
  // We prevent rendering of the screen until UI is actually rotated to screen desired orientation.
@@ -168,19 +121,17 @@ export function Screen(_props: Props) {
168
121
  layoutData,
169
122
  })
170
123
  ) {
171
- return null;
124
+ return <View style={style} />;
172
125
  }
173
126
 
174
127
  return (
175
- <ScreenContextProvider pathname={pathname}>
176
- <View style={style}>
177
- {navBarProps && <NavBar {...navBarProps} hasMenu={hasMenu} />}
178
-
179
- <OfflineFallbackScreen screenData={targetScreenData}>
180
- {/* @TODO RouteManager doesn't use props, can they be removed ? */}
181
- <RouteManager pathname={pathname} screenData={screenData} />
182
- </OfflineFallbackScreen>
183
- </View>
184
- </ScreenContextProvider>
128
+ <View style={style}>
129
+ {navBarProps && <NavBar {...navBarProps} hasMenu={hasMenu} />}
130
+
131
+ <OfflineFallbackScreen screenData={targetScreenData}>
132
+ {/* @TODO RouteManager doesn't use props, can they be removed ? */}
133
+ <RouteManager pathname={pathname} screenData={screenData} />
134
+ </OfflineFallbackScreen>
135
+ </View>
185
136
  );
186
137
  }
@@ -5,6 +5,11 @@
5
5
  * is similar to the navbar, except that it covers scenarios where only the navbar (and not)
6
6
  * the menu, will be hidden
7
7
  *
8
+ * - playable screens
9
+ * - qb_search_screen
10
+ * - screen hooks that specify showNavBar or presentFullScreen
11
+ * - screens or nested screens that have allow_screen_plugin_presentation set to true
12
+ *
8
13
  * @param {String} route current route of the screen
9
14
  * @param {Object} screenData payload associated with the currently presented screen
10
15
  * @returns {Boolean}
@@ -21,9 +26,7 @@ export function isMenuVisible(route, screenData) {
21
26
  if (screenData?.hookPlugin) {
22
27
  const hookPlugin = screenData?.hookPlugin?.module;
23
28
 
24
- return (
25
- hookPlugin?.showNavBar || hookPlugin?.presentFullScreen !== true || false
26
- );
29
+ return hookPlugin?.showNavBar || hookPlugin?.presentFullScreen !== true;
27
30
  }
28
31
 
29
32
  if (
@@ -1,14 +1,16 @@
1
1
  import React, { useLayoutEffect } from "react";
2
+
2
3
  import {
3
4
  allowedOrientationsForScreen,
4
5
  ORIENTATIONS,
5
6
  getOrientation,
6
7
  useGetScreenOrientation,
7
8
  } from "@applicaster/zapp-react-native-utils/appUtils/orientationHelper";
8
-
9
+ import { usePrevious } from "@applicaster/zapp-react-native-utils/reactHooks/utils";
9
10
  import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
10
11
  import { findPluginByType } from "@applicaster/zapp-react-native-utils/pluginUtils";
11
12
  import { useIsTablet } from "@applicaster/zapp-react-native-utils/reactHooks";
13
+
12
14
  import { ZappHookModalContext } from "../../Contexts";
13
15
  import { HookModalContextT } from "../../Contexts/ZappHookModalContext";
14
16
 
@@ -79,14 +81,23 @@ export function useNewOrientationForScreenData({
79
81
  screenOrientation;
80
82
  }
81
83
 
82
- export function useScreenOrientationHandler({
83
- screenData,
84
- }: OrientationHookArgs) {
84
+ type Props = {
85
+ screenData: {
86
+ screen: {};
87
+ };
88
+ isActive: boolean;
89
+ };
90
+
91
+ export function useScreenOrientationHandler({ screenData, isActive }: Props) {
85
92
  const { isHooksExecutionInProgress } = React.useContext<HookModalContextT>(
86
93
  ZappHookModalContext.ReactContext
87
94
  );
88
95
 
89
- const newOrientation = useNewOrientationForScreenData({ screenData });
96
+ const prevIsActive = usePrevious(isActive);
97
+
98
+ const newOrientation = useNewOrientationForScreenData({
99
+ screenData: screenData.screen,
100
+ });
90
101
 
91
102
  useLayoutEffect(() => {
92
103
  // Null means screen does not have orientation preference, so we can skip rotate
@@ -100,12 +111,12 @@ export function useScreenOrientationHandler({
100
111
  return;
101
112
  }
102
113
 
103
- if (newOrientation !== current) {
114
+ if (!prevIsActive && isActive && newOrientation !== current) {
104
115
  current = newOrientation;
105
116
 
106
117
  setOrientation(newOrientation);
107
118
  }
108
- }, [newOrientation, isHooksExecutionInProgress]);
119
+ }, [newOrientation, isHooksExecutionInProgress, prevIsActive, isActive]);
109
120
  }
110
121
 
111
122
  export function useOrientationHandler({ screenData }: OrientationHookArgs) {
@@ -0,0 +1,16 @@
1
+ import { map, split, replace, compose, trim } from "ramda";
2
+
3
+ function colorIsNotTransparent(color) {
4
+ const layers = compose(
5
+ map(trim),
6
+ split(","),
7
+ replace(")", ""),
8
+ replace("rgba(", "")
9
+ )(color);
10
+
11
+ return Number(layers?.[3]) > 0;
12
+ }
13
+
14
+ export function isValidColor(string) {
15
+ return string && string !== "transparent" && colorIsNotTransparent(string);
16
+ }
@@ -1,6 +1,5 @@
1
1
  import * as React from "react";
2
- import * as R from "ramda";
3
- import { useDispatch } from "react-redux";
2
+ import { path, prop } from "ramda";
4
3
  import {
5
4
  findPluginByType,
6
5
  findPluginByIdentifier,
@@ -15,7 +14,6 @@ import { componentsLogger } from "../../Helpers/logger";
15
14
  import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
16
15
  import { useNavigation } from "@applicaster/zapp-react-native-utils/reactHooks";
17
16
  import { useScreenAnalytics } from "@applicaster/zapp-react-native-utils/analyticsUtils/helpers/hooks";
18
- import { setAppStateHasFinishedTransitioning } from "@applicaster/zapp-react-native-redux/appState";
19
17
 
20
18
  const logger = componentsLogger.addSubsystem("ScreenResolver");
21
19
 
@@ -54,11 +52,8 @@ export function ScreenResolverComponent(props: Props) {
54
52
 
55
53
  const [, setScreenContext] = ZappPipesScreenContext.useZappPipesContext();
56
54
 
57
- const dispatch = useDispatch();
58
-
59
55
  React.useEffect(() => {
60
56
  setScreenContext(rivers[screenId]);
61
- dispatch(setAppStateHasFinishedTransitioning());
62
57
  }, [screenId]);
63
58
 
64
59
  const ScreenPlugin =
@@ -100,14 +95,14 @@ export function ScreenResolverComponent(props: Props) {
100
95
  }
101
96
 
102
97
  const ScreenComponent =
103
- R.path(["module", "Component"], ScreenPlugin) ||
104
- R.prop("module", ScreenPlugin) ||
105
- R.prop("Component", ScreenPlugin) ||
98
+ path(["module", "Component"], ScreenPlugin) ||
99
+ prop("module", ScreenPlugin) ||
100
+ prop("Component", ScreenPlugin) ||
106
101
  ScreenPlugin;
107
102
 
108
103
  const configuration =
109
- R.prop("configuration", ScreenPlugin) ||
110
- R.prop("__plugin_configuration", ScreenComponent);
104
+ prop("configuration", ScreenPlugin) ||
105
+ prop("__plugin_configuration", ScreenComponent);
111
106
 
112
107
  if (ScreenComponent) {
113
108
  return (
@@ -1,13 +1,12 @@
1
1
  import React from "react";
2
- import {
3
- Animated,
4
- useWindowDimensions,
5
- ViewProps,
6
- ViewStyle,
7
- } from "react-native";
2
+ import { Animated, ViewProps, ViewStyle } from "react-native";
8
3
  import { useSafeAreaFrame } from "react-native-safe-area-context";
4
+
5
+ import { useScreenOrientationHandler } from "@applicaster/zapp-react-native-ui-components/Components/Screen/orientationHandler";
6
+
9
7
  import { PathnameContext } from "../../Contexts/PathnameContext";
10
8
  import { ScreenDataContext } from "../../Contexts/ScreenDataContext";
9
+ import { ScreenContextProvider } from "../../Contexts/ScreenContext";
11
10
 
12
11
  type Props = {
13
12
  children: any;
@@ -46,6 +45,11 @@ export function Scene({
46
45
  }: Props) {
47
46
  const [initialScreenData, setInitialScreenData] = React.useState(screenData);
48
47
 
48
+ useScreenOrientationHandler({
49
+ screenData,
50
+ isActive,
51
+ });
52
+
49
53
  React.useLayoutEffect(() => {
50
54
  if (isActive) {
51
55
  setInitialScreenData(screenData);
@@ -53,12 +57,14 @@ export function Scene({
53
57
  }, [screenData, isActive]);
54
58
 
55
59
  const frame = useSafeAreaFrame();
56
- const { height, width } = useWindowDimensions();
57
-
58
- // Safe frame takes too long to update,
59
- // so we can not rely on it there, and use height and width instead.
60
60
  const isAnimating = animating && overlayStyle;
61
- const dimensions = isAnimating ? { height, width } : frame;
61
+
62
+ const dimensions = isAnimating
63
+ ? {
64
+ width: "100%",
65
+ height: "100%",
66
+ }
67
+ : frame;
62
68
 
63
69
  return (
64
70
  <Animated.View
@@ -67,7 +73,9 @@ export function Scene({
67
73
  >
68
74
  <ScreenDataContext.Provider value={initialScreenData}>
69
75
  <PathnameContext.Provider value={pathname}>
70
- {children}
76
+ <ScreenContextProvider pathname={pathname}>
77
+ {children}
78
+ </ScreenContextProvider>
71
79
  </PathnameContext.Provider>
72
80
  </ScreenDataContext.Provider>
73
81
  {isAnimating && <Animated.View style={overlayStyle} />}
@@ -1,6 +1,6 @@
1
1
  import * as React from "react";
2
2
  import { View } from "react-native";
3
- import * as R from "ramda";
3
+ import { update, compose, tail, append, take, identity } from "ramda";
4
4
 
5
5
  import { AnimationManager } from "./AnimationManager";
6
6
  import { Scene } from "./Scene";
@@ -46,7 +46,7 @@ function prepareScene(children) {
46
46
  */
47
47
  function scenesForBackTransition(props: SceneProps, { scenes }) {
48
48
  return scenes.length > 1
49
- ? R.identity(scenes)
49
+ ? identity(scenes)
50
50
  : [prepareScene(props.children), scenes[0]];
51
51
  }
52
52
 
@@ -110,7 +110,7 @@ export class TransitionerComponent extends React.PureComponent<Props, State> {
110
110
  pushTransitionStart() {
111
111
  this.setState(
112
112
  {
113
- scenes: R.append(prepareScene(this.props.children), this.state.scenes),
113
+ scenes: append(prepareScene(this.props.children), this.state.scenes),
114
114
  ...this.animationManager.stateForAction(this.state, NAV_ACTION_PUSH),
115
115
  },
116
116
  () => {
@@ -166,21 +166,23 @@ export class TransitionerComponent extends React.PureComponent<Props, State> {
166
166
 
167
167
  transitionWithoutAnimation(resetState) {
168
168
  const { scenes } = this.state;
169
-
170
- const newState = resetState
171
- ? {
172
- scenes: [prepareScene(this.props.children)],
173
- to: {
174
- index: 0,
175
- },
176
- }
177
- : {
178
- scenes: R.update(
179
- scenes.length - 1,
180
- prepareScene(this.props.children),
181
- scenes
182
- ),
183
- };
169
+ const newScene = prepareScene(this.props.children);
170
+ const isLastSceneHook = scenes[scenes.length - 1].key.startsWith("/hook");
171
+
172
+ let newState;
173
+
174
+ if (resetState) {
175
+ newState = {
176
+ scenes: [newScene],
177
+ to: { index: 0 },
178
+ };
179
+ } else if (isLastSceneHook || scenes.length === 1) {
180
+ newState = { scenes: update(scenes.length - 1, newScene, scenes) };
181
+ } else {
182
+ newState = {
183
+ scenes: compose(tail, append(newScene))(scenes),
184
+ };
185
+ }
184
186
 
185
187
  this.setState(newState);
186
188
  }
@@ -223,7 +225,10 @@ export class TransitionerComponent extends React.PureComponent<Props, State> {
223
225
  this.shouldSkipAnimationForRoute(previousRoute) ||
224
226
  this.shouldSkipAnimationForRoute(currentRoute)
225
227
  ) {
226
- return this.transitionWithoutAnimation();
228
+ // we are going back, in this case we need to have only one scene using resetState
229
+ const resetState = isGoingBack ? true : undefined;
230
+
231
+ return this.transitionWithoutAnimation(resetState);
227
232
  }
228
233
 
229
234
  switch (this.props.navigator.previousAction) {
@@ -266,7 +271,7 @@ export class TransitionerComponent extends React.PureComponent<Props, State> {
266
271
  backTransitionEnd(stepsBack) {
267
272
  this.setState({
268
273
  animating: false,
269
- scenes: R.take(this.state.scenes.length - stepsBack, this.state.scenes),
274
+ scenes: take(this.state.scenes.length - stepsBack, this.state.scenes),
270
275
  });
271
276
  }
272
277
 
@@ -282,7 +287,7 @@ export class TransitionerComponent extends React.PureComponent<Props, State> {
282
287
  <View style={styles.container}>
283
288
  {scenes[to.index] && (
284
289
  <Scene
285
- {...{ style: to.style }}
290
+ {...{ style: to?.style || {} }}
286
291
  pathname={pathname}
287
292
  isActive={pathname === this.props.navigator.currentRoute}
288
293
  contentStyle={contentStyle}
@@ -16,6 +16,13 @@ jest.mock("react-native-safe-area-context", () => ({
16
16
  })),
17
17
  }));
18
18
 
19
+ jest.mock(
20
+ "@applicaster/zapp-react-native-ui-components/Components/Screen/orientationHandler",
21
+ () => ({
22
+ useScreenOrientationHandler: jest.fn(),
23
+ })
24
+ );
25
+
19
26
  const { Scene } = require("../Scene");
20
27
 
21
28
  const wrapper = shallow(