@applicaster/zapp-react-native-ui-components 16.0.0-rc.8 → 16.0.0-rc.81

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 (132) 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 +39 -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/MasterCell/DefaultComponents/ActionButton.tsx +16 -5
  26. package/Components/MasterCell/DefaultComponents/ActionButtonsCore/__tests__/placement.test.ts +47 -21
  27. package/Components/MasterCell/DefaultComponents/ActionButtonsCore/placement.ts +34 -6
  28. package/Components/MasterCell/DefaultComponents/Image/hoc/utils/__tests__/withDimensions.test.ts +420 -125
  29. package/Components/MasterCell/DefaultComponents/Image/hoc/utils/index.ts +114 -19
  30. package/Components/MasterCell/DefaultComponents/Image/hoc/withDimensions.tsx +19 -8
  31. package/Components/MasterCell/DefaultComponents/ImageContainer/index.tsx +5 -3
  32. package/Components/MasterCell/DefaultComponents/PressableView.tsx +29 -9
  33. package/Components/MasterCell/DefaultComponents/Text/hooks/useText.ts +4 -0
  34. package/Components/MasterCell/DefaultComponents/Toggle.tsx +36 -14
  35. package/Components/MasterCell/DefaultComponents/__tests__/Toggle.test.tsx +167 -0
  36. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/ActionButton.tsx +154 -100
  37. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/AssetComponent.tsx +15 -4
  38. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/Button.ts +56 -22
  39. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/Spacer.ts +6 -4
  40. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/TextLabelsContainer.ts +3 -1
  41. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/__tests__/PressableView.test.tsx +32 -21
  42. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/__tests__/index.test.ts +15 -4
  43. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/index.ts +23 -16
  44. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/utils/__tests__/insertButtons.test.ts +8 -3
  45. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/utils/index.ts +2 -2
  46. package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/utils/__tests__/insertButtonsBetweenLabels.test.ts +45 -13
  47. package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/utils/index.ts +2 -2
  48. package/Components/MasterCell/contexts/PressedStateContext.ts +3 -0
  49. package/Components/MasterCell/dataAdapter.ts +15 -5
  50. package/Components/MasterCell/hooks/index.ts +2 -0
  51. package/Components/MasterCell/hooks/usePressedState.ts +4 -0
  52. package/Components/MasterCell/index.tsx +30 -5
  53. package/Components/MasterCell/utils/__tests__/resolveColor.test.js +169 -132
  54. package/Components/MasterCell/utils/__tests__/resolveColorForProp.test.js +92 -0
  55. package/Components/MasterCell/utils/index.ts +85 -46
  56. package/Components/ModalComponent/ActionsBottomSheet/ActionButton.tsx +54 -0
  57. package/Components/ModalComponent/ActionsBottomSheet/boundActionButton.tsx +21 -0
  58. package/Components/ModalComponent/ActionsBottomSheet/index.ts +9 -0
  59. package/Components/ModalComponent/ActionsBottomSheet/openActionsBottomSheet.ts +58 -0
  60. package/Components/ModalComponent/AudioPlayer/Components/Action.tsx +314 -0
  61. package/Components/ModalComponent/AudioPlayer/Components/Button.tsx +407 -0
  62. package/Components/ModalComponent/AudioPlayer/Components/Header.tsx +763 -0
  63. package/Components/ModalComponent/AudioPlayer/Components/Input.tsx +653 -0
  64. package/Components/ModalComponent/AudioPlayer/Components/Item.tsx +960 -0
  65. package/Components/ModalComponent/AudioPlayer/Components/NowPlayingHeaderSection.tsx +89 -0
  66. package/Components/ModalComponent/AudioPlayer/Components/index.ts +11 -0
  67. package/Components/ModalComponent/AudioPlayer/utils/__tests__/mergeStyles.test.ts +230 -0
  68. package/Components/ModalComponent/AudioPlayer/utils/mergeStyles.ts +332 -0
  69. package/Components/ModalComponent/BottomSheetDragArea.tsx +33 -0
  70. package/Components/ModalComponent/BottomSheetModalContent.tsx +383 -42
  71. package/Components/ModalComponent/Button/index.tsx +5 -3
  72. package/Components/ModalComponent/Header/index.tsx +20 -7
  73. package/Components/ModalComponent/Header/utils.ts +1 -1
  74. package/Components/ModalComponent/ModalBlocksStyleContext.tsx +10 -0
  75. package/Components/ModalComponent/SortableList.tsx +142 -0
  76. package/Components/ModalComponent/SortableList.web.tsx +34 -0
  77. package/Components/ModalComponent/TextInputContent.tsx +100 -0
  78. package/Components/ModalComponent/__tests__/BottomSheetDragArea.test.tsx +74 -0
  79. package/Components/ModalComponent/__tests__/BottomSheetModalContent.test.tsx +238 -0
  80. package/Components/ModalComponent/__tests__/SortableList.web.test.tsx +16 -0
  81. package/Components/ModalComponent/__tests__/TextInputContent.test.tsx +120 -0
  82. package/Components/ModalComponent/__tests__/showTextInput.test.ts +95 -0
  83. package/Components/ModalComponent/index.tsx +11 -0
  84. package/Components/ModalComponent/presets/__tests__/getCell.test.ts +66 -0
  85. package/Components/ModalComponent/presets/dynamicCollectionCell.tsx +78 -0
  86. package/Components/ModalComponent/presets/index.ts +27 -0
  87. package/Components/ModalComponent/presets/selectableCell.tsx +28 -0
  88. package/Components/ModalComponent/presets/standardCell.tsx +41 -0
  89. package/Components/ModalComponent/presets/types.ts +35 -0
  90. package/Components/ModalComponent/showTextInput.ts +43 -0
  91. package/Components/ModalComponent/utils.ts +82 -21
  92. package/Components/OfflineHandler/__tests__/__snapshots__/index.test.tsx.snap +4 -85
  93. package/Components/OfflineHandler/__tests__/index.test.tsx +78 -18
  94. package/Components/OfflineHandler/hooks.ts +111 -0
  95. package/Components/OfflineHandler/index.tsx +51 -73
  96. package/Components/OfflineHandler/utils/index.ts +1 -13
  97. package/Components/PlayerContainer/PlayerContainer.tsx +25 -17
  98. package/Components/PlayerContainer/ProgramInfo/index.tsx +3 -4
  99. package/Components/PlayerContainer/__tests__/PlayerContainer.test.tsx +337 -0
  100. package/Components/PreloaderWrapper/index.tsx +1 -1
  101. package/Components/River/ComponentsMap/ComponentsMap.tsx +2 -2
  102. package/Components/River/__tests__/__snapshots__/componentsMap.test.js.snap +3 -15
  103. package/Components/Screen/index.tsx +8 -4
  104. package/Components/ScreenFeedLoader/ScreenFeedLoader.tsx +5 -3
  105. package/Components/ScreenResolverFeedProvider/ScreenResolverFeedProvider.tsx +1 -1
  106. package/Components/ScreenRevealManager/ScreenRevealManager.ts +18 -2
  107. package/Components/ScreenRevealManager/__tests__/ScreenRevealManager.test.ts +36 -0
  108. package/Components/ScreenRevealManager/__tests__/withScreenRevealManager.test.tsx +56 -0
  109. package/Components/ScreenRevealManager/withScreenRevealManager.tsx +20 -3
  110. package/Components/TopCutoffOverlay/index.tsx +2 -2
  111. package/Components/Transitioner/Transitioner.tsx +28 -17
  112. package/Components/VideoLive/LiveImageManager.ts +1 -1
  113. package/Components/VideoModal/utils.ts +6 -1
  114. package/Components/ZappFrameworkComponents/BarView/BarView.tsx +12 -5
  115. package/Components/ZappFrameworkComponents/BarView/__tests__/BarView.test.tsx +2 -2
  116. package/Contexts/CachedDimensionsContext/__tests__/index.test.ts +154 -0
  117. package/Contexts/CachedDimensionsContext/index.ts +17 -2
  118. package/Helpers/ComponentCellSelectionHelper/index.js +0 -6
  119. package/Helpers/index.js +0 -39
  120. package/Hooks/useEntryActionsExpander.ts +63 -0
  121. package/package.json +6 -5
  122. package/Components/OfflineHandler/NotificationView/NotificationView.lg.tsx +0 -112
  123. package/Components/OfflineHandler/NotificationView/NotificationView.samsung.tsx +0 -107
  124. package/Components/OfflineHandler/NotificationView/NotificationView.tsx +0 -153
  125. package/Components/OfflineHandler/NotificationView/__tests__/index.test.tsx +0 -66
  126. package/Components/OfflineHandler/NotificationView/utils.ts +0 -34
  127. package/Components/Screen/utils.ts +0 -16
  128. package/Helpers/Analytics/index.js +0 -95
  129. /package/Components/BackgroundImage/{BackgroundImage.tv.android.tsx → BackgroundImage.android.tv.tsx} +0 -0
  130. /package/Components/BackgroundImage/{BackgroundImage.tv.ios.tsx → BackgroundImage.ios.tv.tsx} +0 -0
  131. /package/Components/MasterCell/DefaultComponents/ButtonContainerView/{index.tv.android.tsx → index.android.tv.tsx} +0 -0
  132. /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
+ };