@applicaster/zapp-react-native-ui-components 15.0.0-alpha.6144399951 → 15.0.0-alpha.6351072502
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/Cell.tsx +6 -0
- package/Components/Cell/CellWithFocusable.tsx +9 -0
- package/Components/GeneralContentScreen/utils/__tests__/useCurationAPI.test.js +1 -1
- package/Components/GeneralContentScreen/utils/useCurationAPI.ts +13 -8
- package/Components/MasterCell/DefaultComponents/SecondaryImage/Image.tsx +40 -39
- package/Components/MasterCell/DefaultComponents/SecondaryImage/__tests__/Image.test.tsx +95 -0
- package/Components/MasterCell/DefaultComponents/SecondaryImage/__tests__/__snapshots__/Image.test.tsx.snap +86 -0
- package/Components/MasterCell/DefaultComponents/SecondaryImage/__tests__/index.test.ts +141 -0
- package/Components/MasterCell/DefaultComponents/SecondaryImage/hooks/__tests__/useGetImageDimensions.test.ts +7 -6
- package/Components/MasterCell/DefaultComponents/SecondaryImage/index.ts +1 -1
- package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/index.ts +6 -2
- package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/utils/__tests__/getPluginIdentifier.test.ts +233 -11
- package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/utils/index.ts +19 -15
- package/Components/MasterCell/hoc/__tests__/withAsyncRender.test.tsx +219 -0
- package/Components/MasterCell/hoc/withAsyncRender.tsx +9 -7
- package/Components/OfflineHandler/NotificationView/NotificationView.lg.tsx +17 -9
- package/Components/OfflineHandler/NotificationView/NotificationView.samsung.tsx +16 -8
- package/Components/OfflineHandler/NotificationView/utils.ts +34 -0
- package/Components/River/ComponentsMap/hooks/__tests__/useLoadingState.test.ts +1 -1
- package/Components/Screen/orientationHandler.ts +7 -10
- package/Components/Tabs/TabContent.tsx +7 -4
- package/Components/VideoModal/hooks/__tests__/useDelayedPlayerDetails.test.ts +15 -7
- package/Components/Viewport/ViewportEvents/__tests__/viewportEvents.test.js +1 -1
- package/Contexts/ScreenContext/index.tsx +25 -18
- package/Contexts/ScreenTrackedViewPositionsContext/__tests__/index.test.tsx +1 -1
- package/Contexts/ZappHookModalContext/index.tsx +37 -61
- package/Contexts/index.ts +0 -2
- package/events/index.ts +1 -0
- package/package.json +5 -5
package/Components/Cell/Cell.tsx
CHANGED
|
@@ -26,11 +26,15 @@ type Props = {
|
|
|
26
26
|
componentAnchorPointY: number;
|
|
27
27
|
headerOffset?: number;
|
|
28
28
|
extraAnchorPointYOffset?: number;
|
|
29
|
+
componentPaddingTop?: number;
|
|
29
30
|
}) => void;
|
|
30
31
|
offsetUpdater: (arg1: string, arg2: number, arg3: number) => number;
|
|
31
32
|
componentId: string;
|
|
32
33
|
component: {
|
|
33
34
|
id: string;
|
|
35
|
+
styles?: {
|
|
36
|
+
component_padding_top?: number;
|
|
37
|
+
};
|
|
34
38
|
};
|
|
35
39
|
selected?: boolean;
|
|
36
40
|
CellRenderer: React.FunctionComponent<any> & {
|
|
@@ -178,6 +182,8 @@ export class CellComponent extends React.Component<Props, State> {
|
|
|
178
182
|
componentAnchorPointY,
|
|
179
183
|
headerOffset,
|
|
180
184
|
extraAnchorPointYOffset,
|
|
185
|
+
componentPaddingTop:
|
|
186
|
+
this.props?.component?.styles?.component_padding_top,
|
|
181
187
|
});
|
|
182
188
|
}
|
|
183
189
|
}
|
|
@@ -2,6 +2,7 @@ import * as React from "react";
|
|
|
2
2
|
|
|
3
3
|
import { noop } from "@applicaster/zapp-react-native-utils/functionUtils";
|
|
4
4
|
import { toBooleanWithDefaultFalse } from "@applicaster/zapp-react-native-utils/booleanUtils";
|
|
5
|
+
import { platformSelect } from "@applicaster/zapp-react-native-utils/reactUtils";
|
|
5
6
|
|
|
6
7
|
import { useCellState } from "../MasterCell/utils";
|
|
7
8
|
import { FocusableGroup } from "../FocusableGroup";
|
|
@@ -26,6 +27,13 @@ type Props = {
|
|
|
26
27
|
|
|
27
28
|
const addPrefix = (id: string) => `focusable-cell-wrapper-${id}`;
|
|
28
29
|
|
|
30
|
+
const wrapperStyles = {
|
|
31
|
+
flex: platformSelect({
|
|
32
|
+
tvos: 1,
|
|
33
|
+
default: undefined,
|
|
34
|
+
}),
|
|
35
|
+
};
|
|
36
|
+
|
|
29
37
|
export function CellWithFocusable(props: Props) {
|
|
30
38
|
const {
|
|
31
39
|
index,
|
|
@@ -94,6 +102,7 @@ export function CellWithFocusable(props: Props) {
|
|
|
94
102
|
onFocus={onGroupFocus}
|
|
95
103
|
onBlur={onGroupBlur}
|
|
96
104
|
skipFocusManagerRegistration={skipFocusManagerRegistration}
|
|
105
|
+
style={wrapperStyles}
|
|
97
106
|
>
|
|
98
107
|
<CellWrapper style={styles.cellWrapper}>
|
|
99
108
|
<CellRenderer
|
|
@@ -9,10 +9,9 @@ import {
|
|
|
9
9
|
import { isEmptyOrNil } from "@applicaster/zapp-react-native-utils/cellUtils";
|
|
10
10
|
import { Categories } from "./logger";
|
|
11
11
|
import { createLogger } from "@applicaster/zapp-react-native-utils/logger";
|
|
12
|
-
import {
|
|
12
|
+
import { useScreenContext } from "@applicaster/zapp-react-native-utils/reactHooks/screen/useScreenContext";
|
|
13
13
|
|
|
14
14
|
import {
|
|
15
|
-
ZappPipesEntryContext,
|
|
16
15
|
ZappPipesScreenContext,
|
|
17
16
|
ZappPipesSearchContext,
|
|
18
17
|
} from "@applicaster/zapp-react-native-ui-components/Contexts";
|
|
@@ -37,6 +36,7 @@ type Feeds = Record<string, ZappPipesData>;
|
|
|
37
36
|
type LayoutPresets = PresetsMapping["presets_mappings"];
|
|
38
37
|
|
|
39
38
|
const TABS_SCREEN_TYPE = "tabs_screen";
|
|
39
|
+
const QB_TABS_SCREEN_TYPE = "quick-brick-tabs";
|
|
40
40
|
const SMART_COMPONENT_TYPE = "quick-brick-smart-component";
|
|
41
41
|
const SOURCE_PATH = ["data", "source"];
|
|
42
42
|
const MAPPING_PATH = ["data", "mapping"];
|
|
@@ -135,16 +135,21 @@ export const useCurationAPI = (
|
|
|
135
135
|
[components]
|
|
136
136
|
);
|
|
137
137
|
|
|
138
|
-
const { pathname } = useRoute();
|
|
139
138
|
const [searchContext] = ZappPipesSearchContext.useZappPipesContext();
|
|
140
139
|
const [screenContext] = ZappPipesScreenContext.useZappPipesContext();
|
|
141
140
|
|
|
142
|
-
const
|
|
141
|
+
const screenContextType = screenContext?.type;
|
|
143
142
|
|
|
144
|
-
const
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
143
|
+
const isNestedScreen =
|
|
144
|
+
screenContextType === TABS_SCREEN_TYPE ||
|
|
145
|
+
screenContextType === QB_TABS_SCREEN_TYPE;
|
|
146
|
+
|
|
147
|
+
const screenContextData = useScreenContext();
|
|
148
|
+
|
|
149
|
+
const entryContext = ((isNestedScreen && screenContextData?.nested?.entry
|
|
150
|
+
? screenContextData?.nested?.entry
|
|
151
|
+
: (screenContextData?.entry?.payload ?? screenContextData?.entry)) ||
|
|
152
|
+
{}) as ZappEntry;
|
|
148
153
|
|
|
149
154
|
const urlsMap = useMemo<{ [key: string]: string }>(() => {
|
|
150
155
|
const map = {};
|
|
@@ -3,8 +3,8 @@ import { isNil } from "ramda";
|
|
|
3
3
|
import { ImageStyle, View } from "react-native";
|
|
4
4
|
import {
|
|
5
5
|
FIT_POSITION,
|
|
6
|
-
IMAGE_SIZING_FIT,
|
|
7
6
|
IMAGE_SIZING_FILL,
|
|
7
|
+
IMAGE_SIZING_FIT,
|
|
8
8
|
} from "@applicaster/zapp-react-native-utils/manifestUtils/secondaryImage";
|
|
9
9
|
import { QBImage as Image } from "@applicaster/zapp-react-native-ui-components/Components/Image";
|
|
10
10
|
|
|
@@ -25,49 +25,51 @@ interface Props {
|
|
|
25
25
|
fitPosition: typeof FIT_POSITION;
|
|
26
26
|
fixedWidth: number;
|
|
27
27
|
fixedHeight: number;
|
|
28
|
-
onAsyncRender
|
|
28
|
+
onAsyncRender?: () => void;
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
/** Secondary Image Dynamic does not render until the image is loaded */
|
|
32
|
-
const SecondaryImageDynamic = (
|
|
33
|
-
|
|
34
|
-
|
|
32
|
+
const SecondaryImageDynamic = withAsyncRenderHOC(
|
|
33
|
+
(props: Props & { onAsyncRender: () => void }) => {
|
|
34
|
+
const { uri, style, displayMode, imageSizing, fitPosition, onAsyncRender } =
|
|
35
|
+
props;
|
|
35
36
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
37
|
+
const imageDimension = useGetImageDimensions(
|
|
38
|
+
uri,
|
|
39
|
+
style.width as number,
|
|
40
|
+
isImageSizingFit(imageSizing) ? undefined : (style.height as number)
|
|
41
|
+
);
|
|
41
42
|
|
|
42
|
-
|
|
43
|
+
const containerHeight = imageDimension?.height;
|
|
43
44
|
|
|
44
|
-
|
|
45
|
+
const containerWidth = style?.width;
|
|
45
46
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
47
|
+
if (isNil(imageDimension?.aspectRatio)) {
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
49
50
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
}
|
|
51
|
+
return (
|
|
52
|
+
<View style={style} onLayout={onAsyncRender}>
|
|
53
|
+
<Image
|
|
54
|
+
{...props}
|
|
55
|
+
source={{ uri }}
|
|
56
|
+
style={{
|
|
57
|
+
...getStyle({
|
|
58
|
+
imageSizing,
|
|
59
|
+
fitPosition,
|
|
60
|
+
displayMode,
|
|
61
|
+
imageDimension,
|
|
62
|
+
containerHeight,
|
|
63
|
+
containerWidth,
|
|
64
|
+
}),
|
|
65
|
+
borderRadius: style.borderRadius,
|
|
66
|
+
aspectRatio: imageDimension.aspectRatio,
|
|
67
|
+
}}
|
|
68
|
+
/>
|
|
69
|
+
</View>
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
);
|
|
71
73
|
|
|
72
74
|
/** Secondary Image Fixed does not render the image until the image is loaded, but keep container rendered */
|
|
73
75
|
const SecondaryImageFixed = (props: Props) => {
|
|
@@ -79,7 +81,6 @@ const SecondaryImageFixed = (props: Props) => {
|
|
|
79
81
|
fitPosition,
|
|
80
82
|
fixedHeight,
|
|
81
83
|
fixedWidth,
|
|
82
|
-
onAsyncRender,
|
|
83
84
|
} = props;
|
|
84
85
|
|
|
85
86
|
const imageDimension = useGetImageDimensions(
|
|
@@ -89,7 +90,7 @@ const SecondaryImageFixed = (props: Props) => {
|
|
|
89
90
|
);
|
|
90
91
|
|
|
91
92
|
return (
|
|
92
|
-
<View style={style}
|
|
93
|
+
<View style={style}>
|
|
93
94
|
{isNil(imageDimension?.aspectRatio) ? null : (
|
|
94
95
|
<Image
|
|
95
96
|
{...props}
|
|
@@ -128,4 +129,4 @@ const SecondaryImageComponent = (props: Props) => {
|
|
|
128
129
|
);
|
|
129
130
|
};
|
|
130
131
|
|
|
131
|
-
export const SecondaryImage =
|
|
132
|
+
export const SecondaryImage = SecondaryImageComponent;
|
|
@@ -10,6 +10,10 @@ describe("SecondaryImage - Image", () => {
|
|
|
10
10
|
displayMode="dynamic"
|
|
11
11
|
uri={undefined}
|
|
12
12
|
style={{ width: 100 }}
|
|
13
|
+
imageSizing="fit"
|
|
14
|
+
fitPosition="center"
|
|
15
|
+
fixedWidth={0}
|
|
16
|
+
fixedHeight={0}
|
|
13
17
|
/>
|
|
14
18
|
);
|
|
15
19
|
|
|
@@ -23,6 +27,10 @@ describe("SecondaryImage - Image", () => {
|
|
|
23
27
|
displayMode="dynamic"
|
|
24
28
|
uri="someurl"
|
|
25
29
|
style={{ width: 100 }}
|
|
30
|
+
imageSizing="fit"
|
|
31
|
+
fitPosition="center"
|
|
32
|
+
fixedWidth={0}
|
|
33
|
+
fixedHeight={0}
|
|
26
34
|
/>
|
|
27
35
|
);
|
|
28
36
|
|
|
@@ -36,6 +44,93 @@ describe("SecondaryImage - Image", () => {
|
|
|
36
44
|
uri="someUrl"
|
|
37
45
|
displayMode="dynamic"
|
|
38
46
|
style={{ width: 100, height: 100, borderRadius: 10 }}
|
|
47
|
+
imageSizing="fill"
|
|
48
|
+
fitPosition="center"
|
|
49
|
+
fixedWidth={0}
|
|
50
|
+
fixedHeight={0}
|
|
51
|
+
/>
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
expect(wrapper.toJSON()).not.toEqual(null);
|
|
55
|
+
expect(wrapper.toJSON()).toMatchSnapshot();
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it("SecondaryImage should render in fixed mode without image until loaded", async () => {
|
|
59
|
+
const wrapper = await render(
|
|
60
|
+
<SecondaryImage
|
|
61
|
+
displayMode="fixed"
|
|
62
|
+
uri="someurl"
|
|
63
|
+
style={{ width: 100, height: 100, borderRadius: 5 }}
|
|
64
|
+
imageSizing="fit"
|
|
65
|
+
fitPosition="center"
|
|
66
|
+
fixedWidth={100}
|
|
67
|
+
fixedHeight={100}
|
|
68
|
+
/>
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
expect(wrapper.toJSON()).toMatchSnapshot();
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it("SecondaryImage should not render in dynamic mode without image", async () => {
|
|
75
|
+
const wrapper = await render(
|
|
76
|
+
<SecondaryImage
|
|
77
|
+
displayMode="dynamic"
|
|
78
|
+
uri={null}
|
|
79
|
+
style={{ width: 100, height: 100 }}
|
|
80
|
+
imageSizing="fit"
|
|
81
|
+
fitPosition="center"
|
|
82
|
+
fixedWidth={0}
|
|
83
|
+
fixedHeight={0}
|
|
84
|
+
/>
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
expect(wrapper.toJSON()).toEqual(null);
|
|
88
|
+
expect(wrapper.toJSON()).toMatchSnapshot();
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it("SecondaryImage should render in fixed mode with known dimensions", async () => {
|
|
92
|
+
const wrapper = await render(
|
|
93
|
+
<SecondaryImage
|
|
94
|
+
uri="someUrl"
|
|
95
|
+
displayMode="fixed"
|
|
96
|
+
style={{ width: 100, height: 100, borderRadius: 10 }}
|
|
97
|
+
imageSizing="fill"
|
|
98
|
+
fitPosition="center"
|
|
99
|
+
fixedWidth={100}
|
|
100
|
+
fixedHeight={100}
|
|
101
|
+
/>
|
|
102
|
+
);
|
|
103
|
+
|
|
104
|
+
expect(wrapper.toJSON()).not.toEqual(null);
|
|
105
|
+
expect(wrapper.toJSON()).toMatchSnapshot();
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it("SecondaryImage dynamic mode should call onAsyncRender when provided", async () => {
|
|
109
|
+
const wrapper = await render(
|
|
110
|
+
<SecondaryImage
|
|
111
|
+
uri="someUrl"
|
|
112
|
+
displayMode="dynamic"
|
|
113
|
+
style={{ width: 100, height: 100, borderRadius: 10 }}
|
|
114
|
+
imageSizing="fill"
|
|
115
|
+
fitPosition="center"
|
|
116
|
+
fixedWidth={0}
|
|
117
|
+
fixedHeight={0}
|
|
118
|
+
/>
|
|
119
|
+
);
|
|
120
|
+
|
|
121
|
+
expect(wrapper.toJSON()).not.toEqual(null);
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
it("SecondaryImage fixed mode should not use async render props", async () => {
|
|
125
|
+
const wrapper = await render(
|
|
126
|
+
<SecondaryImage
|
|
127
|
+
uri="someUrl"
|
|
128
|
+
displayMode="fixed"
|
|
129
|
+
style={{ width: 100, height: 100, borderRadius: 10 }}
|
|
130
|
+
imageSizing="fill"
|
|
131
|
+
fitPosition="center"
|
|
132
|
+
fixedWidth={100}
|
|
133
|
+
fixedHeight={100}
|
|
39
134
|
/>
|
|
40
135
|
);
|
|
41
136
|
|
|
@@ -1,9 +1,45 @@
|
|
|
1
1
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
2
2
|
|
|
3
|
+
exports[`SecondaryImage - Image SecondaryImage fixed mode should not use async render props 1`] = `
|
|
4
|
+
<View
|
|
5
|
+
style={
|
|
6
|
+
{
|
|
7
|
+
"borderRadius": 10,
|
|
8
|
+
"height": 100,
|
|
9
|
+
"width": 100,
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
>
|
|
13
|
+
<Image
|
|
14
|
+
displayMode="fixed"
|
|
15
|
+
fitPosition="center"
|
|
16
|
+
fixedHeight={100}
|
|
17
|
+
fixedWidth={100}
|
|
18
|
+
imageSizing="fill"
|
|
19
|
+
source={
|
|
20
|
+
{
|
|
21
|
+
"uri": "someUrl",
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
style={
|
|
25
|
+
{
|
|
26
|
+
"aspectRatio": 1,
|
|
27
|
+
"borderRadius": 10,
|
|
28
|
+
"height": 100,
|
|
29
|
+
"width": 100,
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
uri="someUrl"
|
|
33
|
+
/>
|
|
34
|
+
</View>
|
|
35
|
+
`;
|
|
36
|
+
|
|
3
37
|
exports[`SecondaryImage - Image SecondaryImage should not render if no aspect ratio (dynamic) 1`] = `null`;
|
|
4
38
|
|
|
5
39
|
exports[`SecondaryImage - Image SecondaryImage should not render if no uri 1`] = `null`;
|
|
6
40
|
|
|
41
|
+
exports[`SecondaryImage - Image SecondaryImage should not render in dynamic mode without image 1`] = `null`;
|
|
42
|
+
|
|
7
43
|
exports[`SecondaryImage - Image SecondaryImage should render if known dimensions 1`] = `
|
|
8
44
|
<View
|
|
9
45
|
onLayout={[Function]}
|
|
@@ -17,6 +53,10 @@ exports[`SecondaryImage - Image SecondaryImage should render if known dimensions
|
|
|
17
53
|
>
|
|
18
54
|
<Image
|
|
19
55
|
displayMode="dynamic"
|
|
56
|
+
fitPosition="center"
|
|
57
|
+
fixedHeight={0}
|
|
58
|
+
fixedWidth={0}
|
|
59
|
+
imageSizing="fill"
|
|
20
60
|
onAsyncRender={[Function]}
|
|
21
61
|
source={
|
|
22
62
|
{
|
|
@@ -35,3 +75,49 @@ exports[`SecondaryImage - Image SecondaryImage should render if known dimensions
|
|
|
35
75
|
/>
|
|
36
76
|
</View>
|
|
37
77
|
`;
|
|
78
|
+
|
|
79
|
+
exports[`SecondaryImage - Image SecondaryImage should render in fixed mode with known dimensions 1`] = `
|
|
80
|
+
<View
|
|
81
|
+
style={
|
|
82
|
+
{
|
|
83
|
+
"borderRadius": 10,
|
|
84
|
+
"height": 100,
|
|
85
|
+
"width": 100,
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
>
|
|
89
|
+
<Image
|
|
90
|
+
displayMode="fixed"
|
|
91
|
+
fitPosition="center"
|
|
92
|
+
fixedHeight={100}
|
|
93
|
+
fixedWidth={100}
|
|
94
|
+
imageSizing="fill"
|
|
95
|
+
source={
|
|
96
|
+
{
|
|
97
|
+
"uri": "someUrl",
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
style={
|
|
101
|
+
{
|
|
102
|
+
"aspectRatio": 1,
|
|
103
|
+
"borderRadius": 10,
|
|
104
|
+
"height": 100,
|
|
105
|
+
"width": 100,
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
uri="someUrl"
|
|
109
|
+
/>
|
|
110
|
+
</View>
|
|
111
|
+
`;
|
|
112
|
+
|
|
113
|
+
exports[`SecondaryImage - Image SecondaryImage should render in fixed mode without image until loaded 1`] = `
|
|
114
|
+
<View
|
|
115
|
+
style={
|
|
116
|
+
{
|
|
117
|
+
"borderRadius": 5,
|
|
118
|
+
"height": 100,
|
|
119
|
+
"width": 100,
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
/>
|
|
123
|
+
`;
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { SecondaryImage } from "../index";
|
|
2
|
+
|
|
3
|
+
describe("SecondaryImage - Configuration Builder", () => {
|
|
4
|
+
const mockValue = (config: any) => (key: string, transformer?: Function) => {
|
|
5
|
+
const value = config[key];
|
|
6
|
+
|
|
7
|
+
return transformer ? transformer(value) : value;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
it("should pass false as second argument to image_src_from_media_item", () => {
|
|
11
|
+
const config = {
|
|
12
|
+
secondary_image_switch: true,
|
|
13
|
+
secondary_image_position: "over_image",
|
|
14
|
+
secondary_image_visibility: "always",
|
|
15
|
+
secondary_image_image_key: "custom_image",
|
|
16
|
+
secondary_image_display_mode: "dynamic",
|
|
17
|
+
secondary_image_dynamic_width: 100,
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const result = SecondaryImage({
|
|
21
|
+
value: mockValue(config),
|
|
22
|
+
currentPosition: "over_image",
|
|
23
|
+
state: "default",
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
expect(result).not.toBeNull();
|
|
27
|
+
expect(result?.elements).toBeDefined();
|
|
28
|
+
expect(result?.elements[0].data).toBeDefined();
|
|
29
|
+
|
|
30
|
+
const imageData = result?.elements[0].data[0];
|
|
31
|
+
expect(imageData.func).toBe("image_src_from_media_item");
|
|
32
|
+
expect(imageData.args).toEqual(["custom_image", false]);
|
|
33
|
+
expect(imageData.propName).toBe("uri");
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it("should return null when secondary image is disabled", () => {
|
|
37
|
+
const config = {
|
|
38
|
+
secondary_image_switch: false,
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const result = SecondaryImage({
|
|
42
|
+
value: mockValue(config),
|
|
43
|
+
currentPosition: "over_image",
|
|
44
|
+
state: "default",
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
expect(result).toBeNull();
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it("should return null when position does not match currentPosition", () => {
|
|
51
|
+
const config = {
|
|
52
|
+
secondary_image_switch: true,
|
|
53
|
+
secondary_image_position: "above_text_label_1",
|
|
54
|
+
secondary_image_visibility: "always",
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const result = SecondaryImage({
|
|
58
|
+
value: mockValue(config),
|
|
59
|
+
currentPosition: "over_image",
|
|
60
|
+
state: "default",
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
expect(result).toBeNull();
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it("should return null when visibility does not match state", () => {
|
|
67
|
+
const config = {
|
|
68
|
+
secondary_image_switch: true,
|
|
69
|
+
secondary_image_position: "over_image",
|
|
70
|
+
secondary_image_visibility: "focused",
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
const result = SecondaryImage({
|
|
74
|
+
value: mockValue(config),
|
|
75
|
+
currentPosition: "over_image",
|
|
76
|
+
state: "default",
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
expect(result).toBeNull();
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
it("should include display mode and image sizing in additionalProps", () => {
|
|
83
|
+
const config = {
|
|
84
|
+
secondary_image_switch: true,
|
|
85
|
+
secondary_image_position: "over_image",
|
|
86
|
+
secondary_image_visibility: "always",
|
|
87
|
+
secondary_image_image_key: "logo",
|
|
88
|
+
secondary_image_display_mode: "fixed",
|
|
89
|
+
secondary_image_image_sizing: "fill",
|
|
90
|
+
secondary_image_fit_position: "center",
|
|
91
|
+
secondary_image_fixed_width: 200,
|
|
92
|
+
secondary_image_fixed_height: 150,
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
const result = SecondaryImage({
|
|
96
|
+
value: mockValue(config),
|
|
97
|
+
currentPosition: "over_image",
|
|
98
|
+
state: "default",
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
expect(result?.elements[0].additionalProps).toMatchObject({
|
|
102
|
+
displayMode: "fixed",
|
|
103
|
+
imageSizing: "fill",
|
|
104
|
+
fitPosition: "center",
|
|
105
|
+
fixedWidth: 200,
|
|
106
|
+
fixedHeight: 150,
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
it("should apply correct styles including margins and border radius", () => {
|
|
111
|
+
const config = {
|
|
112
|
+
secondary_image_switch: true,
|
|
113
|
+
secondary_image_position: "over_image",
|
|
114
|
+
secondary_image_visibility: "always",
|
|
115
|
+
secondary_image_display_mode: "fixed",
|
|
116
|
+
secondary_image_fixed_width: 100,
|
|
117
|
+
secondary_image_fixed_height: 100,
|
|
118
|
+
secondary_image_corner_radius: 12,
|
|
119
|
+
secondary_image_margin_top: 10,
|
|
120
|
+
secondary_image_margin_left: 5,
|
|
121
|
+
secondary_image_margin_right: 5,
|
|
122
|
+
secondary_image_margin_bottom: 10,
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
const result = SecondaryImage({
|
|
126
|
+
value: mockValue(config),
|
|
127
|
+
currentPosition: "over_image",
|
|
128
|
+
state: "default",
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
expect(result?.elements[0].style).toMatchObject({
|
|
132
|
+
width: 100,
|
|
133
|
+
height: 100,
|
|
134
|
+
borderRadius: 12,
|
|
135
|
+
marginTop: 10,
|
|
136
|
+
marginLeft: 5,
|
|
137
|
+
marginRight: 5,
|
|
138
|
+
marginBottom: 10,
|
|
139
|
+
});
|
|
140
|
+
});
|
|
141
|
+
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { renderHook } from "@testing-library/react-
|
|
1
|
+
import { renderHook, waitFor } from "@testing-library/react-native";
|
|
2
2
|
import { Image } from "react-native";
|
|
3
3
|
|
|
4
4
|
import { useGetImageDimensions } from "../useGetImageDimensions";
|
|
@@ -13,15 +13,16 @@ jest.spyOn(Image, "getSize").mockImplementation((_uri, success) => {
|
|
|
13
13
|
|
|
14
14
|
describe("useGetImageDimensions", () => {
|
|
15
15
|
it("should return aspect ration initially when known dimensions", async () => {
|
|
16
|
-
const { result
|
|
16
|
+
const { result } = renderHook(() =>
|
|
17
17
|
useGetImageDimensions("https://some_url.com", WIDTH, undefined)
|
|
18
18
|
);
|
|
19
19
|
|
|
20
20
|
expect(result.current).toBeUndefined();
|
|
21
|
-
await waitForNextUpdate();
|
|
22
21
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
22
|
+
await waitFor(() => {
|
|
23
|
+
expect(result.current).toEqual(
|
|
24
|
+
getDimension({ width: WIDTH, height: HEIGTH })
|
|
25
|
+
);
|
|
26
|
+
});
|
|
26
27
|
});
|
|
27
28
|
});
|
|
@@ -4,7 +4,7 @@ import { toNumberWithDefaultZero } from "@applicaster/zapp-react-native-utils/nu
|
|
|
4
4
|
import { Button } from "./Button";
|
|
5
5
|
import {
|
|
6
6
|
getButtonsCount,
|
|
7
|
-
|
|
7
|
+
memoizedGetPluginIdentifier,
|
|
8
8
|
mapSelfAlignment,
|
|
9
9
|
} from "./utils";
|
|
10
10
|
|
|
@@ -80,7 +80,11 @@ export const TvActionButtons = ({
|
|
|
80
80
|
prefix: independentStyles ? prefixSpecificButton : buttonId(1),
|
|
81
81
|
value,
|
|
82
82
|
platformValue,
|
|
83
|
-
pluginIdentifier:
|
|
83
|
+
pluginIdentifier: memoizedGetPluginIdentifier(
|
|
84
|
+
configuration,
|
|
85
|
+
PREFIX,
|
|
86
|
+
index
|
|
87
|
+
),
|
|
84
88
|
suffixId: prefixSpecificButton,
|
|
85
89
|
preferredFocus: index === 0,
|
|
86
90
|
});
|