@applicaster/zapp-react-native-ui-components 15.0.0-rc.99 → 15.1.0-alpha.4285753931
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/BackgroundImage/BackgroundImage.tv.android.tsx +28 -0
- package/Components/BackgroundImage/BackgroundImage.tv.ios.tsx +24 -0
- package/Components/BackgroundImage/BackgroundImage.tv.web.tsx +42 -0
- package/Components/BackgroundImage/index.ts +8 -0
- package/Components/BaseFocusable/index.ios.ts +2 -12
- package/Components/Cell/FocusableWrapper.tsx +0 -3
- package/Components/Cell/TvOSCellComponent.tsx +0 -5
- package/Components/CellRendererResolver/index.ts +1 -1
- package/Components/ComponentResolver/__tests__/componentResolver.test.js +1 -1
- package/Components/Focusable/Focusable.tsx +2 -4
- package/Components/Focusable/FocusableTvOS.tsx +1 -18
- package/Components/Focusable/__tests__/__snapshots__/FocusableTvOS.test.tsx.snap +0 -1
- package/Components/FocusableGroup/FocusableTvOS.tsx +12 -37
- 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/__tests__/useCurationAPI.test.js +1 -1
- package/Components/GeneralContentScreen/utils/getScreenDataSource.ts +9 -0
- package/Components/HandlePlayable/HandlePlayable.tsx +24 -42
- 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/FullWidthRow.tsx +38 -0
- package/Components/Layout/TV/ScreenContainer.tsx +11 -2
- package/Components/Layout/TV/__tests__/__snapshots__/index.test.tsx.snap +5 -1
- package/Components/Layout/TV/index.tsx +6 -6
- package/Components/Layout/TV/index.web.tsx +6 -6
- package/Components/LinkHandler/LinkHandler.tsx +2 -2
- package/Components/MasterCell/DefaultComponents/BorderContainerView/index.tsx +10 -4
- package/Components/MasterCell/DefaultComponents/Image/Image.android.tsx +1 -5
- package/Components/MasterCell/DefaultComponents/Image/Image.ios.tsx +3 -11
- package/Components/MasterCell/DefaultComponents/Image/Image.web.tsx +1 -9
- package/Components/MasterCell/DefaultComponents/Image/hooks/useImage.ts +14 -15
- 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 +34 -16
- package/Components/MasterCell/DefaultComponents/SecondaryImage/hooks/__tests__/useGetImageDimensions.test.ts +6 -7
- package/Components/MasterCell/DefaultComponents/Text/index.tsx +2 -6
- package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/index.ts +2 -6
- package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/utils/__tests__/getPluginIdentifier.test.ts +11 -233
- package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/utils/index.ts +15 -19
- package/Components/Navigator/StackNavigator.tsx +6 -0
- package/Components/OfflineHandler/NotificationView/NotificationView.tsx +2 -2
- package/Components/OfflineHandler/NotificationView/__tests__/index.test.tsx +18 -17
- package/Components/OfflineHandler/__tests__/index.test.tsx +18 -27
- package/Components/PlayerContainer/PlayerContainer.tsx +13 -31
- package/Components/PlayerContainer/__tests__/PlayerContainer.test.tsx +286 -0
- package/Components/PreloaderWrapper/__tests__/index.test.tsx +26 -0
- package/Components/PreloaderWrapper/index.tsx +15 -0
- package/Components/River/ComponentsMap/ComponentsMap.tsx +3 -4
- package/Components/River/ComponentsMap/hooks/__tests__/useLoadingState.test.ts +1 -1
- package/Components/River/RefreshControl.tsx +9 -3
- package/Components/River/RiverItem.tsx +26 -20
- package/Components/River/TV/River.tsx +14 -31
- package/Components/River/TV/index.tsx +4 -8
- package/Components/River/TV/withTVEventHandler.tsx +36 -0
- package/Components/River/__tests__/__snapshots__/componentsMap.test.js.snap +0 -16
- package/Components/River/__tests__/componentsMap.test.js +0 -38
- package/Components/Screen/TV/hooks/__tests__/useAfterPaint.test.ts +60 -0
- package/Components/Screen/TV/hooks/index.ts +2 -0
- package/Components/Screen/TV/hooks/useAfterPaint.ts +23 -0
- package/Components/Screen/TV/index.web.tsx +18 -11
- package/Components/Screen/__tests__/Screen.test.tsx +43 -65
- package/Components/Screen/__tests__/__snapshots__/Screen.test.tsx.snap +44 -68
- package/Components/Screen/hooks.ts +76 -5
- package/Components/Screen/index.tsx +10 -3
- package/Components/Screen/orientationHandler.ts +3 -3
- 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 +9 -115
- 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/Overlay.tsx +34 -0
- package/Components/ScreenRevealManager/ScreenRevealManager.ts +8 -40
- package/Components/ScreenRevealManager/__tests__/Overlay.test.tsx +88 -0
- package/Components/ScreenRevealManager/__tests__/ScreenRevealManager.test.ts +69 -86
- package/Components/ScreenRevealManager/withScreenRevealManager.tsx +10 -18
- package/Components/Tabs/TabContent.tsx +4 -7
- package/Components/Transitioner/Scene.tsx +9 -15
- package/Components/Transitioner/index.js +3 -3
- package/Components/VideoLive/LiveImageManager.ts +209 -53
- package/Components/VideoLive/PlayerLiveImageComponent.tsx +32 -32
- package/Components/VideoLive/__tests__/PlayerLiveImageComponent.test.tsx +2 -17
- package/Components/VideoModal/ModalAnimation/ModalAnimationContext.tsx +5 -5
- package/Components/VideoModal/hooks/__tests__/useDelayedPlayerDetails.test.ts +7 -15
- package/Components/VideoModal/utils.ts +16 -13
- package/Components/Viewport/ViewportEvents/__tests__/viewportEvents.test.js +1 -1
- package/Components/ZappFrameworkComponents/BarView/BarView.tsx +12 -5
- package/Components/ZappFrameworkComponents/BarView/__tests__/BarView.test.tsx +2 -2
- package/Components/ZappUIComponent/index.tsx +12 -6
- package/Components/index.js +1 -1
- package/Contexts/CachedDimensionsContext/index.ts +17 -2
- package/Contexts/ScreenContext/__tests__/index.test.tsx +57 -0
- package/Contexts/ScreenContext/index.tsx +64 -26
- package/Contexts/ScreenTrackedViewPositionsContext/__tests__/index.test.tsx +1 -1
- package/Contexts/ZappPipesContext/ZappPipesContextFactory.tsx +18 -7
- package/Decorators/Analytics/index.tsx +5 -6
- package/Decorators/ConfigurationWrapper/__tests__/__snapshots__/withConfigurationProvider.test.tsx.snap +0 -1
- package/Decorators/ConfigurationWrapper/const.ts +0 -1
- package/Decorators/ZappPipesDataConnector/ResolverSelector.tsx +25 -7
- package/Decorators/ZappPipesDataConnector/__tests__/ResolverSelector.test.tsx +212 -5
- package/Decorators/ZappPipesDataConnector/__tests__/zappPipesDataConnector.test.js +1 -1
- package/Decorators/ZappPipesDataConnector/index.tsx +2 -2
- package/Decorators/ZappPipesDataConnector/resolvers/StaticFeedResolver.tsx +1 -1
- package/Helpers/ComponentCellSelectionHelper/index.js +0 -6
- package/Helpers/DataSourceHelper/index.js +19 -0
- package/Helpers/index.js +7 -40
- package/package.json +5 -5
- package/Components/Layout/TV/LayoutBackground.tsx +0 -31
- package/Components/MasterCell/DefaultComponents/Text/utils/__tests__/withAdjustedLineHeight.test.ts +0 -46
- package/Components/MasterCell/DefaultComponents/Text/utils/index.ts +0 -21
- 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/River/TV/utils/__tests__/toStringOrEmpty.test.ts +0 -30
- package/Components/River/TV/utils/index.ts +0 -4
- package/Components/River/TV/withFocusableGroupForContent.tsx +0 -71
- package/Helpers/Analytics/index.js +0 -95
- package/Helpers/DataSourceHelper/__tests__/itemLimitForData.test.ts +0 -80
- package/Helpers/DataSourceHelper/index.ts +0 -19
- /package/Components/HookRenderer/{index.tsx → index.ts} +0 -0
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import {
|
|
3
|
+
View,
|
|
4
|
+
StyleSheet,
|
|
5
|
+
ImageURISource,
|
|
6
|
+
ImageBackground,
|
|
7
|
+
} from "react-native";
|
|
8
|
+
|
|
9
|
+
import { ASSETS } from "@applicaster/zapp-react-native-ui-components/Helpers";
|
|
10
|
+
|
|
11
|
+
const imageSource: ImageURISource = {
|
|
12
|
+
uri: ASSETS.APP_BACKGROUND_IMAGE,
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const styles = StyleSheet.create({
|
|
16
|
+
container: { flex: 1 },
|
|
17
|
+
backgroundImage: { width: "100%", height: "100%" },
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
export function BackgroundImage({ children }: React.PropsWithChildren) {
|
|
21
|
+
return (
|
|
22
|
+
<View style={styles.container}>
|
|
23
|
+
<ImageBackground style={styles.backgroundImage} source={imageSource}>
|
|
24
|
+
{children}
|
|
25
|
+
</ImageBackground>
|
|
26
|
+
</View>
|
|
27
|
+
);
|
|
28
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { View, StyleSheet, ImageURISource } from "react-native";
|
|
3
|
+
|
|
4
|
+
import { QBImage as Image } from "@applicaster/zapp-react-native-ui-components/Components/Image";
|
|
5
|
+
import { ASSETS } from "@applicaster/zapp-react-native-ui-components/Helpers";
|
|
6
|
+
|
|
7
|
+
const imageSource: ImageURISource = {
|
|
8
|
+
uri: ASSETS.APP_BACKGROUND_IMAGE,
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
const styles = StyleSheet.create({
|
|
12
|
+
container: { flex: 1 },
|
|
13
|
+
backgroundImage: { width: "100%", height: "100%" },
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
export function BackgroundImage({ children }: React.PropsWithChildren) {
|
|
17
|
+
return (
|
|
18
|
+
<View style={styles.container}>
|
|
19
|
+
<Image style={styles.backgroundImage} source={imageSource}>
|
|
20
|
+
{children}
|
|
21
|
+
</Image>
|
|
22
|
+
</View>
|
|
23
|
+
);
|
|
24
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { View, ViewStyle } from "react-native";
|
|
3
|
+
|
|
4
|
+
import { useTheme } from "@applicaster/zapp-react-native-utils/theme";
|
|
5
|
+
import {
|
|
6
|
+
selectRemoteConfigurations,
|
|
7
|
+
useAppSelector,
|
|
8
|
+
} from "@applicaster/zapp-react-native-redux";
|
|
9
|
+
|
|
10
|
+
import { getBackgroundImageUrl } from "../Layout/utils";
|
|
11
|
+
|
|
12
|
+
const baseBackgroundStyles = (imageUrl, backgroundColor) =>
|
|
13
|
+
({
|
|
14
|
+
position: "absolute",
|
|
15
|
+
left: 0,
|
|
16
|
+
top: 0,
|
|
17
|
+
right: 0,
|
|
18
|
+
bottom: 0,
|
|
19
|
+
zIndex: -1,
|
|
20
|
+
backgroundSize: "cover",
|
|
21
|
+
background: imageUrl
|
|
22
|
+
? `url(${imageUrl}) no-repeat top center ${backgroundColor}`
|
|
23
|
+
: backgroundColor,
|
|
24
|
+
}) as ViewStyle;
|
|
25
|
+
|
|
26
|
+
export const BackgroundImage = ({ children }: React.PropsWithChildren) => {
|
|
27
|
+
const theme = useTheme();
|
|
28
|
+
|
|
29
|
+
const remoteConfigurations = useAppSelector(selectRemoteConfigurations);
|
|
30
|
+
|
|
31
|
+
const backgroundColor = theme.app_background_color;
|
|
32
|
+
const backgroundImageUrl = getBackgroundImageUrl(remoteConfigurations);
|
|
33
|
+
|
|
34
|
+
return (
|
|
35
|
+
<View
|
|
36
|
+
id="background"
|
|
37
|
+
style={baseBackgroundStyles(backgroundImageUrl, backgroundColor)}
|
|
38
|
+
>
|
|
39
|
+
{children}
|
|
40
|
+
</View>
|
|
41
|
+
);
|
|
42
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { platformSelect } from "@applicaster/zapp-react-native-utils/reactUtils";
|
|
2
|
+
|
|
3
|
+
export const BackgroundImage = platformSelect({
|
|
4
|
+
tvos: require("./BackgroundImage.tv.ios").BackgroundImage,
|
|
5
|
+
android_tv: require("./BackgroundImage.tv.android").BackgroundImage,
|
|
6
|
+
amazon: require("./BackgroundImage.tv.android").BackgroundImage,
|
|
7
|
+
web: require("./BackgroundImage.tv.web").BackgroundImage,
|
|
8
|
+
});
|
|
@@ -22,7 +22,6 @@ type Props = {
|
|
|
22
22
|
onFocus?: FocusManager.FocusEventCB;
|
|
23
23
|
onBlur?: FocusManager.FocusEventCB;
|
|
24
24
|
selected?: boolean;
|
|
25
|
-
skipFocusManagerRegistration?: boolean;
|
|
26
25
|
};
|
|
27
26
|
|
|
28
27
|
export class BaseFocusable<
|
|
@@ -62,14 +61,10 @@ export class BaseFocusable<
|
|
|
62
61
|
}
|
|
63
62
|
|
|
64
63
|
componentDidMount() {
|
|
65
|
-
const { id
|
|
64
|
+
const { id } = this.props;
|
|
66
65
|
const component = this;
|
|
67
66
|
this.node = this.ref.current;
|
|
68
67
|
|
|
69
|
-
if (skipFocusManagerRegistration) {
|
|
70
|
-
return;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
68
|
focusManager.register({
|
|
74
69
|
id,
|
|
75
70
|
component: component,
|
|
@@ -123,12 +118,7 @@ export class BaseFocusable<
|
|
|
123
118
|
|
|
124
119
|
componentWillUnmount() {
|
|
125
120
|
this._isMounted = false;
|
|
126
|
-
const { id
|
|
127
|
-
|
|
128
|
-
if (skipFocusManagerRegistration) {
|
|
129
|
-
return;
|
|
130
|
-
}
|
|
131
|
-
|
|
121
|
+
const { id } = this.props;
|
|
132
122
|
focusManager.unregister(id, { group: this.isGroup || false });
|
|
133
123
|
}
|
|
134
124
|
|
|
@@ -10,7 +10,6 @@ type Props = {
|
|
|
10
10
|
children: (focused: boolean) => React.ReactNode;
|
|
11
11
|
onFocus: (arg1: any, index?: number) => void;
|
|
12
12
|
onBlur: Callback;
|
|
13
|
-
skipFocusManagerRegistration?: boolean;
|
|
14
13
|
};
|
|
15
14
|
|
|
16
15
|
export const FocusableWrapper = ({
|
|
@@ -21,7 +20,6 @@ export const FocusableWrapper = ({
|
|
|
21
20
|
applyWrapper,
|
|
22
21
|
onFocus,
|
|
23
22
|
onBlur,
|
|
24
|
-
skipFocusManagerRegistration,
|
|
25
23
|
}: Props) => {
|
|
26
24
|
if (applyWrapper) {
|
|
27
25
|
return (
|
|
@@ -36,7 +34,6 @@ export const FocusableWrapper = ({
|
|
|
36
34
|
// @ts-ignore
|
|
37
35
|
offsetUpdater={noop}
|
|
38
36
|
isFocusable
|
|
39
|
-
skipFocusManagerRegistration={skipFocusManagerRegistration}
|
|
40
37
|
>
|
|
41
38
|
{(focused) => children(focused)}
|
|
42
39
|
</Focusable>
|
|
@@ -80,7 +80,6 @@ type Props = {
|
|
|
80
80
|
componentsMapOffset: number;
|
|
81
81
|
applyFocusableWrapper: boolean;
|
|
82
82
|
hasFocusableInside: boolean;
|
|
83
|
-
skipFocusManagerRegistration?: boolean;
|
|
84
83
|
};
|
|
85
84
|
|
|
86
85
|
type State = {
|
|
@@ -267,7 +266,6 @@ class TvOSCell extends React.Component<Props, State> {
|
|
|
267
266
|
behavior,
|
|
268
267
|
applyFocusableWrapper,
|
|
269
268
|
hasFocusableInside,
|
|
270
|
-
skipFocusManagerRegistration,
|
|
271
269
|
} = this.props;
|
|
272
270
|
|
|
273
271
|
const { id } = item;
|
|
@@ -293,7 +291,6 @@ class TvOSCell extends React.Component<Props, State> {
|
|
|
293
291
|
onFocus={handleFocus}
|
|
294
292
|
onBlur={onBlur || this.onBlur}
|
|
295
293
|
applyWrapper={applyFocusableWrapper}
|
|
296
|
-
skipFocusManagerRegistration={skipFocusManagerRegistration}
|
|
297
294
|
>
|
|
298
295
|
{(focused) => (
|
|
299
296
|
<CellWithFocusable
|
|
@@ -308,7 +305,6 @@ class TvOSCell extends React.Component<Props, State> {
|
|
|
308
305
|
focused={focused || this.props.focused}
|
|
309
306
|
behavior={behavior}
|
|
310
307
|
isFocusable={isFocusable}
|
|
311
|
-
skipFocusManagerRegistration={skipFocusManagerRegistration}
|
|
312
308
|
/>
|
|
313
309
|
)}
|
|
314
310
|
</FocusableWrapper>
|
|
@@ -331,7 +327,6 @@ class TvOSCell extends React.Component<Props, State> {
|
|
|
331
327
|
offsetUpdater={offsetUpdater}
|
|
332
328
|
style={baseCellStyles}
|
|
333
329
|
isFocusable={isFocusable}
|
|
334
|
-
skipFocusManagerRegistration={skipFocusManagerRegistration}
|
|
335
330
|
>
|
|
336
331
|
{(focused) => (
|
|
337
332
|
<FocusableCell
|
|
@@ -83,7 +83,7 @@ export function CellRendererResolver({
|
|
|
83
83
|
|
|
84
84
|
if (!cellRendererPlugin && !isGroup(component)) {
|
|
85
85
|
logger.warning({
|
|
86
|
-
message:
|
|
86
|
+
message: `Could not resolve cell builder plugin: ${component?.component_type}`,
|
|
87
87
|
data: { component },
|
|
88
88
|
});
|
|
89
89
|
}
|
|
@@ -107,7 +107,7 @@ describe("ComponentResolverComponent", () => {
|
|
|
107
107
|
expect(mockLogger.warning).toHaveBeenNthCalledWith(
|
|
108
108
|
1,
|
|
109
109
|
expect.objectContaining({
|
|
110
|
-
message: "Could not resolve cell builder plugin",
|
|
110
|
+
message: "Could not resolve cell builder plugin: foo",
|
|
111
111
|
})
|
|
112
112
|
);
|
|
113
113
|
|
|
@@ -8,8 +8,6 @@ import { withFocusableContext } from "../../Contexts/FocusableGroupContext/withF
|
|
|
8
8
|
import { StyleSheet, ViewStyle } from "react-native";
|
|
9
9
|
import { AccessibilityManager } from "@applicaster/zapp-react-native-utils/appUtils/accessibilityManager";
|
|
10
10
|
|
|
11
|
-
import { isSearchInputId } from "@applicaster/zapp-react-native-utils/searchUtils";
|
|
12
|
-
|
|
13
11
|
type Props = {
|
|
14
12
|
initialFocus?: boolean;
|
|
15
13
|
id: string;
|
|
@@ -108,7 +106,7 @@ class Focusable extends BaseFocusable<Props> {
|
|
|
108
106
|
onMouseEnter() {
|
|
109
107
|
const { id } = this.props;
|
|
110
108
|
|
|
111
|
-
if (
|
|
109
|
+
if (id !== "search_input_group_id") {
|
|
112
110
|
this.mouse = true;
|
|
113
111
|
this.props?.handleFocus?.({ mouse: true });
|
|
114
112
|
|
|
@@ -122,7 +120,7 @@ class Focusable extends BaseFocusable<Props> {
|
|
|
122
120
|
onMouseLeave() {
|
|
123
121
|
const { id } = this.props;
|
|
124
122
|
|
|
125
|
-
if (
|
|
123
|
+
if (id !== "search_input_group_id") {
|
|
126
124
|
this.mouse = false;
|
|
127
125
|
this.blur(null);
|
|
128
126
|
}
|
|
@@ -10,12 +10,8 @@ import {
|
|
|
10
10
|
forceFocusableFocus,
|
|
11
11
|
} from "@applicaster/zapp-react-native-utils/appUtils/focusManager/index.ios";
|
|
12
12
|
import { findNodeHandle, ViewStyle } from "react-native";
|
|
13
|
-
import { noop } from "@applicaster/zapp-react-native-utils/functionUtils";
|
|
14
13
|
|
|
15
|
-
|
|
16
|
-
emitFocused,
|
|
17
|
-
emitNativeRegistered,
|
|
18
|
-
} from "@applicaster/zapp-react-native-utils/appUtils/focusManagerAux/utils/utils.ios";
|
|
14
|
+
function noop() {}
|
|
19
15
|
|
|
20
16
|
type Props = {
|
|
21
17
|
id: string;
|
|
@@ -43,7 +39,6 @@ type Props = {
|
|
|
43
39
|
hasReceivedFocus: () => void;
|
|
44
40
|
offsetUpdater: (arg1: string, arg2: number) => number;
|
|
45
41
|
style: ViewStyle;
|
|
46
|
-
skipFocusManagerRegistration?: boolean;
|
|
47
42
|
};
|
|
48
43
|
|
|
49
44
|
export class Focusable extends BaseFocusable<Props> {
|
|
@@ -58,7 +53,6 @@ export class Focusable extends BaseFocusable<Props> {
|
|
|
58
53
|
this.nextFocusableReactTags = {};
|
|
59
54
|
this.preferredFocus = this.preferredFocus.bind(this);
|
|
60
55
|
this.measureView = this.measureView.bind(this);
|
|
61
|
-
this.onRegistered = this.onRegistered.bind(this);
|
|
62
56
|
}
|
|
63
57
|
|
|
64
58
|
/**
|
|
@@ -90,9 +84,6 @@ export class Focusable extends BaseFocusable<Props> {
|
|
|
90
84
|
});
|
|
91
85
|
}
|
|
92
86
|
|
|
93
|
-
const id: string = nativeEvent.itemID;
|
|
94
|
-
emitFocused(id);
|
|
95
|
-
|
|
96
87
|
onFocus(nativeEvent);
|
|
97
88
|
}
|
|
98
89
|
|
|
@@ -178,13 +169,6 @@ export class Focusable extends BaseFocusable<Props> {
|
|
|
178
169
|
});
|
|
179
170
|
}
|
|
180
171
|
|
|
181
|
-
onRegistered({ nativeEvent }) {
|
|
182
|
-
const groupId = nativeEvent?.groupId;
|
|
183
|
-
const id = nativeEvent?.itemId;
|
|
184
|
-
|
|
185
|
-
emitNativeRegistered({ id, groupId, isGroup: false });
|
|
186
|
-
}
|
|
187
|
-
|
|
188
172
|
render() {
|
|
189
173
|
const {
|
|
190
174
|
children,
|
|
@@ -219,7 +203,6 @@ export class Focusable extends BaseFocusable<Props> {
|
|
|
219
203
|
focusable={isFocusable}
|
|
220
204
|
{...this.nextFocusableReactTags}
|
|
221
205
|
{...otherProps}
|
|
222
|
-
onRegistered={this.onRegistered}
|
|
223
206
|
>
|
|
224
207
|
{typeof children === "function" ? children(focused) : children}
|
|
225
208
|
</FocusableItemNative>
|
|
@@ -1,16 +1,14 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import { FocusableGroupNative } from "@applicaster/zapp-react-native-ui-components/Components/NativeFocusables";
|
|
3
3
|
import { BaseFocusable } from "@applicaster/zapp-react-native-ui-components/Components/BaseFocusable";
|
|
4
|
-
|
|
5
|
-
import {
|
|
6
|
-
import { useRoute } from "@applicaster/zapp-react-native-utils/reactHooks/navigation/useRoute";
|
|
7
|
-
import { isScreenPlayable } from "@applicaster/zapp-react-native-utils/navigationUtils/itemTypes";
|
|
8
|
-
import { emitNativeRegistered } from "@applicaster/zapp-react-native-utils/appUtils/focusManagerAux/utils/utils.ios";
|
|
4
|
+
// TODO: Enable when will be feature flags
|
|
5
|
+
// import { createLogger } from "@applicaster/zapp-react-native-utils/logger";
|
|
9
6
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
7
|
+
// TODO: Enable when will be feature flags
|
|
8
|
+
// const { log_verbose } = createLogger({
|
|
9
|
+
// subsystem: "General",
|
|
10
|
+
// category: "FocusableGroup",
|
|
11
|
+
// });
|
|
14
12
|
|
|
15
13
|
type FocusableGroupNativeEvent = {
|
|
16
14
|
nativeEvent: {
|
|
@@ -37,16 +35,9 @@ type Props = {
|
|
|
37
35
|
screenData: { screenId: string; parentScreenId: string };
|
|
38
36
|
};
|
|
39
37
|
|
|
40
|
-
class
|
|
38
|
+
export class FocusableGroup extends BaseFocusable<Props> {
|
|
41
39
|
public readonly isGroup: boolean = true;
|
|
42
40
|
|
|
43
|
-
onRegistered = ({ nativeEvent }) => {
|
|
44
|
-
const groupId = nativeEvent?.groupId;
|
|
45
|
-
const id = nativeEvent?.itemId;
|
|
46
|
-
|
|
47
|
-
emitNativeRegistered({ id, groupId, isGroup: true });
|
|
48
|
-
};
|
|
49
|
-
|
|
50
41
|
render() {
|
|
51
42
|
const {
|
|
52
43
|
children,
|
|
@@ -59,12 +50,14 @@ class FocusableGroupComponent extends BaseFocusable<Props> {
|
|
|
59
50
|
} = this.props;
|
|
60
51
|
|
|
61
52
|
const onGroupFocus = ({ nativeEvent }: FocusableGroupNativeEvent) => {
|
|
62
|
-
|
|
53
|
+
// TODO: Enable when will be feature flags
|
|
54
|
+
// log_verbose("FOCUSABLE_GROUP: onGroupFocus", { nativeEvent });
|
|
63
55
|
this.onFocus(this.ref, nativeEvent.focusHeading);
|
|
64
56
|
};
|
|
65
57
|
|
|
66
58
|
const onGroupBlur = ({ nativeEvent }: FocusableGroupNativeEvent) => {
|
|
67
|
-
|
|
59
|
+
// TODO: Enable when will be feature flags
|
|
60
|
+
// log_verbose("FOCUSABLE_GROUP: onGroupBlur", { nativeEvent });
|
|
68
61
|
this.onBlur(this.ref, nativeEvent.focusHeading);
|
|
69
62
|
};
|
|
70
63
|
|
|
@@ -79,27 +72,9 @@ class FocusableGroupComponent extends BaseFocusable<Props> {
|
|
|
79
72
|
onGroupBlur={onGroupBlur}
|
|
80
73
|
style={style}
|
|
81
74
|
{...otherProps}
|
|
82
|
-
onRegistered={this.onRegistered}
|
|
83
75
|
>
|
|
84
76
|
{children}
|
|
85
77
|
</FocusableGroupNative>
|
|
86
78
|
);
|
|
87
79
|
}
|
|
88
80
|
}
|
|
89
|
-
|
|
90
|
-
export const withFocusDisabled = (Component) => {
|
|
91
|
-
return function WithFocusDisabled(props) {
|
|
92
|
-
// @ts-ignore
|
|
93
|
-
const { screenFocusBlocked } = React.useContext(LayoutContext.ReactContext);
|
|
94
|
-
|
|
95
|
-
const { pathname } = useRoute();
|
|
96
|
-
|
|
97
|
-
const isPlayerPresented = isScreenPlayable(pathname);
|
|
98
|
-
|
|
99
|
-
const blockScreenFocus = isPlayerPresented === false && screenFocusBlocked;
|
|
100
|
-
|
|
101
|
-
return <Component {...props} isFocusDisabled={blockScreenFocus} />;
|
|
102
|
-
};
|
|
103
|
-
};
|
|
104
|
-
|
|
105
|
-
export const FocusableGroup = withFocusDisabled(FocusableGroupComponent);
|
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
<
|
|
112
|
-
<
|
|
113
|
-
<
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
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
|
+
};
|