@applicaster/zapp-react-native-ui-components 15.0.0-rc.144 → 15.0.0-rc.145

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/Components/FocusableGroup/index.tsx +3 -2
  2. package/Components/Layout/TV/__tests__/__snapshots__/index.test.tsx.snap +5 -0
  3. package/Components/MasterCell/CONFIG_BUILDER_TO_REACT_COMPONENT.md +144 -0
  4. package/Components/MasterCell/DefaultComponents/ActionButtonsCore/components/ActionButtonController.tsx +165 -0
  5. package/Components/MasterCell/DefaultComponents/ActionButtonsCore/components/__tests__/ActionButtonController.test.tsx +405 -0
  6. package/Components/MasterCell/DefaultComponents/ActionButtonsCore/components/index.ts +1 -0
  7. package/Components/MasterCell/DefaultComponents/ButtonContainerView/components/HorizontalSeparator.tsx +8 -0
  8. package/Components/MasterCell/DefaultComponents/ButtonContainerView/index.tsx +15 -0
  9. package/Components/MasterCell/DefaultComponents/ButtonContainerView/index.tv.android.tsx +58 -0
  10. package/Components/MasterCell/DefaultComponents/{tv/ButtonContainerView/index.tsx → ButtonContainerView/index.tv.tsx} +3 -11
  11. package/Components/MasterCell/DefaultComponents/ButtonContainerView/index.web.ts +1 -0
  12. package/Components/MasterCell/DefaultComponents/ButtonContainerView/types.ts +40 -0
  13. package/Components/MasterCell/DefaultComponents/DataProvider/index.tsx +163 -0
  14. package/Components/MasterCell/DefaultComponents/FocusableView/index.android.tsx +2 -23
  15. package/Components/MasterCell/DefaultComponents/FocusableView/index.tsx +4 -22
  16. package/Components/MasterCell/DefaultComponents/PressableView.tsx +7 -234
  17. package/Components/MasterCell/DefaultComponents/Text/hooks/useText.ts +11 -0
  18. package/Components/MasterCell/DefaultComponents/__tests__/DataProvider.test.tsx +141 -0
  19. package/Components/MasterCell/DefaultComponents/index.ts +7 -3
  20. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/ActionButton.tsx +135 -0
  21. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/Asset.ts +20 -29
  22. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/AssetComponent.tsx +22 -0
  23. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/Button.ts +67 -69
  24. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/TextLabelsContainer.ts +21 -16
  25. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/__tests__/PressableView.test.tsx +207 -9
  26. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/__tests__/builders.test.ts +56 -55
  27. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/__tests__/index.test.ts +137 -16
  28. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/index.ts +49 -31
  29. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/utils/index.ts +165 -0
  30. package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/Asset.ts +4 -18
  31. package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/Button.ts +24 -73
  32. package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/TextLabelsContainer.ts +37 -18
  33. package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/TvActionButton.tsx +27 -0
  34. package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/__tests__/index.test.ts +24 -21
  35. package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/__tests__/renderedTree.test.tsx +231 -0
  36. package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/index.ts +24 -12
  37. package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/utils/index.ts +62 -0
  38. package/Components/MasterCell/MappingFunctions/index.js +3 -2
  39. package/Components/MasterCell/README.md +4 -0
  40. package/Components/MasterCell/__tests__/__snapshots__/dataAdapter.test.js.snap +24 -0
  41. package/Components/MasterCell/__tests__/configInflater.test.js +1 -0
  42. package/Components/MasterCell/__tests__/elementMapper.test.js +46 -0
  43. package/Components/MasterCell/dataAdapter.ts +4 -1
  44. package/Components/MasterCell/elementMapper.tsx +51 -7
  45. package/Components/MasterCell/utils/__tests__/cloneChildrenWithIds.test.tsx +43 -0
  46. package/Components/MasterCell/utils/__tests__/useFilterChildren.test.tsx +80 -0
  47. package/Components/MasterCell/utils/index.ts +85 -15
  48. package/Components/Navigator/StackNavigator.tsx +6 -0
  49. package/Components/ScreenRevealManager/withScreenRevealManager.tsx +4 -1
  50. package/package.json +5 -5
  51. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/ButtonContainerView.ts +0 -23
  52. package/Components/MasterCell/DefaultComponents/tv/ButtonContainerView/index.android.tsx +0 -135
  53. package/Components/MasterCell/DefaultComponents/tv/ButtonContainerView/types.ts +0 -25
@@ -5,7 +5,6 @@ import {
5
5
  mobileOverImagePositionStyles,
6
6
  } from "./utils";
7
7
  import { Button } from "./Button";
8
- import { ButtonContainerView } from "./ButtonContainerView";
9
8
  import { buildActionButtonsModel } from "../../ActionButtonsCore/model";
10
9
 
11
10
  const CONTAINER_PREFIX = "mobile_buttons_container";
@@ -43,6 +42,34 @@ export const MobileActionButtons = ({
43
42
  return null;
44
43
  }
45
44
 
45
+ const style = {
46
+ alignItems: "center",
47
+ ...(placement === "over_image"
48
+ ? {
49
+ position: "absolute",
50
+ zIndex: 10,
51
+ top: 0,
52
+ left: 0,
53
+ right: 0,
54
+ bottom: 0,
55
+ ...mobileOverImagePositionStyles(
56
+ value(`${CONTAINER_PREFIX}_over_image_position`) as string
57
+ ),
58
+ }
59
+ : {}),
60
+ };
61
+
62
+ const contentStyle = {
63
+ flexDirection: model.container.stacking === "vertical" ? "column" : "row",
64
+ alignSelf:
65
+ placement !== "over_image" ? model.container.horizontalAlign : undefined,
66
+ alignItems: model.container.horizontalAlign,
67
+ marginTop: model.container.margins.top,
68
+ marginRight: model.container.margins.right,
69
+ marginBottom: model.container.margins.bottom,
70
+ marginLeft: model.container.margins.left,
71
+ };
72
+
46
73
  const elements = compact(
47
74
  model.buttons.map(({ renderIndex, specificPrefix, stylePrefix }) => {
48
75
  const isNotLast = renderIndex < model.buttons.length - 1;
@@ -58,47 +85,38 @@ export const MobileActionButtons = ({
58
85
  [isVertical ? "marginBottom" : "marginRight"]: isNotLast ? gutter : 0,
59
86
  };
60
87
 
61
- return Button({
88
+ const button = Button({
62
89
  index: renderIndex,
63
90
  value,
64
91
  stylePrefix,
65
92
  specificPrefix,
66
93
  spacingStyle,
67
94
  });
95
+
96
+ if (!button) return null;
97
+
98
+ return {
99
+ type: "DataProvider",
100
+ data: [
101
+ {
102
+ func: "identity",
103
+ args: [],
104
+ propName: "entry",
105
+ },
106
+ ],
107
+ elements: [button],
108
+ };
68
109
  })
69
110
  );
70
111
 
71
- return ButtonContainerView({
72
- style: {
73
- alignItems: "center",
74
- ...(placement === "over_image"
75
- ? {
76
- position: "absolute",
77
- zIndex: 10,
78
- top: 0,
79
- left: 0,
80
- right: 0,
81
- bottom: 0,
82
- ...mobileOverImagePositionStyles(
83
- value(`${CONTAINER_PREFIX}_over_image_position`) as string
84
- ),
85
- }
86
- : {}),
87
- },
88
- contentStyle: {
89
- flexDirection: model.container.stacking === "vertical" ? "column" : "row",
90
- alignSelf:
91
- placement !== "over_image"
92
- ? model.container.horizontalAlign
93
- : undefined,
94
- alignItems: model.container.horizontalAlign,
95
- marginTop: model.container.margins.top,
96
- marginRight: model.container.margins.right,
97
- marginBottom: model.container.margins.bottom,
98
- marginLeft: model.container.margins.left,
112
+ return {
113
+ type: "ButtonContainerView",
114
+ style: style,
115
+ additionalProps: {
116
+ contentStyle,
99
117
  },
100
118
  elements,
101
- });
119
+ };
102
120
  };
103
121
 
104
122
  export { insertButtonsBetweenLabels, insertButtonsBetweenLabelContainers };
@@ -2,6 +2,8 @@ import {
2
2
  insertBetweenLabelContainers,
3
3
  insertBetweenLabels,
4
4
  } from "../../../ActionButtonsCore/placement";
5
+ import { toNumberWithDefaultZero } from "@applicaster/zapp-react-native-utils/numberUtils";
6
+ import { Platform } from "react-native";
5
7
 
6
8
  export const insertButtonsBetweenLabels = (
7
9
  configuration: Record<string, unknown>,
@@ -71,3 +73,166 @@ export const mobileOverImagePositionStyles = (position: string) => {
71
73
  };
72
74
  }
73
75
  };
76
+
77
+ export function getContentDirection(alignment = "left") {
78
+ switch (alignment) {
79
+ case "right":
80
+ return "row-reverse";
81
+ case "above":
82
+ return "column";
83
+ case "below":
84
+ return "column-reverse";
85
+ case "left":
86
+ default:
87
+ return "row";
88
+ }
89
+ }
90
+
91
+ export function getContentsAlignment(alignment = "center", direction = "left") {
92
+ switch (alignment) {
93
+ case "left":
94
+ return direction === "left" ? "flex-start" : "flex-end";
95
+ case "right":
96
+ return direction === "left" ? "flex-end" : "flex-start";
97
+ case "center":
98
+ default:
99
+ return "center";
100
+ }
101
+ }
102
+
103
+ export function resolveLabelText(label) {
104
+ if (typeof label === "string") {
105
+ return label;
106
+ }
107
+
108
+ return label?.label_1 || "";
109
+ }
110
+
111
+ export function buildLegacySelection(item, actionContext) {
112
+ // Some state are not array. In this case we fallback to the default value provided by the action or false
113
+ const defaultIsSelected = Array.isArray(actionContext?.state)
114
+ ? (actionContext?.state || []).includes(item)
115
+ : false;
116
+
117
+ return actionContext?.masterCell?.isSelected
118
+ ? actionContext?.masterCell?.isSelected(item)
119
+ : defaultIsSelected;
120
+ }
121
+
122
+ export const getMarginStyles = (value) => ({
123
+ marginTop: toNumberWithDefaultZero(value("margin_top")),
124
+ marginRight: toNumberWithDefaultZero(value("margin_right")),
125
+ marginBottom: toNumberWithDefaultZero(value("margin_bottom")),
126
+ marginLeft: toNumberWithDefaultZero(value("margin_left")),
127
+ });
128
+
129
+ export const getPaddingStyles = (value) => ({
130
+ paddingTop: toNumberWithDefaultZero(value("padding_top")),
131
+ paddingRight: toNumberWithDefaultZero(value("padding_right")),
132
+ paddingBottom: toNumberWithDefaultZero(value("padding_bottom")),
133
+ paddingLeft: toNumberWithDefaultZero(value("padding_left")),
134
+ });
135
+
136
+ export const getBorderStyles = (value) => ({
137
+ borderWidth: toNumberWithDefaultZero(value("border_size")),
138
+ borderRadius: toNumberWithDefaultZero(value("corner_radius")),
139
+ borderColor: value("border_color"),
140
+ });
141
+
142
+ export const getPressableStyles = (value) => ({
143
+ ...getMarginStyles(value),
144
+ ...getPaddingStyles(value),
145
+ ...getBorderStyles(value),
146
+ backgroundColor: value("background_color"),
147
+ });
148
+
149
+ export const getAssetStyles = (value) => ({
150
+ ...getMarginStyles((suffix) => value(`asset_${suffix}`)),
151
+ width: toNumberWithDefaultZero(value("asset_width")),
152
+ height: toNumberWithDefaultZero(value("asset_height")),
153
+ backgroundColor: "transparent",
154
+ });
155
+
156
+ export const getTextLabelStyles = (value) => ({
157
+ color: value("font_color"),
158
+ fontSize: toNumberWithDefaultZero(value("font_size")),
159
+ lineHeight: toNumberWithDefaultZero(value("line_height")),
160
+ ...getMarginStyles(value),
161
+ fontFamily:
162
+ Platform.OS === "ios"
163
+ ? value("ios_font_family")
164
+ : value("android_font_family"),
165
+ letterSpacing: toNumberWithDefaultZero(
166
+ Platform.OS === "ios"
167
+ ? value("ios_letter_spacing")
168
+ : value("android_letter_spacing")
169
+ ),
170
+ });
171
+
172
+ /** retrieves asset uri for a given flavour,
173
+ * if flavour is not provided, returns the default asset from `asset` or selected state asset (if available)
174
+ * asset can be:
175
+ * provided as asset path,
176
+ * provided as [default || flavour_1, alternative || flavour_2] array.
177
+ * mobileButtonAssets asset can be:
178
+ * provided as asset path,
179
+ * provided as [default || flavour_1, alternative || flavour_2] array,
180
+ * provided as [[] as flavour_1, [] as flavour_2] array for multiple flavours, where each flavour can be either a path or [default, alternative] array,
181
+ * provided as a React component accepting flavour as prop.
182
+ *
183
+ * isActive reflect the state of the action and can be used to render different asset for active/inactive state if asset is provided as array
184
+ *
185
+ * */
186
+ export const selectByAssetFlavour = (
187
+ actionState: {
188
+ asset?: string | [string, string] | CellActionAssetComponent;
189
+ mobileButtonAssets?:
190
+ | [string, string]
191
+ | [string, string][]
192
+ | CellActionAssetComponent;
193
+ },
194
+ flavour?: "flavour_1" | "flavour_2",
195
+ isActive?: boolean
196
+ ): string | CellActionAssetComponent => {
197
+ if (actionState.mobileButtonAssets) {
198
+ if (typeof actionState.mobileButtonAssets === "function") {
199
+ return actionState.mobileButtonAssets;
200
+ }
201
+
202
+ if (flavour) {
203
+ if (flavour === "flavour_1") {
204
+ if (typeof actionState.mobileButtonAssets[0] === "string") {
205
+ return actionState.mobileButtonAssets[0];
206
+ }
207
+
208
+ if (Array.isArray(actionState.mobileButtonAssets[0])) {
209
+ return actionState.mobileButtonAssets[0][isActive ? 1 : 0];
210
+ }
211
+
212
+ return actionState.mobileButtonAssets[0];
213
+ } else if (flavour === "flavour_2") {
214
+ if (typeof actionState.mobileButtonAssets[1] === "string") {
215
+ return actionState.mobileButtonAssets[1];
216
+ }
217
+
218
+ if (Array.isArray(actionState.mobileButtonAssets[1])) {
219
+ return actionState.mobileButtonAssets[1][isActive ? 1 : 0];
220
+ }
221
+
222
+ return actionState.mobileButtonAssets[1];
223
+ }
224
+ }
225
+
226
+ return Array.isArray(actionState.mobileButtonAssets[0])
227
+ ? actionState.mobileButtonAssets[0][isActive ? 1 : 0]
228
+ : actionState.mobileButtonAssets[0];
229
+ } else {
230
+ if (typeof actionState?.asset === "function") {
231
+ return actionState.asset;
232
+ }
233
+
234
+ return typeof actionState?.asset === "string"
235
+ ? actionState.asset
236
+ : actionState.asset[isActive ? 1 : 0];
237
+ }
238
+ };
@@ -1,31 +1,17 @@
1
- import * as R from "ramda";
2
- import { toNumber } from "@applicaster/zapp-react-native-utils/numberUtils";
3
-
4
1
  const Image = "Image";
5
2
 
6
3
  type Props = {
7
- prefix: string;
8
- value: Function;
9
4
  pluginIdentifier: string;
5
+ style?: Record<string, unknown>;
10
6
  };
11
7
 
12
- export const Asset = ({ prefix, value, pluginIdentifier }: Props) => {
13
- if (!value(`${prefix}_asset_enabled`)) return null;
14
-
8
+ export const Asset = ({ pluginIdentifier, style }: Props) => {
15
9
  return {
16
10
  type: Image,
17
- style: {
18
- marginTop: value(`${prefix}_asset_margin_top`),
19
- marginRight: value(`${prefix}_asset_margin_right`),
20
- marginBottom: value(`${prefix}_asset_margin_bottom`),
21
- marginLeft: value(`${prefix}_asset_margin_left`),
22
-
23
- width: toNumber(value(`${prefix}_asset_width`)) || 40,
24
- height: toNumber(value(`${prefix}_asset_height`)) || 40,
25
- },
11
+ style: style,
26
12
  data: [
27
13
  {
28
- func: R.identity,
14
+ func: "identity",
29
15
  args: [],
30
16
  propName: "entry",
31
17
  },
@@ -1,13 +1,14 @@
1
- import {
2
- toNumberWithDefaultZero,
3
- toNumberWithDefault,
4
- } from "@applicaster/zapp-react-native-utils/numberUtils";
5
-
6
1
  import { compact } from "@applicaster/zapp-react-native-utils/cellUtils";
7
2
 
8
3
  import { TextLabelsContainer } from "./TextLabelsContainer";
9
4
  import { Asset } from "./Asset";
10
5
  import { Spacer } from "./Spacer";
6
+ import {
7
+ getAssetStyles,
8
+ getBorderStyles,
9
+ getDisplayModeStyles,
10
+ getPaddingStyles,
11
+ } from "./utils";
11
12
 
12
13
  const compactAndSort = ({ value, prefix, asset, labels, spacer }) => {
13
14
  const assetAlignment = value(`${prefix}_asset_alignment`) || "left";
@@ -19,31 +20,6 @@ const compactAndSort = ({ value, prefix, asset, labels, spacer }) => {
19
20
  return compact([asset, labels]);
20
21
  };
21
22
 
22
- const displayMode = ({ value, prefix }) => {
23
- const mode = value(`${prefix}_display_mode`) || "dynamic";
24
-
25
- const width = toNumberWithDefault(
26
- 240,
27
- value(`${prefix}_fixed_and_fixed_center_width`)
28
- );
29
-
30
- if (mode === "fixed") {
31
- return {
32
- width,
33
- };
34
- }
35
-
36
- if (mode === "fixed_center") {
37
- return {
38
- width,
39
- justifyContent: "center",
40
- };
41
- }
42
-
43
- // dynamic mode
44
- return {};
45
- };
46
-
47
23
  type Props = {
48
24
  prefix: string;
49
25
  value: Function;
@@ -63,55 +39,30 @@ export const Button = ({
63
39
  }: Props) => {
64
40
  if (!value(`${suffixId}_button_enabled`)) return null;
65
41
 
42
+ const getValue = (suffix: string) => value(`${prefix}_${suffix}`);
43
+
66
44
  return {
67
- type: "FocusableView", // container
45
+ type: "TvActionButton",
68
46
  style: {
69
47
  flexDirection: "row",
70
48
  alignItems: "center",
71
49
  display: "flex",
72
-
73
- paddingTop: toNumberWithDefaultZero(
74
- value(`${prefix}_background_padding_top`)
75
- ),
76
- paddingRight: toNumberWithDefaultZero(
77
- value(`${prefix}_background_padding_right`)
78
- ),
79
- paddingBottom: toNumberWithDefaultZero(
80
- value(`${prefix}_background_padding_bottom`)
81
- ),
82
- paddingLeft: toNumberWithDefaultZero(
83
- value(`${prefix}_background_padding_left`)
84
- ),
85
-
86
- // BORDER
87
- borderRadius: toNumberWithDefaultZero(
88
- value(`${prefix}_background_corner_radius`)
89
- ),
90
- borderWidth: value(`${prefix}_background_border_thickness`),
91
- borderStyle: "solid",
92
- // BORDER
93
-
94
- ...displayMode({ value, prefix }),
50
+ ...getPaddingStyles((suffix) => getValue(`background_${suffix}`)),
51
+ ...getBorderStyles((suffix) => getValue(`background_${suffix}`)),
52
+ ...getDisplayModeStyles(getValue),
95
53
  },
96
- data: [
97
- {
98
- func: (x) => x,
99
- args: [],
100
- propName: "item",
101
- },
102
- ],
103
54
  elements: compactAndSort({
104
55
  prefix,
105
56
  value,
106
- asset: Asset({
107
- prefix,
108
- value,
109
- pluginIdentifier,
110
- }),
57
+ asset: getValue("asset_enabled")
58
+ ? Asset({
59
+ style: getAssetStyles((suffix) => getValue(`asset_${suffix}`)),
60
+ pluginIdentifier,
61
+ })
62
+ : null,
111
63
  labels: TextLabelsContainer({
112
- prefix,
113
- value,
114
- platformValue,
64
+ value: getValue,
65
+ platformValue: (suffix: string) => platformValue(`${prefix}_${suffix}`),
115
66
  pluginIdentifier,
116
67
  }),
117
68
  spacer: Spacer(),
@@ -119,12 +70,12 @@ export const Button = ({
119
70
  additionalProps: {
120
71
  suffixId,
121
72
  focusedStyles: {
122
- backgroundColor: value(`${prefix}_focused_background_color`),
123
- borderColor: value(`${prefix}_focused_background_border_color`),
73
+ backgroundColor: getValue("focused_background_color"),
74
+ borderColor: getValue("focused_background_border_color"),
124
75
  },
125
76
  normalStyles: {
126
- backgroundColor: value(`${prefix}_background_color`),
127
- borderColor: value(`${prefix}_background_border_color`),
77
+ backgroundColor: getValue("background_color"),
78
+ borderColor: getValue("background_border_color"),
128
79
  },
129
80
  pluginIdentifier,
130
81
  preferredFocus,
@@ -1,10 +1,10 @@
1
- import { TextLabel } from "./TextLabel";
2
1
  import { compact } from "@applicaster/zapp-react-native-utils/cellUtils";
2
+ import { getTextLabelStyles } from "./utils";
3
3
 
4
4
  const View = "View";
5
+ const Text = "Text";
5
6
 
6
7
  export const TextLabelsContainer = ({
7
- prefix,
8
8
  value,
9
9
  platformValue,
10
10
  pluginIdentifier,
@@ -14,21 +14,40 @@ export const TextLabelsContainer = ({
14
14
  style: {
15
15
  flexDirection: "column",
16
16
  },
17
- elements: compact([
18
- TextLabel({
19
- prefix: `${prefix}_label_1`,
20
- value,
21
- platformValue,
22
- pluginIdentifier,
23
- name: "label_1",
24
- }),
25
- TextLabel({
26
- prefix: `${prefix}_label_2`,
27
- value,
28
- platformValue,
29
- pluginIdentifier,
30
- name: "label_2",
31
- }),
32
- ]),
17
+ elements: compact(
18
+ ["label_1", "label_2"].map((name) => {
19
+ const getValue = (suffix: string) => value(`${name}_${suffix}`);
20
+
21
+ const getPlatformValue = (suffix: string) =>
22
+ platformValue(`${name}_${suffix}`);
23
+
24
+ return getValue("toggle")
25
+ ? {
26
+ type: Text,
27
+ style: getTextLabelStyles(getValue, getPlatformValue),
28
+ data: [
29
+ {
30
+ func: "identity",
31
+ args: [],
32
+ propName: "entry",
33
+ },
34
+ ],
35
+ additionalProps: {
36
+ label: { context: pluginIdentifier, name },
37
+ numberOfLines: getValue("number_of_lines"),
38
+ transformText: getValue("text_transform"),
39
+ focusedStyles: {
40
+ backgroundColor: getValue("focused_background_color"),
41
+ color: getValue("focused_font_color"),
42
+ },
43
+ normalStyles: {
44
+ backgroundColor: getValue("background_color"),
45
+ color: getValue("font_color"),
46
+ },
47
+ },
48
+ }
49
+ : null;
50
+ })
51
+ ),
33
52
  };
34
53
  };
@@ -0,0 +1,27 @@
1
+ import React from "react";
2
+ import { ActionButtonController } from "../../ActionButtonsCore/components";
3
+ import { FocusableView } from "../../FocusableView";
4
+
5
+ type Props = Record<string, any> & {
6
+ children?: React.ReactNode;
7
+ style?: object;
8
+ entry?: any;
9
+ };
10
+
11
+ export function TvActionButton({
12
+ children,
13
+ pluginIdentifier,
14
+ style,
15
+ entry,
16
+ ...props
17
+ }: Props) {
18
+ return (
19
+ <ActionButtonController pluginIdentifier={pluginIdentifier} entry={entry}>
20
+ {({ onPress }) => (
21
+ <FocusableView {...props} style={style} onPress={onPress}>
22
+ {children}
23
+ </FocusableView>
24
+ )}
25
+ </ActionButtonController>
26
+ );
27
+ }
@@ -37,29 +37,34 @@ describe("TvActionButtons", () => {
37
37
  skipButtons: false,
38
38
  });
39
39
 
40
+ expect(result.type).toBe("ButtonContainerView");
40
41
  expect(result.style.justifyContent).toBe("center");
41
42
  expect(result.additionalProps.buttonsCount).toBe(2);
42
43
  expect(result.elements).toHaveLength(2);
44
+ expect(result.elements[0].type).toBe("DataProvider");
43
45
 
44
- expect(result.elements[0].additionalProps.pluginIdentifier).toBe(
45
- "action_1"
46
- );
46
+ expect(result.elements[0].data).toEqual([
47
+ {
48
+ func: "identity",
49
+ args: [],
50
+ propName: "entry",
51
+ },
52
+ ]);
47
53
 
48
- expect(result.elements[0].additionalProps.suffixId).toBe(
49
- "tv_buttons_button_1"
50
- );
54
+ const firstButton = result.elements[0].elements[0];
55
+ const secondButton = result.elements[1].elements[0];
51
56
 
52
- expect(result.elements[0].additionalProps.preferredFocus).toBe(true);
57
+ expect(firstButton.additionalProps.pluginIdentifier).toBe("action_1");
53
58
 
54
- expect(result.elements[1].additionalProps.pluginIdentifier).toBe(
55
- "action_3"
56
- );
59
+ expect(firstButton.additionalProps.suffixId).toBe("tv_buttons_button_1");
57
60
 
58
- expect(result.elements[1].additionalProps.suffixId).toBe(
59
- "tv_buttons_button_3"
60
- );
61
+ expect(firstButton.additionalProps.preferredFocus).toBe(true);
61
62
 
62
- expect(result.elements[1].additionalProps.preferredFocus).toBe(false);
63
+ expect(secondButton.additionalProps.pluginIdentifier).toBe("action_3");
64
+
65
+ expect(secondButton.additionalProps.suffixId).toBe("tv_buttons_button_3");
66
+
67
+ expect(secondButton.additionalProps.preferredFocus).toBe(false);
63
68
  });
64
69
 
65
70
  it("keeps shared button styles from slot 1 while preserving slot 3 identity", () => {
@@ -73,14 +78,12 @@ describe("TvActionButtons", () => {
73
78
  skipButtons: false,
74
79
  });
75
80
 
76
- expect(result.elements[1].style.paddingTop).toBe(11);
81
+ const secondButton = result.elements[1].elements[0];
82
+
83
+ expect(secondButton.style.paddingTop).toBe(11);
77
84
 
78
- expect(result.elements[1].additionalProps.pluginIdentifier).toBe(
79
- "action_3"
80
- );
85
+ expect(secondButton.additionalProps.pluginIdentifier).toBe("action_3");
81
86
 
82
- expect(result.elements[1].additionalProps.suffixId).toBe(
83
- "tv_buttons_button_3"
84
- );
87
+ expect(secondButton.additionalProps.suffixId).toBe("tv_buttons_button_3");
85
88
  });
86
89
  });