@applicaster/zapp-react-native-ui-components 15.0.0-rc.98 → 15.1.0-alpha.1852552014

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 (138) hide show
  1. package/Components/BackgroundImage/BackgroundImage.tv.android.tsx +28 -0
  2. package/Components/BackgroundImage/BackgroundImage.tv.ios.tsx +24 -0
  3. package/Components/BackgroundImage/BackgroundImage.tv.web.tsx +42 -0
  4. package/Components/BackgroundImage/index.ts +8 -0
  5. package/Components/BaseFocusable/index.ios.ts +2 -12
  6. package/Components/Cell/FocusableWrapper.tsx +0 -3
  7. package/Components/Cell/TvOSCellComponent.tsx +0 -5
  8. package/Components/CellRendererResolver/index.ts +1 -1
  9. package/Components/ComponentResolver/__tests__/componentResolver.test.js +1 -1
  10. package/Components/Focusable/Focusable.tsx +2 -4
  11. package/Components/Focusable/FocusableTvOS.tsx +1 -18
  12. package/Components/Focusable/__tests__/__snapshots__/FocusableTvOS.test.tsx.snap +0 -1
  13. package/Components/FocusableGroup/FocusableTvOS.tsx +12 -37
  14. package/Components/GeneralContentScreen/GeneralContentScreen.tsx +39 -28
  15. package/Components/GeneralContentScreen/__tests__/GeneralContentScreen.test.tsx +104 -0
  16. package/Components/GeneralContentScreen/utils/__tests__/getScreenDataSource.test.ts +19 -0
  17. package/Components/GeneralContentScreen/utils/__tests__/useCurationAPI.test.js +1 -1
  18. package/Components/GeneralContentScreen/utils/getScreenDataSource.ts +9 -0
  19. package/Components/HandlePlayable/HandlePlayable.tsx +24 -42
  20. package/Components/HandlePlayable/utils.ts +31 -0
  21. package/Components/HookRenderer/HookRenderer.tsx +40 -10
  22. package/Components/HookRenderer/__tests__/HookRenderer.test.tsx +60 -0
  23. package/Components/Layout/FullWidthRow.tsx +38 -0
  24. package/Components/Layout/TV/ScreenContainer.tsx +11 -2
  25. package/Components/Layout/TV/__tests__/__snapshots__/index.test.tsx.snap +5 -1
  26. package/Components/Layout/TV/index.tsx +6 -6
  27. package/Components/Layout/TV/index.web.tsx +6 -6
  28. package/Components/LinkHandler/LinkHandler.tsx +2 -2
  29. package/Components/MasterCell/DefaultComponents/BorderContainerView/index.tsx +10 -4
  30. package/Components/MasterCell/DefaultComponents/Image/Image.android.tsx +1 -5
  31. package/Components/MasterCell/DefaultComponents/Image/Image.ios.tsx +3 -11
  32. package/Components/MasterCell/DefaultComponents/Image/Image.web.tsx +1 -9
  33. package/Components/MasterCell/DefaultComponents/Image/hooks/useImage.ts +14 -15
  34. package/Components/MasterCell/DefaultComponents/LiveImage/__tests__/prepareEntry.test.ts +352 -0
  35. package/Components/MasterCell/DefaultComponents/LiveImage/executePreloadHooks.ts +136 -0
  36. package/Components/MasterCell/DefaultComponents/LiveImage/index.tsx +34 -16
  37. package/Components/MasterCell/DefaultComponents/SecondaryImage/hooks/__tests__/useGetImageDimensions.test.ts +6 -7
  38. package/Components/MasterCell/DefaultComponents/Text/index.tsx +2 -6
  39. package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/index.ts +2 -6
  40. package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/utils/__tests__/getPluginIdentifier.test.ts +11 -233
  41. package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/utils/index.ts +15 -19
  42. package/Components/MasterCell/dataAdapter.ts +15 -5
  43. package/Components/MasterCell/index.tsx +10 -1
  44. package/Components/MasterCell/utils/__tests__/resolveColor.test.js +169 -132
  45. package/Components/MasterCell/utils/__tests__/resolveColorForProp.test.js +92 -0
  46. package/Components/MasterCell/utils/index.ts +89 -46
  47. package/Components/Navigator/StackNavigator.tsx +6 -0
  48. package/Components/OfflineHandler/NotificationView/NotificationView.tsx +2 -2
  49. package/Components/OfflineHandler/NotificationView/__tests__/index.test.tsx +18 -17
  50. package/Components/OfflineHandler/__tests__/index.test.tsx +18 -27
  51. package/Components/PlayerContainer/PlayerContainer.tsx +20 -34
  52. package/Components/PlayerContainer/__tests__/PlayerContainer.test.tsx +286 -0
  53. package/Components/PreloaderWrapper/__tests__/index.test.tsx +26 -0
  54. package/Components/PreloaderWrapper/index.tsx +15 -0
  55. package/Components/River/ComponentsMap/ComponentsMap.tsx +15 -0
  56. package/Components/River/ComponentsMap/hooks/__tests__/useLoadingState.test.ts +1 -1
  57. package/Components/River/RefreshControl.tsx +9 -3
  58. package/Components/River/RiverItem.tsx +26 -20
  59. package/Components/River/TV/River.tsx +14 -31
  60. package/Components/River/TV/index.tsx +4 -8
  61. package/Components/River/TV/withTVEventHandler.tsx +36 -0
  62. package/Components/River/__tests__/__snapshots__/componentsMap.test.js.snap +1 -15
  63. package/Components/Screen/TV/hooks/__tests__/useAfterPaint.test.ts +60 -0
  64. package/Components/Screen/TV/hooks/index.ts +2 -0
  65. package/Components/Screen/TV/hooks/useAfterPaint.ts +23 -0
  66. package/Components/Screen/TV/index.web.tsx +18 -11
  67. package/Components/Screen/__tests__/Screen.test.tsx +43 -65
  68. package/Components/Screen/__tests__/__snapshots__/Screen.test.tsx.snap +44 -68
  69. package/Components/Screen/hooks.ts +76 -5
  70. package/Components/Screen/index.tsx +18 -7
  71. package/Components/Screen/orientationHandler.ts +3 -3
  72. package/Components/ScreenFeedLoader/ScreenFeedLoader.tsx +46 -0
  73. package/Components/ScreenFeedLoader/__tests__/ScreenFeedLoader.test.tsx +94 -0
  74. package/Components/ScreenFeedLoader/index.ts +1 -0
  75. package/Components/ScreenResolver/__tests__/screenResolver.test.js +24 -0
  76. package/Components/ScreenResolver/hooks/index.ts +3 -0
  77. package/Components/ScreenResolver/hooks/useGetComponent.ts +15 -0
  78. package/Components/ScreenResolver/hooks/useScreenComponentResolver.tsx +90 -0
  79. package/Components/ScreenResolver/index.tsx +9 -115
  80. package/Components/ScreenResolver/utils/__tests__/getScreenTypeProps.test.ts +45 -0
  81. package/Components/ScreenResolver/utils/getScreenTypeProps.ts +43 -0
  82. package/Components/ScreenResolver/utils/index.ts +1 -0
  83. package/Components/ScreenResolver/withDefaultScreenContext.tsx +16 -0
  84. package/Components/ScreenResolverFeedProvider/ScreenResolverFeedProvider.tsx +25 -0
  85. package/Components/ScreenResolverFeedProvider/__tests__/ScreenResolverFeedProvider.test.tsx +44 -0
  86. package/Components/ScreenResolverFeedProvider/index.ts +1 -0
  87. package/Components/ScreenRevealManager/Overlay.tsx +34 -0
  88. package/Components/ScreenRevealManager/ScreenRevealManager.ts +8 -40
  89. package/Components/ScreenRevealManager/__tests__/Overlay.test.tsx +88 -0
  90. package/Components/ScreenRevealManager/__tests__/ScreenRevealManager.test.ts +69 -86
  91. package/Components/ScreenRevealManager/withScreenRevealManager.tsx +10 -18
  92. package/Components/Tabs/TabContent.tsx +4 -7
  93. package/Components/Transitioner/Scene.tsx +9 -15
  94. package/Components/Transitioner/index.js +3 -3
  95. package/Components/VideoLive/LiveImageManager.ts +209 -53
  96. package/Components/VideoLive/PlayerLiveImageComponent.tsx +32 -32
  97. package/Components/VideoLive/__tests__/PlayerLiveImageComponent.test.tsx +2 -17
  98. package/Components/VideoModal/ModalAnimation/ModalAnimationContext.tsx +5 -5
  99. package/Components/VideoModal/hooks/__tests__/useDelayedPlayerDetails.test.ts +7 -15
  100. package/Components/VideoModal/utils.ts +16 -13
  101. package/Components/Viewport/ViewportEvents/__tests__/viewportEvents.test.js +1 -1
  102. package/Components/ZappFrameworkComponents/BarView/BarView.tsx +12 -5
  103. package/Components/ZappFrameworkComponents/BarView/__tests__/BarView.test.tsx +2 -2
  104. package/Components/ZappUIComponent/index.tsx +12 -6
  105. package/Components/index.js +1 -1
  106. package/Contexts/CachedDimensionsContext/index.ts +17 -2
  107. package/Contexts/ScreenContext/__tests__/index.test.tsx +57 -0
  108. package/Contexts/ScreenContext/index.tsx +64 -26
  109. package/Contexts/ScreenTrackedViewPositionsContext/__tests__/index.test.tsx +1 -1
  110. package/Contexts/ZappPipesContext/ZappPipesContextFactory.tsx +18 -7
  111. package/Decorators/Analytics/index.tsx +5 -6
  112. package/Decorators/ConfigurationWrapper/__tests__/__snapshots__/withConfigurationProvider.test.tsx.snap +0 -1
  113. package/Decorators/ConfigurationWrapper/const.ts +0 -1
  114. package/Decorators/ZappPipesDataConnector/ResolverSelector.tsx +25 -7
  115. package/Decorators/ZappPipesDataConnector/__tests__/ResolverSelector.test.tsx +212 -5
  116. package/Decorators/ZappPipesDataConnector/__tests__/zappPipesDataConnector.test.js +1 -1
  117. package/Decorators/ZappPipesDataConnector/index.tsx +2 -2
  118. package/Decorators/ZappPipesDataConnector/resolvers/StaticFeedResolver.tsx +1 -1
  119. package/Helpers/ComponentCellSelectionHelper/index.js +0 -6
  120. package/Helpers/DataSourceHelper/index.js +19 -0
  121. package/Helpers/index.js +7 -40
  122. package/events/index.ts +2 -0
  123. package/events/scrollEndReached.ts +15 -0
  124. package/package.json +5 -5
  125. package/Components/Layout/TV/LayoutBackground.tsx +0 -31
  126. package/Components/MasterCell/DefaultComponents/Text/utils/__tests__/withAdjustedLineHeight.test.ts +0 -46
  127. package/Components/MasterCell/DefaultComponents/Text/utils/index.ts +0 -21
  128. package/Components/PlayerContainer/ErrorDisplay/ErrorDisplay.tsx +0 -57
  129. package/Components/PlayerContainer/ErrorDisplay/index.ts +0 -9
  130. package/Components/PlayerContainer/useRestrictMobilePlayback.tsx +0 -101
  131. package/Components/River/TV/utils/__tests__/toStringOrEmpty.test.ts +0 -30
  132. package/Components/River/TV/utils/index.ts +0 -4
  133. package/Components/River/TV/withFocusableGroupForContent.tsx +0 -71
  134. package/Components/Screen/utils.ts +0 -16
  135. package/Helpers/Analytics/index.js +0 -95
  136. package/Helpers/DataSourceHelper/__tests__/itemLimitForData.test.ts +0 -80
  137. package/Helpers/DataSourceHelper/index.ts +0 -19
  138. /package/Components/HookRenderer/{index.tsx → index.ts} +0 -0
@@ -1,29 +1,9 @@
1
1
  import * as React from "react";
2
- import { path, prop } from "ramda";
3
- import {
4
- findPluginByType,
5
- findPluginByIdentifier,
6
- } from "@applicaster/zapp-react-native-utils/pluginUtils";
7
- import { HandlePlayable } from "../HandlePlayable";
8
- import { toPascalCase } from "@applicaster/zapp-react-native-utils/stringUtils";
9
- import { HookRenderer } from "../HookRenderer";
10
- import { LinkHandler } from "../LinkHandler";
11
- import { Favorites } from "../Favorites";
12
- import { ZappPipesScreenContext } from "../../Contexts";
2
+
13
3
  import { componentsLogger } from "../../Helpers/logger";
14
- import {
15
- useAppSelector,
16
- usePlugins,
17
- } from "@applicaster/zapp-react-native-redux/hooks";
18
- import {
19
- useNavigation,
20
- useRivers,
21
- } from "@applicaster/zapp-react-native-utils/reactHooks";
22
4
  import { useScreenAnalytics } from "@applicaster/zapp-react-native-utils/analyticsUtils/helpers/hooks";
23
-
24
- import { useCallbackActions } from "@applicaster/zapp-react-native-utils/zappFrameworkUtils/HookCallback/useCallbackActions";
25
- import { ScreenResultCallback } from "@applicaster/zapp-react-native-utils/zappFrameworkUtils/HookCallback/callbackNavigationAction";
26
- import { selectComponents } from "@applicaster/zapp-react-native-redux";
5
+ import { useScreenComponentResolver } from "./hooks/useScreenComponentResolver";
6
+ import { withDefaultScreenContext } from "./withDefaultScreenContext";
27
7
 
28
8
  const logger = componentsLogger.addSubsystem("ScreenResolver");
29
9
 
@@ -34,7 +14,6 @@ type Props = {
34
14
  feedId?: string;
35
15
  feedTitle?: string;
36
16
  focused?: boolean;
37
- resultCallback?: ScreenResultCallback;
38
17
  parentFocus?: {
39
18
  nextFocusDown?: React.Ref<any>;
40
19
  nextFocusRight?: React.Ref<any>;
@@ -50,96 +29,13 @@ export enum PresentationType {
50
29
  }
51
30
 
52
31
  export function ScreenResolverComponent(props: Props) {
53
- useScreenAnalytics(props);
54
-
55
- const { screenType, screenId, screenData, groupId } = props;
56
-
57
- const { hookPlugin } = screenData || {};
58
-
59
- const plugins = usePlugins();
60
- const rivers = useRivers();
61
-
62
- const components = useAppSelector(selectComponents);
63
-
64
- const {
65
- videoModalState: { mode },
66
- } = useNavigation();
67
-
68
- const [, setScreenContext] = ZappPipesScreenContext.useZappPipesContext();
69
-
70
- React.useEffect(() => {
71
- setScreenContext(rivers[screenId]);
72
- }, [rivers, screenId, setScreenContext]);
73
-
74
- const parentCallback = props.resultCallback;
75
-
76
- const screenAction = useCallbackActions(
77
- hookPlugin || screenData,
78
- screenData.callback
79
- );
32
+ const { screenType } = props;
33
+ const component = useScreenComponentResolver(screenType, props);
80
34
 
81
- const callbackAction = parentCallback || screenAction;
82
-
83
- const ScreenPlugin =
84
- findPluginByType(screenType, plugins, { skipWarning: true }) ||
85
- findPluginByIdentifier(screenType, plugins) ||
86
- findPluginByIdentifier(hookPlugin && hookPlugin.identifier, plugins) ||
87
- components[toPascalCase(screenType)];
88
-
89
- if (screenType === "favorites") {
90
- return <Favorites screenData={screenData} />;
91
- }
92
-
93
- if (screenType === "link") {
94
- return <LinkHandler screenData={screenData} />;
95
- }
96
-
97
- if (screenType === "playable") {
98
- return (
99
- // @ts-ignore
100
- <HandlePlayable
101
- item={screenData}
102
- mode={mode === "PIP" ? "PIP" : "FULLSCREEN"}
103
- isModal={false}
104
- groupId={groupId}
105
- />
106
- );
107
- }
108
-
109
- if (hookPlugin || screenType === "hooks") {
110
- return (
111
- screenData && (
112
- <HookRenderer
113
- callback={callbackAction}
114
- screenData={screenData}
115
- focused={props.focused}
116
- parentFocus={props.parentFocus as ParentFocus}
117
- />
118
- )
119
- );
120
- }
121
-
122
- const ScreenComponent =
123
- path(["module", "Component"], ScreenPlugin) ||
124
- prop("module", ScreenPlugin) ||
125
- prop("Component", ScreenPlugin) ||
126
- ScreenPlugin;
127
-
128
- const configuration =
129
- prop("configuration", ScreenPlugin) ||
130
- prop("__plugin_configuration", ScreenComponent);
35
+ useScreenAnalytics(props);
131
36
 
132
- if (ScreenComponent) {
133
- return (
134
- <ScreenComponent
135
- {...props}
136
- callback={callbackAction}
137
- screenId={screenId}
138
- screenData={screenData}
139
- configuration={configuration}
140
- presentationType={PresentationType.Standalone}
141
- />
142
- );
37
+ if (component) {
38
+ return component;
143
39
  }
144
40
 
145
41
  logger.warning({
@@ -150,6 +46,4 @@ export function ScreenResolverComponent(props: Props) {
150
46
  return null;
151
47
  }
152
48
 
153
- export const ScreenResolver = ZappPipesScreenContext.withProvider(
154
- ScreenResolverComponent
155
- );
49
+ export const ScreenResolver = withDefaultScreenContext(ScreenResolverComponent);
@@ -0,0 +1,45 @@
1
+ import { getScreenTypeProps } from "../getScreenTypeProps";
2
+
3
+ const baseProps = {
4
+ screenData: { id: "entry-1" },
5
+ mode: "PIP",
6
+ screenId: "screen-1",
7
+ groupId: "group-1",
8
+ focused: true,
9
+ parentFocus: { nextFocusDown: { current: null } },
10
+ screenAction: jest.fn(),
11
+ resultCallback: null,
12
+ };
13
+
14
+ describe("getScreenTypeProps", () => {
15
+ it("returns props for favorites/link", () => {
16
+ expect(getScreenTypeProps("favorites", baseProps)).toEqual({
17
+ screenData: baseProps.screenData,
18
+ });
19
+
20
+ expect(getScreenTypeProps("link", baseProps)).toEqual({
21
+ screenData: baseProps.screenData,
22
+ });
23
+ });
24
+
25
+ it("returns props for playable", () => {
26
+ expect(getScreenTypeProps("playable", baseProps)).toEqual({
27
+ item: baseProps.screenData,
28
+ mode: "PIP",
29
+ isModal: false,
30
+ groupId: "group-1",
31
+ });
32
+ });
33
+
34
+ it("returns props for hooks", () => {
35
+ const result = getScreenTypeProps("hooks", baseProps);
36
+
37
+ expect(result).toMatchObject({
38
+ screenData: baseProps.screenData,
39
+ focused: true,
40
+ parentFocus: baseProps.parentFocus,
41
+ });
42
+
43
+ expect(result.callback).toBe(baseProps.screenAction);
44
+ });
45
+ });
@@ -0,0 +1,43 @@
1
+ export const getScreenTypeProps = (
2
+ screenType: "favorites" | "link" | "playable" | "hooks",
3
+ props
4
+ ) => {
5
+ const {
6
+ screenData,
7
+ mode,
8
+ screenId,
9
+ groupId,
10
+ focused,
11
+ parentFocus,
12
+ screenAction,
13
+ resultCallback,
14
+ } = props;
15
+
16
+ switch (screenType) {
17
+ case "favorites":
18
+ case "link":
19
+ return {
20
+ screenData,
21
+ };
22
+ case "playable":
23
+ return {
24
+ item: screenData,
25
+ mode: mode === "PIP" ? "PIP" : "FULLSCREEN",
26
+ isModal: false,
27
+ groupId: groupId,
28
+ };
29
+ case "hooks":
30
+ return {
31
+ screenData,
32
+ callback: resultCallback || screenAction,
33
+ focused,
34
+ parentFocus: parentFocus as ParentFocus,
35
+ };
36
+ default:
37
+ return {
38
+ callback: resultCallback || screenAction,
39
+ screenId: screenId,
40
+ screenData,
41
+ };
42
+ }
43
+ };
@@ -0,0 +1 @@
1
+ export { getScreenTypeProps } from "./getScreenTypeProps";
@@ -0,0 +1,16 @@
1
+ import * as React from "react";
2
+ import { useRivers } from "@applicaster/zapp-react-native-utils/reactHooks";
3
+ import { ZappPipesScreenContext } from "../../Contexts";
4
+
5
+ export function withDefaultScreenContext(Component: React.ComponentType<any>) {
6
+ return function WithDefaultScreenContext(props: any) {
7
+ const screenId = props.screenId;
8
+ const rivers = useRivers();
9
+
10
+ return (
11
+ <ZappPipesScreenContext.Provider initialContextValue={rivers[screenId]}>
12
+ <Component {...props} />
13
+ </ZappPipesScreenContext.Provider>
14
+ );
15
+ };
16
+ }
@@ -0,0 +1,25 @@
1
+ import React from "react";
2
+ import { ScreenFeedLoader } from "../ScreenFeedLoader/ScreenFeedLoader";
3
+
4
+ /** Resolves screen-feed for a given screen `id` by using the provided `useFeedData` hook */
5
+ export const ScreenResolverFeedProvider = ({
6
+ id,
7
+ children,
8
+ useFeedData,
9
+ }: {
10
+ id: string;
11
+ children: React.ReactNode;
12
+ useFeedData: (id: string) => Option<ZappDataSource>;
13
+ }) => {
14
+ const feedData = useFeedData(id);
15
+
16
+ if (feedData?.source) {
17
+ return (
18
+ <ScreenFeedLoader id={id} feedData={feedData}>
19
+ {children}
20
+ </ScreenFeedLoader>
21
+ );
22
+ } else {
23
+ return <>{children}</>;
24
+ }
25
+ };
@@ -0,0 +1,44 @@
1
+ import React from "react";
2
+ import { Text } from "react-native";
3
+ import { render } from "@testing-library/react-native";
4
+ import { ScreenResolverFeedProvider } from "../ScreenResolverFeedProvider";
5
+
6
+ jest.mock("../../ScreenFeedLoader/ScreenFeedLoader", () => ({
7
+ ScreenFeedLoader: ({ children }) => {
8
+ const React = require("react");
9
+ const { View } = require("react-native");
10
+
11
+ return <View testID="feed-loader">{children}</View>;
12
+ },
13
+ }));
14
+
15
+ describe("ScreenResolverFeedProvider", () => {
16
+ it("renders ScreenFeedLoader when screen feed source exists", () => {
17
+ const useFeedData = jest.fn(() => ({
18
+ source: "https://feed",
19
+ mapping: {},
20
+ }));
21
+
22
+ const { getByTestId, getByText } = render(
23
+ <ScreenResolverFeedProvider id="screen-1" useFeedData={useFeedData}>
24
+ <Text>content</Text>
25
+ </ScreenResolverFeedProvider>
26
+ );
27
+
28
+ expect(getByTestId("feed-loader")).toBeDefined();
29
+ expect(getByText("content")).toBeDefined();
30
+ });
31
+
32
+ it("renders children directly when screen feed source is missing", () => {
33
+ const useFeedData = jest.fn(() => ({}));
34
+
35
+ const { queryByTestId, getByText } = render(
36
+ <ScreenResolverFeedProvider id="screen-1" useFeedData={useFeedData}>
37
+ <Text>content</Text>
38
+ </ScreenResolverFeedProvider>
39
+ );
40
+
41
+ expect(queryByTestId("feed-loader")).toBeNull();
42
+ expect(getByText("content")).toBeDefined();
43
+ });
44
+ });
@@ -0,0 +1 @@
1
+ export { ScreenResolverFeedProvider } from "./ScreenResolverFeedProvider";
@@ -0,0 +1,34 @@
1
+ import * as React from "react";
2
+ import { Animated, StyleSheet } from "react-native";
3
+
4
+ import { BackgroundImage } from "@applicaster/zapp-react-native-ui-components/Components/BackgroundImage";
5
+
6
+ const styles = StyleSheet.create({
7
+ container: {
8
+ ...StyleSheet.absoluteFillObject,
9
+ position: "absolute",
10
+ },
11
+ });
12
+
13
+ export const Overlay = ({
14
+ opacity,
15
+ backgroundColor,
16
+ }: {
17
+ opacity: Animated.Value;
18
+ backgroundColor: string;
19
+ }) => {
20
+ return (
21
+ <Animated.View
22
+ style={[
23
+ styles.container,
24
+ {
25
+ opacity,
26
+ backgroundColor,
27
+ },
28
+ ]}
29
+ testID="animated-component"
30
+ >
31
+ <BackgroundImage />
32
+ </Animated.View>
33
+ );
34
+ };
@@ -1,11 +1,6 @@
1
1
  import { makeListOf } from "@applicaster/zapp-react-native-utils/arrayUtils";
2
2
  import { isFirstComponentGallery } from "@applicaster/zapp-react-native-utils/componentsUtils";
3
- import { race, Subject, Subscription } from "rxjs";
4
- import { first } from "rxjs/operators";
5
-
6
- import { withTimeout$ } from "@applicaster/zapp-react-native-utils/idleUtils";
7
-
8
- const MAX_TIMEOUT_TO_WAIT_COMPONENTS_TO_LOAD = 2000; // 2 seconds
3
+ import { once } from "ramda";
9
4
 
10
5
  const INITIAL_NUMBER_TO_LOAD = 3;
11
6
 
@@ -39,8 +34,7 @@ const getNumberOfComponentsWaitToLoadBeforePresent = (
39
34
  export class ScreenRevealManager {
40
35
  public numberOfComponentsWaitToLoadBeforePresent: number;
41
36
  private renderingState: Array<ComponentLoadingState>;
42
- private subject$ = new Subject<void>();
43
- private subscription: Subscription;
37
+ private callback: Callback;
44
38
 
45
39
  constructor(componentsToRender: ZappUIComponent[], callback: Callback) {
46
40
  this.numberOfComponentsWaitToLoadBeforePresent =
@@ -51,58 +45,32 @@ export class ScreenRevealManager {
51
45
  this.numberOfComponentsWaitToLoadBeforePresent
52
46
  );
53
47
 
54
- this.subscription = race(
55
- withTimeout$(MAX_TIMEOUT_TO_WAIT_COMPONENTS_TO_LOAD),
56
- this.subject$
57
- )
58
- .pipe(first())
59
- .subscribe(callback);
48
+ this.callback = once(callback);
60
49
  }
61
50
 
62
51
  onLoadFinished = (index: number): void => {
63
- const currentState = this.renderingState[index];
64
-
65
- if (
66
- COMPONENT_LOADING_STATE.LOADED_WITH_SUCCESS === currentState ||
67
- COMPONENT_LOADING_STATE.LOADED_WITH_FAILURE === currentState
68
- ) {
69
- return;
70
- }
71
-
72
52
  this.renderingState[index] = COMPONENT_LOADING_STATE.LOADED_WITH_SUCCESS;
73
53
 
74
54
  if (
75
55
  getNumberOfLoaded(this.renderingState) >=
76
56
  this.numberOfComponentsWaitToLoadBeforePresent
77
57
  ) {
78
- this.subject$.next();
79
- this.subject$.complete();
58
+ this.setIsReadyToShow();
80
59
  }
81
60
  };
82
61
 
83
62
  onLoadFailed = (index: number): void => {
84
- const currentState = this.renderingState[index];
85
-
86
- if (
87
- COMPONENT_LOADING_STATE.LOADED_WITH_SUCCESS === currentState ||
88
- COMPONENT_LOADING_STATE.LOADED_WITH_FAILURE === currentState
89
- ) {
90
- return;
91
- }
92
-
93
63
  this.renderingState[index] = COMPONENT_LOADING_STATE.LOADED_WITH_FAILURE;
94
64
 
95
65
  if (
96
66
  getNumberOfLoaded(this.renderingState) >=
97
67
  this.numberOfComponentsWaitToLoadBeforePresent
98
68
  ) {
99
- this.subject$.next();
100
- this.subject$.complete();
69
+ this.setIsReadyToShow();
101
70
  }
102
71
  };
103
72
 
104
- dispose(): void {
105
- this.subscription?.unsubscribe();
106
- this.subject$.complete();
107
- }
73
+ setIsReadyToShow = (): void => {
74
+ this.callback();
75
+ };
108
76
  }
@@ -0,0 +1,88 @@
1
+ import React from "react";
2
+ import { Animated } from "react-native";
3
+ import { render } from "@testing-library/react-native";
4
+
5
+ jest.mock(
6
+ "@applicaster/zapp-react-native-ui-components/Components/BackgroundImage",
7
+ () => {
8
+ const { Text } = require("react-native");
9
+
10
+ return {
11
+ BackgroundImage: () => (
12
+ <Text testID="background-image">BackgroundImage</Text>
13
+ ),
14
+ };
15
+ }
16
+ );
17
+
18
+ import { Overlay } from "../Overlay";
19
+
20
+ const flattenStyle = (style: unknown): Record<string, unknown> => {
21
+ if (!style) {
22
+ return {};
23
+ }
24
+
25
+ if (Array.isArray(style)) {
26
+ return style.reduce<Record<string, unknown>>(
27
+ (acc, item) => ({ ...acc, ...flattenStyle(item) }),
28
+ {}
29
+ );
30
+ }
31
+
32
+ if (typeof style === "object") {
33
+ return style as Record<string, unknown>;
34
+ }
35
+
36
+ return {};
37
+ };
38
+
39
+ describe("Overlay", () => {
40
+ it("renders the animated overlay container", () => {
41
+ const opacity = new Animated.Value(1);
42
+
43
+ const { getByTestId } = render(
44
+ <Overlay opacity={opacity} backgroundColor="#000000" />
45
+ );
46
+
47
+ expect(getByTestId("animated-component")).toBeTruthy();
48
+ });
49
+
50
+ it("applies opacity and backgroundColor to the overlay", () => {
51
+ const opacity = new Animated.Value(0.5);
52
+
53
+ const { getByTestId } = render(
54
+ <Overlay opacity={opacity} backgroundColor="#ff0000" />
55
+ );
56
+
57
+ const style = flattenStyle(getByTestId("animated-component").props.style);
58
+
59
+ expect(style.backgroundColor).toBe("#ff0000");
60
+ expect(style.opacity).toBe(0.5);
61
+ });
62
+
63
+ it("positions the overlay with absolute fill layout", () => {
64
+ const opacity = new Animated.Value(1);
65
+
66
+ const { getByTestId } = render(
67
+ <Overlay opacity={opacity} backgroundColor="#000000" />
68
+ );
69
+
70
+ const style = flattenStyle(getByTestId("animated-component").props.style);
71
+
72
+ expect(style.position).toBe("absolute");
73
+ expect(style.top).toBe(0);
74
+ expect(style.left).toBe(0);
75
+ expect(style.right).toBe(0);
76
+ expect(style.bottom).toBe(0);
77
+ });
78
+
79
+ it("renders BackgroundImage inside the overlay", () => {
80
+ const opacity = new Animated.Value(1);
81
+
82
+ const { getByTestId } = render(
83
+ <Overlay opacity={opacity} backgroundColor="#000000" />
84
+ );
85
+
86
+ expect(getByTestId("background-image")).toBeTruthy();
87
+ });
88
+ });