@applicaster/zapp-react-native-ui-components 16.0.0-alpha.9225550512 → 16.0.0-alpha.9338540010

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 (111) 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/GeneralContentScreen/GeneralContentScreenHookAdapter.tsx +15 -0
  7. package/Components/GeneralContentScreen/hookAdapter/__tests__/skipExpression.test.ts +294 -0
  8. package/Components/GeneralContentScreen/hookAdapter/__tests__/validationHelper.test.ts +64 -0
  9. package/Components/GeneralContentScreen/hookAdapter/skipExpression.ts +252 -0
  10. package/Components/GeneralContentScreen/hookAdapter/validationHelper.ts +18 -0
  11. package/Components/LinkHandler/LinkHandler.tsx +2 -7
  12. package/Components/MasterCell/DefaultComponents/ActionButton.tsx +5 -1
  13. package/Components/MasterCell/DefaultComponents/ActionButtonsCore/components/ActionButtonController.tsx +19 -4
  14. package/Components/MasterCell/DefaultComponents/ActionButtonsCore/components/__tests__/ActionButtonController.test.tsx +43 -1
  15. package/Components/MasterCell/DefaultComponents/Button.tsx +1 -0
  16. package/Components/MasterCell/DefaultComponents/Image/hoc/utils/__tests__/withDimensions.test.ts +420 -125
  17. package/Components/MasterCell/DefaultComponents/Image/hoc/utils/index.ts +114 -19
  18. package/Components/MasterCell/DefaultComponents/Image/hoc/withDimensions.tsx +19 -8
  19. package/Components/MasterCell/DefaultComponents/LiveImage/executePreloadHooks.ts +2 -4
  20. package/Components/MasterCell/DefaultComponents/LiveImage/index.tsx +14 -6
  21. package/Components/MasterCell/DefaultComponents/Toggle.tsx +36 -14
  22. package/Components/MasterCell/DefaultComponents/__tests__/Toggle.test.tsx +167 -0
  23. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/ActionButton.tsx +1 -1
  24. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/__tests__/PressableView.test.tsx +4 -2
  25. package/Components/MasterCell/SharedUI/CollapsibleTextContainer/__tests__/factory.test.ts +32 -0
  26. package/Components/MasterCell/__tests__/masterCell.test.js +60 -0
  27. package/Components/MasterCell/index.tsx +28 -4
  28. package/Components/MasterCell/utils/__tests__/withoutFocusedState.test.js +20 -0
  29. package/Components/MasterCell/utils/index.ts +18 -0
  30. package/Components/ModalComponent/ActionsBottomSheet/ActionButton.tsx +56 -0
  31. package/Components/ModalComponent/ActionsBottomSheet/__tests__/openActionsBottomSheet.test.ts +38 -0
  32. package/Components/ModalComponent/ActionsBottomSheet/boundActionButton.tsx +24 -0
  33. package/Components/ModalComponent/ActionsBottomSheet/index.ts +9 -0
  34. package/Components/ModalComponent/ActionsBottomSheet/openActionsBottomSheet.ts +61 -0
  35. package/Components/ModalComponent/AudioPlayer/Components/Button.tsx +87 -97
  36. package/Components/ModalComponent/AudioPlayer/Components/Header.tsx +87 -126
  37. package/Components/ModalComponent/AudioPlayer/Components/Input.tsx +140 -83
  38. package/Components/ModalComponent/AudioPlayer/Components/Item.tsx +274 -124
  39. package/Components/ModalComponent/AudioPlayer/Components/NowPlayingHeaderSection.tsx +205 -0
  40. package/Components/ModalComponent/AudioPlayer/Components/__tests__/Item.test.tsx +164 -0
  41. package/Components/ModalComponent/AudioPlayer/Components/__tests__/NowPlayingHeaderSection.test.tsx +36 -0
  42. package/Components/ModalComponent/AudioPlayer/Components/index.ts +3 -3
  43. package/Components/ModalComponent/AudioPlayer/utils/__tests__/mergeStyles.test.ts +433 -0
  44. package/Components/ModalComponent/AudioPlayer/utils/mergeStyles.ts +563 -0
  45. package/Components/ModalComponent/BottomSheetDragArea.tsx +33 -0
  46. package/Components/ModalComponent/BottomSheetModalContent.tsx +440 -66
  47. package/Components/ModalComponent/Button/index.tsx +5 -3
  48. package/Components/ModalComponent/Header/CloseButton.tsx +12 -0
  49. package/Components/ModalComponent/Header/__tests__/CloseButton.test.tsx +72 -0
  50. package/Components/ModalComponent/Header/index.tsx +20 -7
  51. package/Components/ModalComponent/Header/utils.ts +1 -1
  52. package/Components/ModalComponent/ModalBlocksStyleContext.tsx +10 -0
  53. package/Components/ModalComponent/SortableList.tsx +156 -0
  54. package/Components/ModalComponent/SortableList.web.tsx +34 -0
  55. package/Components/ModalComponent/TextInputContent.tsx +135 -0
  56. package/Components/ModalComponent/__tests__/BottomSheetDragArea.test.tsx +74 -0
  57. package/Components/ModalComponent/__tests__/BottomSheetModalContent.test.tsx +343 -0
  58. package/Components/ModalComponent/__tests__/SortableList.web.test.tsx +16 -0
  59. package/Components/ModalComponent/__tests__/TextInputContent.test.tsx +169 -0
  60. package/Components/ModalComponent/__tests__/showTextInput.test.ts +120 -0
  61. package/Components/ModalComponent/index.tsx +18 -9
  62. package/Components/ModalComponent/presets/__tests__/getCell.test.ts +90 -0
  63. package/Components/ModalComponent/presets/dynamicCollectionCell.tsx +78 -0
  64. package/Components/ModalComponent/presets/index.ts +27 -0
  65. package/Components/ModalComponent/presets/selectableCell.tsx +28 -0
  66. package/Components/ModalComponent/presets/standardCell.tsx +41 -0
  67. package/Components/ModalComponent/presets/types.ts +35 -0
  68. package/Components/ModalComponent/showTextInput.ts +54 -0
  69. package/Components/ModalComponent/utils.ts +82 -21
  70. package/Components/OfflineHandler/__tests__/index.test.tsx +109 -0
  71. package/Components/OfflineHandler/hooks.ts +0 -12
  72. package/Components/OfflineHandler/index.tsx +42 -4
  73. package/Components/PlayerContainer/PlayerContainer.tsx +19 -8
  74. package/Components/PlayerContainer/ProgramInfo/index.tsx +3 -4
  75. package/Components/PlayerContainer/__tests__/PlayerContainer.test.tsx +66 -13
  76. package/Components/River/ComponentsMap/ComponentsMap.tsx +89 -60
  77. package/Components/River/River.tsx +4 -0
  78. package/Components/River/__tests__/__snapshots__/componentsMap.test.js.snap +140 -75
  79. package/Components/River/__tests__/componentsMap.test.js +8 -3
  80. package/Components/River/__tests__/resultCallback.test.tsx +47 -0
  81. package/Components/Screen/__tests__/Screen.test.tsx +24 -0
  82. package/Components/Screen/__tests__/__snapshots__/Screen.test.tsx.snap +2 -0
  83. package/Components/Screen/index.tsx +5 -0
  84. package/Components/Screen/navigationHandler.ts +8 -8
  85. package/Components/ScreenRevealManager/ScreenRevealManager.ts +18 -2
  86. package/Components/ScreenRevealManager/__tests__/ScreenRevealManager.test.ts +36 -0
  87. package/Components/ScreenRevealManager/__tests__/withScreenRevealManager.test.tsx +56 -0
  88. package/Components/ScreenRevealManager/withScreenRevealManager.tsx +21 -4
  89. package/Components/Transitioner/AnimationManager.js +1 -1
  90. package/Components/Transitioner/Scene.tsx +4 -3
  91. package/Components/Transitioner/Transitioner.tsx +71 -33
  92. package/Components/Transitioner/__tests__/transitioner.test.js +372 -3
  93. package/Components/VideoLive/LiveImageManager.ts +9 -3
  94. package/Components/VideoLive/__tests__/LiveImageManager.test.ts +59 -0
  95. package/Components/VideoModal/PlayerWrapper.tsx +4 -1
  96. package/Components/VideoModal/__tests__/PlayerWrapper.test.tsx +1 -0
  97. package/Components/VideoModal/__tests__/playerWrapperStyle.test.ts +58 -0
  98. package/Components/VideoModal/__tests__/playerWrapperUtils.test.ts +16 -0
  99. package/Components/VideoModal/playerWrapperStyle.ts +21 -3
  100. package/Components/VideoModal/playerWrapperUtils.ts +7 -1
  101. package/Contexts/ModalNavigationContext/__tests__/index.test.tsx +15 -0
  102. package/Contexts/ModalNavigationContext/index.tsx +2 -2
  103. package/Decorators/ZappPipesDataConnector/__tests__/screenToolbox.test.ts +347 -0
  104. package/Decorators/ZappPipesDataConnector/__tests__/screenToolboxUnavailable.test.ts +53 -0
  105. package/Decorators/ZappPipesDataConnector/index.tsx +19 -4
  106. package/Decorators/ZappPipesDataConnector/screenToolbox.ts +384 -0
  107. package/Hooks/useEntryActionsExpander.ts +63 -0
  108. package/assets/empty-Info.png +0 -0
  109. package/package.json +6 -5
  110. package/Components/ModalComponent/AudioPlayer/Components/Action.tsx +0 -332
  111. /package/Decorators/ZappPipesDataConnector/__tests__/{Hero.js → Hero.tsx} +0 -0
@@ -6,20 +6,20 @@
6
6
  * Green (configurable): background, image, nowPlayingAsset, nowPlayingLabel,
7
7
  * textLabel1, textLabel2
8
8
  * White (hardcoded): container padding/gutters, nowPlaying container layout,
9
- * button sizes/padding/assets
9
+ * button sizes/padding. Play/pause icons use plugin assets when set.
10
10
  *
11
11
  * Variants (VARIANT_*) are preset configuration bundles — not passed as a field.
12
12
  */
13
13
 
14
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";
15
17
  import {
16
- Image,
17
- Platform,
18
- Pressable,
19
- StyleSheet,
20
- Text,
21
- View,
22
- } from "react-native";
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
23
 
24
24
  const styles = StyleSheet.create({
25
25
  row: {
@@ -34,25 +34,6 @@ const styles = StyleSheet.create({
34
34
  flexDirection: "row",
35
35
  alignItems: "center",
36
36
  },
37
- demoScreen: {
38
- flex: 1,
39
- backgroundColor: "#1C1C1E",
40
- paddingTop: 64,
41
- paddingHorizontal: 0,
42
- gap: 16,
43
- },
44
- demoHeading: {
45
- color: "#FFFFFF",
46
- fontSize: 20,
47
- fontWeight: "600",
48
- marginBottom: 8,
49
- paddingHorizontal: 16,
50
- },
51
- demoLabel: {
52
- color: "#999999",
53
- fontSize: 13,
54
- paddingHorizontal: 16,
55
- },
56
37
  });
57
38
 
58
39
  // ---------------------------------------------------------------------------
@@ -69,6 +50,12 @@ export type BackgroundConfiguration = {
69
50
  defaultColor: string;
70
51
  focusedColor: string;
71
52
  cornerRadius: number;
53
+ paddingTop?: number;
54
+ paddingRight?: number;
55
+ paddingBottom?: number;
56
+ paddingLeft?: number;
57
+ highlightInsetLeft?: number;
58
+ highlightInsetRight?: number;
72
59
  };
73
60
 
74
61
  export type ImageConfiguration = {
@@ -95,6 +82,24 @@ export type NowPlayingAssetConfiguration = {
95
82
  asset?: string;
96
83
  };
97
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
+
98
103
  export type ItemConfiguration = {
99
104
  background: BackgroundConfiguration;
100
105
  image: ImageConfiguration;
@@ -102,53 +107,10 @@ export type ItemConfiguration = {
102
107
  nowPlayingLabel: LabelConfiguration;
103
108
  textLabel1: LabelConfiguration;
104
109
  textLabel2: LabelConfiguration;
110
+ checkboxAssets?: CheckboxAssetsConfiguration;
111
+ actionButtonAssets?: ActionButtonAssetsConfiguration;
105
112
  };
106
113
 
107
- export interface Action {
108
- type: string;
109
- payload?: any;
110
- options?: any;
111
- }
112
-
113
- export interface Header {
114
- title: string;
115
- subtitle?: string;
116
- icon?: string;
117
- }
118
-
119
- export interface Content {
120
- title: string;
121
- stickyTitle?: boolean;
122
- items: MenuItem[];
123
- itemsUrl?: string;
124
- action?: Action;
125
- }
126
-
127
- export interface Menu {
128
- header?: Header;
129
- content: Content;
130
- closeButton?: boolean;
131
- }
132
-
133
- export interface PresentSubMenuAction extends Action {
134
- menu: Menu;
135
- }
136
-
137
- export interface SecondaryAction {
138
- action: Action | PresentSubMenuAction;
139
- icon?: string;
140
- }
141
-
142
- export interface MenuItem {
143
- trailingButton?: ItemButtonAction;
144
- title: string;
145
- summary?: string;
146
- icon?: string;
147
- isSelected?: boolean;
148
- action?: Action | PresentSubMenuAction;
149
- secondaryAction?: SecondaryAction;
150
- }
151
-
152
114
  export const DEFAULT_TEXT_LABEL_1_CONFIGURATION: LabelConfiguration = {
153
115
  fontColor: "#FFFFFF",
154
116
  focusedFontColor: "#FFFFFF",
@@ -211,6 +173,7 @@ export type AudioPlayerTrackItemProps = {
211
173
  onPress?: () => void;
212
174
  onLeadingButtonPress?: () => void;
213
175
  onTrailingButtonPress?: () => void;
176
+ renderHandle?: (element: React.ReactElement) => React.ReactElement;
214
177
  };
215
178
 
216
179
  // ---------------------------------------------------------------------------
@@ -246,9 +209,9 @@ const CONTAINER_SPEC_LARGE_IMAGE: ContainerSpec = {
246
209
 
247
210
  const CONTAINER_SPEC_DEFAULT: ContainerSpec = {
248
211
  paddingTop: 8,
249
- paddingRight: 20,
212
+ paddingRight: 10,
250
213
  paddingBottom: 8,
251
- paddingLeft: 20,
214
+ paddingLeft: 10,
252
215
  horizontalGutter: 12,
253
216
  verticalGutter: 2,
254
217
  };
@@ -326,14 +289,18 @@ function resolveContainerSpec(image: ImageConfiguration): ContainerSpec {
326
289
  : CONTAINER_SPEC_DEFAULT;
327
290
  }
328
291
 
329
- export function mapMenuItemToNowPlayingData(item: MenuItem): ItemData {
292
+ export function mapMenuItemToNowPlayingData(
293
+ item: MenuItem,
294
+ isPaused?: boolean,
295
+ nowPlayingLabel = "Now Playing"
296
+ ): ItemData {
330
297
  return {
331
298
  imageUri: item.icon,
332
299
  textLabel1: item.title,
333
300
  textLabel2: item.summary ?? "",
334
- nowPlayingLabel: "Now Playing",
301
+ nowPlayingLabel,
335
302
  trailingButton: "playPause",
336
- isSelected: item.isSelected,
303
+ isSelected: isPaused !== undefined ? !isPaused : item.isSelected,
337
304
  };
338
305
  }
339
306
 
@@ -348,12 +315,23 @@ export function mapMenuItemToQueuedData(item: MenuItem): ItemData {
348
315
  };
349
316
  }
350
317
 
351
- export function mapMenuItemToPlaylistData(item: MenuItem): ItemData {
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
+
352
328
  return {
353
329
  imageUri: item.icon,
354
330
  textLabel1: item.title,
355
- textLabel2: item.summary ?? "",
356
- trailingButton: item.trailingButton || ("multiSelect" as ItemButtonAction),
331
+ textLabel2: summary || "",
332
+ trailingButton: showSelectionWidget
333
+ ? item.trailingButton || ("multiSelect" as ItemButtonAction)
334
+ : undefined,
357
335
  isSelected: item.isSelected,
358
336
  };
359
337
  }
@@ -378,21 +356,30 @@ function ItemContainer({
378
356
  onPress,
379
357
  }: ItemContainerProps) {
380
358
  const container = resolveContainerSpec(image);
381
- const bg = focused ? background.focusedColor : background.defaultColor;
359
+ const insetLeft = background.highlightInsetLeft ?? 0;
360
+ const insetRight = background.highlightInsetRight ?? 0;
382
361
 
383
362
  return (
384
- <Pressable
385
- onPress={onPress}
386
- style={({ pressed }) => ({
387
- backgroundColor: pressed ? background.focusedColor : bg,
388
- borderRadius: background.cornerRadius,
389
- paddingTop: container.paddingTop,
390
- paddingRight: container.paddingRight,
391
- paddingBottom: container.paddingBottom,
392
- paddingLeft: container.paddingLeft,
393
- })}
394
- >
395
- {children}
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
+ )}
396
383
  </Pressable>
397
384
  );
398
385
  }
@@ -425,6 +412,10 @@ type ItemLabelProps = {
425
412
  };
426
413
 
427
414
  function ItemLabel({ text, configuration, focused = false }: ItemLabelProps) {
415
+ if (!text) {
416
+ return null;
417
+ }
418
+
428
419
  const color =
429
420
  focused && configuration.focusedFontColor
430
421
  ? configuration.focusedFontColor
@@ -496,6 +487,8 @@ type ItemButtonProps = {
496
487
  focused?: boolean;
497
488
  onPress?: () => void;
498
489
  isSelected?: boolean;
490
+ checkboxAssets?: CheckboxAssetsConfiguration;
491
+ actionButtonAssets?: ActionButtonAssetsConfiguration;
499
492
  };
500
493
 
501
494
  function ItemButton({
@@ -503,12 +496,35 @@ function ItemButton({
503
496
  focused = false,
504
497
  onPress,
505
498
  isSelected = false,
499
+ checkboxAssets,
500
+ actionButtonAssets,
506
501
  }: ItemButtonProps) {
507
502
  const layout = BUTTON_LAYOUT_SPEC[action];
508
503
 
504
+ if (!layout) {
505
+ return null;
506
+ }
507
+
509
508
  const renderIcon = () => {
510
509
  switch (action) {
511
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
+
512
528
  const iconSize = layout.assetWidth;
513
529
  const iconRadius = iconSize / 2;
514
530
 
@@ -573,6 +589,19 @@ function ItemButton({
573
589
  }
574
590
 
575
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
+
576
605
  return (
577
606
  <View
578
607
  style={{
@@ -607,6 +636,19 @@ function ItemButton({
607
636
  }
608
637
 
609
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
+
610
652
  return (
611
653
  <View
612
654
  style={{
@@ -632,6 +674,23 @@ function ItemButton({
632
674
  }
633
675
 
634
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
+
635
694
  if (!isSelected) {
636
695
  return (
637
696
  <View
@@ -678,15 +737,31 @@ function ItemButton({
678
737
  }
679
738
  };
680
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
+
681
756
  return (
682
757
  <Pressable
683
- onPress={onPress}
758
+ onPress={(e: any) => {
759
+ e?.stopPropagation?.();
760
+ onPress();
761
+ }}
684
762
  style={({ pressed }) => [
763
+ buttonPadding,
685
764
  {
686
- paddingTop: layout.paddingTop,
687
- paddingRight: layout.paddingRight,
688
- paddingBottom: layout.paddingBottom,
689
- paddingLeft: layout.paddingLeft,
690
765
  opacity: pressed || focused ? 0.7 : 1,
691
766
  },
692
767
  ]}
@@ -704,6 +779,9 @@ type ItemButtonsProps = {
704
779
  onLeadingButtonPress?: () => void;
705
780
  onTrailingButtonPress?: () => void;
706
781
  isSelected?: boolean;
782
+ renderHandle?: (element: React.ReactElement) => React.ReactElement;
783
+ checkboxAssets?: CheckboxAssetsConfiguration;
784
+ actionButtonAssets?: ActionButtonAssetsConfiguration;
707
785
  };
708
786
 
709
787
  function ItemButtons({
@@ -714,6 +792,9 @@ function ItemButtons({
714
792
  onLeadingButtonPress,
715
793
  onTrailingButtonPress,
716
794
  isSelected = false,
795
+ renderHandle,
796
+ checkboxAssets,
797
+ actionButtonAssets,
717
798
  }: ItemButtonsProps) {
718
799
  if (!leadingButton && !trailingButton) {
719
800
  return null;
@@ -728,17 +809,45 @@ function ItemButtons({
728
809
  focused={focusedLeadingButton}
729
810
  onPress={onLeadingButtonPress}
730
811
  isSelected={isSelected}
812
+ checkboxAssets={checkboxAssets}
813
+ actionButtonAssets={actionButtonAssets}
731
814
  />
732
815
  <View style={{ width: BUTTONS_CONTAINER_HORIZONTAL_GUTTER }} />
733
816
  </>
734
817
  ) : null}
735
818
  {trailingButton ? (
736
- <ItemButton
737
- action={trailingButton}
738
- focused={focusedTrailingButton}
739
- onPress={onTrailingButtonPress}
740
- isSelected={isSelected}
741
- />
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
+ )
742
851
  ) : null}
743
852
  </View>
744
853
  );
@@ -757,18 +866,36 @@ export function AudioPlayerTrackItem({
757
866
  onPress,
758
867
  onLeadingButtonPress,
759
868
  onTrailingButtonPress,
869
+ renderHandle,
760
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
+
761
883
  const {
762
884
  background,
763
885
  image,
764
- nowPlayingAsset,
765
- nowPlayingLabel,
766
886
  textLabel1,
767
887
  textLabel2,
768
- } = configuration;
888
+ nowPlayingLabel,
889
+ nowPlayingAsset,
890
+ checkboxAssets,
891
+ actionButtonAssets,
892
+ } = effectiveConfig;
769
893
 
770
894
  const container = resolveContainerSpec(image);
771
- const showNowPlaying = !!data.nowPlayingLabel;
895
+
896
+ const handleTrailingButtonPress =
897
+ onTrailingButtonPress ??
898
+ (data.trailingButton === "multiSelect" ? onPress : undefined);
772
899
 
773
900
  return (
774
901
  <ItemContainer
@@ -782,22 +909,28 @@ export function AudioPlayerTrackItem({
782
909
  <View style={{ width: container.horizontalGutter }} />
783
910
  <View style={styles.contentColumn}>
784
911
  {showNowPlaying ? (
785
- <>
786
- <NowPlayingRow
787
- assetConfiguration={nowPlayingAsset}
788
- labelConfiguration={nowPlayingLabel}
789
- label={data.nowPlayingLabel}
790
- />
791
- <View style={{ height: container.verticalGutter }} />
792
- </>
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} />
793
933
  ) : null}
794
- <ItemLabel
795
- text={data.textLabel1}
796
- configuration={textLabel1}
797
- focused={focused}
798
- />
799
- <View style={{ height: container.verticalGutter }} />
800
- <ItemLabel text={data.textLabel2} configuration={textLabel2} />
801
934
  </View>
802
935
  <ItemButtons
803
936
  leadingButton={data.leadingButton}
@@ -805,8 +938,11 @@ export function AudioPlayerTrackItem({
805
938
  focusedLeadingButton={focusedLeadingButton}
806
939
  focusedTrailingButton={focusedTrailingButton}
807
940
  onLeadingButtonPress={onLeadingButtonPress}
808
- onTrailingButtonPress={onTrailingButtonPress}
941
+ onTrailingButtonPress={handleTrailingButtonPress}
809
942
  isSelected={data.isSelected}
943
+ renderHandle={renderHandle}
944
+ checkboxAssets={checkboxAssets}
945
+ actionButtonAssets={actionButtonAssets}
810
946
  />
811
947
  </View>
812
948
  </ItemContainer>
@@ -823,6 +959,10 @@ export const VARIANT_NOW_PLAYING: ItemConfiguration = {
823
959
  defaultColor: "transparent",
824
960
  focusedColor: "transparent",
825
961
  cornerRadius: 0,
962
+ paddingTop: 8,
963
+ paddingRight: 20,
964
+ paddingBottom: 8,
965
+ paddingLeft: 20,
826
966
  },
827
967
  image: {
828
968
  width: 72,
@@ -843,6 +983,12 @@ export const VARIANT_QUEUED_ITEM: ItemConfiguration = {
843
983
  defaultColor: "transparent",
844
984
  focusedColor: "rgba(62, 62, 62, 1)",
845
985
  cornerRadius: 12,
986
+ paddingTop: 8,
987
+ paddingRight: 10,
988
+ paddingBottom: 8,
989
+ paddingLeft: 10,
990
+ highlightInsetLeft: 10,
991
+ highlightInsetRight: 10,
846
992
  },
847
993
  image: {
848
994
  width: 48,
@@ -863,6 +1009,10 @@ export const VARIANT_PLAYLIST_ITEM: ItemConfiguration = {
863
1009
  defaultColor: "transparent",
864
1010
  focusedColor: "rgba(62, 62, 62, 1)",
865
1011
  cornerRadius: 12,
1012
+ paddingTop: 8,
1013
+ paddingRight: 10,
1014
+ paddingBottom: 8,
1015
+ paddingLeft: 10,
866
1016
  },
867
1017
  image: {
868
1018
  width: 48,