@applicaster/zapp-react-native-ui-components 12.0.0-alpha.8121552272 → 12.0.0-alpha.8232897202

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 (107) hide show
  1. package/Components/BaseFocusable/index.tsx +3 -3
  2. package/Components/Cell/Cell.tsx +30 -9
  3. package/Components/Cell/CellWithFocusable.tsx +23 -9
  4. package/Components/Cell/TvOSCellComponent.tsx +3 -7
  5. package/Components/Focusable/Focusable.tsx +6 -1
  6. package/Components/FocusableGroup/index.tsx +11 -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/GeneralContentScreen/utils/__tests__/useCurationAPI.test.js +13 -6
  13. package/Components/GeneralContentScreen/utils/useCurationAPI.ts +1 -1
  14. package/Components/HandlePlayable/HandlePlayable.tsx +3 -0
  15. package/Components/Layout/TV/ScreenContainer.tsx +79 -5
  16. package/Components/Layout/TV/ScreenLayoutContextProvider.tsx +2 -2
  17. package/Components/Layout/TV/__tests__/ScreenContainer.test.tsx +38 -28
  18. package/Components/Layout/TV/__tests__/__snapshots__/ScreenContainer.test.tsx.snap +25 -13
  19. package/Components/Layout/TV/__tests__/__snapshots__/index.test.tsx.snap +10 -50
  20. package/Components/Layout/TV/__tests__/index.test.tsx +20 -75
  21. package/Components/Layout/TV/index.tsx +14 -67
  22. package/Components/Layout/TV/index.web.tsx +33 -0
  23. package/Components/Layout/index.tsx +15 -11
  24. package/Components/MasterCell/DefaultComponents/ActionButton.tsx +4 -1
  25. package/Components/MasterCell/DefaultComponents/BorderContainerView/index.tsx +86 -116
  26. package/Components/MasterCell/DefaultComponents/DynamicBadge.tsx +4 -2
  27. package/Components/MasterCell/DefaultComponents/FocusableView/index.tsx +4 -1
  28. package/Components/MasterCell/DefaultComponents/Image/Image.ios.tsx +5 -3
  29. package/Components/MasterCell/DefaultComponents/ImageBorderContainer/index.ts +71 -0
  30. package/Components/MasterCell/DefaultComponents/ImageContainer/index.tsx +5 -1
  31. package/Components/MasterCell/DefaultComponents/LiveImage/index.tsx +20 -0
  32. package/Components/MasterCell/DefaultComponents/Text/index.tsx +14 -2
  33. package/Components/MasterCell/DefaultComponents/__tests__/image.test.js +1 -1
  34. package/Components/MasterCell/DefaultComponents/__tests__/text.test.tsx +24 -9
  35. package/Components/MasterCell/DefaultComponents/index.ts +2 -0
  36. package/Components/MasterCell/DefaultComponents/tv/ButtonContainerView/index.android.tsx +4 -1
  37. package/Components/MasterCell/DefaultComponents/tv/ButtonContainerView/index.tsx +10 -2
  38. package/Components/MasterCell/SharedUI/CollapsibleTextContainer/index.ts +1 -3
  39. package/Components/MasterCell/SharedUI/ProgressBar/hooks/useFillInPercent.ts +7 -1
  40. package/Components/MasterCell/dataAdapter.ts +21 -7
  41. package/Components/MasterCell/hooks/useAsyncRendering/index.ts +1 -1
  42. package/Components/MasterCell/index.tsx +5 -3
  43. package/Components/MasterCell/utils/__tests__/insertBetween.test.js +9 -0
  44. package/Components/MasterCell/utils/index.ts +17 -30
  45. package/Components/MeasurmentsPortal/BasicMeasurementsPortal.tsx +11 -7
  46. package/Components/MeasurmentsPortal/MeasurementsPortal.tsx +10 -1
  47. package/Components/Navigator/StackNavigator.tsx +57 -0
  48. package/Components/Navigator/index.ts +1 -0
  49. package/Components/PlayerContainer/PlayerContainer.tsx +6 -1
  50. package/Components/River/ComponentsMap/ComponentsMap.tsx +92 -22
  51. package/Components/River/RefreshControl.tsx +55 -1
  52. package/Components/River/TV/River.tsx +0 -23
  53. package/Components/RouteManager/index.tsx +2 -2
  54. package/Components/Screen/TV/hooks/index.ts +1 -0
  55. package/Components/Screen/TV/hooks/useInitialFocus.ts +70 -0
  56. package/Components/Screen/TV/index.web.tsx +178 -0
  57. package/Components/Screen/__tests__/Screen.test.tsx +3 -49
  58. package/Components/Screen/__tests__/__snapshots__/Screen.test.tsx.snap +4 -0
  59. package/Components/Screen/index.tsx +62 -72
  60. package/Components/Screen/navigationHandler.ts +6 -3
  61. package/Components/Screen/orientationHandler.ts +18 -7
  62. package/Components/Screen/utils.ts +16 -0
  63. package/Components/ScreenResolver/index.tsx +9 -12
  64. package/Components/Transitioner/Scene.tsx +39 -26
  65. package/Components/Transitioner/Transitioner.tsx +46 -48
  66. package/Components/Transitioner/__tests__/Scene.test.js +7 -0
  67. package/Components/Transitioner/__tests__/__snapshots__/Scene.test.js.snap +12 -4
  68. package/Components/Transitioner/__tests__/__snapshots__/transitioner.test.js.snap +2 -0
  69. package/Components/VideoLive/LiveImageManager.ts +28 -1
  70. package/Components/VideoLive/PlayerLiveImageComponent.tsx +52 -24
  71. package/Components/VideoLive/__tests__/__snapshots__/PlayerLiveImageComponent.test.tsx.snap +25 -28
  72. package/Components/VideoModal/ModalAnimation/AnimatedPlayerModalWrapper.tsx +2 -14
  73. package/Components/VideoModal/ModalAnimation/AnimatedScrollModal.tsx +79 -45
  74. package/Components/VideoModal/ModalAnimation/AnimatedVideoPlayerComponent.tsx +47 -33
  75. package/Components/VideoModal/ModalAnimation/AnimationComponent.tsx +121 -86
  76. package/Components/VideoModal/ModalAnimation/ModalAnimationContext.tsx +44 -5
  77. package/Components/VideoModal/ModalAnimation/utils.ts +7 -4
  78. package/Components/VideoModal/PlayerDetails.tsx +3 -3
  79. package/Components/VideoModal/PlayerWrapper.tsx +67 -60
  80. package/Components/VideoModal/VideoModal.tsx +17 -17
  81. package/Components/VideoModal/__tests__/PlayerWrapper.test.tsx +7 -0
  82. package/Components/VideoModal/__tests__/__snapshots__/PlayerWrapper.test.tsx.snap +80 -14
  83. package/Components/VideoModal/hooks/useModalSize.ts +10 -12
  84. package/Components/VideoModal/utils.ts +5 -2
  85. package/Components/Viewport/ViewportTracker/ViewportTracker.tsx +31 -40
  86. package/Components/Viewport/ViewportTracker/index.tsx +1 -0
  87. package/Components/Viewport/utils.js +1 -1
  88. package/Components/ZappFrameworkComponents/BarView/BarView.tsx +4 -3
  89. package/Components/default-cell-renderer/__tests__/__snapshots__/defaultCellRenderer.test.tsx.snap +4 -4
  90. package/Contexts/FocusableGroupContext/FocusableGroupContext.ts +3 -0
  91. package/Contexts/FocusableGroupContext/FocusableGroupContextProvider.tsx +16 -0
  92. package/Contexts/FocusableGroupContext/__tests__/FocusableGroupContextProvider.test.tsx +22 -0
  93. package/Contexts/FocusableGroupContext/__tests__/withFocusableContext.test.tsx +26 -0
  94. package/Contexts/FocusableGroupContext/index.ts +7 -0
  95. package/Contexts/FocusableGroupContext/withFocusableContext.tsx +17 -0
  96. package/Contexts/MenuToggleContext/{index.js → index.ts} +16 -0
  97. package/Contexts/ScreenContext/__tests__/__snapshots__/index.test.tsx.snap +3 -0
  98. package/Contexts/ScreenContext/__tests__/index.test.tsx +27 -0
  99. package/Contexts/ScreenContext/index.tsx +94 -25
  100. package/Contexts/ScreenDataContext/index.tsx +20 -0
  101. package/Contexts/ZappPipesContext/ZappPipesEntryContext.ts +1 -1
  102. package/events/index.ts +1 -0
  103. package/package.json +5 -5
  104. package/Components/Layout/TV/TransitionOverlay.tsx +0 -64
  105. /package/Components/FocusableGroup/{index.android.js → index.android.ts} +0 -0
  106. /package/Components/FocusableGroup/{index.ios.js → index.ios.ts} +0 -0
  107. /package/Contexts/{index.js → index.ts} +0 -0
@@ -0,0 +1 @@
1
+ export { useInitialFocus } from "./useInitialFocus";
@@ -0,0 +1,70 @@
1
+ import * as React from "react";
2
+ import {
3
+ useNavigationPluginData,
4
+ useIsNavBarVisible,
5
+ useRoute,
6
+ } from "@applicaster/zapp-react-native-utils/reactHooks";
7
+ import { toBooleanWithDefaultFalse } from "@applicaster/zapp-react-native-utils/booleanUtils";
8
+ import {
9
+ setFocusOnContent,
10
+ setFocusOnMenu,
11
+ } from "@applicaster/zapp-react-native-utils/appUtils/focusManagerAux";
12
+
13
+ type Return =
14
+ | {
15
+ onContent: true;
16
+ onMenu: false;
17
+ }
18
+ | {
19
+ onContent: false;
20
+ onMenu: true;
21
+ };
22
+
23
+ const getInitialFocus = (focusOnContent, isNavBarVisible): Return => {
24
+ if (focusOnContent) {
25
+ return {
26
+ onContent: true,
27
+ onMenu: false,
28
+ };
29
+ }
30
+
31
+ if (!focusOnContent && isNavBarVisible) {
32
+ // put focus on navbar
33
+ return {
34
+ onContent: false,
35
+ onMenu: true,
36
+ };
37
+ }
38
+
39
+ // we don't have navbar, put focus on content anyway
40
+ return {
41
+ onContent: true,
42
+ onMenu: false,
43
+ };
44
+ };
45
+
46
+ export const useInitialFocus = (): void => {
47
+ const navigationPluginData = useNavigationPluginData();
48
+
49
+ const focusOnContent = toBooleanWithDefaultFalse(
50
+ navigationPluginData?.rules?.focus_on_content
51
+ );
52
+
53
+ const isNavBarVisible = useIsNavBarVisible();
54
+
55
+ const { pathname: currentRoute } = useRoute();
56
+
57
+ React.useEffect(() => {
58
+ const initialFocus = getInitialFocus(focusOnContent, isNavBarVisible);
59
+
60
+ if (initialFocus.onContent) {
61
+ setFocusOnContent(currentRoute);
62
+
63
+ return;
64
+ }
65
+
66
+ if (initialFocus.onMenu) {
67
+ setFocusOnMenu(currentRoute);
68
+ }
69
+ }, []);
70
+ };
@@ -0,0 +1,178 @@
1
+ import React from "react";
2
+ import { last } from "ramda";
3
+ import { StyleSheet, View } from "react-native";
4
+ import {
5
+ findMenuPlugin,
6
+ getNavigationProps,
7
+ getPathAttributes,
8
+ } from "@applicaster/zapp-react-native-utils/navigationUtils";
9
+ import {
10
+ useIsScreenActive,
11
+ useNavigation,
12
+ } from "@applicaster/zapp-react-native-utils/reactHooks";
13
+ import { noop } from "@applicaster/zapp-react-native-utils/functionUtils";
14
+ import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
15
+ import {
16
+ useNavbarState,
17
+ useScreenBackgroundColor,
18
+ } from "@applicaster/zapp-react-native-utils/reactHooks/screen";
19
+ import { isNilOrEmpty } from "@applicaster/zapp-react-native-utils/reactUtils/helpers";
20
+
21
+ import { NavBarContainer } from "../../Layout/TV/NavBarContainer";
22
+ import { ScreenResolver } from "../../ScreenResolver";
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";
27
+
28
+ const styles = StyleSheet.create({
29
+ container: {
30
+ position: "absolute",
31
+ top: 0,
32
+ left: 0,
33
+ right: 0,
34
+ bottom: 0,
35
+ },
36
+ });
37
+
38
+ type Components = {
39
+ NavBar: React.ComponentType<any>;
40
+ Background: React.ComponentType<any>;
41
+ };
42
+
43
+ type Props = {
44
+ route: string;
45
+ Components: Components;
46
+ };
47
+
48
+ const getActiveRiver = ({
49
+ screenId,
50
+ screenType,
51
+ routeState,
52
+ rivers,
53
+ fallbackActiveRiver,
54
+ }) => {
55
+ if (rivers[screenId]) {
56
+ if (screenType === "hooks") {
57
+ const navigations = routeState?.state?.entry?.payload?.navigations;
58
+
59
+ if (navigations) {
60
+ return routeState.state.entry.payload;
61
+ }
62
+ }
63
+
64
+ return routeState?.state?.screen;
65
+ }
66
+
67
+ // screenId is not presented into rivers, use fallback instead
68
+ return fallbackActiveRiver;
69
+ };
70
+
71
+ const getNavigations = ({
72
+ screenId,
73
+ screenType,
74
+ routeState,
75
+ rivers,
76
+ fallbackNavigations,
77
+ }) => {
78
+ if (rivers[screenId]) {
79
+ // river presents
80
+ if (screenType === "hooks") {
81
+ const navigations = routeState?.state?.entry?.payload?.navigations;
82
+
83
+ if (navigations) {
84
+ return navigations;
85
+ }
86
+ }
87
+
88
+ return routeState?.state?.screen?.navigations;
89
+ }
90
+
91
+ // screenId is not presented into rivers, use fallback instead
92
+ return fallbackNavigations;
93
+ };
94
+
95
+ export const Screen = ({ route, Components }: Props) => {
96
+ if (isNilOrEmpty(route)) {
97
+ throw Error("Required props: route is missing");
98
+ }
99
+
100
+ const navigator = useNavigation();
101
+ const { plugins = [], rivers = [] } = usePickFromState(["plugins", "rivers"]);
102
+
103
+ const pathAttributes = getPathAttributes({ pathname: route });
104
+ const routeState = navigator.getStackForPathname(route);
105
+
106
+ const { screenType, screenId } = last(pathAttributes);
107
+
108
+ const backgroundColor = useScreenBackgroundColor(screenId);
109
+
110
+ useInitialFocus();
111
+
112
+ const activeRiver = getActiveRiver({
113
+ screenId,
114
+ screenType,
115
+ routeState,
116
+ rivers,
117
+ fallbackActiveRiver: navigator.activeRiver,
118
+ });
119
+
120
+ const navigationProps = getNavigationProps({
121
+ navigator: {
122
+ // @ts-ignore
123
+ activeRiver,
124
+ // @ts-ignore
125
+ screenTitle: routeState.state.entry?.title || routeState.screen?.name,
126
+ },
127
+ category: "menu",
128
+ });
129
+
130
+ const navigations = getNavigations({
131
+ screenId,
132
+ screenType,
133
+ routeState,
134
+ rivers,
135
+ fallbackNavigations: navigator.activeRiver.navigations,
136
+ });
137
+
138
+ const menuPlugin = findMenuPlugin(navigations, plugins);
139
+
140
+ const NavBar = (Components.NavBar ||
141
+ menuPlugin.module) as React.ComponentType<any>;
142
+
143
+ const isPlayer = isPlayerPlugin(routeState);
144
+
145
+ const { visible: isNavBarVisible } = useNavbarState();
146
+
147
+ const screenData =
148
+ screenType === "hooks" || isPlayer
149
+ ? routeState?.state?.entry
150
+ : routeState?.state?.screen;
151
+
152
+ const isScreenActive = useIsScreenActive();
153
+
154
+ return (
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}
173
+ groupId={route}
174
+ />
175
+ </View>
176
+ </FreezeWithCallback>
177
+ );
178
+ };
@@ -10,6 +10,8 @@ const mock_navBarVisibleFlag = true;
10
10
 
11
11
  const mockIsNavBarVisible = jest.fn(() => mock_navBarVisibleFlag);
12
12
 
13
+ const mockIsOrientationCompatible = jest.fn(() => true);
14
+
13
15
  jest.mock("react-native-safe-area-context", () => ({
14
16
  useSafeAreaInsets: () => ({ top: 44 }),
15
17
  }));
@@ -21,6 +23,7 @@ jest.mock("../../RouteManager", () => ({
21
23
  jest.mock(
22
24
  "@applicaster/zapp-react-native-utils/appUtils/orientationHelper",
23
25
  () => ({
26
+ isOrientationCompatible: mockIsOrientationCompatible,
24
27
  allowedOrientationsForScreen: jest.fn(),
25
28
  getOrientation: jest.fn(),
26
29
  getScreenOrientation: jest.fn(),
@@ -96,14 +99,6 @@ jest.mock("@applicaster/zapp-react-native-redux/hooks", () => ({
96
99
  }),
97
100
  }));
98
101
 
99
- const {
100
- ORIENTATIONS,
101
- } = require("@applicaster/zapp-react-native-utils/appUtils/orientationHelper");
102
-
103
- const {
104
- useCurrentScreenData,
105
- } = require("@applicaster/zapp-react-native-utils/reactHooks/screen");
106
-
107
102
  const {
108
103
  allowedOrientationsForScreen,
109
104
  getOrientation,
@@ -155,45 +150,4 @@ describe("<Screen Component />", () => {
155
150
  expect(wrapper.toJSON()).toMatchSnapshot();
156
151
  });
157
152
  });
158
-
159
- it("invokes the orientation hook when the route changes", () => {
160
- act(() => {
161
- wrapper = create(<Screen {...screenProps} />);
162
- });
163
-
164
- // @ts-ignore
165
- useCurrentScreenData.mockReturnValue({
166
- id: "player-testId",
167
- general: { screen_orientation: ORIENTATIONS.landscapeSensor },
168
- plugin_type: "player",
169
- });
170
-
171
- act(() => {
172
- wrapper.update(
173
- <Screen
174
- {...screenProps}
175
- pathname="/playable"
176
- screenData={{
177
- id: "player-testId",
178
- general: { screen_orientation: ORIENTATIONS.landscapeSensor },
179
- plugin_type: "player",
180
- }}
181
- />
182
- );
183
- });
184
-
185
- useCurrentScreenData.mockReturnValue({
186
- id: "player-testId",
187
- general: { screen_orientation: ORIENTATIONS.landscapeSensor },
188
- });
189
-
190
- act(() => {
191
- wrapper.update(<Screen {...screenProps} />);
192
- });
193
-
194
- expect(allowedOrientationsForScreen).toHaveBeenNthCalledWith(
195
- 1,
196
- ORIENTATIONS.landscapeSensor
197
- );
198
- });
199
153
  });
@@ -11,7 +11,9 @@ exports[`<Screen Component /> when the navbar should be hidden renders correctly
11
11
  }
12
12
  >
13
13
  <View
14
+ hasMenu={false}
14
15
  id="/river/testId"
16
+ pathname="/river/testId"
15
17
  selected="testId"
16
18
  testID="navBar"
17
19
  title=""
@@ -41,7 +43,9 @@ exports[`<Screen Component /> when the navbar should show renders correctly 1`]
41
43
  }
42
44
  >
43
45
  <View
46
+ hasMenu={false}
44
47
  id="/river/testId"
48
+ pathname="/river/testId"
45
49
  selected="testId"
46
50
  testID="navBar"
47
51
  title=""
@@ -1,13 +1,19 @@
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";
5
+ import {
6
+ isOrientationCompatible,
7
+ useGetScreenOrientation,
8
+ } from "@applicaster/zapp-react-native-utils/appUtils/orientationHelper";
6
9
 
7
10
  import { useTheme } from "@applicaster/zapp-react-native-utils/theme";
8
11
  import { getComponentModule } from "@applicaster/zapp-react-native-utils/pluginUtils";
9
- import { getNavigationPropsV2 } from "@applicaster/zapp-react-native-utils/navigationUtils";
10
- import { useSafeAreaInsets } from "react-native-safe-area-context";
12
+ import {
13
+ shouldNavBarDisplayMenu,
14
+ getNavBarProps,
15
+ getScreenId,
16
+ } from "@applicaster/zapp-react-native-utils/navigationUtils";
11
17
  import {
12
18
  useDimensions,
13
19
  useRoute,
@@ -18,45 +24,24 @@ import {
18
24
  } from "@applicaster/zapp-react-native-utils/reactHooks";
19
25
  import { getNavigationPluginModule } from "@applicaster/zapp-react-native-app/App/Layout/layoutHelpers";
20
26
 
21
- import { ScreenContextProvider } from "../../Contexts/ScreenContext";
22
27
  import { RouteManager } from "../RouteManager";
23
28
  import { useScreenConfiguration } from "../River/useScreenConfiguration";
24
- import { useScreenOrientationHandler } from "./orientationHandler";
25
-
26
- const getScreenId = (
27
- screenData: LegacyNavigationScreenData,
28
- fallbackRiver: ZappRiver
29
- ) => {
30
- return screenData?.targetScreen
31
- ? screenData?.targetScreen?.id ?? fallbackRiver.id
32
- : "screen_id" in screenData
33
- ? screenData.screen_id
34
- : 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
35
37
  };
36
38
 
37
- function colorIsNotTransparent(color) {
38
- const layers = R.compose(
39
- R.map(R.trim),
40
- R.split(","),
41
- R.replace(")", ""),
42
- R.replace("rgba(", "")
43
- )(color);
44
-
45
- const alpha = Number(layers?.[3]);
46
-
47
- return alpha > 0;
48
- }
49
-
50
- function isValidColor(string) {
51
- return string && string !== "transparent" && colorIsNotTransparent(string);
52
- }
53
-
54
39
  type Props = {
55
- setToggleMenu: () => void;
56
- setCloseMenu: () => void;
40
+ pathname: unknown;
41
+ screenData: unknown;
57
42
  };
58
43
 
59
- export function Screen({ setToggleMenu, setCloseMenu }: Props) {
44
+ export function Screen(_props: Props) {
60
45
  const theme = useTheme<BaseThemePropertiesMobile>();
61
46
  const navigation = useNavigation();
62
47
  const { plugins } = usePickFromState(["plugins"]);
@@ -64,31 +49,35 @@ export function Screen({ setToggleMenu, setCloseMenu }: Props) {
64
49
  // Gets the data for the current screen configuration
65
50
  const currentScreenData = useCurrentScreenData();
66
51
  const { backgroundColor } = useScreenConfiguration(currentScreenData.id);
67
- const insets = useSafeAreaInsets();
68
52
 
69
- const { width: screenWidth } = useDimensions("screen", {
53
+ const {
54
+ width: screenWidth,
55
+ height,
56
+ deviceInfo,
57
+ } = useDimensions("screen", {
70
58
  fullDimensions: true,
71
59
  });
72
60
 
73
- const routeData = useRoute();
61
+ const { screenData, pathname } = useRoute();
74
62
 
75
63
  const currentRiver = useScreenData(
76
- getScreenId(routeData.screenData, navigation.activeRiver)
64
+ getScreenId(screenData, navigation.activeRiver)
77
65
  );
78
66
 
79
67
  const { title } = useNavbarState();
80
68
 
81
- const navBarProps = React.useMemo(
82
- () => ({
83
- ...getNavigationPropsV2({
84
- currentRiver,
85
- title,
86
- category: "nav_bar",
87
- }),
88
- setToggleMenu,
89
- setCloseMenu,
90
- }),
91
- [currentRiver, setCloseMenu, setToggleMenu]
69
+ const isTablet = deviceInfo?.isTablet;
70
+
71
+ const { appData } = usePickFromState(["appData"]);
72
+ const isTabletPortrait = appData?.isTabletPortrait;
73
+
74
+ const layoutData = { isTablet, isTabletPortrait, width: screenWidth, height };
75
+
76
+ const hasMenu = shouldNavBarDisplayMenu(currentRiver, plugins);
77
+
78
+ const navBarProps = React.useMemo<MobileNavBarPluginProps | null>(
79
+ getNavBarProps(currentRiver, pathname, title),
80
+ [currentRiver, pathname]
92
81
  );
93
82
 
94
83
  const NavBar = React.useMemo(
@@ -97,12 +86,10 @@ export function Screen({ setToggleMenu, setCloseMenu }: Props) {
97
86
  "nav_bar",
98
87
  currentRiver,
99
88
  plugins
100
- ) as React.ComponentType<MobileNavBarPluginProps>,
89
+ ) as React.ComponentType<MobileNavBarPluginProps & { hasMenu: boolean }>,
101
90
  []
102
91
  );
103
92
 
104
- const { screenData, pathname } = routeData;
105
-
106
93
  const offlinePlugin = getComponentModule({
107
94
  plugins,
108
95
  components: {},
@@ -113,35 +100,38 @@ export function Screen({ setToggleMenu, setCloseMenu }: Props) {
113
100
 
114
101
  const style = React.useMemo(
115
102
  () => ({
116
- flex: 1,
103
+ ...screenStyles,
117
104
  backgroundColor: isValidColor(backgroundColor)
118
105
  ? backgroundColor
119
106
  : theme.app_background_color,
120
- paddingTop: 0,
121
- // paddingBottom: insets.bottom, // Should be applied directly by UI plugin
122
- // paddingLeft: insets.left, // Should be applied directly by UI plugin
123
- // paddingRight: insets.right, // Should be applied directly by UI plugin
124
107
  }),
125
- [insets, screenWidth, theme.app_background_color, backgroundColor]
108
+ [theme.app_background_color, backgroundColor]
126
109
  );
127
110
 
128
111
  const targetScreenData =
129
112
  currentScreenData || (screenData as any)?.targetScreen || screenData;
130
113
 
131
- useScreenOrientationHandler({ screenData: targetScreenData });
114
+ const orientation = useGetScreenOrientation(targetScreenData);
115
+
116
+ // We prevent rendering of the screen until UI is actually rotated to screen desired orientation.
117
+ // This saves unnecessary re-renders and user will not see distorted aspect screen.
118
+ if (
119
+ !isOrientationCompatible({
120
+ orientation,
121
+ layoutData,
122
+ })
123
+ ) {
124
+ return <View style={style} />;
125
+ }
132
126
 
133
127
  return (
134
- <ScreenContextProvider pathname={pathname}>
135
- <View style={style}>
136
- <NavBar
137
- {...{ ...(navBarProps as MobileNavBarPluginProps), id: pathname }}
138
- />
139
-
140
- <OfflineFallbackScreen screenData={targetScreenData}>
141
- {/* @TODO RouteManager doesn't use props, can they be removed ? */}
142
- <RouteManager pathname={pathname} screenData={screenData} />
143
- </OfflineFallbackScreen>
144
- </View>
145
- </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>
146
136
  );
147
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
+ }