@applicaster/zapp-react-native-ui-components 15.0.0-rc.99 → 16.0.0-rc.1
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.
- package/Components/Cell/TvOSCellComponent.tsx +1 -3
- package/Components/GeneralContentScreen/GeneralContentScreen.tsx +39 -28
- package/Components/GeneralContentScreen/__tests__/GeneralContentScreen.test.tsx +104 -0
- package/Components/GeneralContentScreen/utils/__tests__/getScreenDataSource.test.ts +19 -0
- package/Components/GeneralContentScreen/utils/getScreenDataSource.ts +9 -0
- package/Components/HandlePlayable/HandlePlayable.tsx +16 -29
- package/Components/HandlePlayable/utils.ts +31 -0
- package/Components/HookRenderer/HookRenderer.tsx +40 -10
- package/Components/HookRenderer/__tests__/HookRenderer.test.tsx +60 -0
- package/Components/Layout/TV/NavBarContainer.tsx +1 -10
- package/Components/Layout/TV/__tests__/__snapshots__/NavBarContainer.test.tsx.snap +7 -12
- package/Components/Layout/TV/__tests__/__snapshots__/ScreenContainer.test.tsx.snap +7 -12
- package/Components/Layout/TV/__tests__/__snapshots__/index.test.tsx.snap +5 -0
- package/Components/MasterCell/CONFIG_BUILDER_TO_REACT_COMPONENT.md +144 -0
- package/Components/MasterCell/DefaultComponents/ActionButtonsCore/__tests__/model.test.ts +80 -0
- package/Components/MasterCell/DefaultComponents/ActionButtonsCore/__tests__/placement.test.ts +187 -0
- package/Components/MasterCell/DefaultComponents/ActionButtonsCore/__tests__/selectors.test.ts +45 -0
- package/Components/MasterCell/DefaultComponents/ActionButtonsCore/__tests__/style.test.ts +49 -0
- package/Components/MasterCell/DefaultComponents/ActionButtonsCore/components/ActionButtonController.tsx +165 -0
- package/Components/MasterCell/DefaultComponents/ActionButtonsCore/components/__tests__/ActionButtonController.test.tsx +405 -0
- package/Components/MasterCell/DefaultComponents/ActionButtonsCore/components/index.ts +1 -0
- package/Components/MasterCell/DefaultComponents/ActionButtonsCore/model.ts +47 -0
- package/Components/MasterCell/DefaultComponents/ActionButtonsCore/placement.ts +170 -0
- package/Components/MasterCell/DefaultComponents/ActionButtonsCore/selectors.ts +26 -0
- package/Components/MasterCell/DefaultComponents/ActionButtonsCore/style.ts +29 -0
- package/Components/MasterCell/DefaultComponents/ActionButtonsCore/types.ts +37 -0
- package/Components/MasterCell/DefaultComponents/Button.tsx +0 -15
- package/Components/MasterCell/DefaultComponents/ButtonContainerView/components/HorizontalSeparator.tsx +8 -0
- package/Components/MasterCell/DefaultComponents/ButtonContainerView/index.tsx +15 -0
- package/Components/MasterCell/DefaultComponents/ButtonContainerView/index.tv.android.tsx +58 -0
- package/Components/MasterCell/DefaultComponents/{tv/ButtonContainerView/index.tsx → ButtonContainerView/index.tv.tsx} +3 -11
- package/Components/MasterCell/DefaultComponents/ButtonContainerView/index.web.ts +1 -0
- package/Components/MasterCell/DefaultComponents/ButtonContainerView/types.ts +40 -0
- package/Components/MasterCell/DefaultComponents/DataProvider/index.tsx +163 -0
- package/Components/MasterCell/DefaultComponents/FocusableView/index.android.tsx +2 -23
- package/Components/MasterCell/DefaultComponents/FocusableView/index.tsx +4 -22
- package/Components/MasterCell/DefaultComponents/Image/Image.android.tsx +3 -1
- package/Components/MasterCell/DefaultComponents/LiveImage/__tests__/prepareEntry.test.ts +352 -0
- package/Components/MasterCell/DefaultComponents/LiveImage/executePreloadHooks.ts +136 -0
- package/Components/MasterCell/DefaultComponents/LiveImage/index.tsx +33 -16
- package/Components/MasterCell/DefaultComponents/PressableView.tsx +34 -0
- package/Components/MasterCell/DefaultComponents/Text/hooks/useText.ts +11 -0
- package/Components/MasterCell/DefaultComponents/Text/index.tsx +2 -6
- package/Components/MasterCell/DefaultComponents/__tests__/DataProvider.test.tsx +141 -0
- package/Components/MasterCell/DefaultComponents/index.ts +9 -3
- package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/ActionButton.tsx +135 -0
- package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/Asset.ts +33 -0
- package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/AssetComponent.tsx +22 -0
- package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/Button.ts +125 -0
- package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/Spacer.ts +16 -0
- package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/TextLabel.ts +67 -0
- package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/TextLabelsContainer.ts +37 -0
- package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/__tests__/PressableView.test.tsx +393 -0
- package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/__tests__/builders.test.ts +141 -0
- package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/__tests__/index.test.ts +343 -0
- package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/helpers.ts +105 -0
- package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/index.ts +122 -0
- package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/utils/__tests__/insertButtons.test.ts +118 -0
- package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/utils/index.ts +238 -0
- package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/Asset.ts +4 -18
- package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/Button.ts +24 -73
- package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/TextLabelsContainer.ts +37 -18
- package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/TvActionButton.tsx +27 -0
- package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/__tests__/index.test.ts +89 -0
- package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/__tests__/renderedTree.test.tsx +231 -0
- package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/index.ts +47 -52
- package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/utils/__tests__/getPluginIdentifier.test.ts +35 -171
- package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/utils/index.ts +98 -145
- package/Components/MasterCell/MappingFunctions/index.js +3 -2
- package/Components/MasterCell/README.md +4 -0
- package/Components/MasterCell/__tests__/__snapshots__/dataAdapter.test.js.snap +24 -0
- package/Components/MasterCell/__tests__/configInflater.test.js +1 -0
- package/Components/MasterCell/__tests__/elementMapper.test.js +46 -0
- package/Components/MasterCell/dataAdapter.ts +4 -1
- package/Components/MasterCell/elementMapper.tsx +52 -7
- package/Components/MasterCell/utils/__tests__/cloneChildrenWithIds.test.tsx +43 -0
- package/Components/MasterCell/utils/__tests__/useFilterChildren.test.tsx +80 -0
- package/Components/MasterCell/utils/index.ts +85 -15
- package/Components/Navigator/StackNavigator.tsx +6 -0
- package/Components/PlayerContainer/PlayerContainer.tsx +2 -19
- package/Components/PreloaderWrapper/__tests__/index.test.tsx +26 -0
- package/Components/PreloaderWrapper/index.tsx +15 -0
- package/Components/River/ComponentsMap/ComponentsMap.tsx +2 -16
- package/Components/River/RefreshControl.tsx +19 -82
- package/Components/River/River.tsx +9 -82
- package/Components/River/RiverItem.tsx +26 -20
- package/Components/River/hooks/__tests__/usePullToRefresh.test.ts +132 -0
- package/Components/River/hooks/index.ts +1 -0
- package/Components/River/hooks/usePullToRefresh.ts +51 -0
- package/Components/Screen/__tests__/Screen.test.tsx +1 -0
- package/Components/Screen/hooks.ts +73 -3
- package/Components/Screen/index.tsx +7 -1
- package/Components/ScreenFeedLoader/ScreenFeedLoader.tsx +46 -0
- package/Components/ScreenFeedLoader/__tests__/ScreenFeedLoader.test.tsx +94 -0
- package/Components/ScreenFeedLoader/index.ts +1 -0
- package/Components/ScreenResolver/__tests__/screenResolver.test.js +24 -0
- package/Components/ScreenResolver/hooks/index.ts +3 -0
- package/Components/ScreenResolver/hooks/useGetComponent.ts +15 -0
- package/Components/ScreenResolver/hooks/useScreenComponentResolver.tsx +90 -0
- package/Components/ScreenResolver/index.tsx +15 -117
- package/Components/ScreenResolver/utils/__tests__/getScreenTypeProps.test.ts +45 -0
- package/Components/ScreenResolver/utils/getScreenTypeProps.ts +43 -0
- package/Components/ScreenResolver/utils/index.ts +1 -0
- package/Components/ScreenResolver/withDefaultScreenContext.tsx +16 -0
- package/Components/ScreenResolverFeedProvider/ScreenResolverFeedProvider.tsx +25 -0
- package/Components/ScreenResolverFeedProvider/__tests__/ScreenResolverFeedProvider.test.tsx +44 -0
- package/Components/ScreenResolverFeedProvider/index.ts +1 -0
- package/Components/ScreenRevealManager/withScreenRevealManager.tsx +4 -1
- package/Components/TopCutoffOverlay/__tests__/TopCutoffOverlay.test.tsx +201 -0
- package/Components/TopCutoffOverlay/hooks/__tests__/useMarginTop.test.ts +130 -0
- package/Components/TopCutoffOverlay/hooks/index.ts +1 -0
- package/Components/TopCutoffOverlay/hooks/useMarginTop.ts +59 -0
- package/Components/TopCutoffOverlay/index.tsx +55 -0
- package/Components/Transitioner/Scene.tsx +9 -15
- package/Components/VideoLive/LiveImageManager.ts +199 -54
- package/Components/VideoLive/PlayerLiveImageComponent.tsx +31 -33
- package/Components/VideoLive/__tests__/PlayerLiveImageComponent.test.tsx +2 -17
- package/Components/Viewport/ViewportAware/__tests__/viewportAware.test.js +0 -2
- package/Components/Viewport/ViewportAware/index.tsx +16 -7
- package/Components/ZappUIComponent/index.tsx +12 -6
- package/Components/default-cell-renderer/viewTrees/mobile/index.ts +0 -3
- package/Components/index.js +1 -1
- package/Contexts/ScreenContext/__tests__/index.test.tsx +57 -0
- package/Contexts/ScreenContext/index.tsx +46 -1
- package/Contexts/ZappPipesContext/ZappPipesContextFactory.tsx +18 -7
- package/Decorators/ZappPipesDataConnector/ResolverSelector.tsx +25 -7
- package/Decorators/ZappPipesDataConnector/__tests__/ResolverSelector.test.tsx +212 -5
- package/Decorators/ZappPipesDataConnector/__tests__/UrlFeedResolver.test.tsx +39 -21
- package/Decorators/ZappPipesDataConnector/resolvers/UrlFeedResolver.tsx +18 -7
- package/package.json +5 -5
- package/Components/MasterCell/DefaultComponents/Text/utils/__tests__/withAdjustedLineHeight.test.ts +0 -46
- package/Components/MasterCell/DefaultComponents/Text/utils/index.ts +0 -21
- package/Components/MasterCell/DefaultComponents/tv/ButtonContainerView/index.android.tsx +0 -135
- package/Components/MasterCell/DefaultComponents/tv/ButtonContainerView/types.ts +0 -25
- package/Components/PlayerContainer/ErrorDisplay/ErrorDisplay.tsx +0 -57
- package/Components/PlayerContainer/ErrorDisplay/index.ts +0 -9
- package/Components/PlayerContainer/useRestrictMobilePlayback.tsx +0 -101
- /package/Components/HookRenderer/{index.tsx → index.ts} +0 -0
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
|
|
3
|
+
import { toPascalCase } from "@applicaster/zapp-react-native-utils/stringUtils";
|
|
4
|
+
import {
|
|
5
|
+
useAppSelector,
|
|
6
|
+
selectComponents,
|
|
7
|
+
} from "@applicaster/zapp-react-native-redux";
|
|
8
|
+
|
|
9
|
+
export const useGetComponent = (screenType) => {
|
|
10
|
+
const components = useAppSelector(selectComponents);
|
|
11
|
+
|
|
12
|
+
return React.useMemo(() => {
|
|
13
|
+
return components[toPascalCase(screenType)];
|
|
14
|
+
}, [components, screenType]);
|
|
15
|
+
};
|
|
@@ -0,0 +1,90 @@
|
|
|
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 { HookRenderer } from "../../HookRenderer";
|
|
9
|
+
import { LinkHandler } from "../../LinkHandler";
|
|
10
|
+
import { Favorites } from "../../Favorites";
|
|
11
|
+
import { usePlugins } from "@applicaster/zapp-react-native-redux/hooks";
|
|
12
|
+
import { useNavigation } from "@applicaster/zapp-react-native-utils/reactHooks";
|
|
13
|
+
|
|
14
|
+
import { useCallbackActions } from "@applicaster/zapp-react-native-utils/zappFrameworkUtils/HookCallback/useCallbackActions";
|
|
15
|
+
import { useGetComponent } from "./useGetComponent";
|
|
16
|
+
import { getScreenTypeProps } from "../utils";
|
|
17
|
+
|
|
18
|
+
export enum PresentationType {
|
|
19
|
+
Standalone = "Standalone",
|
|
20
|
+
Hook = "Hook",
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const screenTypeComponents = {
|
|
24
|
+
favorites: Favorites,
|
|
25
|
+
link: LinkHandler,
|
|
26
|
+
playable: HandlePlayable,
|
|
27
|
+
hooks: HookRenderer,
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export const useScreenComponentResolver = (screenType, props) => {
|
|
31
|
+
const plugins = usePlugins();
|
|
32
|
+
const { hookPlugin } = props.screenData || {};
|
|
33
|
+
const component = useGetComponent(screenType);
|
|
34
|
+
|
|
35
|
+
const screenAction = useCallbackActions(
|
|
36
|
+
hookPlugin || props.screenData,
|
|
37
|
+
props.screenData.callback
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
const {
|
|
41
|
+
videoModalState: { mode },
|
|
42
|
+
} = useNavigation();
|
|
43
|
+
|
|
44
|
+
const componentProps = {
|
|
45
|
+
...props,
|
|
46
|
+
mode,
|
|
47
|
+
screenAction,
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
const ScreenTypeComponent = screenTypeComponents?.[screenType];
|
|
51
|
+
|
|
52
|
+
if (ScreenTypeComponent) {
|
|
53
|
+
return (
|
|
54
|
+
<ScreenTypeComponent
|
|
55
|
+
{...getScreenTypeProps(screenType, componentProps)}
|
|
56
|
+
/>
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const ScreenPlugin =
|
|
61
|
+
findPluginByType(screenType, plugins, { skipWarning: true }) ||
|
|
62
|
+
findPluginByIdentifier(screenType, plugins) ||
|
|
63
|
+
findPluginByIdentifier(hookPlugin && hookPlugin.identifier, plugins) ||
|
|
64
|
+
component;
|
|
65
|
+
|
|
66
|
+
const ScreenComponent =
|
|
67
|
+
path(["module", "Component"], ScreenPlugin) ||
|
|
68
|
+
prop("module", ScreenPlugin) ||
|
|
69
|
+
prop("Component", ScreenPlugin) ||
|
|
70
|
+
ScreenPlugin;
|
|
71
|
+
|
|
72
|
+
const configuration =
|
|
73
|
+
prop("configuration", ScreenPlugin) ||
|
|
74
|
+
prop("__plugin_configuration", ScreenComponent);
|
|
75
|
+
|
|
76
|
+
if (!ScreenComponent) {
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return (
|
|
81
|
+
<ScreenComponent
|
|
82
|
+
{...props}
|
|
83
|
+
callback={props.resultCallback || screenAction}
|
|
84
|
+
screenId={props.screenId}
|
|
85
|
+
screenData={props.screenData}
|
|
86
|
+
presentationType={PresentationType.Standalone}
|
|
87
|
+
configuration={configuration}
|
|
88
|
+
/>
|
|
89
|
+
);
|
|
90
|
+
};
|
|
@@ -1,29 +1,17 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
|
|
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
|
-
|
|
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";
|
|
4
|
+
|
|
22
5
|
import { useScreenAnalytics } from "@applicaster/zapp-react-native-utils/analyticsUtils/helpers/hooks";
|
|
23
6
|
|
|
24
|
-
import { useCallbackActions } from "@applicaster/zapp-react-native-utils/zappFrameworkUtils/HookCallback/useCallbackActions";
|
|
25
7
|
import { ScreenResultCallback } from "@applicaster/zapp-react-native-utils/zappFrameworkUtils/HookCallback/callbackNavigationAction";
|
|
26
|
-
import {
|
|
8
|
+
import { useScreenComponentResolver } from "./hooks/useScreenComponentResolver";
|
|
9
|
+
import { withDefaultScreenContext } from "./withDefaultScreenContext";
|
|
10
|
+
|
|
11
|
+
export enum PresentationType {
|
|
12
|
+
Standalone = "Standalone",
|
|
13
|
+
Hook = "Hook",
|
|
14
|
+
}
|
|
27
15
|
|
|
28
16
|
const logger = componentsLogger.addSubsystem("ScreenResolver");
|
|
29
17
|
|
|
@@ -44,102 +32,14 @@ type Props = {
|
|
|
44
32
|
groupId?: string;
|
|
45
33
|
};
|
|
46
34
|
|
|
47
|
-
export enum PresentationType {
|
|
48
|
-
Standalone = "Standalone",
|
|
49
|
-
Hook = "Hook",
|
|
50
|
-
}
|
|
51
|
-
|
|
52
35
|
export function ScreenResolverComponent(props: Props) {
|
|
53
|
-
|
|
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);
|
|
36
|
+
const { screenType } = props;
|
|
37
|
+
const component = useScreenComponentResolver(screenType, props);
|
|
63
38
|
|
|
64
|
-
|
|
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
|
-
);
|
|
80
|
-
|
|
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);
|
|
39
|
+
useScreenAnalytics(props);
|
|
131
40
|
|
|
132
|
-
if (
|
|
133
|
-
return
|
|
134
|
-
<ScreenComponent
|
|
135
|
-
{...props}
|
|
136
|
-
callback={callbackAction}
|
|
137
|
-
screenId={screenId}
|
|
138
|
-
screenData={screenData}
|
|
139
|
-
configuration={configuration}
|
|
140
|
-
presentationType={PresentationType.Standalone}
|
|
141
|
-
/>
|
|
142
|
-
);
|
|
41
|
+
if (component) {
|
|
42
|
+
return component;
|
|
143
43
|
}
|
|
144
44
|
|
|
145
45
|
logger.warning({
|
|
@@ -150,6 +50,4 @@ export function ScreenResolverComponent(props: Props) {
|
|
|
150
50
|
return null;
|
|
151
51
|
}
|
|
152
52
|
|
|
153
|
-
export const ScreenResolver =
|
|
154
|
-
ScreenResolverComponent
|
|
155
|
-
);
|
|
53
|
+
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";
|
|
@@ -25,6 +25,7 @@ export const SHOWN = 1; // opacity = 1
|
|
|
25
25
|
|
|
26
26
|
type Props = {
|
|
27
27
|
componentsToRender: ZappUIComponent[];
|
|
28
|
+
backgroundColor?: string;
|
|
28
29
|
};
|
|
29
30
|
|
|
30
31
|
export const withScreenRevealManager = (Component) => {
|
|
@@ -97,7 +98,9 @@ export const withScreenRevealManager = (Component) => {
|
|
|
97
98
|
styles.container,
|
|
98
99
|
{
|
|
99
100
|
opacity: opacityRef.current,
|
|
100
|
-
|
|
101
|
+
// TODO: we should support background image as well, but for now we will use background color from theme
|
|
102
|
+
backgroundColor:
|
|
103
|
+
props.backgroundColor ?? theme.app_background_color,
|
|
101
104
|
},
|
|
102
105
|
]}
|
|
103
106
|
testID="animated-component"
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { Text } from "react-native";
|
|
3
|
+
import { render } from "@testing-library/react-native";
|
|
4
|
+
|
|
5
|
+
jest.mock(
|
|
6
|
+
"@applicaster/zapp-react-native-ui-components/Components/River/useScreenConfiguration",
|
|
7
|
+
() => ({
|
|
8
|
+
useScreenConfiguration: jest.fn(),
|
|
9
|
+
})
|
|
10
|
+
);
|
|
11
|
+
|
|
12
|
+
jest.mock(
|
|
13
|
+
"@applicaster/zapp-react-native-ui-components/Components/TopCutoffOverlay/hooks",
|
|
14
|
+
() => ({
|
|
15
|
+
useMarginTop: jest.fn(),
|
|
16
|
+
})
|
|
17
|
+
);
|
|
18
|
+
|
|
19
|
+
jest.mock("@applicaster/zapp-react-native-utils/theme", () => ({
|
|
20
|
+
useTheme: jest.fn(),
|
|
21
|
+
}));
|
|
22
|
+
|
|
23
|
+
import { TopCutoffOverlay } from "../index";
|
|
24
|
+
import { useMarginTop } from "../hooks";
|
|
25
|
+
import { useScreenConfiguration } from "../../River/useScreenConfiguration";
|
|
26
|
+
import { useTheme } from "@applicaster/zapp-react-native-utils/theme";
|
|
27
|
+
|
|
28
|
+
// Recursively find a View with position: absolute in the JSON tree
|
|
29
|
+
const findOverlayStyle = (node: any): Record<string, any> | null => {
|
|
30
|
+
if (!node) return null;
|
|
31
|
+
|
|
32
|
+
// Style can be a plain object or an array of style objects
|
|
33
|
+
const styles = Array.isArray(node.props?.style)
|
|
34
|
+
? node.props.style
|
|
35
|
+
: node.props?.style
|
|
36
|
+
? [node.props.style]
|
|
37
|
+
: [];
|
|
38
|
+
|
|
39
|
+
const styleObj = styles.find((s: any) => s?.position === "absolute");
|
|
40
|
+
if (styleObj) return styleObj;
|
|
41
|
+
|
|
42
|
+
const children = node.children || [];
|
|
43
|
+
|
|
44
|
+
if (Array.isArray(children)) {
|
|
45
|
+
for (const child of children) {
|
|
46
|
+
const result = findOverlayStyle(child);
|
|
47
|
+
if (result) return result;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const propChildren = node.props?.children;
|
|
52
|
+
|
|
53
|
+
if (propChildren && Array.isArray(propChildren)) {
|
|
54
|
+
for (const child of propChildren) {
|
|
55
|
+
const result = findOverlayStyle(child);
|
|
56
|
+
if (result) return result;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (
|
|
61
|
+
typeof propChildren === "object" &&
|
|
62
|
+
propChildren !== null &&
|
|
63
|
+
"type" in propChildren
|
|
64
|
+
) {
|
|
65
|
+
return findOverlayStyle(propChildren);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return null;
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
describe("TopCutoffOverlay", () => {
|
|
72
|
+
const mockUseMarginTop = useMarginTop as jest.MockedFunction<
|
|
73
|
+
typeof useMarginTop
|
|
74
|
+
>;
|
|
75
|
+
|
|
76
|
+
const mockUseScreenConfig = useScreenConfiguration as jest.MockedFunction<
|
|
77
|
+
typeof useScreenConfiguration
|
|
78
|
+
>;
|
|
79
|
+
|
|
80
|
+
const mockUseTheme = useTheme as jest.MockedFunction<typeof useTheme>;
|
|
81
|
+
|
|
82
|
+
beforeEach(() => {
|
|
83
|
+
jest.clearAllMocks();
|
|
84
|
+
mockUseMarginTop.mockReturnValue(60);
|
|
85
|
+
mockUseScreenConfig.mockReturnValue({ backgroundColor: "#1a1a1a" });
|
|
86
|
+
mockUseTheme.mockReturnValue({ app_background_color: "#222222" });
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it("renders children when applyTopCutoff is false", () => {
|
|
90
|
+
const { getByText } = render(
|
|
91
|
+
<TopCutoffOverlay applyTopCutoff={false}>
|
|
92
|
+
<Text>Child content</Text>
|
|
93
|
+
</TopCutoffOverlay>
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
expect(getByText("Child content")).toBeTruthy();
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it("does not render overlay when applyTopCutoff is false", () => {
|
|
100
|
+
const tree = render(
|
|
101
|
+
<TopCutoffOverlay applyTopCutoff={false}>
|
|
102
|
+
<Text>Child content</Text>
|
|
103
|
+
</TopCutoffOverlay>
|
|
104
|
+
);
|
|
105
|
+
|
|
106
|
+
expect(findOverlayStyle(tree.toJSON())).toBeNull();
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
it("renders overlay when applyTopCutoff is true (default)", () => {
|
|
110
|
+
const tree = render(
|
|
111
|
+
<TopCutoffOverlay>
|
|
112
|
+
<Text>Child content</Text>
|
|
113
|
+
</TopCutoffOverlay>
|
|
114
|
+
);
|
|
115
|
+
|
|
116
|
+
expect(findOverlayStyle(tree.toJSON())).not.toBeNull();
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
it("renders overlay with correct height from useMarginTop", () => {
|
|
120
|
+
const tree = render(
|
|
121
|
+
<TopCutoffOverlay>
|
|
122
|
+
<Text>Child content</Text>
|
|
123
|
+
</TopCutoffOverlay>
|
|
124
|
+
);
|
|
125
|
+
|
|
126
|
+
expect(findOverlayStyle(tree.toJSON())?.height).toBe(60);
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
it("uses screenBackgroundColor from useScreenConfiguration when available", () => {
|
|
130
|
+
mockUseScreenConfig.mockReturnValue({ backgroundColor: "#ff0000" });
|
|
131
|
+
|
|
132
|
+
const tree = render(
|
|
133
|
+
<TopCutoffOverlay>
|
|
134
|
+
<Text>Child content</Text>
|
|
135
|
+
</TopCutoffOverlay>
|
|
136
|
+
);
|
|
137
|
+
|
|
138
|
+
expect(findOverlayStyle(tree.toJSON())?.backgroundColor).toBe("#ff0000");
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
it("falls back to themeBackgroundColor when screenBackgroundColor is not available", () => {
|
|
142
|
+
mockUseScreenConfig.mockReturnValue({ backgroundColor: undefined });
|
|
143
|
+
|
|
144
|
+
const tree = render(
|
|
145
|
+
<TopCutoffOverlay>
|
|
146
|
+
<Text>Child content</Text>
|
|
147
|
+
</TopCutoffOverlay>
|
|
148
|
+
);
|
|
149
|
+
|
|
150
|
+
expect(findOverlayStyle(tree.toJSON())?.backgroundColor).toBe("#222222");
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
it("falls back to transparent when neither screenBackgroundColor nor themeBackgroundColor is available", () => {
|
|
154
|
+
mockUseScreenConfig.mockReturnValue({ backgroundColor: undefined });
|
|
155
|
+
mockUseTheme.mockReturnValue({});
|
|
156
|
+
|
|
157
|
+
const tree = render(
|
|
158
|
+
<TopCutoffOverlay>
|
|
159
|
+
<Text>Child content</Text>
|
|
160
|
+
</TopCutoffOverlay>
|
|
161
|
+
);
|
|
162
|
+
|
|
163
|
+
expect(findOverlayStyle(tree.toJSON())?.backgroundColor).toBe(
|
|
164
|
+
"transparent"
|
|
165
|
+
);
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
it("passes targetScreenId to useMarginTop and useScreenConfiguration", () => {
|
|
169
|
+
render(
|
|
170
|
+
<TopCutoffOverlay targetScreenId="custom-screen-1">
|
|
171
|
+
<Text>Child content</Text>
|
|
172
|
+
</TopCutoffOverlay>
|
|
173
|
+
);
|
|
174
|
+
|
|
175
|
+
expect(mockUseMarginTop).toHaveBeenCalledWith("custom-screen-1");
|
|
176
|
+
expect(mockUseScreenConfig).toHaveBeenCalledWith("custom-screen-1");
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
it("positions overlay at top with left/right 0", () => {
|
|
180
|
+
const tree = render(
|
|
181
|
+
<TopCutoffOverlay>
|
|
182
|
+
<Text>Child content</Text>
|
|
183
|
+
</TopCutoffOverlay>
|
|
184
|
+
);
|
|
185
|
+
|
|
186
|
+
const style = findOverlayStyle(tree.toJSON());
|
|
187
|
+
expect(style?.top).toBe(0);
|
|
188
|
+
expect(style?.left).toBe(0);
|
|
189
|
+
expect(style?.right).toBe(0);
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
it("renders children inside the container", () => {
|
|
193
|
+
const { getByText } = render(
|
|
194
|
+
<TopCutoffOverlay>
|
|
195
|
+
<Text>Child content</Text>
|
|
196
|
+
</TopCutoffOverlay>
|
|
197
|
+
);
|
|
198
|
+
|
|
199
|
+
expect(getByText("Child content")).toBeTruthy();
|
|
200
|
+
});
|
|
201
|
+
});
|