@applicaster/zapp-react-native-ui-components 15.1.0-rc.3 → 16.0.0-alpha.7128076344

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 (144) hide show
  1. package/Components/BaseFocusable/index.ios.ts +12 -2
  2. package/Components/Cell/FocusableWrapper.tsx +3 -0
  3. package/Components/Cell/TvOSCellComponent.tsx +6 -3
  4. package/Components/Focusable/Focusable.tsx +4 -2
  5. package/Components/Focusable/FocusableTvOS.tsx +18 -1
  6. package/Components/Focusable/__tests__/__snapshots__/FocusableTvOS.test.tsx.snap +1 -0
  7. package/Components/FocusableGroup/FocusableTvOS.tsx +30 -1
  8. package/Components/GeneralContentScreen/utils/__tests__/useCurationAPI.test.js +1 -1
  9. package/Components/HandlePlayable/HandlePlayable.tsx +13 -8
  10. package/Components/Layout/TV/LayoutBackground.tsx +5 -2
  11. package/Components/Layout/TV/NavBarContainer.tsx +1 -10
  12. package/Components/Layout/TV/ScreenContainer.tsx +2 -6
  13. package/Components/Layout/TV/__tests__/__snapshots__/NavBarContainer.test.tsx.snap +7 -12
  14. package/Components/Layout/TV/__tests__/__snapshots__/ScreenContainer.test.tsx.snap +7 -12
  15. package/Components/Layout/TV/index.tsx +3 -4
  16. package/Components/Layout/TV/index.web.tsx +3 -4
  17. package/Components/LinkHandler/LinkHandler.tsx +2 -2
  18. package/Components/MasterCell/CONFIG_BUILDER_TO_REACT_COMPONENT.md +144 -0
  19. package/Components/MasterCell/DefaultComponents/ActionButtonsCore/__tests__/model.test.ts +80 -0
  20. package/Components/MasterCell/DefaultComponents/ActionButtonsCore/__tests__/placement.test.ts +187 -0
  21. package/Components/MasterCell/DefaultComponents/ActionButtonsCore/__tests__/selectors.test.ts +45 -0
  22. package/Components/MasterCell/DefaultComponents/ActionButtonsCore/__tests__/style.test.ts +49 -0
  23. package/Components/MasterCell/DefaultComponents/ActionButtonsCore/components/ActionButtonController.tsx +165 -0
  24. package/Components/MasterCell/DefaultComponents/ActionButtonsCore/components/__tests__/ActionButtonController.test.tsx +405 -0
  25. package/Components/MasterCell/DefaultComponents/ActionButtonsCore/components/index.ts +1 -0
  26. package/Components/MasterCell/DefaultComponents/ActionButtonsCore/model.ts +47 -0
  27. package/Components/MasterCell/DefaultComponents/ActionButtonsCore/placement.ts +170 -0
  28. package/Components/MasterCell/DefaultComponents/ActionButtonsCore/selectors.ts +26 -0
  29. package/Components/MasterCell/DefaultComponents/ActionButtonsCore/style.ts +29 -0
  30. package/Components/MasterCell/DefaultComponents/ActionButtonsCore/types.ts +37 -0
  31. package/Components/MasterCell/DefaultComponents/BorderContainerView/index.tsx +4 -10
  32. package/Components/MasterCell/DefaultComponents/Button.tsx +0 -15
  33. package/Components/MasterCell/DefaultComponents/ButtonContainerView/components/HorizontalSeparator.tsx +8 -0
  34. package/Components/MasterCell/DefaultComponents/ButtonContainerView/index.tsx +15 -0
  35. package/Components/MasterCell/DefaultComponents/ButtonContainerView/index.tv.android.tsx +58 -0
  36. package/Components/MasterCell/DefaultComponents/{tv/ButtonContainerView/index.tsx → ButtonContainerView/index.tv.tsx} +3 -11
  37. package/Components/MasterCell/DefaultComponents/ButtonContainerView/index.web.ts +1 -0
  38. package/Components/MasterCell/DefaultComponents/ButtonContainerView/types.ts +40 -0
  39. package/Components/MasterCell/DefaultComponents/DataProvider/index.tsx +163 -0
  40. package/Components/MasterCell/DefaultComponents/FocusableView/index.android.tsx +2 -23
  41. package/Components/MasterCell/DefaultComponents/FocusableView/index.tsx +4 -22
  42. package/Components/MasterCell/DefaultComponents/Image/Image.android.tsx +8 -2
  43. package/Components/MasterCell/DefaultComponents/Image/Image.ios.tsx +11 -3
  44. package/Components/MasterCell/DefaultComponents/Image/Image.web.tsx +9 -1
  45. package/Components/MasterCell/DefaultComponents/Image/hooks/useImage.ts +15 -14
  46. package/Components/MasterCell/DefaultComponents/LiveImage/index.tsx +1 -2
  47. package/Components/MasterCell/DefaultComponents/PressableView.tsx +34 -0
  48. package/Components/MasterCell/DefaultComponents/SecondaryImage/hooks/__tests__/useGetImageDimensions.test.ts +7 -6
  49. package/Components/MasterCell/DefaultComponents/Text/hooks/useText.ts +11 -0
  50. package/Components/MasterCell/DefaultComponents/__tests__/DataProvider.test.tsx +141 -0
  51. package/Components/MasterCell/DefaultComponents/index.ts +9 -3
  52. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/ActionButton.tsx +135 -0
  53. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/Asset.ts +33 -0
  54. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/AssetComponent.tsx +22 -0
  55. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/Button.ts +125 -0
  56. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/Spacer.ts +16 -0
  57. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/TextLabel.ts +67 -0
  58. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/TextLabelsContainer.ts +37 -0
  59. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/__tests__/PressableView.test.tsx +393 -0
  60. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/__tests__/builders.test.ts +141 -0
  61. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/__tests__/index.test.ts +343 -0
  62. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/helpers.ts +105 -0
  63. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/index.ts +122 -0
  64. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/utils/__tests__/insertButtons.test.ts +118 -0
  65. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/utils/index.ts +238 -0
  66. package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/Asset.ts +4 -18
  67. package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/Button.ts +24 -73
  68. package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/TextLabelsContainer.ts +37 -18
  69. package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/TvActionButton.tsx +27 -0
  70. package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/__tests__/index.test.ts +89 -0
  71. package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/__tests__/renderedTree.test.tsx +231 -0
  72. package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/index.ts +47 -48
  73. package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/utils/__tests__/getPluginIdentifier.test.ts +115 -29
  74. package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/utils/index.ts +101 -144
  75. package/Components/MasterCell/MappingFunctions/index.js +3 -2
  76. package/Components/MasterCell/README.md +4 -0
  77. package/Components/MasterCell/__tests__/__snapshots__/dataAdapter.test.js.snap +24 -0
  78. package/Components/MasterCell/__tests__/configInflater.test.js +1 -0
  79. package/Components/MasterCell/__tests__/elementMapper.test.js +46 -0
  80. package/Components/MasterCell/dataAdapter.ts +4 -1
  81. package/Components/MasterCell/elementMapper.tsx +52 -7
  82. package/Components/MasterCell/utils/__tests__/cloneChildrenWithIds.test.tsx +43 -0
  83. package/Components/MasterCell/utils/__tests__/useFilterChildren.test.tsx +80 -0
  84. package/Components/MasterCell/utils/index.ts +85 -15
  85. package/Components/OfflineHandler/NotificationView/NotificationView.tsx +2 -2
  86. package/Components/OfflineHandler/NotificationView/__tests__/index.test.tsx +17 -18
  87. package/Components/OfflineHandler/__tests__/index.test.tsx +27 -18
  88. package/Components/PlayerContainer/PlayerContainer.tsx +14 -13
  89. package/Components/River/ComponentsMap/ComponentsMap.tsx +6 -19
  90. package/Components/River/ComponentsMap/hooks/__tests__/useLoadingState.test.ts +1 -1
  91. package/Components/River/RefreshControl.tsx +19 -88
  92. package/Components/River/River.tsx +9 -82
  93. package/Components/River/TV/River.tsx +31 -14
  94. package/Components/River/TV/index.tsx +8 -4
  95. package/Components/River/TV/utils/__tests__/toStringOrEmpty.test.ts +30 -0
  96. package/Components/River/TV/utils/index.ts +4 -0
  97. package/Components/River/TV/withFocusableGroupForContent.tsx +71 -0
  98. package/Components/River/__tests__/__snapshots__/componentsMap.test.js.snap +1 -0
  99. package/Components/River/__tests__/componentsMap.test.js +38 -0
  100. package/Components/River/hooks/__tests__/usePullToRefresh.test.ts +132 -0
  101. package/Components/River/hooks/index.ts +1 -0
  102. package/Components/River/hooks/usePullToRefresh.ts +51 -0
  103. package/Components/Screen/TV/index.web.tsx +4 -2
  104. package/Components/Screen/__tests__/Screen.test.tsx +65 -42
  105. package/Components/Screen/__tests__/__snapshots__/Screen.test.tsx.snap +68 -44
  106. package/Components/Screen/hooks.ts +2 -3
  107. package/Components/Screen/index.tsx +2 -3
  108. package/Components/Screen/orientationHandler.ts +3 -3
  109. package/Components/ScreenResolver/index.tsx +9 -5
  110. package/Components/ScreenRevealManager/ScreenRevealManager.ts +40 -8
  111. package/Components/ScreenRevealManager/__tests__/ScreenRevealManager.test.ts +86 -69
  112. package/Components/Tabs/TabContent.tsx +7 -4
  113. package/Components/TopCutoffOverlay/__tests__/TopCutoffOverlay.test.tsx +201 -0
  114. package/Components/TopCutoffOverlay/hooks/__tests__/useMarginTop.test.ts +130 -0
  115. package/Components/TopCutoffOverlay/hooks/index.ts +1 -0
  116. package/Components/TopCutoffOverlay/hooks/useMarginTop.ts +59 -0
  117. package/Components/TopCutoffOverlay/index.tsx +55 -0
  118. package/Components/Transitioner/index.js +3 -3
  119. package/Components/VideoModal/ModalAnimation/ModalAnimationContext.tsx +5 -5
  120. package/Components/VideoModal/hooks/__tests__/useDelayedPlayerDetails.test.ts +15 -7
  121. package/Components/VideoModal/utils.ts +12 -9
  122. package/Components/Viewport/ViewportAware/__tests__/viewportAware.test.js +0 -2
  123. package/Components/Viewport/ViewportAware/index.tsx +16 -7
  124. package/Components/Viewport/ViewportEvents/__tests__/viewportEvents.test.js +1 -1
  125. package/Components/ZappFrameworkComponents/BarView/BarView.tsx +4 -6
  126. package/Components/ZappFrameworkComponents/BarView/__tests__/BarView.test.tsx +2 -2
  127. package/Components/default-cell-renderer/viewTrees/mobile/index.ts +0 -3
  128. package/Contexts/ScreenContext/index.tsx +25 -18
  129. package/Contexts/ScreenTrackedViewPositionsContext/__tests__/index.test.tsx +1 -1
  130. package/Decorators/Analytics/index.tsx +6 -5
  131. package/Decorators/ConfigurationWrapper/__tests__/__snapshots__/withConfigurationProvider.test.tsx.snap +1 -0
  132. package/Decorators/ConfigurationWrapper/const.ts +1 -0
  133. package/Decorators/ZappPipesDataConnector/__tests__/UrlFeedResolver.test.tsx +39 -21
  134. package/Decorators/ZappPipesDataConnector/__tests__/zappPipesDataConnector.test.js +1 -1
  135. package/Decorators/ZappPipesDataConnector/index.tsx +2 -2
  136. package/Decorators/ZappPipesDataConnector/resolvers/StaticFeedResolver.tsx +1 -1
  137. package/Decorators/ZappPipesDataConnector/resolvers/UrlFeedResolver.tsx +18 -7
  138. package/Helpers/DataSourceHelper/__tests__/itemLimitForData.test.ts +80 -0
  139. package/Helpers/DataSourceHelper/index.ts +19 -0
  140. package/package.json +5 -5
  141. package/Components/MasterCell/DefaultComponents/tv/ButtonContainerView/index.android.tsx +0 -135
  142. package/Components/MasterCell/DefaultComponents/tv/ButtonContainerView/types.ts +0 -25
  143. package/Components/River/TV/withTVEventHandler.tsx +0 -36
  144. package/Helpers/DataSourceHelper/index.js +0 -19
@@ -0,0 +1,238 @@
1
+ import {
2
+ insertBetweenLabelContainers,
3
+ insertBetweenLabels,
4
+ } from "../../../ActionButtonsCore/placement";
5
+ import { toNumberWithDefaultZero } from "@applicaster/zapp-react-native-utils/numberUtils";
6
+ import { Platform } from "react-native";
7
+
8
+ export const insertButtonsBetweenLabels = (
9
+ configuration: Record<string, unknown>,
10
+ buttons,
11
+ labels = []
12
+ ) =>
13
+ insertBetweenLabels(
14
+ {
15
+ position: configuration?.mobile_buttons_container_position as
16
+ | string
17
+ | undefined,
18
+ allowOnTop: false,
19
+ appendWhenMissing: false,
20
+ },
21
+ buttons,
22
+ labels // "text_label_1", "text_label_2", "text_label_3", "text_label_4"
23
+ );
24
+
25
+ export const insertButtonsBetweenLabelContainers = (
26
+ configuration: Record<string, unknown>,
27
+ buttons,
28
+ labelContainers = []
29
+ ) =>
30
+ insertBetweenLabelContainers(
31
+ {
32
+ position: configuration?.mobile_buttons_container_position as
33
+ | string
34
+ | undefined,
35
+ allowOnTop: false,
36
+ appendWhenMissing: true,
37
+ },
38
+ buttons,
39
+ labelContainers // top_label_1, top_label_2, bottom_label_1, bottom_label_2, etc.
40
+ );
41
+
42
+ export const mobileOverImagePositionStyles = (position: string) => {
43
+ switch (position) {
44
+ case "top_left":
45
+ return {
46
+ justifyContent: "flex-start",
47
+ alignItems: "flex-start",
48
+ };
49
+ case "top_right":
50
+ return {
51
+ justifyContent: "flex-start",
52
+ alignItems: "flex-end",
53
+ };
54
+ case "bottom_left":
55
+ return {
56
+ justifyContent: "flex-end",
57
+ alignItems: "flex-start",
58
+ };
59
+ case "bottom_right":
60
+ return {
61
+ justifyContent: "flex-end",
62
+ alignItems: "flex-end",
63
+ };
64
+ case "center":
65
+ default:
66
+ return {
67
+ justifyContent: "center",
68
+ alignItems: "center",
69
+ top: 0,
70
+ left: 0,
71
+ right: 0,
72
+ bottom: 0,
73
+ };
74
+ }
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
+ }
@@ -0,0 +1,89 @@
1
+ import { TvActionButtons } from "..";
2
+
3
+ describe("TvActionButtons", () => {
4
+ const baseConfiguration = {
5
+ tv_buttons_container_buttons_enabled: true,
6
+ tv_buttons_container_align: "middle",
7
+ tv_buttons_container_margin_top: 1,
8
+ tv_buttons_container_margin_right: 2,
9
+ tv_buttons_container_margin_bottom: 3,
10
+ tv_buttons_container_margin_left: 4,
11
+ tv_buttons_container_horizontal_gutter: 10,
12
+ tv_buttons_container_independent_styles: false,
13
+ tv_buttons_button_1_button_enabled: true,
14
+ tv_buttons_button_1_assign_action: "action_1",
15
+ tv_buttons_button_1_background_padding_top: 11,
16
+ tv_buttons_button_1_background_padding_right: 12,
17
+ tv_buttons_button_1_background_padding_bottom: 13,
18
+ tv_buttons_button_1_background_padding_left: 14,
19
+ tv_buttons_button_3_button_enabled: true,
20
+ tv_buttons_button_3_assign_action: "action_3",
21
+ tv_buttons_button_3_background_padding_top: 31,
22
+ tv_buttons_button_3_background_padding_right: 32,
23
+ tv_buttons_button_3_background_padding_bottom: 33,
24
+ tv_buttons_button_3_background_padding_left: 34,
25
+ };
26
+
27
+ const platformValue = jest.fn();
28
+
29
+ it("renders sparse enabled slots with slot-based action lookup and ids", () => {
30
+ const value = (key) => baseConfiguration[key];
31
+
32
+ const result = TvActionButtons({
33
+ value,
34
+ platformValue,
35
+ configuration: baseConfiguration,
36
+ state: "focused",
37
+ skipButtons: false,
38
+ });
39
+
40
+ expect(result.type).toBe("ButtonContainerView");
41
+ expect(result.style.justifyContent).toBe("center");
42
+ expect(result.additionalProps.buttonsCount).toBe(2);
43
+ expect(result.elements).toHaveLength(2);
44
+ expect(result.elements[0].type).toBe("DataProvider");
45
+
46
+ expect(result.elements[0].data).toEqual([
47
+ {
48
+ func: "identity",
49
+ args: [],
50
+ propName: "entry",
51
+ },
52
+ ]);
53
+
54
+ const firstButton = result.elements[0].elements[0];
55
+ const secondButton = result.elements[1].elements[0];
56
+
57
+ expect(firstButton.additionalProps.pluginIdentifier).toBe("action_1");
58
+
59
+ expect(firstButton.additionalProps.suffixId).toBe("tv_buttons_button_1");
60
+
61
+ expect(firstButton.additionalProps.preferredFocus).toBe(true);
62
+
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);
68
+ });
69
+
70
+ it("keeps shared button styles from slot 1 while preserving slot 3 identity", () => {
71
+ const value = (key) => baseConfiguration[key];
72
+
73
+ const result = TvActionButtons({
74
+ value,
75
+ platformValue,
76
+ configuration: baseConfiguration,
77
+ state: "focused",
78
+ skipButtons: false,
79
+ });
80
+
81
+ const secondButton = result.elements[1].elements[0];
82
+
83
+ expect(secondButton.style.paddingTop).toBe(11);
84
+
85
+ expect(secondButton.additionalProps.pluginIdentifier).toBe("action_3");
86
+
87
+ expect(secondButton.additionalProps.suffixId).toBe("tv_buttons_button_3");
88
+ });
89
+ });