@applicaster/zapp-react-native-ui-components 15.1.4 → 16.0.0-alpha.1042942411

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 (202) hide show
  1. package/Components/BackgroundImage/index.ts +1 -8
  2. package/Components/BaseFocusable/index.ios.ts +12 -2
  3. package/Components/Cell/FocusableWrapper.tsx +3 -0
  4. package/Components/Cell/TvOSCellComponent.tsx +6 -3
  5. package/Components/CellRendererResolver/index.ts +1 -1
  6. package/Components/Focusable/Focusable.tsx +4 -2
  7. package/Components/Focusable/FocusableTvOS.tsx +18 -1
  8. package/Components/Focusable/__tests__/__snapshots__/FocusableTvOS.test.tsx.snap +1 -0
  9. package/Components/FocusableGroup/FocusableTvOS.tsx +30 -1
  10. package/Components/GeneralContentScreen/GeneralContentScreenHookAdapter.tsx +39 -0
  11. package/Components/GeneralContentScreen/__tests__/GeneralContentScreenHookAdapter.test.tsx +64 -0
  12. package/Components/GeneralContentScreen/__tests__/HookContentFocusGroup.web.test.tsx +91 -0
  13. package/Components/GeneralContentScreen/hookAdapter/__tests__/networkService.test.ts +74 -0
  14. package/Components/GeneralContentScreen/hookAdapter/__tests__/runInBackground.test.ts +139 -0
  15. package/Components/GeneralContentScreen/hookAdapter/__tests__/validationHelper.test.ts +124 -0
  16. package/Components/GeneralContentScreen/hookAdapter/logger.ts +6 -0
  17. package/Components/GeneralContentScreen/hookAdapter/networkService.ts +53 -0
  18. package/Components/GeneralContentScreen/hookAdapter/runInBackground.ts +48 -0
  19. package/Components/GeneralContentScreen/hookAdapter/validationHelper.ts +72 -0
  20. package/Components/GeneralContentScreen/hookFocus/index.tsx +13 -0
  21. package/Components/GeneralContentScreen/hookFocus/index.web.tsx +69 -0
  22. package/Components/GeneralContentScreen/index.ts +2 -0
  23. package/Components/GeneralContentScreen/utils/__tests__/useCurationAPI.test.js +1 -1
  24. package/Components/HandlePlayable/HandlePlayable.tsx +13 -8
  25. package/Components/Layout/TV/NavBarContainer.tsx +1 -10
  26. package/Components/Layout/TV/ScreenContainer.tsx +2 -6
  27. package/Components/Layout/TV/__tests__/__snapshots__/NavBarContainer.test.tsx.snap +7 -12
  28. package/Components/Layout/TV/__tests__/__snapshots__/ScreenContainer.test.tsx.snap +7 -12
  29. package/Components/Layout/TV/index.tsx +3 -4
  30. package/Components/Layout/TV/index.web.tsx +3 -4
  31. package/Components/LinkHandler/LinkHandler.tsx +2 -2
  32. package/Components/MasterCell/CONFIG_BUILDER_TO_REACT_COMPONENT.md +144 -0
  33. package/Components/MasterCell/DefaultComponents/ActionButton.tsx +27 -48
  34. package/Components/MasterCell/DefaultComponents/ActionButtonsCore/__tests__/model.test.ts +80 -0
  35. package/Components/MasterCell/DefaultComponents/ActionButtonsCore/__tests__/placement.test.ts +213 -0
  36. package/Components/MasterCell/DefaultComponents/ActionButtonsCore/__tests__/selectors.test.ts +45 -0
  37. package/Components/MasterCell/DefaultComponents/ActionButtonsCore/__tests__/style.test.ts +49 -0
  38. package/Components/MasterCell/DefaultComponents/ActionButtonsCore/components/ActionButtonController.tsx +165 -0
  39. package/Components/MasterCell/DefaultComponents/ActionButtonsCore/components/__tests__/ActionButtonController.test.tsx +405 -0
  40. package/Components/MasterCell/DefaultComponents/ActionButtonsCore/components/index.ts +1 -0
  41. package/Components/MasterCell/DefaultComponents/ActionButtonsCore/model.ts +47 -0
  42. package/Components/MasterCell/DefaultComponents/ActionButtonsCore/placement.ts +198 -0
  43. package/Components/MasterCell/DefaultComponents/ActionButtonsCore/selectors.ts +26 -0
  44. package/Components/MasterCell/DefaultComponents/ActionButtonsCore/style.ts +29 -0
  45. package/Components/MasterCell/DefaultComponents/ActionButtonsCore/types.ts +37 -0
  46. package/Components/MasterCell/DefaultComponents/BorderContainerView/__tests__/index.test.tsx +217 -46
  47. package/Components/MasterCell/DefaultComponents/BorderContainerView/index.tsx +50 -119
  48. package/Components/MasterCell/DefaultComponents/Button.tsx +50 -58
  49. package/Components/MasterCell/DefaultComponents/ButtonContainerView/components/HorizontalSeparator.tsx +8 -0
  50. package/Components/MasterCell/DefaultComponents/ButtonContainerView/index.android.tv.tsx +58 -0
  51. package/Components/MasterCell/DefaultComponents/ButtonContainerView/index.tsx +15 -0
  52. package/Components/MasterCell/DefaultComponents/{tv/ButtonContainerView/index.tsx → ButtonContainerView/index.tv.tsx} +3 -11
  53. package/Components/MasterCell/DefaultComponents/ButtonContainerView/index.web.ts +1 -0
  54. package/Components/MasterCell/DefaultComponents/ButtonContainerView/types.ts +40 -0
  55. package/Components/MasterCell/DefaultComponents/CellBadge/__tests__/__snapshots__/index.test.tsx.snap +18 -0
  56. package/Components/MasterCell/DefaultComponents/CellBadge/__tests__/index.test.tsx +90 -0
  57. package/Components/MasterCell/DefaultComponents/CellBadge/index.tsx +13 -14
  58. package/Components/MasterCell/DefaultComponents/DataProvider/index.tsx +163 -0
  59. package/Components/MasterCell/DefaultComponents/FocusableView/index.android.tsx +2 -23
  60. package/Components/MasterCell/DefaultComponents/FocusableView/index.tsx +4 -22
  61. package/Components/MasterCell/DefaultComponents/Image/Image.android.tsx +8 -2
  62. package/Components/MasterCell/DefaultComponents/Image/Image.ios.tsx +11 -3
  63. package/Components/MasterCell/DefaultComponents/Image/Image.web.tsx +9 -1
  64. package/Components/MasterCell/DefaultComponents/Image/hooks/useImage.ts +15 -14
  65. package/Components/MasterCell/DefaultComponents/ImageContainer/index.tsx +5 -3
  66. package/Components/MasterCell/DefaultComponents/LiveImage/index.tsx +1 -2
  67. package/Components/MasterCell/DefaultComponents/PressableView.tsx +54 -0
  68. package/Components/MasterCell/DefaultComponents/SecondaryImage/Image.tsx +46 -50
  69. package/Components/MasterCell/DefaultComponents/SecondaryImage/__tests__/__snapshots__/Image.test.tsx.snap +47 -39
  70. package/Components/MasterCell/DefaultComponents/SecondaryImage/hooks/__tests__/useGetImageDimensions.test.ts +7 -6
  71. package/Components/MasterCell/DefaultComponents/SecondaryImage/utils.ts +19 -6
  72. package/Components/MasterCell/DefaultComponents/Text/hooks/useText.ts +15 -0
  73. package/Components/MasterCell/DefaultComponents/Text/index.tsx +45 -15
  74. package/Components/MasterCell/DefaultComponents/UIKitAdapters/Badge.tsx +49 -0
  75. package/Components/MasterCell/DefaultComponents/__tests__/ActionButton.test.tsx +122 -0
  76. package/Components/MasterCell/DefaultComponents/__tests__/Button.test.tsx +186 -0
  77. package/Components/MasterCell/DefaultComponents/__tests__/DataProvider.test.tsx +141 -0
  78. package/Components/MasterCell/DefaultComponents/__tests__/DynamicBadge.test.tsx +156 -0
  79. package/Components/MasterCell/DefaultComponents/__tests__/__snapshots__/ActionButton.test.tsx.snap +60 -0
  80. package/Components/MasterCell/DefaultComponents/__tests__/text.test.tsx +196 -67
  81. package/Components/MasterCell/DefaultComponents/index.ts +13 -3
  82. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/ActionButton.tsx +189 -0
  83. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/Asset.ts +33 -0
  84. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/AssetComponent.tsx +33 -0
  85. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/Button.ts +159 -0
  86. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/Spacer.ts +18 -0
  87. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/TextLabel.ts +67 -0
  88. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/TextLabelsContainer.ts +39 -0
  89. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/__tests__/PressableView.test.tsx +402 -0
  90. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/__tests__/builders.test.ts +141 -0
  91. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/__tests__/index.test.ts +354 -0
  92. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/helpers.ts +105 -0
  93. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/index.ts +129 -0
  94. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/utils/__tests__/insertButtons.test.ts +123 -0
  95. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/utils/index.ts +238 -0
  96. package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/Asset.ts +4 -18
  97. package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/Button.ts +24 -73
  98. package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/TextLabelsContainer.ts +37 -18
  99. package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/TvActionButton.tsx +27 -0
  100. package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/__tests__/index.test.ts +89 -0
  101. package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/__tests__/renderedTree.test.tsx +231 -0
  102. package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/index.ts +47 -48
  103. package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/utils/__tests__/getPluginIdentifier.test.ts +115 -29
  104. package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/utils/__tests__/insertButtonsBetweenLabels.test.ts +45 -13
  105. package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/utils/index.ts +101 -144
  106. package/Components/MasterCell/MappingFunctions/index.js +3 -2
  107. package/Components/MasterCell/README.md +4 -0
  108. package/Components/MasterCell/__tests__/__snapshots__/dataAdapter.test.js.snap +24 -0
  109. package/Components/MasterCell/__tests__/configInflater.test.js +1 -0
  110. package/Components/MasterCell/__tests__/elementMapper.test.js +46 -0
  111. package/Components/MasterCell/contexts/PressedStateContext.ts +3 -0
  112. package/Components/MasterCell/dataAdapter.ts +4 -1
  113. package/Components/MasterCell/elementMapper.tsx +54 -7
  114. package/Components/MasterCell/hooks/index.ts +2 -0
  115. package/Components/MasterCell/hooks/usePressedState.ts +4 -0
  116. package/Components/MasterCell/index.tsx +20 -4
  117. package/Components/MasterCell/utils/__tests__/cloneChildrenWithIds.test.tsx +43 -0
  118. package/Components/MasterCell/utils/__tests__/useFilterChildren.test.tsx +80 -0
  119. package/Components/MasterCell/utils/index.ts +82 -16
  120. package/Components/ModalComponent/AudioPlayer/Components/Action.tsx +33 -69
  121. package/Components/ModalComponent/AudioPlayer/Components/Button.tsx +25 -47
  122. package/Components/ModalComponent/AudioPlayer/Components/Header.tsx +122 -39
  123. package/Components/ModalComponent/AudioPlayer/Components/Input.tsx +671 -0
  124. package/Components/ModalComponent/AudioPlayer/Components/Item.tsx +257 -88
  125. package/Components/ModalComponent/AudioPlayer/Components/index.ts +6 -4
  126. package/Components/ModalComponent/BottomSheetDragArea.tsx +33 -0
  127. package/Components/ModalComponent/BottomSheetModalContent.tsx +17 -10
  128. package/Components/ModalComponent/__tests__/BottomSheetDragArea.test.tsx +74 -0
  129. package/Components/OfflineHandler/__tests__/__snapshots__/index.test.tsx.snap +4 -85
  130. package/Components/OfflineHandler/__tests__/index.test.tsx +101 -32
  131. package/Components/OfflineHandler/hooks.ts +123 -0
  132. package/Components/OfflineHandler/index.tsx +51 -73
  133. package/Components/OfflineHandler/utils/index.ts +1 -13
  134. package/Components/PlayerContainer/PlayerContainer.tsx +6 -5
  135. package/Components/PlayerContainer/__tests__/PlayerContainer.test.tsx +2 -4
  136. package/Components/PreloaderWrapper/index.tsx +1 -1
  137. package/Components/River/ComponentsMap/ComponentsMap.tsx +8 -21
  138. package/Components/River/ComponentsMap/hooks/__tests__/useLoadingState.test.ts +1 -1
  139. package/Components/River/RefreshControl.tsx +19 -105
  140. package/Components/River/River.tsx +9 -82
  141. package/Components/River/TV/River.tsx +31 -14
  142. package/Components/River/TV/index.tsx +8 -4
  143. package/Components/River/TV/utils/__tests__/toStringOrEmpty.test.ts +30 -0
  144. package/Components/River/TV/utils/index.ts +4 -0
  145. package/Components/River/TV/withFocusableGroupForContent.tsx +71 -0
  146. package/Components/River/__tests__/__snapshots__/componentsMap.test.js.snap +4 -0
  147. package/Components/River/__tests__/componentsMap.test.js +38 -0
  148. package/Components/River/hooks/__tests__/usePullToRefresh.test.ts +132 -0
  149. package/Components/River/hooks/index.ts +1 -0
  150. package/Components/River/hooks/usePullToRefresh.ts +51 -0
  151. package/Components/Screen/TV/index.web.tsx +4 -2
  152. package/Components/Screen/__tests__/Screen.test.tsx +65 -42
  153. package/Components/Screen/__tests__/__snapshots__/Screen.test.tsx.snap +68 -44
  154. package/Components/Screen/hooks.ts +2 -3
  155. package/Components/Screen/index.tsx +2 -3
  156. package/Components/Screen/orientationHandler.ts +3 -3
  157. package/Components/ScreenFeedLoader/ScreenFeedLoader.tsx +5 -3
  158. package/Components/ScreenResolver/index.tsx +9 -5
  159. package/Components/ScreenResolverFeedProvider/ScreenResolverFeedProvider.tsx +1 -1
  160. package/Components/ScreenRevealManager/ScreenRevealManager.ts +40 -8
  161. package/Components/ScreenRevealManager/__tests__/ScreenRevealManager.test.ts +86 -69
  162. package/Components/ScreenRevealManager/withScreenRevealManager.tsx +1 -1
  163. package/Components/Tabs/TabContent.tsx +7 -4
  164. package/Components/TopCutoffOverlay/__tests__/TopCutoffOverlay.test.tsx +201 -0
  165. package/Components/TopCutoffOverlay/hooks/__tests__/useMarginTop.test.ts +130 -0
  166. package/Components/TopCutoffOverlay/hooks/index.ts +1 -0
  167. package/Components/TopCutoffOverlay/hooks/useMarginTop.ts +59 -0
  168. package/Components/TopCutoffOverlay/index.tsx +55 -0
  169. package/Components/Transitioner/index.js +3 -3
  170. package/Components/VideoModal/ModalAnimation/ModalAnimationContext.tsx +5 -5
  171. package/Components/VideoModal/hooks/__tests__/useDelayedPlayerDetails.test.ts +15 -7
  172. package/Components/VideoModal/utils.ts +12 -10
  173. package/Components/Viewport/ViewportAware/__tests__/viewportAware.test.js +0 -2
  174. package/Components/Viewport/ViewportAware/index.tsx +16 -7
  175. package/Components/Viewport/ViewportEvents/__tests__/viewportEvents.test.js +1 -1
  176. package/Components/default-cell-renderer/viewTrees/mobile/index.ts +0 -3
  177. package/Contexts/CachedDimensionsContext/__tests__/index.test.ts +154 -0
  178. package/Contexts/ScreenContext/index.tsx +25 -18
  179. package/Contexts/ScreenTrackedViewPositionsContext/__tests__/index.test.tsx +1 -1
  180. package/Decorators/Analytics/index.tsx +6 -5
  181. package/Decorators/ConfigurationWrapper/__tests__/__snapshots__/withConfigurationProvider.test.tsx.snap +1 -0
  182. package/Decorators/ConfigurationWrapper/const.ts +1 -0
  183. package/Decorators/ZappPipesDataConnector/__tests__/UrlFeedResolver.test.tsx +39 -21
  184. package/Decorators/ZappPipesDataConnector/__tests__/zappPipesDataConnector.test.js +1 -1
  185. package/Decorators/ZappPipesDataConnector/index.tsx +2 -2
  186. package/Decorators/ZappPipesDataConnector/resolvers/StaticFeedResolver.tsx +1 -1
  187. package/Decorators/ZappPipesDataConnector/resolvers/UrlFeedResolver.tsx +18 -7
  188. package/Helpers/DataSourceHelper/__tests__/itemLimitForData.test.ts +80 -0
  189. package/Helpers/DataSourceHelper/index.ts +19 -0
  190. package/package.json +5 -5
  191. package/Components/MasterCell/DefaultComponents/tv/ButtonContainerView/index.android.tsx +0 -135
  192. package/Components/MasterCell/DefaultComponents/tv/ButtonContainerView/types.ts +0 -25
  193. package/Components/OfflineHandler/NotificationView/NotificationView.lg.tsx +0 -112
  194. package/Components/OfflineHandler/NotificationView/NotificationView.samsung.tsx +0 -107
  195. package/Components/OfflineHandler/NotificationView/NotificationView.tsx +0 -153
  196. package/Components/OfflineHandler/NotificationView/__tests__/index.test.tsx +0 -67
  197. package/Components/OfflineHandler/NotificationView/utils.ts +0 -34
  198. package/Components/River/TV/withTVEventHandler.tsx +0 -36
  199. package/Helpers/DataSourceHelper/index.js +0 -19
  200. /package/Components/BackgroundImage/{BackgroundImage.tv.android.tsx → BackgroundImage.android.tv.tsx} +0 -0
  201. /package/Components/BackgroundImage/{BackgroundImage.tv.ios.tsx → BackgroundImage.ios.tv.tsx} +0 -0
  202. /package/Components/BackgroundImage/{BackgroundImage.tv.web.tsx → BackgroundImage.tsx} +0 -0
@@ -10,11 +10,11 @@ import { pathOr, get, isNil } from "@applicaster/zapp-react-native-utils/utils";
10
10
  import { isNilOrEmpty } from "@applicaster/zapp-react-native-utils/reactUtils/helpers";
11
11
  import { useRoute } from "@applicaster/zapp-react-native-utils/reactHooks";
12
12
  import { useScreenStateStore } from "@applicaster/zapp-react-native-utils/reactHooks/navigation/useScreenStateStore";
13
-
14
13
  import { isNotEmptyString } from "@applicaster/zapp-react-native-utils/stringUtils";
15
14
  import { masterCellLogger } from "../logger";
16
15
  import { getCellState } from "../../Cell/utils";
17
16
  import { isCellSelected, useBehaviorUpdate } from "./behaviorProvider";
17
+ import { DataProvider } from "../DefaultComponents/DataProvider";
18
18
 
19
19
  const hasElementSpecificViewType = (viewType) => (element) => {
20
20
  if (isNil(element)) {
@@ -166,10 +166,50 @@ export function isVideoPreviewEnabled({
166
166
  return enable_video_preview && !R.isEmpty(player_screen_id);
167
167
  }
168
168
 
169
+ export const unwrapDataProviderChild = (
170
+ child: React.ReactElement
171
+ ): React.ReactElement => {
172
+ if ((child as any)?.type !== DataProvider) {
173
+ return child;
174
+ }
175
+
176
+ const [wrappedChild] = React.Children.toArray((child as any).props.children);
177
+
178
+ return (
179
+ React.isValidElement(wrappedChild) ? wrappedChild : child
180
+ ) as React.ReactElement;
181
+ };
182
+
183
+ /**
184
+ * Resolves the entry value passed by DataProvider.
185
+ * Prefer the direct `entry` prop and fall back to `dataProviderProps[_dataKey]`
186
+ * for older wrappers that still read from namespaced provider props.
187
+ */
188
+ const getEntryFromProps = (props: {
189
+ dataProviderProps?: {
190
+ _dataKey: string;
191
+ [key: string]: unknown;
192
+ };
193
+ entry?: any;
194
+ }) => {
195
+ const dataProviderProps = props.dataProviderProps;
196
+
197
+ return (
198
+ props.entry ??
199
+ (dataProviderProps?._dataKey
200
+ ? dataProviderProps[dataProviderProps._dataKey]
201
+ : undefined)
202
+ );
203
+ };
204
+
169
205
  export const useFilterChildren = <
170
206
  T extends {
171
207
  props: {
172
- item: any;
208
+ dataProviderProps?: {
209
+ _dataKey: string;
210
+ [key: string]: unknown;
211
+ };
212
+ entry?: any;
173
213
  pluginIdentifier: string;
174
214
  };
175
215
  },
@@ -179,8 +219,13 @@ export const useFilterChildren = <
179
219
  const actions = useActions("");
180
220
 
181
221
  const filteredChildren = children.filter((child) => {
182
- const item = child.props.item;
183
- const actionIdentifier = child.props.pluginIdentifier;
222
+ const wrappedChild = unwrapDataProviderChild(
223
+ child as unknown as React.ReactElement
224
+ ) as unknown as T;
225
+
226
+ const item = getEntryFromProps(wrappedChild.props);
227
+
228
+ const actionIdentifier = wrappedChild.props.pluginIdentifier;
184
229
  const action = actions.actions[actionIdentifier];
185
230
 
186
231
  // context value of specific plugin
@@ -194,7 +239,7 @@ export const useFilterChildren = <
194
239
 
195
240
  masterCellLogger.error({
196
241
  message: `Action plugin for ${actionIdentifier} could not be found, check the configuration of your action button`,
197
- data: { item, action: child.props.pluginIdentifier },
242
+ data: { item, action: wrappedChild.props.pluginIdentifier },
198
243
  });
199
244
 
200
245
  return false;
@@ -242,7 +287,7 @@ export const recursiveCloneElementsWithState = (focused: boolean, children) => {
242
287
  const next = (currentIndex, items) => items[currentIndex + 1];
243
288
  const previous = (currentIndex, items) => items[currentIndex - 1];
244
289
 
245
- export const cloneElementsWithIds = (
290
+ export const cloneChildrenWithIds = (
246
291
  ids: string[],
247
292
  children: React.ReactElement[]
248
293
  ) => {
@@ -250,12 +295,34 @@ export const cloneElementsWithIds = (
250
295
  return undefined;
251
296
  }
252
297
 
253
- return React.Children.map(children, (element, index) =>
254
- React.cloneElement(element, {
255
- nextFocusLeft: previous(index, ids),
256
- nextFocusRight: next(index, ids),
257
- })
258
- );
298
+ return React.Children.map(children, (element, index) => {
299
+ const nextFocusLeft = previous(index, ids);
300
+ const nextFocusRight = next(index, ids);
301
+
302
+ if (element?.type !== DataProvider) {
303
+ return React.cloneElement(element, {
304
+ nextFocusLeft,
305
+ nextFocusRight,
306
+ });
307
+ }
308
+
309
+ const wrappedChild = unwrapDataProviderChild(element) as React.ReactElement<
310
+ Record<string, unknown>
311
+ >;
312
+
313
+ if (!React.isValidElement(wrappedChild)) {
314
+ return element;
315
+ }
316
+
317
+ const injectedWrappedChild = React.cloneElement(wrappedChild, {
318
+ nextFocusLeft,
319
+ nextFocusRight,
320
+ });
321
+
322
+ return React.cloneElement(element, {
323
+ children: injectedWrappedChild,
324
+ });
325
+ });
259
326
  };
260
327
 
261
328
  export const getFocusedButtonId = (focusable) => {
@@ -295,10 +362,9 @@ export const useCellState = ({
295
362
  export const hasFocusableInsideBuilder = (elementsBuilder) => (item) => {
296
363
  const elements = elementsBuilder({ entry: item });
297
364
 
298
- return R.anyPass([
299
- hasElementsSpecificViewType("ButtonContainerView"),
300
- hasElementsSpecificViewType("FocusableView"),
301
- ])(elements);
365
+ return R.anyPass([hasElementsSpecificViewType("ButtonContainerView")])(
366
+ elements
367
+ );
302
368
  };
303
369
 
304
370
  export function getEntryState(state, selected) {
@@ -11,7 +11,14 @@
11
11
  */
12
12
 
13
13
  import React from "react";
14
- import { Image, Platform, StyleSheet, Text, View } from "react-native";
14
+ import {
15
+ Image,
16
+ Platform,
17
+ Pressable,
18
+ StyleSheet,
19
+ Text,
20
+ View,
21
+ } from "react-native";
15
22
 
16
23
  const styles = StyleSheet.create({
17
24
  row: {
@@ -123,10 +130,11 @@ export type ActionData = {
123
130
  showTrailingChevron?: boolean;
124
131
  };
125
132
 
126
- export type ItemProps = {
133
+ export type AudioPlayerActionProps = {
127
134
  configuration: ActionConfiguration;
128
135
  data: ActionData;
129
136
  focused?: boolean;
137
+ onPress?: () => void;
130
138
  };
131
139
 
132
140
  // ---------------------------------------------------------------------------
@@ -187,28 +195,32 @@ type ActionContainerProps = {
187
195
  configuration: BackgroundConfiguration;
188
196
  focused: boolean;
189
197
  children: React.ReactNode;
198
+ onPress?: () => void;
190
199
  };
191
200
 
192
201
  function ActionContainer({
193
202
  configuration,
194
203
  focused,
195
204
  children,
205
+ onPress,
196
206
  }: ActionContainerProps) {
197
207
  return (
198
- <View
199
- style={{
200
- backgroundColor: focused
201
- ? configuration.focusedColor
202
- : configuration.defaultColor,
208
+ <Pressable
209
+ onPress={onPress}
210
+ style={({ pressed }) => ({
211
+ backgroundColor:
212
+ pressed || focused
213
+ ? configuration.focusedColor
214
+ : configuration.defaultColor,
203
215
  borderRadius: configuration.cornerRadius,
204
216
  paddingTop: CONTAINER_SPEC.paddingTop,
205
217
  paddingRight: CONTAINER_SPEC.paddingRight,
206
218
  paddingBottom: CONTAINER_SPEC.paddingBottom,
207
219
  paddingLeft: CONTAINER_SPEC.paddingLeft,
208
- }}
220
+ })}
209
221
  >
210
222
  {children}
211
- </View>
223
+ </Pressable>
212
224
  );
213
225
  }
214
226
 
@@ -279,10 +291,15 @@ function ActionTrailingIcon({ configuration }: ActionTrailingIconProps) {
279
291
  }
280
292
 
281
293
  // ---------------------------------------------------------------------------
282
- // Item
294
+ // AudioPlayerAction
283
295
  // ---------------------------------------------------------------------------
284
296
 
285
- export function Item({ configuration, data, focused = false }: ItemProps) {
297
+ export function AudioPlayerAction({
298
+ configuration,
299
+ data,
300
+ focused = false,
301
+ onPress,
302
+ }: AudioPlayerActionProps) {
286
303
  const { background, title, trailingIcon } = configuration;
287
304
  const { title: label, leadingActionType, showTrailingChevron } = data;
288
305
 
@@ -290,7 +307,11 @@ export function Item({ configuration, data, focused = false }: ItemProps) {
290
307
  const showTrailing = shouldShowTrailingIcon(showTrailingChevron);
291
308
 
292
309
  return (
293
- <ActionContainer configuration={background} focused={focused}>
310
+ <ActionContainer
311
+ configuration={background}
312
+ focused={focused}
313
+ onPress={onPress}
314
+ >
294
315
  <View style={styles.row}>
295
316
  {showLeading ? (
296
317
  <>
@@ -309,60 +330,3 @@ export function Item({ configuration, data, focused = false }: ItemProps) {
309
330
  </ActionContainer>
310
331
  );
311
332
  }
312
-
313
- // ---------------------------------------------------------------------------
314
- // Demo
315
- // ---------------------------------------------------------------------------
316
-
317
- export default function App() {
318
- return (
319
- <View style={styles.demoScreen}>
320
- <Text style={styles.demoHeading}>Modal Action Building Block</Text>
321
-
322
- <Text style={styles.demoLabel}>
323
- Leading icon + text — Add To Queue (focused)
324
- </Text>
325
- <Item
326
- configuration={DEFAULT_ACTION_CONFIGURATION}
327
- data={{ title: "Add To Queue", leadingActionType: "addToQueue" }}
328
- focused
329
- />
330
-
331
- <Text style={styles.demoLabel}>
332
- Leading icon + text + trailing chevron — Add To Playlist
333
- </Text>
334
- <Item
335
- configuration={DEFAULT_ACTION_CONFIGURATION}
336
- data={{
337
- title: "Add To Playlist",
338
- leadingActionType: "addToPlaylist",
339
- showTrailingChevron: true,
340
- }}
341
- />
342
-
343
- <Text style={styles.demoLabel}>Text only — Go To Playlist</Text>
344
- <Item
345
- configuration={DEFAULT_ACTION_CONFIGURATION}
346
- data={{ title: "Go To Playlist" }}
347
- />
348
-
349
- <Text style={styles.demoLabel}>Leading icon + text — Favorite</Text>
350
- <Item
351
- configuration={DEFAULT_ACTION_CONFIGURATION}
352
- data={{ title: "Favorite", leadingActionType: "favorite" }}
353
- />
354
-
355
- <Text style={styles.demoLabel}>Leading icon + text — Share</Text>
356
- <Item
357
- configuration={DEFAULT_ACTION_CONFIGURATION}
358
- data={{ title: "Share", leadingActionType: "share" }}
359
- />
360
-
361
- <Text style={styles.demoLabel}>Text only — Go To Artist</Text>
362
- <Item
363
- configuration={DEFAULT_ACTION_CONFIGURATION}
364
- data={{ title: "Go To Artist" }}
365
- />
366
- </View>
367
- );
368
- }
@@ -9,7 +9,14 @@
9
9
  */
10
10
 
11
11
  import React from "react";
12
- import { Image, Platform, StyleSheet, Text, View } from "react-native";
12
+ import {
13
+ Image,
14
+ Platform,
15
+ Pressable,
16
+ StyleSheet,
17
+ Text,
18
+ View,
19
+ } from "react-native";
13
20
 
14
21
  const styles = StyleSheet.create({
15
22
  container: {
@@ -148,11 +155,12 @@ export type ButtonData = {
148
155
  disabled?: boolean;
149
156
  };
150
157
 
151
- export type ItemProps = {
158
+ export type AudioPlayerButtonProps = {
152
159
  configuration: ButtonConfiguration;
153
160
  data: ButtonData;
154
161
  disabled?: boolean;
155
162
  focused?: boolean;
163
+ onPress?: () => void;
156
164
  };
157
165
 
158
166
  // ---------------------------------------------------------------------------
@@ -170,7 +178,7 @@ const ACTION_ICON_ASSETS: Record<ButtonActionType, string> = {
170
178
  confirm:
171
179
  "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAJElEQVR42mNgGAWjYBSQCv4TwKMWDHELho/hNE/3o2AUDDcAAPv0QMAyy1CtAAAAAElFTkSuQmCC",
172
180
  cancel:
173
- "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAASElEQVR42mNgGAUjGvynkVoUTf+pqA6nxv8UqiHbEooNx2cQ1QzHZiDVDcdlCcOQsoCmQUTTSKZpMqV5RqNLUUHTwm4UDBMAALBLQ73LTvoyAAAAAElFTkSuQmCC",
181
+ "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAASElEQVR42mNgGAWjGvynkVoUTf+pqA6nxv8UqiHbEooNx2cQ1QzHZiDVDcdlCcOQsoCmQUTTSKZpMqV5RqNLUUHTwm4UDBMAALBLQ73LTvoyAAAAAElFTkSuQmCC",
174
182
  };
175
183
 
176
184
  function getTextTransformStyle(
@@ -192,6 +200,7 @@ type ButtonContainerProps = {
192
200
  disabled: boolean;
193
201
  configuration: BackgroundConfiguration;
194
202
  children: React.ReactNode;
203
+ onPress?: () => void;
195
204
  };
196
205
 
197
206
  function ButtonContainer({
@@ -199,19 +208,22 @@ function ButtonContainer({
199
208
  disabled,
200
209
  configuration,
201
210
  children,
211
+ onPress,
202
212
  }: ButtonContainerProps) {
203
- const backgroundColor = disabled
213
+ const defaultBgColor = disabled
204
214
  ? configuration.inactiveColor
205
215
  : focused
206
216
  ? configuration.focusedColor
207
217
  : configuration.defaultColor;
208
218
 
209
219
  return (
210
- <View
211
- style={[
220
+ <Pressable
221
+ onPress={disabled ? undefined : onPress}
222
+ style={({ pressed }) => [
212
223
  styles.container,
213
224
  {
214
- backgroundColor,
225
+ backgroundColor:
226
+ pressed && !disabled ? configuration.focusedColor : defaultBgColor,
215
227
  borderRadius: configuration.cornerRadius,
216
228
  paddingTop: configuration.paddingTop,
217
229
  paddingRight: configuration.paddingRight,
@@ -221,7 +233,7 @@ function ButtonContainer({
221
233
  ]}
222
234
  >
223
235
  {children}
224
- </View>
236
+ </Pressable>
225
237
  );
226
238
  }
227
239
 
@@ -295,15 +307,16 @@ function ButtonLeadingIcon({
295
307
  }
296
308
 
297
309
  // ---------------------------------------------------------------------------
298
- // Item — single building block driven by configuration + data
310
+ // AudioPlayerButton — single building block driven by configuration + data
299
311
  // ---------------------------------------------------------------------------
300
312
 
301
- export function Item({
313
+ export function AudioPlayerButton({
302
314
  configuration,
303
315
  data,
304
316
  disabled,
305
317
  focused = false,
306
- }: ItemProps) {
318
+ onPress,
319
+ }: AudioPlayerButtonProps) {
307
320
  const {
308
321
  background: backgroundConfiguration,
309
322
  title: titleConfiguration,
@@ -321,6 +334,7 @@ export function Item({
321
334
  focused={focused}
322
335
  disabled={isDisabled}
323
336
  configuration={backgroundConfiguration}
337
+ onPress={onPress}
324
338
  >
325
339
  <View style={styles.contentRow}>
326
340
  {showIcon ? (
@@ -386,39 +400,3 @@ export const VARIANT_LARGE_ICON: ButtonConfiguration = {
386
400
  },
387
401
  },
388
402
  };
389
-
390
- export default function App() {
391
- return (
392
- <View style={styles.demoScreen}>
393
- <Text style={styles.demoHeading}>Modal Button Building Block</Text>
394
-
395
- <Text style={styles.demoLabel}>Variant 1 — Text only (confirmation)</Text>
396
- <Item configuration={VARIANT_TEXT_ONLY} data={{ title: "Confirm" }} />
397
-
398
- <Text style={styles.demoLabel}>Variant 2 — Leading icon + text</Text>
399
- <Item
400
- configuration={VARIANT_WITH_ICON}
401
- data={{ title: "Add To Playlist" }}
402
- />
403
-
404
- <Text style={styles.demoLabel}>Inactive state</Text>
405
- <Item
406
- configuration={VARIANT_TEXT_ONLY}
407
- data={{ title: "Unavailable" }}
408
- disabled
409
- />
410
-
411
- <Text style={styles.demoLabel}>Custom title config — uppercase</Text>
412
- <Item
413
- configuration={VARIANT_UPPERCASE_TITLE}
414
- data={{ title: "Save Changes" }}
415
- />
416
-
417
- <Text style={styles.demoLabel}>Custom icons config — 32×32</Text>
418
- <Item
419
- configuration={VARIANT_LARGE_ICON}
420
- data={{ title: "Add To Queue" }}
421
- />
422
- </View>
423
- );
424
- }