@applicaster/zapp-react-native-ui-components 15.0.0-alpha.5219062121 → 15.0.0-alpha.5262500595

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 (136) hide show
  1. package/Components/Cell/TvOSCellComponent.tsx +1 -3
  2. package/Components/GeneralContentScreen/GeneralContentScreen.tsx +39 -28
  3. package/Components/GeneralContentScreen/__tests__/GeneralContentScreen.test.tsx +104 -0
  4. package/Components/GeneralContentScreen/utils/__tests__/getScreenDataSource.test.ts +19 -0
  5. package/Components/GeneralContentScreen/utils/getScreenDataSource.ts +9 -0
  6. package/Components/HandlePlayable/HandlePlayable.tsx +16 -29
  7. package/Components/HookRenderer/HookRenderer.tsx +40 -10
  8. package/Components/HookRenderer/__tests__/HookRenderer.test.tsx +60 -0
  9. package/Components/Layout/TV/NavBarContainer.tsx +1 -10
  10. package/Components/Layout/TV/__tests__/__snapshots__/NavBarContainer.test.tsx.snap +7 -12
  11. package/Components/Layout/TV/__tests__/__snapshots__/ScreenContainer.test.tsx.snap +7 -12
  12. package/Components/Layout/TV/__tests__/__snapshots__/index.test.tsx.snap +5 -0
  13. package/Components/MasterCell/CONFIG_BUILDER_TO_REACT_COMPONENT.md +144 -0
  14. package/Components/MasterCell/DefaultComponents/ActionButtonsCore/__tests__/model.test.ts +80 -0
  15. package/Components/MasterCell/DefaultComponents/ActionButtonsCore/__tests__/placement.test.ts +187 -0
  16. package/Components/MasterCell/DefaultComponents/ActionButtonsCore/__tests__/selectors.test.ts +45 -0
  17. package/Components/MasterCell/DefaultComponents/ActionButtonsCore/__tests__/style.test.ts +49 -0
  18. package/Components/MasterCell/DefaultComponents/ActionButtonsCore/components/ActionButtonController.tsx +165 -0
  19. package/Components/MasterCell/DefaultComponents/ActionButtonsCore/components/__tests__/ActionButtonController.test.tsx +405 -0
  20. package/Components/MasterCell/DefaultComponents/ActionButtonsCore/components/index.ts +1 -0
  21. package/Components/MasterCell/DefaultComponents/ActionButtonsCore/model.ts +47 -0
  22. package/Components/MasterCell/DefaultComponents/ActionButtonsCore/placement.ts +170 -0
  23. package/Components/MasterCell/DefaultComponents/ActionButtonsCore/selectors.ts +26 -0
  24. package/Components/MasterCell/DefaultComponents/ActionButtonsCore/style.ts +29 -0
  25. package/Components/MasterCell/DefaultComponents/ActionButtonsCore/types.ts +37 -0
  26. package/Components/MasterCell/DefaultComponents/Button.tsx +0 -15
  27. package/Components/MasterCell/DefaultComponents/ButtonContainerView/components/HorizontalSeparator.tsx +8 -0
  28. package/Components/MasterCell/DefaultComponents/ButtonContainerView/index.tsx +15 -0
  29. package/Components/MasterCell/DefaultComponents/ButtonContainerView/index.tv.android.tsx +58 -0
  30. package/Components/MasterCell/DefaultComponents/{tv/ButtonContainerView/index.tsx → ButtonContainerView/index.tv.tsx} +3 -11
  31. package/Components/MasterCell/DefaultComponents/ButtonContainerView/index.web.ts +1 -0
  32. package/Components/MasterCell/DefaultComponents/ButtonContainerView/types.ts +40 -0
  33. package/Components/MasterCell/DefaultComponents/DataProvider/index.tsx +163 -0
  34. package/Components/MasterCell/DefaultComponents/FocusableView/index.android.tsx +2 -23
  35. package/Components/MasterCell/DefaultComponents/FocusableView/index.tsx +4 -22
  36. package/Components/MasterCell/DefaultComponents/Image/Image.android.tsx +3 -1
  37. package/Components/MasterCell/DefaultComponents/LiveImage/__tests__/prepareEntry.test.ts +352 -0
  38. package/Components/MasterCell/DefaultComponents/LiveImage/executePreloadHooks.ts +136 -0
  39. package/Components/MasterCell/DefaultComponents/LiveImage/index.tsx +33 -16
  40. package/Components/MasterCell/DefaultComponents/PressableView.tsx +34 -0
  41. package/Components/MasterCell/DefaultComponents/Text/hooks/useText.ts +11 -0
  42. package/Components/MasterCell/DefaultComponents/Text/index.tsx +2 -6
  43. package/Components/MasterCell/DefaultComponents/__tests__/DataProvider.test.tsx +141 -0
  44. package/Components/MasterCell/DefaultComponents/index.ts +9 -3
  45. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/ActionButton.tsx +135 -0
  46. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/Asset.ts +33 -0
  47. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/AssetComponent.tsx +22 -0
  48. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/Button.ts +125 -0
  49. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/Spacer.ts +16 -0
  50. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/TextLabel.ts +67 -0
  51. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/TextLabelsContainer.ts +37 -0
  52. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/__tests__/PressableView.test.tsx +393 -0
  53. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/__tests__/builders.test.ts +141 -0
  54. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/__tests__/index.test.ts +343 -0
  55. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/helpers.ts +105 -0
  56. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/index.ts +122 -0
  57. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/utils/__tests__/insertButtons.test.ts +118 -0
  58. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/utils/index.ts +238 -0
  59. package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/Asset.ts +4 -18
  60. package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/Button.ts +24 -73
  61. package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/TextLabelsContainer.ts +37 -18
  62. package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/TvActionButton.tsx +27 -0
  63. package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/__tests__/index.test.ts +89 -0
  64. package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/__tests__/renderedTree.test.tsx +231 -0
  65. package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/index.ts +47 -52
  66. package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/utils/__tests__/getPluginIdentifier.test.ts +35 -171
  67. package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/utils/index.ts +98 -145
  68. package/Components/MasterCell/MappingFunctions/index.js +3 -2
  69. package/Components/MasterCell/README.md +4 -0
  70. package/Components/MasterCell/__tests__/__snapshots__/dataAdapter.test.js.snap +24 -0
  71. package/Components/MasterCell/__tests__/configInflater.test.js +1 -0
  72. package/Components/MasterCell/__tests__/elementMapper.test.js +46 -0
  73. package/Components/MasterCell/dataAdapter.ts +4 -1
  74. package/Components/MasterCell/elementMapper.tsx +52 -7
  75. package/Components/MasterCell/utils/__tests__/cloneChildrenWithIds.test.tsx +43 -0
  76. package/Components/MasterCell/utils/__tests__/useFilterChildren.test.tsx +80 -0
  77. package/Components/MasterCell/utils/index.ts +85 -15
  78. package/Components/Navigator/StackNavigator.tsx +6 -0
  79. package/Components/PlayerContainer/PlayerContainer.tsx +2 -18
  80. package/Components/PreloaderWrapper/__tests__/index.test.tsx +26 -0
  81. package/Components/PreloaderWrapper/index.tsx +15 -0
  82. package/Components/River/ComponentsMap/ComponentsMap.tsx +2 -16
  83. package/Components/River/RefreshControl.tsx +19 -82
  84. package/Components/River/River.tsx +9 -82
  85. package/Components/River/RiverItem.tsx +26 -20
  86. package/Components/River/hooks/__tests__/usePullToRefresh.test.ts +132 -0
  87. package/Components/River/hooks/index.ts +1 -0
  88. package/Components/River/hooks/usePullToRefresh.ts +51 -0
  89. package/Components/Screen/__tests__/Screen.test.tsx +1 -0
  90. package/Components/Screen/hooks.ts +73 -3
  91. package/Components/Screen/index.tsx +7 -1
  92. package/Components/ScreenFeedLoader/ScreenFeedLoader.tsx +46 -0
  93. package/Components/ScreenFeedLoader/__tests__/ScreenFeedLoader.test.tsx +94 -0
  94. package/Components/ScreenFeedLoader/index.ts +1 -0
  95. package/Components/ScreenResolver/__tests__/screenResolver.test.js +24 -0
  96. package/Components/ScreenResolver/hooks/index.ts +3 -0
  97. package/Components/ScreenResolver/hooks/useGetComponent.ts +15 -0
  98. package/Components/ScreenResolver/hooks/useScreenComponentResolver.tsx +90 -0
  99. package/Components/ScreenResolver/index.tsx +15 -117
  100. package/Components/ScreenResolver/utils/__tests__/getScreenTypeProps.test.ts +45 -0
  101. package/Components/ScreenResolver/utils/getScreenTypeProps.ts +43 -0
  102. package/Components/ScreenResolver/utils/index.ts +1 -0
  103. package/Components/ScreenResolver/withDefaultScreenContext.tsx +16 -0
  104. package/Components/ScreenResolverFeedProvider/ScreenResolverFeedProvider.tsx +25 -0
  105. package/Components/ScreenResolverFeedProvider/__tests__/ScreenResolverFeedProvider.test.tsx +44 -0
  106. package/Components/ScreenResolverFeedProvider/index.ts +1 -0
  107. package/Components/ScreenRevealManager/withScreenRevealManager.tsx +4 -1
  108. package/Components/TopCutoffOverlay/__tests__/TopCutoffOverlay.test.tsx +201 -0
  109. package/Components/TopCutoffOverlay/hooks/__tests__/useMarginTop.test.ts +130 -0
  110. package/Components/TopCutoffOverlay/hooks/index.ts +1 -0
  111. package/Components/TopCutoffOverlay/hooks/useMarginTop.ts +59 -0
  112. package/Components/TopCutoffOverlay/index.tsx +55 -0
  113. package/Components/Transitioner/Scene.tsx +9 -15
  114. package/Components/VideoLive/LiveImageManager.ts +199 -54
  115. package/Components/VideoLive/PlayerLiveImageComponent.tsx +31 -33
  116. package/Components/VideoLive/__tests__/PlayerLiveImageComponent.test.tsx +2 -17
  117. package/Components/Viewport/ViewportAware/__tests__/viewportAware.test.js +0 -2
  118. package/Components/ZappUIComponent/index.tsx +12 -6
  119. package/Components/default-cell-renderer/viewTrees/mobile/index.ts +0 -3
  120. package/Components/index.js +1 -1
  121. package/Contexts/ScreenContext/__tests__/index.test.tsx +57 -0
  122. package/Contexts/ScreenContext/index.tsx +46 -1
  123. package/Contexts/ZappPipesContext/ZappPipesContextFactory.tsx +18 -7
  124. package/Decorators/ZappPipesDataConnector/ResolverSelector.tsx +25 -7
  125. package/Decorators/ZappPipesDataConnector/__tests__/ResolverSelector.test.tsx +212 -5
  126. package/Decorators/ZappPipesDataConnector/__tests__/UrlFeedResolver.test.tsx +39 -21
  127. package/Decorators/ZappPipesDataConnector/resolvers/UrlFeedResolver.tsx +18 -7
  128. package/package.json +5 -5
  129. package/Components/MasterCell/DefaultComponents/Text/utils/__tests__/withAdjustedLineHeight.test.ts +0 -46
  130. package/Components/MasterCell/DefaultComponents/Text/utils/index.ts +0 -21
  131. package/Components/MasterCell/DefaultComponents/tv/ButtonContainerView/index.android.tsx +0 -135
  132. package/Components/MasterCell/DefaultComponents/tv/ButtonContainerView/types.ts +0 -25
  133. package/Components/PlayerContainer/ErrorDisplay/ErrorDisplay.tsx +0 -57
  134. package/Components/PlayerContainer/ErrorDisplay/index.ts +0 -9
  135. package/Components/PlayerContainer/useRestrictMobilePlayback.tsx +0 -131
  136. /package/Components/HookRenderer/{index.tsx → index.ts} +0 -0
@@ -195,7 +195,6 @@ class TvOSCell extends React.Component<Props, State> {
195
195
  groupId,
196
196
  component,
197
197
  index,
198
- componentsMapOffset,
199
198
  } = this.props;
200
199
 
201
200
  this.setScreenLayout(componentAnchorPointY, screenLayout);
@@ -222,8 +221,7 @@ class TvOSCell extends React.Component<Props, State> {
222
221
  const totalOffset =
223
222
  headerOffset +
224
223
  toNumberWithDefaultZero(componentAnchorPointY) +
225
- extraAnchorPointYOffset -
226
- toNumberWithDefaultZero(componentsMapOffset) +
224
+ extraAnchorPointYOffset +
227
225
  componentMarginTop +
228
226
  componentPaddingTop;
229
227
 
@@ -12,12 +12,26 @@ import { createLogger } from "@applicaster/zapp-react-native-utils/logger";
12
12
  import { isNilOrEmpty } from "@applicaster/zapp-react-native-utils/reactUtils/helpers";
13
13
  import { ScreenTrackedViewPositionsContext } from "@applicaster/zapp-react-native-ui-components/Contexts/ScreenTrackedViewPositionsContext";
14
14
  import { useEventAlerts } from "./utils/useEventAlerts";
15
-
16
- const { log_info } = createLogger({
15
+ import {
16
+ selectRiverById,
17
+ useAppSelector,
18
+ } from "@applicaster/zapp-react-native-redux";
19
+ import { getScreenDataSource } from "./utils/getScreenDataSource";
20
+ import { ScreenResolverFeedProvider } from "../ScreenResolverFeedProvider/ScreenResolverFeedProvider";
21
+
22
+ const { log_debug } = createLogger({
17
23
  category: "ScreenContainer",
18
24
  subsystem: "General",
19
25
  });
20
26
 
27
+ /** Provides screen-feed from general-screen configuration (if defined) */
28
+ const useFeedData = (id) => {
29
+ const river = useAppSelector((state) => selectRiverById(state, id));
30
+ const feedData = getScreenDataSource(river);
31
+
32
+ return feedData;
33
+ };
34
+
21
35
  export const GeneralContentScreen = ({
22
36
  feed,
23
37
  screenId,
@@ -54,20 +68,15 @@ export const GeneralContentScreen = ({
54
68
  useEffect(() => {
55
69
  if (!riverActionProvidersReady) {
56
70
  if (actionsInitialStateSetters.length > 0) {
57
- log_info(
58
- "ScreenContainer: starting to check river action providers to initialize",
59
- { actionsInitialStateSetters }
60
- );
61
-
62
71
  allSettled(actionsInitialStateSetters).finally(() => {
63
- log_info(
72
+ log_debug(
64
73
  "ScreenContainer: action provider ready, completed. Starting to present screen"
65
74
  );
66
75
 
67
76
  setRiverActionProvidersReady(true);
68
77
  });
69
78
  } else {
70
- log_info(
79
+ log_debug(
71
80
  "ScreenContainer: no action provider to check, completed. Starting to present screen"
72
81
  );
73
82
 
@@ -108,24 +117,26 @@ export const GeneralContentScreen = ({
108
117
  if (!isReady || isNilOrEmpty(components || uiComponents)) return null;
109
118
 
110
119
  return (
111
- <ScreenTrackedViewPositionsContext.Provider>
112
- <CellTapContext.Provider value={contextValue}>
113
- <ComponentsMap
114
- feed={feed}
115
- riverId={screenId}
116
- groupId={groupId || `general-content-screen-${screenId}`}
117
- riverComponents={components || uiComponents}
118
- scrollViewExtraProps={scrollViewExtraProps}
119
- getStaticComponentFeed={getStaticComponentFeed}
120
- extraAnchorPointYOffset={extraAnchorPointYOffset}
121
- isScreenWrappedInContainer={isScreenWrappedInContainer}
122
- parentFocus={parentFocus}
123
- focused={focused}
124
- containerHeight={containerHeight}
125
- preferredFocus={preferredFocus}
126
- {...componentsMapExtraProps}
127
- />
128
- </CellTapContext.Provider>
129
- </ScreenTrackedViewPositionsContext.Provider>
120
+ <ScreenResolverFeedProvider id={screenId} useFeedData={useFeedData}>
121
+ <ScreenTrackedViewPositionsContext.Provider>
122
+ <CellTapContext.Provider value={contextValue}>
123
+ <ComponentsMap
124
+ feed={feed}
125
+ riverId={screenId}
126
+ groupId={groupId || `general-content-screen-${screenId}`}
127
+ riverComponents={components || uiComponents}
128
+ scrollViewExtraProps={scrollViewExtraProps}
129
+ getStaticComponentFeed={getStaticComponentFeed}
130
+ extraAnchorPointYOffset={extraAnchorPointYOffset}
131
+ isScreenWrappedInContainer={isScreenWrappedInContainer}
132
+ parentFocus={parentFocus}
133
+ focused={focused}
134
+ containerHeight={containerHeight}
135
+ preferredFocus={preferredFocus}
136
+ {...componentsMapExtraProps}
137
+ />
138
+ </CellTapContext.Provider>
139
+ </ScreenTrackedViewPositionsContext.Provider>
140
+ </ScreenResolverFeedProvider>
130
141
  );
131
142
  };
@@ -0,0 +1,104 @@
1
+ import React from "react";
2
+ import { render } from "@testing-library/react-native";
3
+ import { GeneralContentScreen } from "../GeneralContentScreen";
4
+
5
+ const mockUseAppSelector = jest.fn();
6
+ const mockSelectRiverById = jest.fn();
7
+ const mockProviderSpy = jest.fn();
8
+
9
+ jest.mock("../../River/ComponentsMap", () => ({
10
+ ComponentsMap: () => {
11
+ const React = require("react");
12
+ const { View } = require("react-native");
13
+
14
+ return <View testID="components-map" />;
15
+ },
16
+ }));
17
+
18
+ jest.mock("@applicaster/zapp-react-native-utils/reactHooks/actions", () => ({
19
+ useActions: jest.fn(() => jest.fn()),
20
+ }));
21
+
22
+ jest.mock("../utils", () => ({
23
+ logger: { warn: jest.fn() },
24
+ whenMatchingType: jest.fn((_type, value) => value),
25
+ }));
26
+
27
+ jest.mock("@applicaster/zapp-react-native-utils/reactHooks/layout", () => ({
28
+ useLayoutVersion: jest.fn(() => false),
29
+ }));
30
+
31
+ jest.mock(
32
+ "@applicaster/zapp-react-native-utils/reactHooks/screen/useScreenData",
33
+ () => ({
34
+ useScreenData: jest.fn(() => ({
35
+ ui_components: [{ id: "ui-component" }],
36
+ general: {},
37
+ })),
38
+ })
39
+ );
40
+
41
+ jest.mock("../utils/useCurationAPI", () => ({
42
+ useCurationAPI: jest.fn(() => [{ id: "curation-component" }]),
43
+ }));
44
+
45
+ jest.mock("@applicaster/quick-brick-core/App/ActionSetters", () => ({
46
+ useRiverInitialState: jest.fn(() => []),
47
+ }));
48
+
49
+ jest.mock("../utils/useEventAlerts", () => ({
50
+ useEventAlerts: jest.fn(),
51
+ }));
52
+
53
+ jest.mock("@applicaster/zapp-react-native-redux", () => ({
54
+ useAppSelector: (...args) => mockUseAppSelector(...args),
55
+ selectRiverById: (...args) => mockSelectRiverById(...args),
56
+ }));
57
+
58
+ jest.mock("../utils/getScreenDataSource", () => ({
59
+ getScreenDataSource: jest.fn(() => ({
60
+ source: "https://feed",
61
+ mapping: {},
62
+ })),
63
+ }));
64
+
65
+ jest.mock(
66
+ "../../ScreenResolverFeedProvider/ScreenResolverFeedProvider",
67
+ () => ({
68
+ ScreenResolverFeedProvider: ({ id, useFeedData, children }) => {
69
+ const React = require("react");
70
+ const { View } = require("react-native");
71
+
72
+ mockProviderSpy(id, useFeedData);
73
+ useFeedData(id);
74
+
75
+ return <View testID="screen-resolver-feed-provider">{children}</View>;
76
+ },
77
+ })
78
+ );
79
+
80
+ describe("GeneralContentScreen", () => {
81
+ beforeEach(() => {
82
+ jest.clearAllMocks();
83
+ mockUseAppSelector.mockImplementation((selector) => selector({}));
84
+ mockSelectRiverById.mockReturnValue({ id: "screen-1" });
85
+ });
86
+
87
+ it("wraps content with ScreenResolverFeedProvider and renders ComponentsMap", () => {
88
+ const { getByTestId } = render(
89
+ <GeneralContentScreen
90
+ screenId="screen-1"
91
+ feed={null}
92
+ components={[{ id: "component-1" }]}
93
+ />
94
+ );
95
+
96
+ expect(getByTestId("screen-resolver-feed-provider")).toBeDefined();
97
+ expect(getByTestId("components-map")).toBeDefined();
98
+
99
+ expect(mockProviderSpy).toHaveBeenCalledWith(
100
+ "screen-1",
101
+ expect.any(Function)
102
+ );
103
+ });
104
+ });
@@ -0,0 +1,19 @@
1
+ import { getScreenDataSource } from "../getScreenDataSource";
2
+
3
+ describe("getScreenDataSource", () => {
4
+ it("returns screen_feed data when present", () => {
5
+ const result = getScreenDataSource({
6
+ data: {
7
+ screen_feed: {
8
+ source: "https://feed",
9
+ },
10
+ },
11
+ });
12
+
13
+ expect(result).toEqual({ source: "https://feed" });
14
+ });
15
+
16
+ it("returns undefined when screen_feed is missing", () => {
17
+ expect(getScreenDataSource({ data: {} })).toBeUndefined();
18
+ });
19
+ });
@@ -0,0 +1,9 @@
1
+ import { get } from "@applicaster/zapp-react-native-utils/utils";
2
+
3
+ const lookupPath = ["data", "screen_feed"];
4
+
5
+ export const getScreenDataSource = (
6
+ screenData: any
7
+ ): Option<ZappDataSource> => {
8
+ return get(screenData, lookupPath) as ZappDataSource | undefined;
9
+ };
@@ -5,8 +5,6 @@ import {
5
5
  usePlugins,
6
6
  } from "@applicaster/zapp-react-native-redux/hooks";
7
7
  import {
8
- useDimensions,
9
- useIsTablet as isTablet,
10
8
  useNavigation,
11
9
  useRivers,
12
10
  } from "@applicaster/zapp-react-native-utils/reactHooks";
@@ -15,8 +13,8 @@ import { BufferAnimation } from "../PlayerContainer/BufferAnimation";
15
13
  import { PlayerContainer } from "../PlayerContainer";
16
14
  import { useModalSize } from "../VideoModal/hooks";
17
15
  import { ViewStyle } from "react-native";
18
- import { platformSelect } from "@applicaster/zapp-react-native-utils/reactUtils";
19
16
  import { findCastPlugin, getPlayer } from "./utils";
17
+ import { useWaitForValidOrientation } from "../Screen/hooks";
20
18
 
21
19
  type Props = {
22
20
  item: ZappEntry;
@@ -31,13 +29,6 @@ type PlayableComponent = {
31
29
  Component: React.ComponentType<any>;
32
30
  };
33
31
 
34
- const dimensionsContext: "window" | "screen" = platformSelect({
35
- android_tv: "window",
36
- amazon: "window",
37
- // eslint-disable-next-line react-hooks/rules-of-hooks
38
- default: isTablet() ? "window" : "screen", // on tablet, window represents correct values, on phone it's not as the screen could be rotated
39
- });
40
-
41
32
  export function HandlePlayable({
42
33
  item,
43
34
  isModal,
@@ -97,27 +88,23 @@ export function HandlePlayable({
97
88
  });
98
89
  }, [casting]);
99
90
 
100
- const { width: screenWidth, height: screenHeight } =
101
- useDimensions(dimensionsContext);
102
-
103
91
  const modalSize = useModalSize();
104
92
 
105
- const style = React.useMemo(
106
- () =>
107
- ({
108
- width: isModal
109
- ? modalSize.width
110
- : mode === "PIP"
111
- ? "100%"
112
- : screenWidth,
113
- height: isModal
114
- ? modalSize.height
115
- : mode === "PIP"
116
- ? "100%"
117
- : screenHeight,
118
- }) as ViewStyle,
119
- [screenWidth, screenHeight, modalSize, isModal, mode]
120
- );
93
+ const isOrientationReady = useWaitForValidOrientation();
94
+
95
+ const style = React.useMemo(() => {
96
+ const isFullScreenReady =
97
+ mode === "PIP" || (mode === "FULLSCREEN" && isOrientationReady);
98
+
99
+ const getDimensionValue = (value: string | number) => {
100
+ return isModal ? value : isFullScreenReady ? "100%" : 0; // do not show player, until full screen mode is ready
101
+ };
102
+
103
+ return {
104
+ width: getDimensionValue(modalSize.width),
105
+ height: getDimensionValue(modalSize.height),
106
+ } as ViewStyle;
107
+ }, [modalSize, isModal, mode, isOrientationReady]);
121
108
 
122
109
  const Component = playable?.Component;
123
110
 
@@ -6,7 +6,12 @@ import {
6
6
  } from "@applicaster/zapp-react-native-utils/reactHooks/navigation";
7
7
  import { useHookAnalytics } from "@applicaster/zapp-react-native-utils/analyticsUtils/helpers/hooks";
8
8
  import { useSetNavbarState } from "@applicaster/zapp-react-native-utils/reactHooks";
9
- import { PresentationType } from "../ScreenResolver";
9
+
10
+ import { componentsLogger } from "../../Helpers/logger";
11
+
12
+ const logger = componentsLogger.addSubsystem("HookRenderer");
13
+
14
+ const HOOK_PRESENTATION_TYPE = "Hook";
10
15
 
11
16
  type Props = {
12
17
  focused?: boolean;
@@ -15,20 +20,17 @@ type Props = {
15
20
  callback: hookCallback;
16
21
  };
17
22
 
18
- export const HookRenderer = (props: Props) => {
19
- const {
20
- focused,
21
- screenData: { payload, hookPlugin },
22
- callback,
23
- } = props;
24
-
25
- const { setVisible: showNavBar } = useSetNavbarState();
23
+ const HookRenderer = (props: Props) => {
24
+ const { focused, screenData, callback } = props;
25
+ const { payload, hookPlugin } = screenData;
26
26
 
27
27
  const {
28
28
  module: { Component: HookComponent, presentFullScreen },
29
29
  configuration,
30
30
  } = hookPlugin;
31
31
 
32
+ const { setVisible: showNavBar } = useSetNavbarState();
33
+
32
34
  useHookAnalytics(props);
33
35
 
34
36
  const isNavBarVisible = useIsNavBarVisible();
@@ -63,8 +65,36 @@ export const HookRenderer = (props: Props) => {
63
65
  hookPlugin,
64
66
  focused,
65
67
  parentFocus,
66
- presentationType: PresentationType.Hook,
68
+ presentationType: HOOK_PRESENTATION_TYPE,
67
69
  }}
68
70
  />
69
71
  );
70
72
  };
73
+
74
+ /**
75
+ * Guard component to prevent rendering HookRenderer when screenData or hookPlugin is missing. This is to avoid potential crashes due to missing data.
76
+ */
77
+ const HookRendererGuard = (props: Props) => {
78
+ React.useEffect(() => {
79
+ if (!props.screenData) {
80
+ logger.error(
81
+ "HookRenderer received no screenData, screen cannot be rendered"
82
+ );
83
+ } else if (!props.screenData.hookPlugin) {
84
+ logger.error(
85
+ "HookRenderer received screenData with no hookPlugin, screen cannot be rendered",
86
+ {
87
+ screenData: props.screenData,
88
+ }
89
+ );
90
+ }
91
+ }, [props.screenData]);
92
+
93
+ if (!props.screenData || !props.screenData.hookPlugin) {
94
+ return null;
95
+ }
96
+
97
+ return <HookRenderer {...props} />;
98
+ };
99
+
100
+ export { HookRendererGuard as HookRenderer };
@@ -0,0 +1,60 @@
1
+ import React from "react";
2
+ import { View } from "react-native";
3
+ import { render } from "@testing-library/react-native";
4
+ import { HookRenderer } from "..";
5
+
6
+ jest.mock("@applicaster/zapp-react-native-utils/reactUtils", () => ({
7
+ isTV: jest.fn(() => false),
8
+ }));
9
+
10
+ jest.mock("@applicaster/zapp-react-native-utils/reactHooks/navigation", () => ({
11
+ useBackHandler: jest.fn(),
12
+ useIsNavBarVisible: jest.fn(() => true),
13
+ }));
14
+
15
+ jest.mock(
16
+ "@applicaster/zapp-react-native-utils/analyticsUtils/helpers/hooks",
17
+ () => ({
18
+ useHookAnalytics: jest.fn(),
19
+ })
20
+ );
21
+
22
+ jest.mock("@applicaster/zapp-react-native-utils/reactHooks", () => ({
23
+ useSetNavbarState: jest.fn(() => ({
24
+ setVisible: jest.fn(),
25
+ })),
26
+ }));
27
+
28
+ describe("HookRenderer", () => {
29
+ it("returns null when hookPlugin is missing", () => {
30
+ const { toJSON } = render(
31
+ <HookRenderer callback={jest.fn()} screenData={{ payload: {} } as any} />
32
+ );
33
+
34
+ expect(toJSON()).toBeNull();
35
+ });
36
+
37
+ it("passes Hook presentationType to rendered hook component", () => {
38
+ const HookComponent = (props) => (
39
+ <View testID="hook-component" {...props} />
40
+ );
41
+
42
+ const { getByTestId } = render(
43
+ <HookRenderer
44
+ callback={jest.fn()}
45
+ screenData={{
46
+ payload: { foo: "bar" },
47
+ hookPlugin: {
48
+ module: {
49
+ Component: HookComponent,
50
+ presentFullScreen: false,
51
+ },
52
+ configuration: {},
53
+ },
54
+ }}
55
+ />
56
+ );
57
+
58
+ expect(getByTestId("hook-component").props.presentationType).toBe("Hook");
59
+ });
60
+ });
@@ -15,12 +15,6 @@ const styles = StyleSheet.create({
15
15
  flex: 1,
16
16
  width: "100%",
17
17
  },
18
- themeStyles: {
19
- // limits the height of the focusable container of the TopMenuBarTV component
20
- // to prevent it from being overlapped by the screen content,
21
- // as it makes TopMenuBarTV unfocusable on tvOS
22
- maxHeight: 1,
23
- },
24
18
  });
25
19
 
26
20
  export const NavBarContainer = ({ children, isVisible, onReady }: Props) => {
@@ -31,10 +25,7 @@ export const NavBarContainer = ({ children, isVisible, onReady }: Props) => {
31
25
  }, [onReady]);
32
26
 
33
27
  return isVisible ? (
34
- <View
35
- testID="nav-bar-container"
36
- style={[styles.container, styles.themeStyles]}
37
- >
28
+ <View testID="nav-bar-container" style={styles.container}>
38
29
  {children}
39
30
  </View>
40
31
  ) : null;
@@ -3,18 +3,13 @@
3
3
  exports[`NavBarContainer renders 1`] = `
4
4
  <View
5
5
  style={
6
- [
7
- {
8
- "flex": 1,
9
- "position": "absolute",
10
- "top": 0,
11
- "width": "100%",
12
- "zIndex": 10,
13
- },
14
- {
15
- "maxHeight": 1,
16
- },
17
- ]
6
+ {
7
+ "flex": 1,
8
+ "position": "absolute",
9
+ "top": 0,
10
+ "width": "100%",
11
+ "zIndex": 10,
12
+ }
18
13
  }
19
14
  testID="nav-bar-container"
20
15
  >
@@ -14,18 +14,13 @@ exports[`ScreenContainer renders 1`] = `
14
14
  >
15
15
  <View
16
16
  style={
17
- [
18
- {
19
- "flex": 1,
20
- "position": "absolute",
21
- "top": 0,
22
- "width": "100%",
23
- "zIndex": 10,
24
- },
25
- {
26
- "maxHeight": 1,
27
- },
28
- ]
17
+ {
18
+ "flex": 1,
19
+ "position": "absolute",
20
+ "top": 0,
21
+ "width": "100%",
22
+ "zIndex": 10,
23
+ }
29
24
  }
30
25
  testID="nav-bar-container"
31
26
  >
@@ -9,6 +9,11 @@ exports[`Layout TV renders 1`] = `
9
9
  excludeFromFocusSearching={true}
10
10
  id="/river/A1234"
11
11
  preferredFocus={true}
12
+ style={
13
+ {
14
+ "flex": 1,
15
+ }
16
+ }
12
17
  >
13
18
  <View
14
19
  Components={