@applicaster/zapp-react-native-ui-components 16.0.0-rc.11 → 16.0.0-rc.110

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 (156) 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/Cell/Cell.tsx +3 -6
  5. package/Components/Cell/TvOSCellComponent.tsx +0 -1
  6. package/Components/CellRendererResolver/index.ts +2 -2
  7. package/Components/ComponentResolver/__tests__/componentResolver.test.js +1 -1
  8. package/Components/FocusableGroup/FocusableTvOS.tsx +11 -7
  9. package/Components/GeneralContentScreen/GeneralContentScreenHookAdapter.tsx +54 -0
  10. package/Components/GeneralContentScreen/__tests__/GeneralContentScreenHookAdapter.test.tsx +64 -0
  11. package/Components/GeneralContentScreen/__tests__/HookContentFocusGroup.web.test.tsx +91 -0
  12. package/Components/GeneralContentScreen/hookAdapter/__tests__/networkService.test.ts +74 -0
  13. package/Components/GeneralContentScreen/hookAdapter/__tests__/runInBackground.test.ts +139 -0
  14. package/Components/GeneralContentScreen/hookAdapter/__tests__/skipExpression.test.ts +294 -0
  15. package/Components/GeneralContentScreen/hookAdapter/__tests__/validationHelper.test.ts +188 -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/skipExpression.ts +252 -0
  20. package/Components/GeneralContentScreen/hookAdapter/validationHelper.ts +90 -0
  21. package/Components/GeneralContentScreen/hookFocus/index.tsx +13 -0
  22. package/Components/GeneralContentScreen/hookFocus/index.web.tsx +69 -0
  23. package/Components/GeneralContentScreen/index.ts +2 -0
  24. package/Components/Layout/FullWidthRow.tsx +38 -0
  25. package/Components/LinkHandler/LinkHandler.tsx +2 -7
  26. package/Components/MasterCell/DefaultComponents/ActionButton.tsx +5 -1
  27. package/Components/MasterCell/DefaultComponents/ActionButtonsCore/__tests__/placement.test.ts +47 -21
  28. package/Components/MasterCell/DefaultComponents/ActionButtonsCore/components/ActionButtonController.tsx +19 -4
  29. package/Components/MasterCell/DefaultComponents/ActionButtonsCore/components/__tests__/ActionButtonController.test.tsx +43 -1
  30. package/Components/MasterCell/DefaultComponents/ActionButtonsCore/placement.ts +34 -6
  31. package/Components/MasterCell/DefaultComponents/Button.tsx +1 -0
  32. package/Components/MasterCell/DefaultComponents/Image/hoc/utils/__tests__/withDimensions.test.ts +420 -125
  33. package/Components/MasterCell/DefaultComponents/Image/hoc/utils/index.ts +114 -19
  34. package/Components/MasterCell/DefaultComponents/Image/hoc/withDimensions.tsx +19 -8
  35. package/Components/MasterCell/DefaultComponents/ImageContainer/index.tsx +5 -3
  36. package/Components/MasterCell/DefaultComponents/LiveImage/executePreloadHooks.ts +2 -4
  37. package/Components/MasterCell/DefaultComponents/LiveImage/index.tsx +2 -3
  38. package/Components/MasterCell/DefaultComponents/PressableView.tsx +29 -9
  39. package/Components/MasterCell/DefaultComponents/Text/hooks/useText.ts +4 -0
  40. package/Components/MasterCell/DefaultComponents/Toggle.tsx +36 -14
  41. package/Components/MasterCell/DefaultComponents/__tests__/Toggle.test.tsx +167 -0
  42. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/ActionButton.tsx +154 -100
  43. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/AssetComponent.tsx +15 -4
  44. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/Button.ts +56 -22
  45. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/Spacer.ts +6 -4
  46. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/TextLabelsContainer.ts +3 -1
  47. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/__tests__/PressableView.test.tsx +32 -21
  48. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/__tests__/index.test.ts +15 -4
  49. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/index.ts +23 -16
  50. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/utils/__tests__/insertButtons.test.ts +8 -3
  51. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/utils/index.ts +2 -2
  52. package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/utils/__tests__/insertButtonsBetweenLabels.test.ts +45 -13
  53. package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/utils/index.ts +2 -2
  54. package/Components/MasterCell/SharedUI/CollapsibleTextContainer/__tests__/factory.test.ts +32 -0
  55. package/Components/MasterCell/contexts/PressedStateContext.ts +3 -0
  56. package/Components/MasterCell/dataAdapter.ts +15 -5
  57. package/Components/MasterCell/hooks/index.ts +2 -0
  58. package/Components/MasterCell/hooks/usePressedState.ts +4 -0
  59. package/Components/MasterCell/index.tsx +30 -5
  60. package/Components/MasterCell/utils/__tests__/resolveColor.test.js +169 -132
  61. package/Components/MasterCell/utils/__tests__/resolveColorForProp.test.js +92 -0
  62. package/Components/MasterCell/utils/index.ts +85 -46
  63. package/Components/ModalComponent/ActionsBottomSheet/ActionButton.tsx +56 -0
  64. package/Components/ModalComponent/ActionsBottomSheet/__tests__/openActionsBottomSheet.test.ts +38 -0
  65. package/Components/ModalComponent/ActionsBottomSheet/boundActionButton.tsx +24 -0
  66. package/Components/ModalComponent/ActionsBottomSheet/index.ts +9 -0
  67. package/Components/ModalComponent/ActionsBottomSheet/openActionsBottomSheet.ts +61 -0
  68. package/Components/ModalComponent/AudioPlayer/Components/Button.tsx +392 -0
  69. package/Components/ModalComponent/AudioPlayer/Components/Header.tsx +772 -0
  70. package/Components/ModalComponent/AudioPlayer/Components/Input.tsx +728 -0
  71. package/Components/ModalComponent/AudioPlayer/Components/Item.tsx +1028 -0
  72. package/Components/ModalComponent/AudioPlayer/Components/NowPlayingHeaderSection.tsx +205 -0
  73. package/Components/ModalComponent/AudioPlayer/Components/__tests__/Item.test.tsx +164 -0
  74. package/Components/ModalComponent/AudioPlayer/Components/__tests__/NowPlayingHeaderSection.test.tsx +36 -0
  75. package/Components/ModalComponent/AudioPlayer/Components/index.ts +9 -0
  76. package/Components/ModalComponent/AudioPlayer/utils/__tests__/mergeStyles.test.ts +393 -0
  77. package/Components/ModalComponent/AudioPlayer/utils/mergeStyles.ts +523 -0
  78. package/Components/ModalComponent/BottomSheetDragArea.tsx +33 -0
  79. package/Components/ModalComponent/BottomSheetModalContent.tsx +436 -50
  80. package/Components/ModalComponent/Button/index.tsx +5 -3
  81. package/Components/ModalComponent/Header/CloseButton.tsx +12 -0
  82. package/Components/ModalComponent/Header/__tests__/CloseButton.test.tsx +72 -0
  83. package/Components/ModalComponent/Header/index.tsx +20 -7
  84. package/Components/ModalComponent/Header/utils.ts +1 -1
  85. package/Components/ModalComponent/ModalBlocksStyleContext.tsx +10 -0
  86. package/Components/ModalComponent/SortableList.tsx +156 -0
  87. package/Components/ModalComponent/SortableList.web.tsx +34 -0
  88. package/Components/ModalComponent/TextInputContent.tsx +135 -0
  89. package/Components/ModalComponent/__tests__/BottomSheetDragArea.test.tsx +74 -0
  90. package/Components/ModalComponent/__tests__/BottomSheetModalContent.test.tsx +343 -0
  91. package/Components/ModalComponent/__tests__/SortableList.web.test.tsx +16 -0
  92. package/Components/ModalComponent/__tests__/TextInputContent.test.tsx +169 -0
  93. package/Components/ModalComponent/__tests__/showTextInput.test.ts +95 -0
  94. package/Components/ModalComponent/index.tsx +18 -9
  95. package/Components/ModalComponent/presets/__tests__/getCell.test.ts +90 -0
  96. package/Components/ModalComponent/presets/dynamicCollectionCell.tsx +78 -0
  97. package/Components/ModalComponent/presets/index.ts +27 -0
  98. package/Components/ModalComponent/presets/selectableCell.tsx +28 -0
  99. package/Components/ModalComponent/presets/standardCell.tsx +41 -0
  100. package/Components/ModalComponent/presets/types.ts +35 -0
  101. package/Components/ModalComponent/showTextInput.ts +52 -0
  102. package/Components/ModalComponent/utils.ts +82 -21
  103. package/Components/OfflineHandler/__tests__/__snapshots__/index.test.tsx.snap +4 -85
  104. package/Components/OfflineHandler/__tests__/index.test.tsx +186 -17
  105. package/Components/OfflineHandler/hooks.ts +111 -0
  106. package/Components/OfflineHandler/index.tsx +91 -75
  107. package/Components/OfflineHandler/utils/index.ts +1 -13
  108. package/Components/PlayerContainer/PlayerContainer.tsx +33 -18
  109. package/Components/PlayerContainer/ProgramInfo/index.tsx +3 -4
  110. package/Components/PlayerContainer/__tests__/PlayerContainer.test.tsx +337 -0
  111. package/Components/PreloaderWrapper/index.tsx +1 -1
  112. package/Components/River/ComponentsMap/ComponentsMap.tsx +87 -61
  113. package/Components/River/River.tsx +4 -0
  114. package/Components/River/__tests__/__snapshots__/componentsMap.test.js.snap +140 -89
  115. package/Components/River/__tests__/componentsMap.test.js +8 -3
  116. package/Components/River/__tests__/resultCallback.test.tsx +47 -0
  117. package/Components/Screen/__tests__/Screen.test.tsx +24 -0
  118. package/Components/Screen/__tests__/__snapshots__/Screen.test.tsx.snap +2 -0
  119. package/Components/Screen/index.tsx +13 -4
  120. package/Components/Screen/navigationHandler.ts +8 -8
  121. package/Components/ScreenFeedLoader/ScreenFeedLoader.tsx +5 -3
  122. package/Components/ScreenResolverFeedProvider/ScreenResolverFeedProvider.tsx +1 -1
  123. package/Components/ScreenRevealManager/ScreenRevealManager.ts +18 -2
  124. package/Components/ScreenRevealManager/__tests__/ScreenRevealManager.test.ts +36 -0
  125. package/Components/ScreenRevealManager/__tests__/withScreenRevealManager.test.tsx +56 -0
  126. package/Components/ScreenRevealManager/withScreenRevealManager.tsx +21 -4
  127. package/Components/TopCutoffOverlay/index.tsx +2 -2
  128. package/Components/Transitioner/AnimationManager.js +1 -1
  129. package/Components/Transitioner/Scene.tsx +4 -3
  130. package/Components/Transitioner/Transitioner.tsx +98 -49
  131. package/Components/Transitioner/__tests__/transitioner.test.js +372 -3
  132. package/Components/VideoLive/LiveImageManager.ts +9 -3
  133. package/Components/VideoLive/__tests__/LiveImageManager.test.ts +59 -0
  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/Contexts/ModalNavigationContext/__tests__/index.test.tsx +15 -0
  140. package/Contexts/ModalNavigationContext/index.tsx +2 -2
  141. package/Helpers/ComponentCellSelectionHelper/index.js +0 -6
  142. package/Helpers/index.js +0 -39
  143. package/Hooks/useEntryActionsExpander.ts +63 -0
  144. package/assets/empty-Info.png +0 -0
  145. package/package.json +6 -5
  146. package/Components/OfflineHandler/NotificationView/NotificationView.lg.tsx +0 -112
  147. package/Components/OfflineHandler/NotificationView/NotificationView.samsung.tsx +0 -107
  148. package/Components/OfflineHandler/NotificationView/NotificationView.tsx +0 -153
  149. package/Components/OfflineHandler/NotificationView/__tests__/index.test.tsx +0 -66
  150. package/Components/OfflineHandler/NotificationView/utils.ts +0 -34
  151. package/Components/Screen/utils.ts +0 -16
  152. package/Helpers/Analytics/index.js +0 -95
  153. /package/Components/BackgroundImage/{BackgroundImage.tv.android.tsx → BackgroundImage.android.tv.tsx} +0 -0
  154. /package/Components/BackgroundImage/{BackgroundImage.tv.ios.tsx → BackgroundImage.ios.tv.tsx} +0 -0
  155. /package/Components/MasterCell/DefaultComponents/ButtonContainerView/{index.tv.android.tsx → index.android.tv.tsx} +0 -0
  156. /package/Decorators/ZappPipesDataConnector/__tests__/{Hero.js → Hero.tsx} +0 -0
@@ -0,0 +1,1028 @@
1
+ /**
2
+ * Modal Building Block — Item (Queue / Playlist)
3
+ *
4
+ * Single-file Expo Snack demo. Three item forms driven by configuration + data.
5
+ *
6
+ * Green (configurable): background, image, nowPlayingAsset, nowPlayingLabel,
7
+ * textLabel1, textLabel2
8
+ * White (hardcoded): container padding/gutters, nowPlaying container layout,
9
+ * button sizes/padding. Play/pause icons use plugin assets when set.
10
+ *
11
+ * Variants (VARIANT_*) are preset configuration bundles — not passed as a field.
12
+ */
13
+
14
+ import React from "react";
15
+ import { QBImage as Image } from "@applicaster/zapp-react-native-ui-components/Components/Image";
16
+ import { Platform, Pressable, StyleSheet, Text, View } from "react-native";
17
+ import {
18
+ MenuItem,
19
+ SelectionBehavior,
20
+ } from "@applicaster/zapp-react-native-utils/modalState/types";
21
+ import { useModalBlocksStyle } from "../../ModalBlocksStyleContext";
22
+ import { mergeItemConfiguration } from "../utils/mergeStyles";
23
+
24
+ const styles = StyleSheet.create({
25
+ row: {
26
+ flexDirection: "row",
27
+ alignItems: "center",
28
+ },
29
+ contentColumn: {
30
+ flex: 1,
31
+ justifyContent: "center",
32
+ },
33
+ buttonsRow: {
34
+ flexDirection: "row",
35
+ alignItems: "center",
36
+ },
37
+ });
38
+
39
+ // ---------------------------------------------------------------------------
40
+ // Configuration (green fields)
41
+ // ---------------------------------------------------------------------------
42
+
43
+ export type TextTransform =
44
+ | "default"
45
+ | "lowercase"
46
+ | "uppercase"
47
+ | "capitalize";
48
+
49
+ export type BackgroundConfiguration = {
50
+ defaultColor: string;
51
+ focusedColor: string;
52
+ cornerRadius: number;
53
+ paddingTop?: number;
54
+ paddingRight?: number;
55
+ paddingBottom?: number;
56
+ paddingLeft?: number;
57
+ highlightInsetLeft?: number;
58
+ highlightInsetRight?: number;
59
+ };
60
+
61
+ export type ImageConfiguration = {
62
+ width: number;
63
+ height: number;
64
+ borderWidth: number;
65
+ borderColor: string;
66
+ cornerRadius: number;
67
+ };
68
+
69
+ export type LabelConfiguration = {
70
+ fontColor: string;
71
+ focusedFontColor?: string;
72
+ iosFontFamily: string;
73
+ androidFontFamily: string;
74
+ fontSize: number;
75
+ lineHeight: number;
76
+ iosLetterSpacing: number;
77
+ androidLetterSpacing: number;
78
+ textTransform: TextTransform;
79
+ };
80
+
81
+ export type NowPlayingAssetConfiguration = {
82
+ asset?: string;
83
+ };
84
+
85
+ export type CheckboxAssetsConfiguration = {
86
+ /** Unchecked multiSelect control (item.checkbox_asset). */
87
+ asset?: string;
88
+ /** Checked multiSelect control (item.checked_checkbox_asset). */
89
+ checkedAsset?: string;
90
+ };
91
+
92
+ export type ActionButtonAssetsConfiguration = {
93
+ /** Leading remove control on Edit Order rows. */
94
+ removeAsset?: string;
95
+ /** Trailing drag handle on Edit Order / queue rows. */
96
+ dragAsset?: string;
97
+ /** Shown on the Now Playing row while the track is paused. */
98
+ playAsset?: string;
99
+ /** Shown on the Now Playing row while the track is playing. */
100
+ pauseAsset?: string;
101
+ };
102
+
103
+ export type ItemConfiguration = {
104
+ background: BackgroundConfiguration;
105
+ image: ImageConfiguration;
106
+ nowPlayingAsset: NowPlayingAssetConfiguration;
107
+ nowPlayingLabel: LabelConfiguration;
108
+ textLabel1: LabelConfiguration;
109
+ textLabel2: LabelConfiguration;
110
+ checkboxAssets?: CheckboxAssetsConfiguration;
111
+ actionButtonAssets?: ActionButtonAssetsConfiguration;
112
+ };
113
+
114
+ export const DEFAULT_TEXT_LABEL_1_CONFIGURATION: LabelConfiguration = {
115
+ fontColor: "#FFFFFF",
116
+ focusedFontColor: "#FFFFFF",
117
+ iosFontFamily: "SFProText-Semibold",
118
+ androidFontFamily: "Roboto-Medium",
119
+ fontSize: 15,
120
+ lineHeight: 18,
121
+ iosLetterSpacing: -0.2,
122
+ androidLetterSpacing: 0,
123
+ textTransform: "default",
124
+ };
125
+
126
+ export const DEFAULT_TEXT_LABEL_2_CONFIGURATION: LabelConfiguration = {
127
+ fontColor: "#999999",
128
+ iosFontFamily: "SFProText-Medium",
129
+ androidFontFamily: "Roboto-Medium",
130
+ fontSize: 13,
131
+ lineHeight: 16,
132
+ iosLetterSpacing: -0.1,
133
+ androidLetterSpacing: 0,
134
+ textTransform: "default",
135
+ };
136
+
137
+ export const DEFAULT_NOW_PLAYING_LABEL_CONFIGURATION: LabelConfiguration = {
138
+ fontColor: "#FFFFFF",
139
+ iosFontFamily: "SFProText-Semibold",
140
+ androidFontFamily: "Roboto-Medium",
141
+ fontSize: 13,
142
+ lineHeight: 16,
143
+ iosLetterSpacing: 0,
144
+ androidLetterSpacing: 0,
145
+ textTransform: "default",
146
+ };
147
+
148
+ // ---------------------------------------------------------------------------
149
+ // Data
150
+ // ---------------------------------------------------------------------------
151
+
152
+ export type ItemButtonAction = "playPause" | "drag" | "multiSelect" | "remove";
153
+
154
+ export type ItemData = {
155
+ imageUri?: string;
156
+ textLabel1: string;
157
+ textLabel2: string;
158
+ /** When set, shows the Now Playing row (equalizer + label). */
159
+ nowPlayingLabel?: string;
160
+ /** Button 2 (left most) — hardcoded action decides icon. */
161
+ leadingButton?: ItemButtonAction;
162
+ /** Button 1 (right most) — hardcoded action decides icon. */
163
+ trailingButton?: ItemButtonAction;
164
+ isSelected?: boolean;
165
+ };
166
+
167
+ export type AudioPlayerTrackItemProps = {
168
+ configuration: ItemConfiguration;
169
+ data: ItemData;
170
+ focused?: boolean;
171
+ focusedLeadingButton?: boolean;
172
+ focusedTrailingButton?: boolean;
173
+ onPress?: () => void;
174
+ onLeadingButtonPress?: () => void;
175
+ onTrailingButtonPress?: () => void;
176
+ renderHandle?: (element: React.ReactElement) => React.ReactElement;
177
+ };
178
+
179
+ // ---------------------------------------------------------------------------
180
+ // Hardcoded (white fields)
181
+ // ---------------------------------------------------------------------------
182
+
183
+ type ContainerSpec = {
184
+ paddingTop: number;
185
+ paddingRight: number;
186
+ paddingBottom: number;
187
+ paddingLeft: number;
188
+ horizontalGutter: number;
189
+ verticalGutter: number;
190
+ };
191
+
192
+ type ButtonLayoutSpec = {
193
+ assetWidth: number;
194
+ assetHeight: number;
195
+ paddingTop: number;
196
+ paddingRight: number;
197
+ paddingBottom: number;
198
+ paddingLeft: number;
199
+ };
200
+
201
+ const CONTAINER_SPEC_LARGE_IMAGE: ContainerSpec = {
202
+ paddingTop: 8,
203
+ paddingRight: 20,
204
+ paddingBottom: 8,
205
+ paddingLeft: 20,
206
+ horizontalGutter: 12,
207
+ verticalGutter: 2,
208
+ };
209
+
210
+ const CONTAINER_SPEC_DEFAULT: ContainerSpec = {
211
+ paddingTop: 8,
212
+ paddingRight: 10,
213
+ paddingBottom: 8,
214
+ paddingLeft: 10,
215
+ horizontalGutter: 12,
216
+ verticalGutter: 2,
217
+ };
218
+
219
+ const BUTTONS_CONTAINER_HORIZONTAL_GUTTER = 4;
220
+
221
+ const NOW_PLAYING_CONTAINER_SPEC = {
222
+ horizontalGutter: 4,
223
+ marginTop: 0,
224
+ marginRight: 0,
225
+ marginBottom: 6,
226
+ marginLeft: 0,
227
+ };
228
+
229
+ const NOW_PLAYING_ASSET_SPEC = {
230
+ width: 16,
231
+ height: 16,
232
+ };
233
+
234
+ const BUTTON_LAYOUT_SPEC: Record<ItemButtonAction, ButtonLayoutSpec> = {
235
+ playPause: {
236
+ assetWidth: 44,
237
+ assetHeight: 44,
238
+ paddingTop: 0,
239
+ paddingRight: 0,
240
+ paddingBottom: 0,
241
+ paddingLeft: 0,
242
+ },
243
+ drag: {
244
+ assetWidth: 24,
245
+ assetHeight: 24,
246
+ paddingTop: 10,
247
+ paddingRight: 10,
248
+ paddingBottom: 10,
249
+ paddingLeft: 10,
250
+ },
251
+ multiSelect: {
252
+ assetWidth: 24,
253
+ assetHeight: 24,
254
+ paddingTop: 10,
255
+ paddingRight: 10,
256
+ paddingBottom: 10,
257
+ paddingLeft: 10,
258
+ },
259
+ remove: {
260
+ assetWidth: 24,
261
+ assetHeight: 24,
262
+ paddingTop: 10,
263
+ paddingRight: 10,
264
+ paddingBottom: 10,
265
+ paddingLeft: 10,
266
+ },
267
+ };
268
+
269
+ const DEFAULT_THUMB_ASSET =
270
+ "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAAQklEQVR42u3PMQ0AAAgDsEmcfzNggZekRwU0beezCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAhcLQVXaABdK6k6AAAAAElFTkSuQmCC";
271
+
272
+ const DEFAULT_EQUALIZER_ASSET =
273
+ "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAI0lEQVR42mNgGNTgPxTQzwB0DVQ3gKCBowbQwYAhkBIHBAAA9TvPMeOFaLMAAAAASUVORK5CYII=";
274
+
275
+ function getTextTransformStyle(
276
+ textTransform: TextTransform
277
+ ): "none" | "lowercase" | "uppercase" | "capitalize" {
278
+ return textTransform === "default" ? "none" : textTransform;
279
+ }
280
+
281
+ function getFontFamily(ios: string, android: string) {
282
+ return Platform.select({ ios, android, default: android });
283
+ }
284
+
285
+ /** Hardcoded: large image (72) uses wider horizontal container padding. */
286
+ function resolveContainerSpec(image: ImageConfiguration): ContainerSpec {
287
+ return image.width >= 72
288
+ ? CONTAINER_SPEC_LARGE_IMAGE
289
+ : CONTAINER_SPEC_DEFAULT;
290
+ }
291
+
292
+ export function mapMenuItemToNowPlayingData(
293
+ item: MenuItem,
294
+ isPaused?: boolean,
295
+ nowPlayingLabel = "Now Playing"
296
+ ): ItemData {
297
+ return {
298
+ imageUri: item.icon,
299
+ textLabel1: item.title,
300
+ textLabel2: item.summary ?? "",
301
+ nowPlayingLabel,
302
+ trailingButton: "playPause",
303
+ isSelected: isPaused !== undefined ? !isPaused : item.isSelected,
304
+ };
305
+ }
306
+
307
+ export function mapMenuItemToQueuedData(item: MenuItem): ItemData {
308
+ return {
309
+ imageUri: item.icon,
310
+ textLabel1: item.title,
311
+ textLabel2: item.summary ?? "",
312
+ leadingButton: "remove",
313
+ trailingButton: "drag",
314
+ isSelected: item.isSelected,
315
+ };
316
+ }
317
+
318
+ export function mapMenuItemToPlaylistData(
319
+ item: MenuItem,
320
+ behavior?: SelectionBehavior
321
+ ): ItemData {
322
+ const showSelectionWidget =
323
+ behavior?.selectMode !== "none" && item.trailingButton !== "none";
324
+
325
+ const summary =
326
+ typeof item.summary === "string" ? item.summary.trim() : item.summary;
327
+
328
+ return {
329
+ imageUri: item.icon,
330
+ textLabel1: item.title,
331
+ textLabel2: summary || "",
332
+ trailingButton: showSelectionWidget
333
+ ? item.trailingButton || ("multiSelect" as ItemButtonAction)
334
+ : undefined,
335
+ isSelected: item.isSelected,
336
+ };
337
+ }
338
+
339
+ // ---------------------------------------------------------------------------
340
+ // Inner components
341
+ // ---------------------------------------------------------------------------
342
+
343
+ type ItemContainerProps = {
344
+ image: ImageConfiguration;
345
+ background: BackgroundConfiguration;
346
+ focused: boolean;
347
+ children: React.ReactNode;
348
+ onPress?: () => void;
349
+ };
350
+
351
+ function ItemContainer({
352
+ image,
353
+ background,
354
+ focused,
355
+ children,
356
+ onPress,
357
+ }: ItemContainerProps) {
358
+ const container = resolveContainerSpec(image);
359
+ const insetLeft = background.highlightInsetLeft ?? 0;
360
+ const insetRight = background.highlightInsetRight ?? 0;
361
+
362
+ return (
363
+ <Pressable onPress={onPress}>
364
+ {({ pressed }) => (
365
+ <View
366
+ style={{
367
+ marginLeft: insetLeft,
368
+ marginRight: insetRight,
369
+ backgroundColor:
370
+ pressed || focused
371
+ ? background.focusedColor
372
+ : background.defaultColor,
373
+ borderRadius: background.cornerRadius,
374
+ paddingTop: background.paddingTop ?? container.paddingTop,
375
+ paddingRight: background.paddingRight ?? container.paddingRight,
376
+ paddingBottom: background.paddingBottom ?? container.paddingBottom,
377
+ paddingLeft: background.paddingLeft ?? container.paddingLeft,
378
+ }}
379
+ >
380
+ {children}
381
+ </View>
382
+ )}
383
+ </Pressable>
384
+ );
385
+ }
386
+
387
+ type ItemThumbnailProps = {
388
+ configuration: ImageConfiguration;
389
+ imageUri?: string;
390
+ };
391
+
392
+ function ItemThumbnail({ configuration, imageUri }: ItemThumbnailProps) {
393
+ return (
394
+ <Image
395
+ source={{ uri: imageUri ?? DEFAULT_THUMB_ASSET }}
396
+ style={{
397
+ width: configuration.width,
398
+ height: configuration.height,
399
+ borderWidth: configuration.borderWidth,
400
+ borderColor: configuration.borderColor,
401
+ borderRadius: configuration.cornerRadius,
402
+ }}
403
+ resizeMode="cover"
404
+ />
405
+ );
406
+ }
407
+
408
+ type ItemLabelProps = {
409
+ text: string;
410
+ configuration: LabelConfiguration;
411
+ focused?: boolean;
412
+ };
413
+
414
+ function ItemLabel({ text, configuration, focused = false }: ItemLabelProps) {
415
+ if (!text) {
416
+ return null;
417
+ }
418
+
419
+ const color =
420
+ focused && configuration.focusedFontColor
421
+ ? configuration.focusedFontColor
422
+ : configuration.fontColor;
423
+
424
+ return (
425
+ <Text
426
+ style={{
427
+ color,
428
+ fontSize: configuration.fontSize,
429
+ lineHeight: configuration.lineHeight,
430
+ letterSpacing:
431
+ Platform.OS === "ios"
432
+ ? configuration.iosLetterSpacing
433
+ : configuration.androidLetterSpacing,
434
+ fontFamily: getFontFamily(
435
+ configuration.iosFontFamily,
436
+ configuration.androidFontFamily
437
+ ),
438
+ textTransform: getTextTransformStyle(configuration.textTransform),
439
+ }}
440
+ numberOfLines={1}
441
+ >
442
+ {text}
443
+ </Text>
444
+ );
445
+ }
446
+
447
+ type NowPlayingRowProps = {
448
+ assetConfiguration: NowPlayingAssetConfiguration;
449
+ labelConfiguration: LabelConfiguration;
450
+ label: string;
451
+ };
452
+
453
+ function NowPlayingRow({
454
+ assetConfiguration,
455
+ labelConfiguration,
456
+ label,
457
+ }: NowPlayingRowProps) {
458
+ const asset = assetConfiguration.asset ?? DEFAULT_EQUALIZER_ASSET;
459
+
460
+ return (
461
+ <View
462
+ style={{
463
+ flexDirection: "row",
464
+ alignItems: "center",
465
+ marginTop: NOW_PLAYING_CONTAINER_SPEC.marginTop,
466
+ marginRight: NOW_PLAYING_CONTAINER_SPEC.marginRight,
467
+ marginBottom: NOW_PLAYING_CONTAINER_SPEC.marginBottom,
468
+ marginLeft: NOW_PLAYING_CONTAINER_SPEC.marginLeft,
469
+ }}
470
+ >
471
+ <Image
472
+ source={{ uri: asset }}
473
+ style={{
474
+ width: NOW_PLAYING_ASSET_SPEC.width,
475
+ height: NOW_PLAYING_ASSET_SPEC.height,
476
+ }}
477
+ resizeMode="contain"
478
+ />
479
+ <View style={{ width: NOW_PLAYING_CONTAINER_SPEC.horizontalGutter }} />
480
+ <ItemLabel text={label} configuration={labelConfiguration} />
481
+ </View>
482
+ );
483
+ }
484
+
485
+ type ItemButtonProps = {
486
+ action: ItemButtonAction;
487
+ focused?: boolean;
488
+ onPress?: () => void;
489
+ isSelected?: boolean;
490
+ checkboxAssets?: CheckboxAssetsConfiguration;
491
+ actionButtonAssets?: ActionButtonAssetsConfiguration;
492
+ };
493
+
494
+ function ItemButton({
495
+ action,
496
+ focused = false,
497
+ onPress,
498
+ isSelected = false,
499
+ checkboxAssets,
500
+ actionButtonAssets,
501
+ }: ItemButtonProps) {
502
+ const layout = BUTTON_LAYOUT_SPEC[action];
503
+
504
+ if (!layout) {
505
+ return null;
506
+ }
507
+
508
+ const renderIcon = () => {
509
+ switch (action) {
510
+ case "playPause": {
511
+ const playbackAsset = isSelected
512
+ ? actionButtonAssets?.pauseAsset
513
+ : actionButtonAssets?.playAsset;
514
+
515
+ if (playbackAsset) {
516
+ return (
517
+ <Image
518
+ source={{ uri: playbackAsset }}
519
+ style={{
520
+ width: layout.assetWidth,
521
+ height: layout.assetHeight,
522
+ }}
523
+ resizeMode="contain"
524
+ />
525
+ );
526
+ }
527
+
528
+ const iconSize = layout.assetWidth;
529
+ const iconRadius = iconSize / 2;
530
+
531
+ return (
532
+ <View
533
+ style={{
534
+ width: iconSize,
535
+ height: iconSize,
536
+ borderRadius: iconRadius,
537
+ backgroundColor: "#FFFFFF",
538
+ justifyContent: "center",
539
+ alignItems: "center",
540
+ }}
541
+ >
542
+ {isSelected ? (
543
+ <View
544
+ style={{
545
+ flexDirection: "row",
546
+ justifyContent: "space-between",
547
+ width: 10,
548
+ height: 16,
549
+ }}
550
+ >
551
+ <View
552
+ style={{
553
+ width: 3.5,
554
+ height: 16,
555
+ backgroundColor: "#1e1e1e",
556
+ borderRadius: 1,
557
+ }}
558
+ />
559
+ <View
560
+ style={{
561
+ width: 3.5,
562
+ height: 16,
563
+ backgroundColor: "#1e1e1e",
564
+ borderRadius: 1,
565
+ }}
566
+ />
567
+ </View>
568
+ ) : (
569
+ <View
570
+ style={{
571
+ width: 0,
572
+ height: 0,
573
+ backgroundColor: "transparent",
574
+ borderStyle: "solid",
575
+ borderLeftWidth: 14,
576
+ borderRightWidth: 0,
577
+ borderTopWidth: 8,
578
+ borderBottomWidth: 8,
579
+ borderLeftColor: "#1e1e1e",
580
+ borderRightColor: "transparent",
581
+ borderTopColor: "transparent",
582
+ borderBottomColor: "transparent",
583
+ marginLeft: 3,
584
+ }}
585
+ />
586
+ )}
587
+ </View>
588
+ );
589
+ }
590
+
591
+ case "drag": {
592
+ if (actionButtonAssets?.dragAsset) {
593
+ return (
594
+ <Image
595
+ source={{ uri: actionButtonAssets.dragAsset }}
596
+ style={{
597
+ width: layout.assetWidth,
598
+ height: layout.assetHeight,
599
+ }}
600
+ resizeMode="contain"
601
+ />
602
+ );
603
+ }
604
+
605
+ return (
606
+ <View
607
+ style={{
608
+ width: 20,
609
+ height: 12,
610
+ justifyContent: "space-between",
611
+ }}
612
+ >
613
+ <View
614
+ style={{
615
+ height: 2,
616
+ backgroundColor: "rgba(255, 255, 255, 0.7)",
617
+ borderRadius: 1,
618
+ }}
619
+ />
620
+ <View
621
+ style={{
622
+ height: 2,
623
+ backgroundColor: "rgba(255, 255, 255, 0.7)",
624
+ borderRadius: 1,
625
+ }}
626
+ />
627
+ <View
628
+ style={{
629
+ height: 2,
630
+ backgroundColor: "rgba(255, 255, 255, 0.7)",
631
+ borderRadius: 1,
632
+ }}
633
+ />
634
+ </View>
635
+ );
636
+ }
637
+
638
+ case "remove": {
639
+ if (actionButtonAssets?.removeAsset) {
640
+ return (
641
+ <Image
642
+ source={{ uri: actionButtonAssets.removeAsset }}
643
+ style={{
644
+ width: layout.assetWidth,
645
+ height: layout.assetHeight,
646
+ }}
647
+ resizeMode="contain"
648
+ />
649
+ );
650
+ }
651
+
652
+ return (
653
+ <View
654
+ style={{
655
+ width: 24,
656
+ height: 24,
657
+ borderRadius: 12,
658
+ borderWidth: 1.5,
659
+ borderColor: "rgba(255, 255, 255, 0.7)",
660
+ justifyContent: "center",
661
+ alignItems: "center",
662
+ }}
663
+ >
664
+ <View
665
+ style={{
666
+ width: 10,
667
+ height: 1.5,
668
+ backgroundColor: "rgba(255, 255, 255, 0.7)",
669
+ borderRadius: 1,
670
+ }}
671
+ />
672
+ </View>
673
+ );
674
+ }
675
+
676
+ case "multiSelect": {
677
+ const studioAsset = isSelected
678
+ ? checkboxAssets?.checkedAsset
679
+ : checkboxAssets?.asset;
680
+
681
+ if (studioAsset) {
682
+ return (
683
+ <Image
684
+ source={{ uri: studioAsset }}
685
+ style={{
686
+ width: layout.assetWidth,
687
+ height: layout.assetHeight,
688
+ }}
689
+ resizeMode="contain"
690
+ />
691
+ );
692
+ }
693
+
694
+ if (!isSelected) {
695
+ return (
696
+ <View
697
+ style={{
698
+ width: layout.assetWidth,
699
+ height: layout.assetHeight,
700
+ borderRadius: layout.assetWidth / 2,
701
+ borderWidth: 1.5,
702
+ borderColor: "rgba(255, 255, 255, 0.7)",
703
+ backgroundColor: "transparent",
704
+ }}
705
+ />
706
+ );
707
+ }
708
+
709
+ return (
710
+ <View
711
+ style={{
712
+ width: 24,
713
+ height: 24,
714
+ borderRadius: 12,
715
+ backgroundColor: "#FFFFFF",
716
+ justifyContent: "center",
717
+ alignItems: "center",
718
+ }}
719
+ >
720
+ <View
721
+ style={{
722
+ width: 6,
723
+ height: 10,
724
+ borderBottomWidth: 2,
725
+ borderRightWidth: 2,
726
+ borderColor: "#1e1e1e",
727
+ transform: [{ rotate: "45deg" }],
728
+ marginTop: -2,
729
+ }}
730
+ />
731
+ </View>
732
+ );
733
+ }
734
+
735
+ default:
736
+ return null;
737
+ }
738
+ };
739
+
740
+ const buttonPadding = {
741
+ paddingTop: layout.paddingTop,
742
+ paddingRight: layout.paddingRight,
743
+ paddingBottom: layout.paddingBottom,
744
+ paddingLeft: layout.paddingLeft,
745
+ };
746
+
747
+ // A nested Pressable with no handler swallows the parent row press.
748
+ if (!onPress) {
749
+ return (
750
+ <View pointerEvents="none" style={buttonPadding}>
751
+ {renderIcon()}
752
+ </View>
753
+ );
754
+ }
755
+
756
+ return (
757
+ <Pressable
758
+ onPress={(e: any) => {
759
+ e?.stopPropagation?.();
760
+ onPress();
761
+ }}
762
+ style={({ pressed }) => [
763
+ buttonPadding,
764
+ {
765
+ opacity: pressed || focused ? 0.7 : 1,
766
+ },
767
+ ]}
768
+ >
769
+ {renderIcon()}
770
+ </Pressable>
771
+ );
772
+ }
773
+
774
+ type ItemButtonsProps = {
775
+ leadingButton?: ItemButtonAction;
776
+ trailingButton?: ItemButtonAction;
777
+ focusedLeadingButton?: boolean;
778
+ focusedTrailingButton?: boolean;
779
+ onLeadingButtonPress?: () => void;
780
+ onTrailingButtonPress?: () => void;
781
+ isSelected?: boolean;
782
+ renderHandle?: (element: React.ReactElement) => React.ReactElement;
783
+ checkboxAssets?: CheckboxAssetsConfiguration;
784
+ actionButtonAssets?: ActionButtonAssetsConfiguration;
785
+ };
786
+
787
+ function ItemButtons({
788
+ leadingButton,
789
+ trailingButton,
790
+ focusedLeadingButton = false,
791
+ focusedTrailingButton = false,
792
+ onLeadingButtonPress,
793
+ onTrailingButtonPress,
794
+ isSelected = false,
795
+ renderHandle,
796
+ checkboxAssets,
797
+ actionButtonAssets,
798
+ }: ItemButtonsProps) {
799
+ if (!leadingButton && !trailingButton) {
800
+ return null;
801
+ }
802
+
803
+ return (
804
+ <View style={styles.buttonsRow}>
805
+ {leadingButton ? (
806
+ <>
807
+ <ItemButton
808
+ action={leadingButton}
809
+ focused={focusedLeadingButton}
810
+ onPress={onLeadingButtonPress}
811
+ isSelected={isSelected}
812
+ checkboxAssets={checkboxAssets}
813
+ actionButtonAssets={actionButtonAssets}
814
+ />
815
+ <View style={{ width: BUTTONS_CONTAINER_HORIZONTAL_GUTTER }} />
816
+ </>
817
+ ) : null}
818
+ {trailingButton ? (
819
+ trailingButton === "drag" ? (
820
+ renderHandle ? (
821
+ renderHandle(
822
+ <ItemButton
823
+ action={trailingButton}
824
+ focused={focusedTrailingButton}
825
+ onPress={onTrailingButtonPress}
826
+ isSelected={isSelected}
827
+ checkboxAssets={checkboxAssets}
828
+ actionButtonAssets={actionButtonAssets}
829
+ />
830
+ )
831
+ ) : (
832
+ <ItemButton
833
+ action={trailingButton}
834
+ focused={focusedTrailingButton}
835
+ onPress={onTrailingButtonPress}
836
+ isSelected={isSelected}
837
+ checkboxAssets={checkboxAssets}
838
+ actionButtonAssets={actionButtonAssets}
839
+ />
840
+ )
841
+ ) : (
842
+ <ItemButton
843
+ action={trailingButton}
844
+ focused={focusedTrailingButton}
845
+ onPress={onTrailingButtonPress}
846
+ isSelected={isSelected}
847
+ checkboxAssets={checkboxAssets}
848
+ actionButtonAssets={actionButtonAssets}
849
+ />
850
+ )
851
+ ) : null}
852
+ </View>
853
+ );
854
+ }
855
+
856
+ // ---------------------------------------------------------------------------
857
+ // AudioPlayerTrackItem
858
+ // ---------------------------------------------------------------------------
859
+
860
+ export function AudioPlayerTrackItem({
861
+ configuration,
862
+ data,
863
+ focused = false,
864
+ focusedLeadingButton = false,
865
+ focusedTrailingButton = false,
866
+ onPress,
867
+ onLeadingButtonPress,
868
+ onTrailingButtonPress,
869
+ renderHandle,
870
+ }: AudioPlayerTrackItemProps) {
871
+ const modalBlocksStyle = useModalBlocksStyle();
872
+ const showNowPlaying = !!data.nowPlayingLabel;
873
+
874
+ const itemBlock =
875
+ showNowPlaying && modalBlocksStyle?.nowPlayingItem
876
+ ? modalBlocksStyle.nowPlayingItem
877
+ : modalBlocksStyle?.item;
878
+
879
+ const effectiveConfig = React.useMemo(() => {
880
+ return mergeItemConfiguration(configuration, itemBlock);
881
+ }, [configuration, itemBlock]);
882
+
883
+ const {
884
+ background,
885
+ image,
886
+ textLabel1,
887
+ textLabel2,
888
+ nowPlayingLabel,
889
+ nowPlayingAsset,
890
+ checkboxAssets,
891
+ actionButtonAssets,
892
+ } = effectiveConfig;
893
+
894
+ const container = resolveContainerSpec(image);
895
+
896
+ const handleTrailingButtonPress =
897
+ onTrailingButtonPress ??
898
+ (data.trailingButton === "multiSelect" ? onPress : undefined);
899
+
900
+ return (
901
+ <ItemContainer
902
+ image={image}
903
+ background={background}
904
+ focused={focused}
905
+ onPress={onPress}
906
+ >
907
+ <View style={styles.row}>
908
+ <ItemThumbnail configuration={image} imageUri={data.imageUri} />
909
+ <View style={{ width: container.horizontalGutter }} />
910
+ <View style={styles.contentColumn}>
911
+ {showNowPlaying ? (
912
+ <NowPlayingRow
913
+ assetConfiguration={nowPlayingAsset}
914
+ labelConfiguration={nowPlayingLabel}
915
+ label={data.nowPlayingLabel}
916
+ />
917
+ ) : null}
918
+ {showNowPlaying && (data.textLabel1 || data.textLabel2) ? (
919
+ <View style={{ height: container.verticalGutter }} />
920
+ ) : null}
921
+ {data.textLabel1 ? (
922
+ <ItemLabel
923
+ text={data.textLabel1}
924
+ configuration={textLabel1}
925
+ focused={focused}
926
+ />
927
+ ) : null}
928
+ {data.textLabel1 && data.textLabel2 ? (
929
+ <View style={{ height: container.verticalGutter }} />
930
+ ) : null}
931
+ {data.textLabel2 ? (
932
+ <ItemLabel text={data.textLabel2} configuration={textLabel2} />
933
+ ) : null}
934
+ </View>
935
+ <ItemButtons
936
+ leadingButton={data.leadingButton}
937
+ trailingButton={data.trailingButton}
938
+ focusedLeadingButton={focusedLeadingButton}
939
+ focusedTrailingButton={focusedTrailingButton}
940
+ onLeadingButtonPress={onLeadingButtonPress}
941
+ onTrailingButtonPress={handleTrailingButtonPress}
942
+ isSelected={data.isSelected}
943
+ renderHandle={renderHandle}
944
+ checkboxAssets={checkboxAssets}
945
+ actionButtonAssets={actionButtonAssets}
946
+ />
947
+ </View>
948
+ </ItemContainer>
949
+ );
950
+ }
951
+
952
+ // ---------------------------------------------------------------------------
953
+ // Variant presets — collections of configuration keys (not a variant field)
954
+ // ---------------------------------------------------------------------------
955
+
956
+ /** Variant 1 — Now Playing */
957
+ export const VARIANT_NOW_PLAYING: ItemConfiguration = {
958
+ background: {
959
+ defaultColor: "transparent",
960
+ focusedColor: "transparent",
961
+ cornerRadius: 0,
962
+ paddingTop: 8,
963
+ paddingRight: 20,
964
+ paddingBottom: 8,
965
+ paddingLeft: 20,
966
+ },
967
+ image: {
968
+ width: 72,
969
+ height: 72,
970
+ borderWidth: 1,
971
+ borderColor: "rgba(255, 255, 255, 0.1)",
972
+ cornerRadius: 8,
973
+ },
974
+ nowPlayingAsset: {},
975
+ nowPlayingLabel: DEFAULT_NOW_PLAYING_LABEL_CONFIGURATION,
976
+ textLabel1: DEFAULT_TEXT_LABEL_1_CONFIGURATION,
977
+ textLabel2: DEFAULT_TEXT_LABEL_2_CONFIGURATION,
978
+ };
979
+
980
+ /** Default / Variant 2 — Queued Item */
981
+ export const VARIANT_QUEUED_ITEM: ItemConfiguration = {
982
+ background: {
983
+ defaultColor: "transparent",
984
+ focusedColor: "rgba(62, 62, 62, 1)",
985
+ cornerRadius: 12,
986
+ paddingTop: 8,
987
+ paddingRight: 10,
988
+ paddingBottom: 8,
989
+ paddingLeft: 10,
990
+ highlightInsetLeft: 10,
991
+ highlightInsetRight: 10,
992
+ },
993
+ image: {
994
+ width: 48,
995
+ height: 48,
996
+ borderWidth: 1,
997
+ borderColor: "rgba(255, 255, 255, 0.1)",
998
+ cornerRadius: 6,
999
+ },
1000
+ nowPlayingAsset: {},
1001
+ nowPlayingLabel: DEFAULT_NOW_PLAYING_LABEL_CONFIGURATION,
1002
+ textLabel1: DEFAULT_TEXT_LABEL_1_CONFIGURATION,
1003
+ textLabel2: DEFAULT_TEXT_LABEL_2_CONFIGURATION,
1004
+ };
1005
+
1006
+ /** Variant 3 — Playlist Item */
1007
+ export const VARIANT_PLAYLIST_ITEM: ItemConfiguration = {
1008
+ background: {
1009
+ defaultColor: "transparent",
1010
+ focusedColor: "rgba(62, 62, 62, 1)",
1011
+ cornerRadius: 12,
1012
+ paddingTop: 8,
1013
+ paddingRight: 10,
1014
+ paddingBottom: 8,
1015
+ paddingLeft: 10,
1016
+ },
1017
+ image: {
1018
+ width: 48,
1019
+ height: 48,
1020
+ borderWidth: 1,
1021
+ borderColor: "rgba(255, 255, 255, 0.1)",
1022
+ cornerRadius: 6,
1023
+ },
1024
+ nowPlayingAsset: {},
1025
+ nowPlayingLabel: DEFAULT_NOW_PLAYING_LABEL_CONFIGURATION,
1026
+ textLabel1: DEFAULT_TEXT_LABEL_1_CONFIGURATION,
1027
+ textLabel2: DEFAULT_TEXT_LABEL_2_CONFIGURATION,
1028
+ };