@applicaster/zapp-react-native-ui-components 16.0.0-alpha.1529223058 → 16.0.0-alpha.1803625751
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/MasterCell/DefaultComponents/ActionButtonsCore/__tests__/placement.test.ts +47 -21
- package/Components/MasterCell/DefaultComponents/ActionButtonsCore/placement.ts +34 -6
- package/Components/MasterCell/DefaultComponents/ImageContainer/index.tsx +4 -3
- package/Components/MasterCell/DefaultComponents/PressableView.tsx +3 -3
- package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/ActionButton.tsx +38 -2
- package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/AssetComponent.tsx +15 -4
- package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/Button.ts +30 -16
- package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/TextLabelsContainer.ts +3 -0
- package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/index.ts +2 -1
- package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/utils/__tests__/insertButtons.test.ts +8 -3
- package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/utils/index.ts +2 -2
- package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/utils/__tests__/insertButtonsBetweenLabels.test.ts +45 -13
- package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/utils/index.ts +2 -2
- package/Helpers/ComponentCellSelectionHelper/index.js +0 -6
- package/Helpers/index.js +0 -39
- package/package.json +5 -5
- package/Helpers/Analytics/index.js +0 -95
package/Components/MasterCell/DefaultComponents/ActionButtonsCore/__tests__/placement.test.ts
CHANGED
|
@@ -6,28 +6,54 @@ import {
|
|
|
6
6
|
describe("ActionButtonsCore placement", () => {
|
|
7
7
|
const buttons = { type: "View", name: "buttons" };
|
|
8
8
|
|
|
9
|
-
const
|
|
10
|
-
{ name: "
|
|
11
|
-
{ name: "
|
|
12
|
-
{ name: "
|
|
9
|
+
const slots = [
|
|
10
|
+
{ name: "text_label_1", element: { type: "View", id: "label_1" } },
|
|
11
|
+
{ name: "text_label_2", element: { type: "View", id: "label_2" } },
|
|
12
|
+
{ name: "text_label_3", element: { type: "View", id: "label_3" } },
|
|
13
13
|
];
|
|
14
14
|
|
|
15
|
-
const
|
|
16
|
-
{ name: "below_label_1" },
|
|
17
|
-
{ name: "below_label_2" },
|
|
18
|
-
{ name: "below_label_3" },
|
|
19
|
-
];
|
|
15
|
+
const labels = slots.map((slot) => slot.element);
|
|
20
16
|
|
|
21
17
|
it("inserts buttons after the matching label", () => {
|
|
22
18
|
expect(
|
|
23
|
-
insertBetweenLabels({ position: "
|
|
24
|
-
).toEqual([
|
|
19
|
+
insertBetweenLabels({ position: "below_text_label_2" }, buttons, slots)
|
|
20
|
+
).toEqual([labels[0], labels[1], buttons, labels[2]]);
|
|
25
21
|
});
|
|
26
22
|
|
|
27
23
|
it("inserts buttons before the matching label", () => {
|
|
28
24
|
expect(
|
|
29
|
-
insertBetweenLabels({ position: "
|
|
30
|
-
).toEqual([
|
|
25
|
+
insertBetweenLabels({ position: "above_text_label_2" }, buttons, slots)
|
|
26
|
+
).toEqual([labels[0], buttons, labels[1], labels[2]]);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it("inserts buttons after the matching label on a plain name match", () => {
|
|
30
|
+
expect(
|
|
31
|
+
insertBetweenLabels({ position: "text_label_2" }, buttons, slots)
|
|
32
|
+
).toEqual([labels[0], labels[1], buttons, labels[2]]);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it("keeps the slot when its label is empty (null element)", () => {
|
|
36
|
+
const slotsWithEmpty = [
|
|
37
|
+
{ name: "text_label_1", element: { id: "label_1" } },
|
|
38
|
+
{ name: "text_label_2", element: null },
|
|
39
|
+
{ name: "text_label_3", element: { id: "label_3" } },
|
|
40
|
+
];
|
|
41
|
+
|
|
42
|
+
expect(
|
|
43
|
+
insertBetweenLabels(
|
|
44
|
+
{ position: "above_text_label_2" },
|
|
45
|
+
buttons,
|
|
46
|
+
slotsWithEmpty
|
|
47
|
+
)
|
|
48
|
+
).toEqual([{ id: "label_1" }, buttons, { id: "label_3" }]);
|
|
49
|
+
|
|
50
|
+
expect(
|
|
51
|
+
insertBetweenLabels(
|
|
52
|
+
{ position: "below_text_label_2" },
|
|
53
|
+
buttons,
|
|
54
|
+
slotsWithEmpty
|
|
55
|
+
)
|
|
56
|
+
).toEqual([{ id: "label_1" }, buttons, { id: "label_3" }]);
|
|
31
57
|
});
|
|
32
58
|
|
|
33
59
|
it("prepends buttons only when on_top is allowed", () => {
|
|
@@ -35,17 +61,17 @@ describe("ActionButtonsCore placement", () => {
|
|
|
35
61
|
insertBetweenLabels(
|
|
36
62
|
{ position: "on_top", allowOnTop: true },
|
|
37
63
|
buttons,
|
|
38
|
-
|
|
64
|
+
slots
|
|
39
65
|
)
|
|
40
|
-
).toEqual([buttons, ...
|
|
66
|
+
).toEqual([buttons, ...labels]);
|
|
41
67
|
|
|
42
68
|
expect(
|
|
43
69
|
insertBetweenLabels(
|
|
44
70
|
{ position: "on_top", allowOnTop: false },
|
|
45
71
|
buttons,
|
|
46
|
-
|
|
72
|
+
slots
|
|
47
73
|
)
|
|
48
|
-
).toEqual(
|
|
74
|
+
).toEqual(labels);
|
|
49
75
|
});
|
|
50
76
|
|
|
51
77
|
it("appends buttons when appendWhenMissing is enabled", () => {
|
|
@@ -53,9 +79,9 @@ describe("ActionButtonsCore placement", () => {
|
|
|
53
79
|
insertBetweenLabels(
|
|
54
80
|
{ position: "unknown", appendWhenMissing: true },
|
|
55
81
|
buttons,
|
|
56
|
-
|
|
82
|
+
slots
|
|
57
83
|
)
|
|
58
|
-
).toEqual([...
|
|
84
|
+
).toEqual([...labels, buttons]);
|
|
59
85
|
});
|
|
60
86
|
|
|
61
87
|
it("returns labels unchanged when appendWhenMissing is disabled", () => {
|
|
@@ -63,9 +89,9 @@ describe("ActionButtonsCore placement", () => {
|
|
|
63
89
|
insertBetweenLabels(
|
|
64
90
|
{ position: "unknown", appendWhenMissing: false },
|
|
65
91
|
buttons,
|
|
66
|
-
|
|
92
|
+
slots
|
|
67
93
|
)
|
|
68
|
-
).toEqual(
|
|
94
|
+
).toEqual(labels);
|
|
69
95
|
});
|
|
70
96
|
|
|
71
97
|
const labelContainers = [
|
|
@@ -17,6 +17,11 @@ type InsertOptions = {
|
|
|
17
17
|
appendWhenMissing?: boolean;
|
|
18
18
|
};
|
|
19
19
|
|
|
20
|
+
type Slot = {
|
|
21
|
+
name: string;
|
|
22
|
+
element?: unknown;
|
|
23
|
+
};
|
|
24
|
+
|
|
20
25
|
const hasLabelName = (value: unknown): value is Label =>
|
|
21
26
|
!!value &&
|
|
22
27
|
typeof value === "object" &&
|
|
@@ -100,8 +105,14 @@ const containsNestedLabel = (
|
|
|
100
105
|
export const insertBetweenLabels = (
|
|
101
106
|
{ position, allowOnTop = false, appendWhenMissing = false }: InsertOptions,
|
|
102
107
|
buttons: unknown,
|
|
103
|
-
|
|
108
|
+
slots: Slot[] = []
|
|
104
109
|
) => {
|
|
110
|
+
// Slots are defined by the canonical label list, so an empty (null) label
|
|
111
|
+
// still keeps its position — buttons placed above/below it survive.
|
|
112
|
+
const labels = slots
|
|
113
|
+
.map((slot) => slot.element)
|
|
114
|
+
.filter((element) => element != null);
|
|
115
|
+
|
|
105
116
|
if (buttons == null) {
|
|
106
117
|
return labels;
|
|
107
118
|
}
|
|
@@ -110,14 +121,31 @@ export const insertBetweenLabels = (
|
|
|
110
121
|
return [buttons, ...labels];
|
|
111
122
|
}
|
|
112
123
|
|
|
113
|
-
|
|
114
|
-
const
|
|
124
|
+
let inserted = false;
|
|
125
|
+
const result: unknown[] = [];
|
|
126
|
+
|
|
127
|
+
for (const { name, element } of slots) {
|
|
128
|
+
if (position === `above_${name}`) {
|
|
129
|
+
result.push(buttons);
|
|
130
|
+
inserted = true;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
if (element != null) {
|
|
134
|
+
result.push(element);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Insert after on `below_*` or a plain label-name match.
|
|
138
|
+
if (position === `below_${name}` || position === name) {
|
|
139
|
+
result.push(buttons);
|
|
140
|
+
inserted = true;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
115
143
|
|
|
116
|
-
if (!inserted
|
|
117
|
-
return [...labels, buttons];
|
|
144
|
+
if (!inserted) {
|
|
145
|
+
return appendWhenMissing ? [...labels, buttons] : labels;
|
|
118
146
|
}
|
|
119
147
|
|
|
120
|
-
return
|
|
148
|
+
return result;
|
|
121
149
|
};
|
|
122
150
|
|
|
123
151
|
export const insertBetweenLabelContainers = (
|
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
import React from "react";
|
|
1
|
+
import React, { PropsWithChildren } from "react";
|
|
2
2
|
import { isVideoPreviewEnabled } from "@applicaster/zapp-react-native-ui-components/Components/MasterCell/utils";
|
|
3
3
|
import { LiveImage } from "../LiveImage";
|
|
4
4
|
import PureImage from "../Image";
|
|
5
5
|
import { useIsScreenActive } from "@applicaster/zapp-react-native-utils/reactHooks";
|
|
6
6
|
|
|
7
|
-
type Props = {
|
|
7
|
+
type Props = PropsWithChildren<{
|
|
8
8
|
enable_video_preview: boolean;
|
|
9
9
|
player_screen_id: string;
|
|
10
|
-
|
|
10
|
+
uri?: string;
|
|
11
|
+
}>;
|
|
11
12
|
|
|
12
13
|
export const ImageContainer = (props: Props) => {
|
|
13
14
|
const isActive = useIsScreenActive();
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import { TouchableOpacity } from "react-native";
|
|
2
|
+
import { TouchableOpacity, ViewStyle } from "react-native";
|
|
3
3
|
|
|
4
4
|
type Props = {
|
|
5
5
|
children?: React.ReactNode;
|
|
6
|
-
style?:
|
|
6
|
+
style?: ViewStyle | ViewStyle[];
|
|
7
7
|
testID?: string;
|
|
8
8
|
accessibilityLabel?: string;
|
|
9
9
|
accessibilityHint?: string;
|
|
@@ -12,7 +12,7 @@ type Props = {
|
|
|
12
12
|
|
|
13
13
|
export function PressableView({
|
|
14
14
|
children,
|
|
15
|
-
style
|
|
15
|
+
style,
|
|
16
16
|
testID,
|
|
17
17
|
accessibilityLabel,
|
|
18
18
|
accessibilityHint,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
+
import { StyleSheet, View, ViewStyle } from "react-native";
|
|
2
3
|
import { PressableView } from "../../PressableView";
|
|
3
4
|
|
|
4
5
|
import { ActionButtonController } from "../../ActionButtonsCore/components";
|
|
@@ -15,6 +16,22 @@ type ChildElementProps = {
|
|
|
15
16
|
entry?: any;
|
|
16
17
|
};
|
|
17
18
|
|
|
19
|
+
const styles = StyleSheet.create({
|
|
20
|
+
pressableView: {
|
|
21
|
+
overflow: "hidden",
|
|
22
|
+
flexDirection: "row",
|
|
23
|
+
},
|
|
24
|
+
maxWidthFull: {
|
|
25
|
+
width: "100%",
|
|
26
|
+
},
|
|
27
|
+
innerWrapper: {
|
|
28
|
+
flexDirection: "row",
|
|
29
|
+
flexGrow: 0,
|
|
30
|
+
flexShrink: 1,
|
|
31
|
+
overflow: "hidden",
|
|
32
|
+
},
|
|
33
|
+
});
|
|
34
|
+
|
|
18
35
|
const isValidElement = (
|
|
19
36
|
child: React.ReactNode
|
|
20
37
|
): child is React.ReactElement<ChildElementProps> =>
|
|
@@ -121,12 +138,31 @@ export const ActionButton = ({ style, children, action, entry, ...props }) => {
|
|
|
121
138
|
return (
|
|
122
139
|
<PressableView
|
|
123
140
|
testID={props.testID || `${entry?.id}`}
|
|
124
|
-
style={
|
|
141
|
+
style={[
|
|
142
|
+
isActive
|
|
143
|
+
? {
|
|
144
|
+
...(style as ViewStyle),
|
|
145
|
+
...(props.focusedStyles as ViewStyle),
|
|
146
|
+
}
|
|
147
|
+
: (style as ViewStyle),
|
|
148
|
+
styles.pressableView,
|
|
149
|
+
]}
|
|
125
150
|
onPress={onPress}
|
|
126
151
|
accessibilityLabel={props.accessibilityLabel || `${entry?.id}`}
|
|
127
152
|
accessibilityHint={props.accessibilityHint}
|
|
128
153
|
>
|
|
129
|
-
|
|
154
|
+
<View
|
|
155
|
+
style={{
|
|
156
|
+
maxWidth: (style as ViewStyle).maxWidth,
|
|
157
|
+
...((style as ViewStyle).maxWidth
|
|
158
|
+
? styles.maxWidthFull
|
|
159
|
+
: undefined),
|
|
160
|
+
}}
|
|
161
|
+
>
|
|
162
|
+
<View style={[styles.innerWrapper, props.alignment]}>
|
|
163
|
+
{_cloneChildrenWithState(children)}
|
|
164
|
+
</View>
|
|
165
|
+
</View>
|
|
130
166
|
</PressableView>
|
|
131
167
|
);
|
|
132
168
|
}}
|
package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/AssetComponent.tsx
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import { View } from "react-native";
|
|
2
|
+
import { StyleSheet, View } from "react-native";
|
|
3
3
|
import { ImageContainer } from "../../ImageContainer";
|
|
4
4
|
|
|
5
5
|
type Props = {
|
|
@@ -10,13 +10,24 @@ type Props = {
|
|
|
10
10
|
cellUUID?: string;
|
|
11
11
|
};
|
|
12
12
|
|
|
13
|
+
const styles = StyleSheet.create({
|
|
14
|
+
assetContainer: {
|
|
15
|
+
flexShrink: 0,
|
|
16
|
+
justifyContent: "center",
|
|
17
|
+
alignItems: "center",
|
|
18
|
+
},
|
|
19
|
+
});
|
|
20
|
+
|
|
13
21
|
export const AssetComponent = (props: Props & Record<string, unknown>) => {
|
|
14
22
|
return props.asset && React.isValidElement(props.asset) ? (
|
|
15
|
-
<View style={props.style} testID={props.testID}>
|
|
23
|
+
<View style={[styles.assetContainer, props.style]} testID={props.testID}>
|
|
16
24
|
{React.cloneElement(props.asset, { cellUUID: props.cellUUID })}
|
|
17
25
|
</View>
|
|
18
26
|
) : (
|
|
19
|
-
|
|
20
|
-
|
|
27
|
+
<ImageContainer
|
|
28
|
+
style={[styles.assetContainer, props.style]}
|
|
29
|
+
{...(props as any)}
|
|
30
|
+
uri={props.uri}
|
|
31
|
+
/>
|
|
21
32
|
);
|
|
22
33
|
};
|
|
@@ -10,23 +10,33 @@ import {
|
|
|
10
10
|
getPressableStyles,
|
|
11
11
|
getTextLabelStyles,
|
|
12
12
|
} from "./utils";
|
|
13
|
+
import { ViewStyle } from "react-native";
|
|
13
14
|
|
|
14
15
|
const displayModeStyle = (value) => {
|
|
15
16
|
const mode = value("display_mode") || "dynamic";
|
|
16
17
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
};
|
|
21
|
-
}
|
|
18
|
+
const defaultStyle = {
|
|
19
|
+
flexShrink: 1,
|
|
20
|
+
};
|
|
22
21
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
22
|
+
switch (mode) {
|
|
23
|
+
case "fixed":
|
|
24
|
+
return {
|
|
25
|
+
...defaultStyle,
|
|
26
|
+
width: toNumberWithDefault(140, value("width")),
|
|
27
|
+
maxWidth: toNumberWithDefault(140, value("width")),
|
|
28
|
+
};
|
|
29
|
+
case "fill":
|
|
30
|
+
return {
|
|
31
|
+
...defaultStyle,
|
|
32
|
+
flex: 1,
|
|
33
|
+
};
|
|
34
|
+
case "dynamic":
|
|
35
|
+
default:
|
|
36
|
+
return {
|
|
37
|
+
...defaultStyle,
|
|
38
|
+
};
|
|
27
39
|
}
|
|
28
|
-
|
|
29
|
-
return {};
|
|
30
40
|
};
|
|
31
41
|
|
|
32
42
|
type Props = {
|
|
@@ -34,7 +44,7 @@ type Props = {
|
|
|
34
44
|
value: Function;
|
|
35
45
|
stylePrefix: string;
|
|
36
46
|
specificPrefix: string;
|
|
37
|
-
spacingStyle:
|
|
47
|
+
spacingStyle: ViewStyle;
|
|
38
48
|
};
|
|
39
49
|
|
|
40
50
|
export const Button = ({
|
|
@@ -75,14 +85,17 @@ export const Button = ({
|
|
|
75
85
|
type: "MobileActionButton",
|
|
76
86
|
style: {
|
|
77
87
|
flexDirection: getContentDirection(assetAlignment),
|
|
78
|
-
alignContent: "center",
|
|
79
|
-
alignItems: getContentsAlignment(contentsAlignment, assetAlignment),
|
|
80
|
-
justifyContent: getContentsAlignment(contentsAlignment, assetAlignment),
|
|
88
|
+
// alignContent: "center", Why do we need this?
|
|
81
89
|
...getPressableStyles(getValue),
|
|
82
90
|
...displayModeStyle(getValue),
|
|
83
91
|
...spacingStyle,
|
|
84
92
|
},
|
|
85
93
|
additionalProps: {
|
|
94
|
+
alignment: {
|
|
95
|
+
alignContent: "center",
|
|
96
|
+
alignItems: getContentsAlignment(contentsAlignment, assetAlignment),
|
|
97
|
+
justifyContent: getContentsAlignment(contentsAlignment, assetAlignment),
|
|
98
|
+
},
|
|
86
99
|
action: {
|
|
87
100
|
identifier: actionIdentifier,
|
|
88
101
|
flavour: actionAssetFlavour,
|
|
@@ -114,7 +127,8 @@ export const Button = ({
|
|
|
114
127
|
color: getValue("focused_font_color"),
|
|
115
128
|
},
|
|
116
129
|
transformText: getValue("text_transform") || "default",
|
|
117
|
-
numberOfLines: getValue("number_of_lines"),
|
|
130
|
+
numberOfLines: getValue("number_of_lines") || 1,
|
|
131
|
+
ellipseMode: "tail",
|
|
118
132
|
},
|
|
119
133
|
actionIdentifier,
|
|
120
134
|
testID,
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
} from "./utils";
|
|
7
7
|
import { Button } from "./Button";
|
|
8
8
|
import { buildActionButtonsModel } from "../../ActionButtonsCore/model";
|
|
9
|
+
import { ViewStyle } from "react-native";
|
|
9
10
|
|
|
10
11
|
const CONTAINER_PREFIX = "mobile_buttons_container";
|
|
11
12
|
const BUTTON_PREFIX = "mobile_button";
|
|
@@ -81,7 +82,7 @@ export const MobileActionButtons = ({
|
|
|
81
82
|
const isVertical = stacking === "vertical";
|
|
82
83
|
const gutter = isVertical ? verticalGutter : horizontalGutter;
|
|
83
84
|
|
|
84
|
-
const spacingStyle = {
|
|
85
|
+
const spacingStyle: ViewStyle = {
|
|
85
86
|
[isVertical ? "marginBottom" : "marginRight"]: isNotLast ? gutter : 0,
|
|
86
87
|
};
|
|
87
88
|
|
|
@@ -5,14 +5,19 @@ import {
|
|
|
5
5
|
} from "..";
|
|
6
6
|
|
|
7
7
|
describe("mobile action insertion helpers", () => {
|
|
8
|
-
const
|
|
8
|
+
const slots = [
|
|
9
|
+
{ name: "text_label_1", element: { type: "View", id: "text_label_1" } },
|
|
10
|
+
{ name: "text_label_2", element: { type: "View", id: "text_label_2" } },
|
|
11
|
+
];
|
|
12
|
+
|
|
13
|
+
const labels = slots.map((slot) => slot.element);
|
|
9
14
|
const buttons = { type: "View", name: "buttons" };
|
|
10
15
|
|
|
11
16
|
it("inserts label buttons below target label", () => {
|
|
12
17
|
const result = insertButtonsBetweenLabels(
|
|
13
18
|
{ mobile_buttons_container_position: "below_text_label_1" },
|
|
14
19
|
buttons,
|
|
15
|
-
|
|
20
|
+
slots
|
|
16
21
|
);
|
|
17
22
|
|
|
18
23
|
expect(result).toEqual([labels[0], buttons, labels[1]]);
|
|
@@ -22,7 +27,7 @@ describe("mobile action insertion helpers", () => {
|
|
|
22
27
|
const result = insertButtonsBetweenLabels(
|
|
23
28
|
{ mobile_buttons_container_position: "unknown" },
|
|
24
29
|
buttons,
|
|
25
|
-
|
|
30
|
+
slots
|
|
26
31
|
);
|
|
27
32
|
|
|
28
33
|
expect(result).toEqual([labels[0], labels[1]]);
|
|
@@ -8,7 +8,7 @@ import { Platform } from "react-native";
|
|
|
8
8
|
export const insertButtonsBetweenLabels = (
|
|
9
9
|
configuration: Record<string, unknown>,
|
|
10
10
|
buttons,
|
|
11
|
-
|
|
11
|
+
slots = [] // { name, element } per canonical text label slot
|
|
12
12
|
) =>
|
|
13
13
|
insertBetweenLabels(
|
|
14
14
|
{
|
|
@@ -19,7 +19,7 @@ export const insertButtonsBetweenLabels = (
|
|
|
19
19
|
appendWhenMissing: false,
|
|
20
20
|
},
|
|
21
21
|
buttons,
|
|
22
|
-
|
|
22
|
+
slots
|
|
23
23
|
);
|
|
24
24
|
|
|
25
25
|
export const insertButtonsBetweenLabelContainers = (
|
|
@@ -3,18 +3,20 @@ import { insertButtonsBetweenLabels } from "..";
|
|
|
3
3
|
describe("insertButtonsBetweenLabels - depthlevel 1", () => {
|
|
4
4
|
const buttons = "buttons";
|
|
5
5
|
|
|
6
|
-
const
|
|
7
|
-
{ name: "label_1" },
|
|
8
|
-
{ name: "label_2" },
|
|
9
|
-
{ name: "label_3" },
|
|
6
|
+
const slots = [
|
|
7
|
+
{ name: "label_1", element: { id: "label_1" } },
|
|
8
|
+
{ name: "label_2", element: { id: "label_2" } },
|
|
9
|
+
{ name: "label_3", element: { id: "label_3" } },
|
|
10
10
|
];
|
|
11
11
|
|
|
12
|
+
const labels = slots.map((slot) => slot.element);
|
|
13
|
+
|
|
12
14
|
it("put buttons on top", () => {
|
|
13
15
|
const configuration = {
|
|
14
16
|
tv_buttons_container_position: "on_top",
|
|
15
17
|
};
|
|
16
18
|
|
|
17
|
-
const result = insertButtonsBetweenLabels(configuration, buttons,
|
|
19
|
+
const result = insertButtonsBetweenLabels(configuration, buttons, slots);
|
|
18
20
|
|
|
19
21
|
expect(result).toEqual([buttons, ...labels]);
|
|
20
22
|
});
|
|
@@ -24,7 +26,7 @@ describe("insertButtonsBetweenLabels - depthlevel 1", () => {
|
|
|
24
26
|
tv_buttons_container_position: "unknown_position",
|
|
25
27
|
};
|
|
26
28
|
|
|
27
|
-
const result = insertButtonsBetweenLabels(configuration, buttons,
|
|
29
|
+
const result = insertButtonsBetweenLabels(configuration, buttons, slots);
|
|
28
30
|
|
|
29
31
|
expect(result).toEqual([...labels, buttons]);
|
|
30
32
|
});
|
|
@@ -34,7 +36,7 @@ describe("insertButtonsBetweenLabels - depthlevel 1", () => {
|
|
|
34
36
|
tv_buttons_container_position: "label_1",
|
|
35
37
|
};
|
|
36
38
|
|
|
37
|
-
const result = insertButtonsBetweenLabels(configuration, buttons,
|
|
39
|
+
const result = insertButtonsBetweenLabels(configuration, buttons, slots);
|
|
38
40
|
|
|
39
41
|
expect(result).toEqual([labels[0], buttons, labels[1], labels[2]]);
|
|
40
42
|
});
|
|
@@ -44,7 +46,7 @@ describe("insertButtonsBetweenLabels - depthlevel 1", () => {
|
|
|
44
46
|
tv_buttons_container_position: "label_2",
|
|
45
47
|
};
|
|
46
48
|
|
|
47
|
-
const result = insertButtonsBetweenLabels(configuration, buttons,
|
|
49
|
+
const result = insertButtonsBetweenLabels(configuration, buttons, slots);
|
|
48
50
|
|
|
49
51
|
expect(result).toEqual([labels[0], labels[1], buttons, labels[2]]);
|
|
50
52
|
});
|
|
@@ -54,22 +56,52 @@ describe("insertButtonsBetweenLabels - depthlevel 1", () => {
|
|
|
54
56
|
tv_buttons_container_position: "label_3",
|
|
55
57
|
};
|
|
56
58
|
|
|
57
|
-
const result = insertButtonsBetweenLabels(configuration, buttons,
|
|
59
|
+
const result = insertButtonsBetweenLabels(configuration, buttons, slots);
|
|
58
60
|
|
|
59
61
|
expect(result).toEqual([labels[0], labels[1], labels[2], buttons]);
|
|
60
62
|
});
|
|
61
63
|
|
|
62
|
-
it("put
|
|
64
|
+
it("put above label_2", () => {
|
|
65
|
+
const configuration = {
|
|
66
|
+
tv_buttons_container_position: "above_label_2",
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
const result = insertButtonsBetweenLabels(configuration, buttons, slots);
|
|
70
|
+
|
|
71
|
+
expect(result).toEqual([labels[0], buttons, labels[1], labels[2]]);
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it("keeps the slot when its label is empty (null element)", () => {
|
|
75
|
+
const slotsWithEmpty = [
|
|
76
|
+
{ name: "label_1", element: { id: "label_1" } },
|
|
77
|
+
{ name: "label_2", element: null },
|
|
78
|
+
{ name: "label_3", element: { id: "label_3" } },
|
|
79
|
+
];
|
|
80
|
+
|
|
81
|
+
const configuration = {
|
|
82
|
+
tv_buttons_container_position: "above_label_2",
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
const result = insertButtonsBetweenLabels(
|
|
86
|
+
configuration,
|
|
87
|
+
buttons,
|
|
88
|
+
slotsWithEmpty
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
expect(result).toEqual([{ id: "label_1" }, buttons, { id: "label_3" }]);
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it("appends buttons when the target is unknown", () => {
|
|
63
95
|
const configuration = {
|
|
64
96
|
tv_buttons_container_position: "label_X",
|
|
65
97
|
};
|
|
66
98
|
|
|
67
|
-
const result = insertButtonsBetweenLabels(configuration, buttons,
|
|
99
|
+
const result = insertButtonsBetweenLabels(configuration, buttons, slots);
|
|
68
100
|
|
|
69
101
|
expect(result).toEqual([labels[0], labels[1], labels[2], buttons]);
|
|
70
102
|
});
|
|
71
103
|
|
|
72
|
-
it("
|
|
104
|
+
it("appends buttons when there are no slots", () => {
|
|
73
105
|
const configuration = {
|
|
74
106
|
tv_buttons_container_position: "label_X",
|
|
75
107
|
};
|
|
@@ -88,7 +120,7 @@ describe("insertButtonsBetweenLabels - depthlevel 1", () => {
|
|
|
88
120
|
tv_buttons_container_position: "label_X",
|
|
89
121
|
};
|
|
90
122
|
|
|
91
|
-
const result = insertButtonsBetweenLabels(configuration, null,
|
|
123
|
+
const result = insertButtonsBetweenLabels(configuration, null, slots);
|
|
92
124
|
|
|
93
125
|
expect(result).toEqual(labels);
|
|
94
126
|
});
|
|
@@ -34,7 +34,7 @@ export const memoizedGetPluginIdentifier = memoizee(getPluginIdentifier);
|
|
|
34
34
|
export const insertButtonsBetweenLabels = (
|
|
35
35
|
configuration: Record<string, unknown>,
|
|
36
36
|
buttons,
|
|
37
|
-
|
|
37
|
+
slots = [] // { name, element } per canonical text label slot
|
|
38
38
|
) =>
|
|
39
39
|
insertBetweenLabels(
|
|
40
40
|
{
|
|
@@ -45,7 +45,7 @@ export const insertButtonsBetweenLabels = (
|
|
|
45
45
|
appendWhenMissing: true,
|
|
46
46
|
},
|
|
47
47
|
buttons,
|
|
48
|
-
|
|
48
|
+
slots
|
|
49
49
|
);
|
|
50
50
|
|
|
51
51
|
export const insertButtonsBetweenLabelContainers = (
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { sendTapCellEvent, sendTapMenuItem } from "../Analytics";
|
|
2
1
|
import { getItemType } from "@applicaster/zapp-react-native-utils/navigationUtils";
|
|
3
2
|
import { SCREEN_TYPES } from "@applicaster/zapp-react-native-utils/navigationUtils/itemTypes";
|
|
4
3
|
|
|
@@ -12,7 +11,6 @@ export function onCellPress(
|
|
|
12
11
|
itemIndex,
|
|
13
12
|
layoutVersion = "v1"
|
|
14
13
|
) {
|
|
15
|
-
sendTapCellEvent(entry, component, headerTitle, itemIndex);
|
|
16
14
|
const componentScreenType = screenTypeFromComponent(component);
|
|
17
15
|
const entryScreenType = screenTypeFromEntry(entry);
|
|
18
16
|
const itemType = getItemType(entry, layoutVersion);
|
|
@@ -37,7 +35,3 @@ function screenTypeFromComponent(component) {
|
|
|
37
35
|
function screenTypeFromEntry(entry) {
|
|
38
36
|
return entry && entry.screen_type;
|
|
39
37
|
}
|
|
40
|
-
|
|
41
|
-
export function onMenuItemFocus({ item, index, isHome }) {
|
|
42
|
-
sendTapMenuItem({ item, index, isHome });
|
|
43
|
-
}
|
package/Helpers/index.js
CHANGED
|
@@ -7,42 +7,3 @@ export const ASSETS = {
|
|
|
7
7
|
amazon: "tv_app_background",
|
|
8
8
|
}),
|
|
9
9
|
};
|
|
10
|
-
|
|
11
|
-
export const ANALYTICS_CORE_EVENTS = {
|
|
12
|
-
TAP_CELL: "Tap Cell",
|
|
13
|
-
PLAY_VOD_ITEM: "Play VOD Item",
|
|
14
|
-
VOD_ITEM_PLAY_WAS_TRIGGERED: "VOD Item: Play Was Triggered",
|
|
15
|
-
CHANNEL_ITEM_PLAY_WAS_TRIGGERED: "Channel Item: Play Was Triggered",
|
|
16
|
-
PROGRAM_ITEM_PLAY_WAS_TRIGGERED: "Program Item: Play Was Triggered",
|
|
17
|
-
TAP_MENU_ICON: "Tap Menu Item",
|
|
18
|
-
HOME_SCREEN_VIEWED: "Home Screen: Viewed",
|
|
19
|
-
ITEM_NOT_AVAILABLE: "N/A",
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
export const ANALYTICS_ENTRY_EVENTS = {
|
|
23
|
-
ITEM_TYPE: "Item Type",
|
|
24
|
-
ITEM_TITLE: "Item Name",
|
|
25
|
-
ITEM_ID: "Item ID",
|
|
26
|
-
ITEM_LINK: "Item Link",
|
|
27
|
-
ITEM_INDEX: "Item Number",
|
|
28
|
-
ITEM_TIME_PLAYED: "Item Total Time Played",
|
|
29
|
-
ITEM_TOTAL_TIME_PLAYED: "Item Total Time Played",
|
|
30
|
-
ITEM_PLAY_COMPLETED: "Completed",
|
|
31
|
-
ITEM_CUSTOM_PROPERTY: "Custom Property",
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
export const ANALYTICS_COMPONENT_EVENTS = {
|
|
35
|
-
COMPONENT_ID: "Component ID",
|
|
36
|
-
COMPONENT_TYPE: "Component Type",
|
|
37
|
-
CELL_STYLE: "Cell Style",
|
|
38
|
-
HEADER_TITLE: "Header Name",
|
|
39
|
-
COMPONENT_SOURCE: "Component Source",
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
export const ANALYTICS_MENU_ITEM_EVENTS = {
|
|
43
|
-
ITEM_TYPE: "Item Type",
|
|
44
|
-
ITEM_TITLE: "Item Name",
|
|
45
|
-
ITEM_ID: "Item ID",
|
|
46
|
-
ITEM_HOME_SCREEN: "Home Screen",
|
|
47
|
-
ITEM_INDEX: "Item Number",
|
|
48
|
-
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@applicaster/zapp-react-native-ui-components",
|
|
3
|
-
"version": "16.0.0-alpha.
|
|
3
|
+
"version": "16.0.0-alpha.1803625751",
|
|
4
4
|
"description": "Applicaster Zapp React Native ui components for the Quick Brick App",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "index.d.ts",
|
|
@@ -28,10 +28,10 @@
|
|
|
28
28
|
},
|
|
29
29
|
"homepage": "https://github.com/applicaster/quickbrick#readme",
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"@applicaster/applicaster-types": "16.0.0-alpha.
|
|
32
|
-
"@applicaster/zapp-react-native-bridge": "16.0.0-alpha.
|
|
33
|
-
"@applicaster/zapp-react-native-redux": "16.0.0-alpha.
|
|
34
|
-
"@applicaster/zapp-react-native-utils": "16.0.0-alpha.
|
|
31
|
+
"@applicaster/applicaster-types": "16.0.0-alpha.1803625751",
|
|
32
|
+
"@applicaster/zapp-react-native-bridge": "16.0.0-alpha.1803625751",
|
|
33
|
+
"@applicaster/zapp-react-native-redux": "16.0.0-alpha.1803625751",
|
|
34
|
+
"@applicaster/zapp-react-native-utils": "16.0.0-alpha.1803625751",
|
|
35
35
|
"fast-json-stable-stringify": "^2.1.0",
|
|
36
36
|
"promise": "^8.3.0",
|
|
37
37
|
"url": "^0.11.0",
|
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
import * as R from "ramda";
|
|
2
|
-
import { postAnalyticEvent } from "@applicaster/zapp-react-native-tvos-app/AnalyticsManager";
|
|
3
|
-
import { extensionsEvents } from "@applicaster/zapp-react-native-utils/analyticsUtils/AnalyticsEvents/helper";
|
|
4
|
-
import {
|
|
5
|
-
ANALYTICS_CORE_EVENTS,
|
|
6
|
-
ANALYTICS_ENTRY_EVENTS,
|
|
7
|
-
ANALYTICS_COMPONENT_EVENTS,
|
|
8
|
-
ANALYTICS_MENU_ITEM_EVENTS,
|
|
9
|
-
} from "../";
|
|
10
|
-
|
|
11
|
-
export function sendTapCellEvent(item, component, headerTitle, itemIndex) {
|
|
12
|
-
const itemReadableIndex = itemIndex + 1;
|
|
13
|
-
|
|
14
|
-
const analyticsProperties = R.compose(
|
|
15
|
-
R.reject(R.isNil),
|
|
16
|
-
R.merge(eventForEntry(item, itemReadableIndex))
|
|
17
|
-
)(eventForComponent(component, headerTitle));
|
|
18
|
-
|
|
19
|
-
postEvent(ANALYTICS_CORE_EVENTS.TAP_CELL, analyticsProperties);
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export function sendTapMenuItem({ item, index, isHome }) {
|
|
23
|
-
const analyticsProperties = R.compose(R.reject(R.isNil))(
|
|
24
|
-
eventForMenuItemEntry({ item, index, isHome })
|
|
25
|
-
);
|
|
26
|
-
|
|
27
|
-
postEvent(ANALYTICS_CORE_EVENTS.TAP_MENU_ICON, analyticsProperties);
|
|
28
|
-
|
|
29
|
-
if (isHome) {
|
|
30
|
-
postEvent(ANALYTICS_CORE_EVENTS.HOME_SCREEN_VIEWED, null);
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
function postEvent(event, properties) {
|
|
35
|
-
postAnalyticEvent(event, properties);
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
function eventForEntry(item, itemIndex) {
|
|
39
|
-
const {
|
|
40
|
-
title,
|
|
41
|
-
type: { value: valueType },
|
|
42
|
-
id,
|
|
43
|
-
} = item;
|
|
44
|
-
|
|
45
|
-
const analyticsCustomProperties = extensionsEvents(item.extensions);
|
|
46
|
-
|
|
47
|
-
const analyticsEvents = {
|
|
48
|
-
[ANALYTICS_ENTRY_EVENTS.ITEM_TYPE]: valueType,
|
|
49
|
-
[ANALYTICS_ENTRY_EVENTS.ITEM_TITLE]: title,
|
|
50
|
-
[ANALYTICS_ENTRY_EVENTS.ITEM_ID]: id,
|
|
51
|
-
[ANALYTICS_ENTRY_EVENTS.ITEM_INDEX]:
|
|
52
|
-
(itemIndex && itemIndex.toString()) || null,
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
if (analyticsCustomProperties) {
|
|
56
|
-
analyticsEvents.analyticsCustomProperties = analyticsCustomProperties;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
return analyticsEvents;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
function eventForComponent(
|
|
63
|
-
component,
|
|
64
|
-
headerTitle, // Zapp Pipes data passed for group components
|
|
65
|
-
zappPipesData = null
|
|
66
|
-
) {
|
|
67
|
-
const { id, component_type, styles, data } = component;
|
|
68
|
-
const { cell_style } = styles;
|
|
69
|
-
const source = data?.source || zappPipesData?.data?.url || null;
|
|
70
|
-
|
|
71
|
-
return {
|
|
72
|
-
[ANALYTICS_COMPONENT_EVENTS.COMPONENT_ID]: id,
|
|
73
|
-
[ANALYTICS_COMPONENT_EVENTS.COMPONENT_TYPE]: component_type,
|
|
74
|
-
[ANALYTICS_COMPONENT_EVENTS.CELL_STYLE]:
|
|
75
|
-
cell_style || ANALYTICS_CORE_EVENTS.ITEM_NOT_AVAILABLE,
|
|
76
|
-
[ANALYTICS_COMPONENT_EVENTS.COMPONENT_SOURCE]:
|
|
77
|
-
(source && encodeURIComponent(source)) || null,
|
|
78
|
-
[ANALYTICS_COMPONENT_EVENTS.HEADER_TITLE]: headerTitle,
|
|
79
|
-
};
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
function eventForMenuItemEntry({ item, index, isHome }) {
|
|
83
|
-
const { title, type, id } = item;
|
|
84
|
-
|
|
85
|
-
const itemReadableIndex = index + 1;
|
|
86
|
-
|
|
87
|
-
return {
|
|
88
|
-
[ANALYTICS_MENU_ITEM_EVENTS.ITEM_INDEX]:
|
|
89
|
-
(itemReadableIndex && itemReadableIndex.toString()) || null,
|
|
90
|
-
[ANALYTICS_MENU_ITEM_EVENTS.ITEM_TYPE]: type,
|
|
91
|
-
[ANALYTICS_MENU_ITEM_EVENTS.ITEM_TITLE]: title,
|
|
92
|
-
[ANALYTICS_MENU_ITEM_EVENTS.ITEM_ID]: id,
|
|
93
|
-
[ANALYTICS_MENU_ITEM_EVENTS.ITEM_HOME_SCREEN]: isHome ? "YES" : "NO",
|
|
94
|
-
};
|
|
95
|
-
}
|