@applicaster/zapp-react-native-ui-components 16.0.0-alpha.6593152532 → 16.0.0-alpha.6918106967

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 (152) hide show
  1. package/Components/AudioPlayer/tv/__tests__/audioPlayer.test.js +19 -0
  2. package/Components/AudioPlayer/tv/__tests__/index.test.tsx +120 -0
  3. package/Components/AudioPlayer/tv/index.tsx +5 -1
  4. package/Components/BackgroundImage/BackgroundImage.android.tv.tsx +28 -0
  5. package/Components/BackgroundImage/BackgroundImage.ios.tv.tsx +24 -0
  6. package/Components/BackgroundImage/BackgroundImage.tsx +42 -0
  7. package/Components/BackgroundImage/index.ts +1 -0
  8. package/Components/Cell/Cell.tsx +3 -6
  9. package/Components/Cell/TvOSCellComponent.tsx +0 -1
  10. package/Components/CellRendererResolver/index.ts +2 -2
  11. package/Components/ComponentResolver/__tests__/componentResolver.test.js +1 -1
  12. package/Components/FocusableGroup/FocusableTvOS.tsx +11 -7
  13. package/Components/GeneralContentScreen/GeneralContentScreenHookAdapter.tsx +54 -0
  14. package/Components/GeneralContentScreen/__tests__/GeneralContentScreenHookAdapter.test.tsx +64 -0
  15. package/Components/GeneralContentScreen/__tests__/HookContentFocusGroup.web.test.tsx +91 -0
  16. package/Components/GeneralContentScreen/hookAdapter/__tests__/networkService.test.ts +74 -0
  17. package/Components/GeneralContentScreen/hookAdapter/__tests__/runInBackground.test.ts +139 -0
  18. package/Components/GeneralContentScreen/hookAdapter/__tests__/skipExpression.test.ts +294 -0
  19. package/Components/GeneralContentScreen/hookAdapter/__tests__/validationHelper.test.ts +188 -0
  20. package/Components/GeneralContentScreen/hookAdapter/logger.ts +6 -0
  21. package/Components/GeneralContentScreen/hookAdapter/networkService.ts +53 -0
  22. package/Components/GeneralContentScreen/hookAdapter/runInBackground.ts +48 -0
  23. package/Components/GeneralContentScreen/hookAdapter/skipExpression.ts +252 -0
  24. package/Components/GeneralContentScreen/hookAdapter/validationHelper.ts +90 -0
  25. package/Components/GeneralContentScreen/hookFocus/index.tsx +13 -0
  26. package/Components/GeneralContentScreen/hookFocus/index.web.tsx +69 -0
  27. package/Components/GeneralContentScreen/index.ts +2 -0
  28. package/Components/Layout/FullWidthRow.tsx +38 -0
  29. package/Components/Layout/TV/ScreenContainer.tsx +5 -0
  30. package/Components/Layout/TV/__tests__/__snapshots__/index.test.tsx.snap +0 -1
  31. package/Components/Layout/TV/index.tsx +3 -4
  32. package/Components/Layout/TV/index.web.tsx +2 -3
  33. package/Components/MasterCell/DefaultComponents/ActionButton.tsx +17 -5
  34. package/Components/MasterCell/DefaultComponents/ActionButtonsCore/__tests__/placement.test.ts +47 -21
  35. package/Components/MasterCell/DefaultComponents/ActionButtonsCore/placement.ts +34 -6
  36. package/Components/MasterCell/DefaultComponents/Button.tsx +1 -0
  37. package/Components/MasterCell/DefaultComponents/ButtonContainerView/index.tsx +1 -1
  38. package/Components/MasterCell/DefaultComponents/Image/hoc/utils/__tests__/withDimensions.test.ts +420 -125
  39. package/Components/MasterCell/DefaultComponents/Image/hoc/utils/index.ts +114 -19
  40. package/Components/MasterCell/DefaultComponents/Image/hoc/withDimensions.tsx +19 -8
  41. package/Components/MasterCell/DefaultComponents/ImageContainer/index.tsx +5 -3
  42. package/Components/MasterCell/DefaultComponents/PressableView.tsx +29 -9
  43. package/Components/MasterCell/DefaultComponents/Text/hooks/useText.ts +4 -0
  44. package/Components/MasterCell/DefaultComponents/Toggle.tsx +36 -14
  45. package/Components/MasterCell/DefaultComponents/__tests__/Toggle.test.tsx +167 -0
  46. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/ActionButton.tsx +154 -100
  47. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/AssetComponent.tsx +15 -4
  48. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/Button.ts +56 -22
  49. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/Spacer.ts +6 -4
  50. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/TextLabelsContainer.ts +3 -1
  51. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/__tests__/PressableView.test.tsx +32 -21
  52. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/__tests__/index.test.ts +15 -4
  53. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/index.ts +23 -16
  54. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/utils/__tests__/insertButtons.test.ts +8 -3
  55. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/utils/index.ts +2 -2
  56. package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/utils/__tests__/insertButtonsBetweenLabels.test.ts +45 -13
  57. package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/utils/index.ts +2 -2
  58. package/Components/MasterCell/contexts/PressedStateContext.ts +3 -0
  59. package/Components/MasterCell/dataAdapter.ts +15 -5
  60. package/Components/MasterCell/hooks/index.ts +2 -0
  61. package/Components/MasterCell/hooks/usePressedState.ts +4 -0
  62. package/Components/MasterCell/index.tsx +30 -5
  63. package/Components/MasterCell/utils/__tests__/resolveColor.test.js +169 -132
  64. package/Components/MasterCell/utils/__tests__/resolveColorForProp.test.js +92 -0
  65. package/Components/MasterCell/utils/index.ts +85 -46
  66. package/Components/ModalComponent/ActionsBottomSheet/ActionButton.tsx +54 -0
  67. package/Components/ModalComponent/ActionsBottomSheet/boundActionButton.tsx +21 -0
  68. package/Components/ModalComponent/ActionsBottomSheet/index.ts +9 -0
  69. package/Components/ModalComponent/ActionsBottomSheet/openActionsBottomSheet.ts +58 -0
  70. package/Components/ModalComponent/AudioPlayer/Components/Action.tsx +314 -0
  71. package/Components/ModalComponent/AudioPlayer/Components/Button.tsx +407 -0
  72. package/Components/ModalComponent/AudioPlayer/Components/Header.tsx +763 -0
  73. package/Components/ModalComponent/AudioPlayer/Components/Input.tsx +653 -0
  74. package/Components/ModalComponent/AudioPlayer/Components/Item.tsx +960 -0
  75. package/Components/ModalComponent/AudioPlayer/Components/NowPlayingHeaderSection.tsx +89 -0
  76. package/Components/ModalComponent/AudioPlayer/Components/index.ts +11 -0
  77. package/Components/ModalComponent/AudioPlayer/utils/__tests__/mergeStyles.test.ts +230 -0
  78. package/Components/ModalComponent/AudioPlayer/utils/mergeStyles.ts +332 -0
  79. package/Components/ModalComponent/BottomSheetDragArea.tsx +33 -0
  80. package/Components/ModalComponent/BottomSheetModalContent.tsx +383 -42
  81. package/Components/ModalComponent/Button/index.tsx +5 -3
  82. package/Components/ModalComponent/Header/CloseButton.tsx +12 -0
  83. package/Components/ModalComponent/Header/__tests__/CloseButton.test.tsx +72 -0
  84. package/Components/ModalComponent/Header/index.tsx +20 -7
  85. package/Components/ModalComponent/Header/utils.ts +1 -1
  86. package/Components/ModalComponent/ModalBlocksStyleContext.tsx +10 -0
  87. package/Components/ModalComponent/SortableList.tsx +142 -0
  88. package/Components/ModalComponent/SortableList.web.tsx +34 -0
  89. package/Components/ModalComponent/TextInputContent.tsx +100 -0
  90. package/Components/ModalComponent/__tests__/BottomSheetDragArea.test.tsx +74 -0
  91. package/Components/ModalComponent/__tests__/BottomSheetModalContent.test.tsx +238 -0
  92. package/Components/ModalComponent/__tests__/SortableList.web.test.tsx +16 -0
  93. package/Components/ModalComponent/__tests__/TextInputContent.test.tsx +120 -0
  94. package/Components/ModalComponent/__tests__/showTextInput.test.ts +95 -0
  95. package/Components/ModalComponent/index.tsx +11 -0
  96. package/Components/ModalComponent/presets/__tests__/getCell.test.ts +66 -0
  97. package/Components/ModalComponent/presets/dynamicCollectionCell.tsx +78 -0
  98. package/Components/ModalComponent/presets/index.ts +27 -0
  99. package/Components/ModalComponent/presets/selectableCell.tsx +28 -0
  100. package/Components/ModalComponent/presets/standardCell.tsx +41 -0
  101. package/Components/ModalComponent/presets/types.ts +35 -0
  102. package/Components/ModalComponent/showTextInput.ts +43 -0
  103. package/Components/ModalComponent/utils.ts +82 -21
  104. package/Components/OfflineHandler/__tests__/__snapshots__/index.test.tsx.snap +4 -85
  105. package/Components/OfflineHandler/__tests__/index.test.tsx +78 -18
  106. package/Components/OfflineHandler/hooks.ts +111 -0
  107. package/Components/OfflineHandler/index.tsx +51 -73
  108. package/Components/OfflineHandler/utils/index.ts +1 -13
  109. package/Components/PlayerContainer/PlayerContainer.tsx +25 -17
  110. package/Components/PlayerContainer/ProgramInfo/index.tsx +3 -4
  111. package/Components/PlayerContainer/__tests__/PlayerContainer.test.tsx +337 -0
  112. package/Components/PreloaderWrapper/index.tsx +1 -1
  113. package/Components/River/ComponentsMap/ComponentsMap.tsx +81 -53
  114. package/Components/River/River.tsx +4 -0
  115. package/Components/River/__tests__/__snapshots__/componentsMap.test.js.snap +3 -15
  116. package/Components/River/__tests__/resultCallback.test.tsx +47 -0
  117. package/Components/Screen/TV/hooks/__tests__/useAfterPaint.test.ts +60 -0
  118. package/Components/Screen/TV/hooks/index.ts +2 -0
  119. package/Components/Screen/TV/hooks/useAfterPaint.ts +23 -0
  120. package/Components/Screen/TV/index.web.tsx +16 -7
  121. package/Components/Screen/index.tsx +8 -4
  122. package/Components/ScreenFeedLoader/ScreenFeedLoader.tsx +5 -3
  123. package/Components/ScreenResolverFeedProvider/ScreenResolverFeedProvider.tsx +1 -1
  124. package/Components/ScreenRevealManager/Overlay.tsx +34 -0
  125. package/Components/ScreenRevealManager/ScreenRevealManager.ts +18 -2
  126. package/Components/ScreenRevealManager/__tests__/Overlay.test.tsx +88 -0
  127. package/Components/ScreenRevealManager/__tests__/ScreenRevealManager.test.ts +36 -0
  128. package/Components/ScreenRevealManager/__tests__/withScreenRevealManager.test.tsx +56 -0
  129. package/Components/ScreenRevealManager/withScreenRevealManager.tsx +28 -22
  130. package/Components/TopCutoffOverlay/index.tsx +2 -2
  131. package/Components/Transitioner/Transitioner.tsx +28 -17
  132. package/Components/VideoLive/LiveImageManager.ts +57 -46
  133. package/Components/VideoLive/PlayerLiveImageComponent.tsx +4 -2
  134. package/Components/VideoModal/utils.ts +6 -1
  135. package/Components/ZappFrameworkComponents/BarView/BarView.tsx +12 -5
  136. package/Components/ZappFrameworkComponents/BarView/__tests__/BarView.test.tsx +2 -2
  137. package/Contexts/CachedDimensionsContext/__tests__/index.test.ts +154 -0
  138. package/Contexts/CachedDimensionsContext/index.ts +17 -2
  139. package/Helpers/ComponentCellSelectionHelper/index.js +0 -6
  140. package/Helpers/index.js +7 -40
  141. package/Hooks/useEntryActionsExpander.ts +63 -0
  142. package/package.json +6 -5
  143. package/Components/Layout/TV/LayoutBackground.tsx +0 -31
  144. package/Components/OfflineHandler/NotificationView/NotificationView.lg.tsx +0 -112
  145. package/Components/OfflineHandler/NotificationView/NotificationView.samsung.tsx +0 -107
  146. package/Components/OfflineHandler/NotificationView/NotificationView.tsx +0 -153
  147. package/Components/OfflineHandler/NotificationView/__tests__/index.test.tsx +0 -66
  148. package/Components/OfflineHandler/NotificationView/utils.ts +0 -34
  149. package/Components/Screen/utils.ts +0 -16
  150. package/Helpers/Analytics/index.js +0 -95
  151. /package/Components/MasterCell/DefaultComponents/ButtonContainerView/{index.tv.android.tsx → index.android.tv.tsx} +0 -0
  152. /package/Decorators/ZappPipesDataConnector/__tests__/{Hero.js → Hero.tsx} +0 -0
@@ -0,0 +1,407 @@
1
+ /**
2
+ * Modal Building Block — Button
3
+ *
4
+ * Single-file Expo Snack demo for the Button building block spec.
5
+ * Two variants (with / without leading icon) are driven only by configuration + data.
6
+ *
7
+ * Green (configurable): background, title, icons (size + leading icon enable/action type)
8
+ * Black (hardcoded): action type → icon asset mapping
9
+ */
10
+
11
+ import React from "react";
12
+ import {
13
+ Image,
14
+ Platform,
15
+ Pressable,
16
+ StyleSheet,
17
+ Text,
18
+ View,
19
+ } from "react-native";
20
+
21
+ const styles = StyleSheet.create({
22
+ container: {
23
+ alignSelf: "stretch",
24
+ alignItems: "center",
25
+ justifyContent: "center",
26
+ },
27
+ contentRow: {
28
+ flexDirection: "row",
29
+ alignItems: "center",
30
+ justifyContent: "center",
31
+ },
32
+ title: {
33
+ textAlign: "center",
34
+ },
35
+ });
36
+
37
+ // ---------------------------------------------------------------------------
38
+ // Configuration (green / editable fields from spec)
39
+ // ---------------------------------------------------------------------------
40
+
41
+ export type ButtonActionType =
42
+ | "addToQueue"
43
+ | "addToPlaylist"
44
+ | "goToPlaylist"
45
+ | "confirm"
46
+ | "cancel";
47
+
48
+ export type TextTransform =
49
+ | "default"
50
+ | "lowercase"
51
+ | "uppercase"
52
+ | "capitalize";
53
+
54
+ export type BackgroundConfiguration = {
55
+ defaultColor: string;
56
+ focusedColor: string;
57
+ inactiveColor: string;
58
+ cornerRadius: number;
59
+ paddingTop: number;
60
+ paddingRight: number;
61
+ paddingBottom: number;
62
+ paddingLeft: number;
63
+ horizontalGutter: number;
64
+ };
65
+
66
+ export type TitleConfiguration = {
67
+ fontColor: string;
68
+ focusedFontColor: string;
69
+ inactiveFontColor: string;
70
+ iosFontFamily: string;
71
+ androidFontFamily: string;
72
+ fontSize: number;
73
+ lineHeight: number;
74
+ iosLetterSpacing: number;
75
+ androidLetterSpacing: number;
76
+ textTransform: TextTransform;
77
+ };
78
+
79
+ export type LeadingIconConfiguration = {
80
+ /** Enable: On / Off */
81
+ enabled: boolean;
82
+ /** Decides which icon will be displayed when enabled */
83
+ actionType?: ButtonActionType;
84
+ /** Optional Studio / modal-blocks asset URI (overrides actionType mapping) */
85
+ asset?: string;
86
+ };
87
+
88
+ export type IconsConfiguration = {
89
+ width: number;
90
+ height: number;
91
+ leadingIcon: LeadingIconConfiguration;
92
+ };
93
+
94
+ export type ButtonConfiguration = {
95
+ background: BackgroundConfiguration;
96
+ title: TitleConfiguration;
97
+ icons: IconsConfiguration;
98
+ };
99
+
100
+ export const DEFAULT_BACKGROUND_CONFIGURATION: BackgroundConfiguration = {
101
+ defaultColor: "#FFFFFF",
102
+ focusedColor: "#E0E0E0",
103
+ inactiveColor: "#999999",
104
+ cornerRadius: 12,
105
+ paddingTop: 12,
106
+ paddingRight: 12,
107
+ paddingBottom: 12,
108
+ paddingLeft: 12,
109
+ horizontalGutter: 6,
110
+ };
111
+
112
+ export const DEFAULT_TITLE_CONFIGURATION: TitleConfiguration = {
113
+ fontColor: "#000000",
114
+ focusedFontColor: "#000000",
115
+ inactiveFontColor: "#000000",
116
+ iosFontFamily: "SFProText-Bold",
117
+ androidFontFamily: "Roboto-Bold",
118
+ fontSize: 15,
119
+ lineHeight: 24,
120
+ iosLetterSpacing: -0.2,
121
+ androidLetterSpacing: 0,
122
+ textTransform: "default",
123
+ };
124
+
125
+ export const DEFAULT_ICONS_CONFIGURATION: IconsConfiguration = {
126
+ width: 24,
127
+ height: 24,
128
+ leadingIcon: {
129
+ enabled: false,
130
+ },
131
+ };
132
+
133
+ // ---------------------------------------------------------------------------
134
+ // Data (runtime / localization — not styling config)
135
+ // ---------------------------------------------------------------------------
136
+
137
+ export type ButtonData = {
138
+ title: string;
139
+ disabled?: boolean;
140
+ };
141
+
142
+ export type AudioPlayerButtonProps = {
143
+ configuration: ButtonConfiguration;
144
+ data: ButtonData;
145
+ disabled?: boolean;
146
+ focused?: boolean;
147
+ onPress?: () => void;
148
+ };
149
+
150
+ // ---------------------------------------------------------------------------
151
+ // Hardcoded spec values (black fields)
152
+ // ---------------------------------------------------------------------------
153
+
154
+ // Hardcoded: action type → icon asset mapping (base64 PNG)
155
+ const ACTION_ICON_ASSETS: Record<ButtonActionType, string> = {
156
+ addToQueue:
157
+ "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAKUlEQVR42mNgGAVDCfxHw6MWjFpAvEGk4lELKLdgNJmOWkA7C0YBbQAAwiZvkR9eFgQAAAAASUVORK5CYII=",
158
+ addToPlaylist:
159
+ "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAJklEQVR42mNgGAUjFvzHgmluATF4cFswGsmjkTwayaORPAqGLwAA6Jpxj9Ms9QMAAAAASUVORK5CYII=",
160
+ goToPlaylist:
161
+ "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAALklEQVR42mNgGAWjYNiD/7Q2/D8tLflPiSX/ycQ0t+D/yLGAEkeMWjAKRgG9AQB4zlSshwSzWwAAAABJRU5ErkJggg==",
162
+ confirm:
163
+ "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAJElEQVR42mNgGAWjYBSQCv4TwKMWDHELho/hNE/3o2AUDDcAAPv0QMAyy1CtAAAAAElFTkSuQmCC",
164
+ cancel:
165
+ "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAASElEQVR42mNgGAWjGvynkVoUTf+pqA6nxv8UqiHbEooNx2cQ1QzHZiDVDcdlCcOQsoCmQUTTSKZpMqV5RqNLUUHTwm4UDBMAALBLQ73LTvoyAAAAAElFTkSuQmCC",
166
+ };
167
+
168
+ function getTextTransformStyle(
169
+ textTransform: TextTransform
170
+ ): "none" | "lowercase" | "uppercase" | "capitalize" {
171
+ return textTransform === "default" ? "none" : textTransform;
172
+ }
173
+
174
+ function shouldShowLeadingIcon(leadingIcon: LeadingIconConfiguration) {
175
+ return (
176
+ leadingIcon.enabled && (!!leadingIcon.actionType || !!leadingIcon.asset)
177
+ );
178
+ }
179
+
180
+ // ---------------------------------------------------------------------------
181
+ // Inner components (hardcoded styling lives here)
182
+ // ---------------------------------------------------------------------------
183
+
184
+ type ButtonContainerProps = {
185
+ focused: boolean;
186
+ disabled: boolean;
187
+ configuration: BackgroundConfiguration;
188
+ children: React.ReactNode;
189
+ onPress?: () => void;
190
+ };
191
+
192
+ function ButtonContainer({
193
+ focused,
194
+ disabled,
195
+ configuration,
196
+ children,
197
+ onPress,
198
+ }: ButtonContainerProps) {
199
+ const defaultBgColor = disabled
200
+ ? configuration.inactiveColor
201
+ : focused
202
+ ? configuration.focusedColor
203
+ : configuration.defaultColor;
204
+
205
+ return (
206
+ <Pressable
207
+ onPress={disabled ? undefined : onPress}
208
+ style={({ pressed }) => [
209
+ styles.container,
210
+ {
211
+ backgroundColor:
212
+ pressed && !disabled ? configuration.focusedColor : defaultBgColor,
213
+ borderRadius: configuration.cornerRadius,
214
+ paddingTop: configuration.paddingTop,
215
+ paddingRight: configuration.paddingRight,
216
+ paddingBottom: configuration.paddingBottom,
217
+ paddingLeft: configuration.paddingLeft,
218
+ },
219
+ ]}
220
+ >
221
+ {children}
222
+ </Pressable>
223
+ );
224
+ }
225
+
226
+ type ButtonTitleProps = {
227
+ title: string;
228
+ focused: boolean;
229
+ disabled: boolean;
230
+ configuration: TitleConfiguration;
231
+ };
232
+
233
+ function ButtonTitle({
234
+ title,
235
+ focused,
236
+ disabled,
237
+ configuration,
238
+ }: ButtonTitleProps) {
239
+ const color = disabled
240
+ ? configuration.inactiveFontColor
241
+ : focused
242
+ ? configuration.focusedFontColor
243
+ : configuration.fontColor;
244
+
245
+ const letterSpacing =
246
+ Platform.OS === "ios"
247
+ ? configuration.iosLetterSpacing
248
+ : configuration.androidLetterSpacing;
249
+
250
+ return (
251
+ <Text
252
+ style={[
253
+ styles.title,
254
+ {
255
+ color,
256
+ fontSize: configuration.fontSize,
257
+ lineHeight: configuration.lineHeight,
258
+ letterSpacing,
259
+ fontFamily: Platform.select({
260
+ ios: configuration.iosFontFamily,
261
+ android: configuration.androidFontFamily,
262
+ default: configuration.androidFontFamily,
263
+ }),
264
+ textTransform: getTextTransformStyle(configuration.textTransform),
265
+ },
266
+ ]}
267
+ numberOfLines={1}
268
+ >
269
+ {title}
270
+ </Text>
271
+ );
272
+ }
273
+
274
+ type ButtonLeadingIconProps = {
275
+ actionType?: ButtonActionType;
276
+ configuration: IconsConfiguration;
277
+ };
278
+
279
+ function ButtonLeadingIcon({
280
+ actionType,
281
+ configuration,
282
+ }: ButtonLeadingIconProps) {
283
+ const asset =
284
+ configuration.leadingIcon.asset ||
285
+ (actionType ? ACTION_ICON_ASSETS[actionType] : undefined);
286
+
287
+ if (!asset) {
288
+ return null;
289
+ }
290
+
291
+ return (
292
+ <Image
293
+ source={{ uri: asset }}
294
+ style={{
295
+ width: configuration.width,
296
+ height: configuration.height,
297
+ }}
298
+ resizeMode="contain"
299
+ />
300
+ );
301
+ }
302
+
303
+ // ---------------------------------------------------------------------------
304
+ // AudioPlayerButton — single building block driven by configuration + data
305
+ // ---------------------------------------------------------------------------
306
+
307
+ import { useModalBlocksStyle } from "../../ModalBlocksStyleContext";
308
+ import { mergeButtonConfiguration } from "../utils/mergeStyles";
309
+
310
+ export function AudioPlayerButton({
311
+ configuration,
312
+ data,
313
+ disabled,
314
+ focused = false,
315
+ onPress,
316
+ }: AudioPlayerButtonProps) {
317
+ const modalBlocksStyle = useModalBlocksStyle();
318
+ const buttonBlock = modalBlocksStyle?.button;
319
+ const actionBlock = modalBlocksStyle?.action;
320
+
321
+ const effectiveConfig = React.useMemo(() => {
322
+ return mergeButtonConfiguration(configuration, buttonBlock, actionBlock);
323
+ }, [configuration, buttonBlock, actionBlock]);
324
+
325
+ const {
326
+ background: effectiveBgConfig,
327
+ title: effectiveTitleConfig,
328
+ icons: iconsConfiguration,
329
+ } = effectiveConfig;
330
+
331
+ const { title } = data;
332
+ const isDisabled = disabled ?? data.disabled ?? false;
333
+
334
+ const { leadingIcon } = iconsConfiguration;
335
+ const showIcon = shouldShowLeadingIcon(leadingIcon);
336
+
337
+ return (
338
+ <ButtonContainer
339
+ focused={focused}
340
+ disabled={isDisabled}
341
+ configuration={effectiveBgConfig}
342
+ onPress={onPress}
343
+ >
344
+ <View style={styles.contentRow}>
345
+ {showIcon ? (
346
+ <>
347
+ <ButtonLeadingIcon
348
+ actionType={leadingIcon.actionType}
349
+ configuration={iconsConfiguration}
350
+ />
351
+ <View style={{ width: effectiveBgConfig.horizontalGutter }} />
352
+ </>
353
+ ) : null}
354
+ <ButtonTitle
355
+ title={title}
356
+ focused={focused}
357
+ disabled={isDisabled}
358
+ configuration={effectiveTitleConfig}
359
+ />
360
+ </View>
361
+ </ButtonContainer>
362
+ );
363
+ }
364
+
365
+ // ---------------------------------------------------------------------------
366
+ // Snack demo — two Button variants from configuration only
367
+ // ---------------------------------------------------------------------------
368
+
369
+ export const VARIANT_TEXT_ONLY: ButtonConfiguration = {
370
+ background: DEFAULT_BACKGROUND_CONFIGURATION,
371
+ title: DEFAULT_TITLE_CONFIGURATION,
372
+ icons: DEFAULT_ICONS_CONFIGURATION,
373
+ };
374
+
375
+ export const VARIANT_WITH_ICON: ButtonConfiguration = {
376
+ background: DEFAULT_BACKGROUND_CONFIGURATION,
377
+ title: DEFAULT_TITLE_CONFIGURATION,
378
+ icons: {
379
+ ...DEFAULT_ICONS_CONFIGURATION,
380
+ leadingIcon: {
381
+ enabled: true,
382
+ actionType: "addToPlaylist",
383
+ },
384
+ },
385
+ };
386
+
387
+ export const VARIANT_UPPERCASE_TITLE: ButtonConfiguration = {
388
+ background: DEFAULT_BACKGROUND_CONFIGURATION,
389
+ title: {
390
+ ...DEFAULT_TITLE_CONFIGURATION,
391
+ textTransform: "uppercase",
392
+ },
393
+ icons: DEFAULT_ICONS_CONFIGURATION,
394
+ };
395
+
396
+ export const VARIANT_LARGE_ICON: ButtonConfiguration = {
397
+ background: DEFAULT_BACKGROUND_CONFIGURATION,
398
+ title: DEFAULT_TITLE_CONFIGURATION,
399
+ icons: {
400
+ width: 32,
401
+ height: 32,
402
+ leadingIcon: {
403
+ enabled: true,
404
+ actionType: "addToQueue",
405
+ },
406
+ },
407
+ };