@applicaster/zapp-react-native-ui-components 15.1.13-alpha.1034774223 → 15.1.13

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 (40) hide show
  1. package/Components/MasterCell/DefaultComponents/ActionButton.tsx +1 -0
  2. package/Components/MasterCell/DefaultComponents/Button.tsx +1 -0
  3. package/Components/ModalComponent/AudioPlayer/Components/Action.tsx +87 -33
  4. package/Components/ModalComponent/AudioPlayer/Components/Button.tsx +74 -57
  5. package/Components/ModalComponent/AudioPlayer/Components/Header.tsx +107 -142
  6. package/Components/ModalComponent/AudioPlayer/Components/Item.tsx +159 -410
  7. package/Components/ModalComponent/AudioPlayer/Components/index.ts +4 -8
  8. package/Components/ModalComponent/BottomSheetModalContent.tsx +61 -379
  9. package/Components/ModalComponent/Button/index.tsx +3 -5
  10. package/Components/ModalComponent/Header/CloseButton.tsx +12 -0
  11. package/Components/ModalComponent/Header/__tests__/CloseButton.test.tsx +72 -0
  12. package/Components/ModalComponent/Header/index.tsx +7 -20
  13. package/Components/ModalComponent/Header/utils.ts +1 -1
  14. package/Components/ModalComponent/index.tsx +0 -11
  15. package/Components/ModalComponent/utils.ts +21 -82
  16. package/package.json +5 -6
  17. package/Components/ModalComponent/ActionsBottomSheet/ActionButton.tsx +0 -54
  18. package/Components/ModalComponent/ActionsBottomSheet/boundActionButton.tsx +0 -21
  19. package/Components/ModalComponent/ActionsBottomSheet/index.ts +0 -9
  20. package/Components/ModalComponent/ActionsBottomSheet/openActionsBottomSheet.ts +0 -58
  21. package/Components/ModalComponent/AudioPlayer/Components/Input.tsx +0 -653
  22. package/Components/ModalComponent/AudioPlayer/Components/NowPlayingHeaderSection.tsx +0 -89
  23. package/Components/ModalComponent/AudioPlayer/utils/__tests__/mergeStyles.test.ts +0 -230
  24. package/Components/ModalComponent/AudioPlayer/utils/mergeStyles.ts +0 -332
  25. package/Components/ModalComponent/ModalBlocksStyleContext.tsx +0 -10
  26. package/Components/ModalComponent/SortableList.tsx +0 -142
  27. package/Components/ModalComponent/SortableList.web.tsx +0 -102
  28. package/Components/ModalComponent/TextInputContent.tsx +0 -100
  29. package/Components/ModalComponent/__tests__/BottomSheetModalContent.test.tsx +0 -238
  30. package/Components/ModalComponent/__tests__/TextInputContent.test.tsx +0 -120
  31. package/Components/ModalComponent/__tests__/showTextInput.test.ts +0 -95
  32. package/Components/ModalComponent/presets/__tests__/getCell.test.ts +0 -66
  33. package/Components/ModalComponent/presets/dynamicCollectionCell.tsx +0 -78
  34. package/Components/ModalComponent/presets/index.ts +0 -27
  35. package/Components/ModalComponent/presets/selectableCell.tsx +0 -28
  36. package/Components/ModalComponent/presets/standardCell.tsx +0 -41
  37. package/Components/ModalComponent/presets/types.ts +0 -35
  38. package/Components/ModalComponent/showTextInput.ts +0 -43
  39. package/Hooks/useEntryActionsExpander.ts +0 -63
  40. /package/Decorators/ZappPipesDataConnector/__tests__/{Hero.tsx → Hero.js} +0 -0
@@ -12,20 +12,7 @@
12
12
  */
13
13
 
14
14
  import React from "react";
15
- import {
16
- Image,
17
- Platform,
18
- Pressable,
19
- StyleSheet,
20
- Text,
21
- View,
22
- } from "react-native";
23
- import {
24
- MenuItem,
25
- SelectionBehavior,
26
- } from "@applicaster/zapp-react-native-utils/modalState/types";
27
- import { useModalBlocksStyle } from "../../ModalBlocksStyleContext";
28
- import { mergeItemConfiguration } from "../utils/mergeStyles";
15
+ import { Image, Platform, StyleSheet, Text, View } from "react-native";
29
16
 
30
17
  const styles = StyleSheet.create({
31
18
  row: {
@@ -40,6 +27,25 @@ const styles = StyleSheet.create({
40
27
  flexDirection: "row",
41
28
  alignItems: "center",
42
29
  },
30
+ demoScreen: {
31
+ flex: 1,
32
+ backgroundColor: "#1C1C1E",
33
+ paddingTop: 64,
34
+ paddingHorizontal: 0,
35
+ gap: 16,
36
+ },
37
+ demoHeading: {
38
+ color: "#FFFFFF",
39
+ fontSize: 20,
40
+ fontWeight: "600",
41
+ marginBottom: 8,
42
+ paddingHorizontal: 16,
43
+ },
44
+ demoLabel: {
45
+ color: "#999999",
46
+ fontSize: 13,
47
+ paddingHorizontal: 16,
48
+ },
43
49
  });
44
50
 
45
51
  // ---------------------------------------------------------------------------
@@ -56,10 +62,6 @@ export type BackgroundConfiguration = {
56
62
  defaultColor: string;
57
63
  focusedColor: string;
58
64
  cornerRadius: number;
59
- paddingTop?: number;
60
- paddingRight?: number;
61
- paddingBottom?: number;
62
- paddingLeft?: number;
63
65
  };
64
66
 
65
67
  export type ImageConfiguration = {
@@ -86,20 +88,6 @@ export type NowPlayingAssetConfiguration = {
86
88
  asset?: string;
87
89
  };
88
90
 
89
- export type CheckboxAssetsConfiguration = {
90
- /** Unchecked multiSelect control (item.checkbox_asset). */
91
- asset?: string;
92
- /** Checked multiSelect control (item.checked_checkbox_asset). */
93
- checkedAsset?: string;
94
- };
95
-
96
- export type ActionButtonAssetsConfiguration = {
97
- /** Leading remove control on Edit Order rows. */
98
- removeAsset?: string;
99
- /** Trailing drag handle on Edit Order / queue rows. */
100
- dragAsset?: string;
101
- };
102
-
103
91
  export type ItemConfiguration = {
104
92
  background: BackgroundConfiguration;
105
93
  image: ImageConfiguration;
@@ -107,10 +95,52 @@ export type ItemConfiguration = {
107
95
  nowPlayingLabel: LabelConfiguration;
108
96
  textLabel1: LabelConfiguration;
109
97
  textLabel2: LabelConfiguration;
110
- checkboxAssets?: CheckboxAssetsConfiguration;
111
- actionButtonAssets?: ActionButtonAssetsConfiguration;
112
98
  };
113
99
 
100
+ export interface Action {
101
+ type: string;
102
+ payload?: any;
103
+ options?: any;
104
+ }
105
+
106
+ export interface Header {
107
+ title: string;
108
+ subtitle?: string;
109
+ icon?: string;
110
+ }
111
+
112
+ export interface Content {
113
+ title: string;
114
+ stickyTitle?: boolean;
115
+ items: MenuItem[];
116
+ itemsUrl?: string;
117
+ action?: Action;
118
+ }
119
+
120
+ export interface Menu {
121
+ header?: Header;
122
+ content: Content;
123
+ closeButton?: boolean;
124
+ }
125
+
126
+ export interface PresentSubMenuAction extends Action {
127
+ menu: Menu;
128
+ }
129
+
130
+ export interface SecondaryAction {
131
+ action: Action | PresentSubMenuAction;
132
+ icon?: string;
133
+ }
134
+
135
+ export interface MenuItem {
136
+ title: string;
137
+ summary?: string;
138
+ icon?: string;
139
+ isSelected?: boolean;
140
+ action?: Action | PresentSubMenuAction;
141
+ secondaryAction?: SecondaryAction;
142
+ }
143
+
114
144
  export const DEFAULT_TEXT_LABEL_1_CONFIGURATION: LabelConfiguration = {
115
145
  fontColor: "#FFFFFF",
116
146
  focusedFontColor: "#FFFFFF",
@@ -161,19 +191,14 @@ export type ItemData = {
161
191
  leadingButton?: ItemButtonAction;
162
192
  /** Button 1 (right most) — hardcoded action decides icon. */
163
193
  trailingButton?: ItemButtonAction;
164
- isSelected?: boolean;
165
194
  };
166
195
 
167
- export type AudioPlayerTrackItemProps = {
196
+ export type ItemProps = {
168
197
  configuration: ItemConfiguration;
169
198
  data: ItemData;
170
199
  focused?: boolean;
171
200
  focusedLeadingButton?: boolean;
172
201
  focusedTrailingButton?: boolean;
173
- onPress?: () => void;
174
- onLeadingButtonPress?: () => void;
175
- onTrailingButtonPress?: () => void;
176
- renderHandle?: (element: React.ReactElement) => React.ReactElement;
177
202
  };
178
203
 
179
204
  // ---------------------------------------------------------------------------
@@ -209,9 +234,9 @@ const CONTAINER_SPEC_LARGE_IMAGE: ContainerSpec = {
209
234
 
210
235
  const CONTAINER_SPEC_DEFAULT: ContainerSpec = {
211
236
  paddingTop: 8,
212
- paddingRight: 20,
237
+ paddingRight: 10,
213
238
  paddingBottom: 8,
214
- paddingLeft: 20,
239
+ paddingLeft: 10,
215
240
  horizontalGutter: 12,
216
241
  verticalGutter: 2,
217
242
  };
@@ -272,6 +297,16 @@ const DEFAULT_THUMB_ASSET =
272
297
  const DEFAULT_EQUALIZER_ASSET =
273
298
  "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAI0lEQVR42mNgGNTgPxTQzwB0DVQ3gKCBowbQwYAhkBIHBAAA9TvPMeOFaLMAAAAASUVORK5CYII=";
274
299
 
300
+ const BUTTON_ASSETS: Record<ItemButtonAction, string> = {
301
+ playPause:
302
+ "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACwAAAAsCAYAAAAehFoBAAAAdklEQVR42u3ZwRUAERAEUfkn3TaF5TFTrSuCf3CgjZGg6ast7G8YaAlcB8JAj8F1MRR2G63CUNglNAqsRvmB1TAfsBoXcMABV4MFKEci4IADNrkAed2H80R66SHqvUvglh/ktoZcL5H7MHKBx/5xYH+RsP90t5t2UpF6+22a+AAAAABJRU5ErkJggg==",
303
+ drag: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAIklEQVR42mNgGAWjYGiC/2SCwWPBaByMxsFoHIyCUTDYAAAqhk7AVXdZJwAAAABJRU5ErkJggg==",
304
+ multiSelect:
305
+ "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAWklEQVR42t2VUQ4AIAhCvf+lrQsULJJZbH7GM1cS0Uk5dd0Qqcz4GJSCSs0pSCkAHNoWBfkTgIxpgGK+ujyEKABqRGyn9FO1A+yfrf+qsGxTSx5YEs2WyU9oAKBJKg8Kfq4dAAAAAElFTkSuQmCC",
306
+ remove:
307
+ "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAUklEQVR42mNgGPbgPx5AVYOJlSPJcGqrJU8DKXooCVui9FIacXj1UyNl4DWDLhYgc8nA+INpeFgwtCOZ5vmALjmZ5mURXUpTutQHdKnRRgEMAACwjWWprU1B+AAAAABJRU5ErkJggg==",
308
+ };
309
+
275
310
  function getTextTransformStyle(
276
311
  textTransform: TextTransform
277
312
  ): "none" | "lowercase" | "uppercase" | "capitalize" {
@@ -289,49 +324,32 @@ function resolveContainerSpec(image: ImageConfiguration): ContainerSpec {
289
324
  : CONTAINER_SPEC_DEFAULT;
290
325
  }
291
326
 
292
- export function mapMenuItemToNowPlayingData(
293
- item: MenuItem,
294
- isPaused?: boolean
295
- ): ItemData {
327
+ function mapMenuItemToNowPlayingData(item: MenuItem): ItemData {
296
328
  return {
297
329
  imageUri: item.icon,
298
330
  textLabel1: item.title,
299
331
  textLabel2: item.summary ?? "",
300
332
  nowPlayingLabel: "Now Playing",
301
333
  trailingButton: "playPause",
302
- isSelected: isPaused !== undefined ? !isPaused : item.isSelected,
303
334
  };
304
335
  }
305
336
 
306
- export function mapMenuItemToQueuedData(item: MenuItem): ItemData {
337
+ function mapMenuItemToQueuedData(item: MenuItem): ItemData {
307
338
  return {
308
339
  imageUri: item.icon,
309
340
  textLabel1: item.title,
310
341
  textLabel2: item.summary ?? "",
311
342
  leadingButton: "remove",
312
343
  trailingButton: "drag",
313
- isSelected: item.isSelected,
314
344
  };
315
345
  }
316
346
 
317
- export function mapMenuItemToPlaylistData(
318
- item: MenuItem,
319
- behavior?: SelectionBehavior
320
- ): ItemData {
321
- const showSelectionWidget =
322
- behavior?.selectMode !== "none" && item.trailingButton !== "none";
323
-
324
- const summary =
325
- typeof item.summary === "string" ? item.summary.trim() : item.summary;
326
-
347
+ function mapMenuItemToPlaylistData(item: MenuItem): ItemData {
327
348
  return {
328
349
  imageUri: item.icon,
329
350
  textLabel1: item.title,
330
- textLabel2: summary || "",
331
- trailingButton: showSelectionWidget
332
- ? item.trailingButton || ("multiSelect" as ItemButtonAction)
333
- : undefined,
334
- isSelected: item.isSelected,
351
+ textLabel2: item.summary ?? "",
352
+ trailingButton: "multiSelect",
335
353
  };
336
354
  }
337
355
 
@@ -344,7 +362,6 @@ type ItemContainerProps = {
344
362
  background: BackgroundConfiguration;
345
363
  focused: boolean;
346
364
  children: React.ReactNode;
347
- onPress?: () => void;
348
365
  };
349
366
 
350
367
  function ItemContainer({
@@ -352,25 +369,23 @@ function ItemContainer({
352
369
  background,
353
370
  focused,
354
371
  children,
355
- onPress,
356
372
  }: ItemContainerProps) {
357
373
  const container = resolveContainerSpec(image);
358
374
  const bg = focused ? background.focusedColor : background.defaultColor;
359
375
 
360
376
  return (
361
- <Pressable
362
- onPress={onPress}
363
- style={({ pressed }) => ({
364
- backgroundColor: pressed ? background.focusedColor : bg,
377
+ <View
378
+ style={{
379
+ backgroundColor: bg,
365
380
  borderRadius: background.cornerRadius,
366
- paddingTop: background.paddingTop ?? container.paddingTop,
367
- paddingRight: background.paddingRight ?? container.paddingRight,
368
- paddingBottom: background.paddingBottom ?? container.paddingBottom,
369
- paddingLeft: background.paddingLeft ?? container.paddingLeft,
370
- })}
381
+ paddingTop: container.paddingTop,
382
+ paddingRight: container.paddingRight,
383
+ paddingBottom: container.paddingBottom,
384
+ paddingLeft: container.paddingLeft,
385
+ }}
371
386
  >
372
387
  {children}
373
- </Pressable>
388
+ </View>
374
389
  );
375
390
  }
376
391
 
@@ -471,259 +486,27 @@ function NowPlayingRow({
471
486
  type ItemButtonProps = {
472
487
  action: ItemButtonAction;
473
488
  focused?: boolean;
474
- onPress?: () => void;
475
- isSelected?: boolean;
476
- checkboxAssets?: CheckboxAssetsConfiguration;
477
- actionButtonAssets?: ActionButtonAssetsConfiguration;
478
489
  };
479
490
 
480
- function ItemButton({
481
- action,
482
- focused = false,
483
- onPress,
484
- isSelected = false,
485
- checkboxAssets,
486
- actionButtonAssets,
487
- }: ItemButtonProps) {
491
+ function ItemButton({ action, focused = false }: ItemButtonProps) {
488
492
  const layout = BUTTON_LAYOUT_SPEC[action];
489
493
 
490
- if (!layout) {
491
- return null;
492
- }
493
-
494
- const renderIcon = () => {
495
- switch (action) {
496
- case "playPause": {
497
- const iconSize = layout.assetWidth;
498
- const iconRadius = iconSize / 2;
499
-
500
- return (
501
- <View
502
- style={{
503
- width: iconSize,
504
- height: iconSize,
505
- borderRadius: iconRadius,
506
- backgroundColor: "#FFFFFF",
507
- justifyContent: "center",
508
- alignItems: "center",
509
- }}
510
- >
511
- {isSelected ? (
512
- <View
513
- style={{
514
- flexDirection: "row",
515
- justifyContent: "space-between",
516
- width: 10,
517
- height: 16,
518
- }}
519
- >
520
- <View
521
- style={{
522
- width: 3.5,
523
- height: 16,
524
- backgroundColor: "#1e1e1e",
525
- borderRadius: 1,
526
- }}
527
- />
528
- <View
529
- style={{
530
- width: 3.5,
531
- height: 16,
532
- backgroundColor: "#1e1e1e",
533
- borderRadius: 1,
534
- }}
535
- />
536
- </View>
537
- ) : (
538
- <View
539
- style={{
540
- width: 0,
541
- height: 0,
542
- backgroundColor: "transparent",
543
- borderStyle: "solid",
544
- borderLeftWidth: 14,
545
- borderRightWidth: 0,
546
- borderTopWidth: 8,
547
- borderBottomWidth: 8,
548
- borderLeftColor: "#1e1e1e",
549
- borderRightColor: "transparent",
550
- borderTopColor: "transparent",
551
- borderBottomColor: "transparent",
552
- marginLeft: 3,
553
- }}
554
- />
555
- )}
556
- </View>
557
- );
558
- }
559
-
560
- case "drag": {
561
- if (actionButtonAssets?.dragAsset) {
562
- return (
563
- <Image
564
- source={{ uri: actionButtonAssets.dragAsset }}
565
- style={{
566
- width: layout.assetWidth,
567
- height: layout.assetHeight,
568
- }}
569
- resizeMode="contain"
570
- />
571
- );
572
- }
573
-
574
- return (
575
- <View
576
- style={{
577
- width: 20,
578
- height: 12,
579
- justifyContent: "space-between",
580
- }}
581
- >
582
- <View
583
- style={{
584
- height: 2,
585
- backgroundColor: "rgba(255, 255, 255, 0.7)",
586
- borderRadius: 1,
587
- }}
588
- />
589
- <View
590
- style={{
591
- height: 2,
592
- backgroundColor: "rgba(255, 255, 255, 0.7)",
593
- borderRadius: 1,
594
- }}
595
- />
596
- <View
597
- style={{
598
- height: 2,
599
- backgroundColor: "rgba(255, 255, 255, 0.7)",
600
- borderRadius: 1,
601
- }}
602
- />
603
- </View>
604
- );
605
- }
606
-
607
- case "remove": {
608
- if (actionButtonAssets?.removeAsset) {
609
- return (
610
- <Image
611
- source={{ uri: actionButtonAssets.removeAsset }}
612
- style={{
613
- width: layout.assetWidth,
614
- height: layout.assetHeight,
615
- }}
616
- resizeMode="contain"
617
- />
618
- );
619
- }
620
-
621
- return (
622
- <View
623
- style={{
624
- width: 24,
625
- height: 24,
626
- borderRadius: 12,
627
- borderWidth: 1.5,
628
- borderColor: "rgba(255, 255, 255, 0.7)",
629
- justifyContent: "center",
630
- alignItems: "center",
631
- }}
632
- >
633
- <View
634
- style={{
635
- width: 10,
636
- height: 1.5,
637
- backgroundColor: "rgba(255, 255, 255, 0.7)",
638
- borderRadius: 1,
639
- }}
640
- />
641
- </View>
642
- );
643
- }
644
-
645
- case "multiSelect": {
646
- const studioAsset = isSelected
647
- ? checkboxAssets?.checkedAsset
648
- : checkboxAssets?.asset;
649
-
650
- if (studioAsset) {
651
- return (
652
- <Image
653
- source={{ uri: studioAsset }}
654
- style={{
655
- width: layout.assetWidth,
656
- height: layout.assetHeight,
657
- }}
658
- resizeMode="contain"
659
- />
660
- );
661
- }
662
-
663
- if (!isSelected) {
664
- return (
665
- <View
666
- style={{
667
- width: layout.assetWidth,
668
- height: layout.assetHeight,
669
- borderRadius: layout.assetWidth / 2,
670
- borderWidth: 1.5,
671
- borderColor: "rgba(255, 255, 255, 0.7)",
672
- backgroundColor: "transparent",
673
- }}
674
- />
675
- );
676
- }
677
-
678
- return (
679
- <View
680
- style={{
681
- width: 24,
682
- height: 24,
683
- borderRadius: 12,
684
- backgroundColor: "#FFFFFF",
685
- justifyContent: "center",
686
- alignItems: "center",
687
- }}
688
- >
689
- <View
690
- style={{
691
- width: 6,
692
- height: 10,
693
- borderBottomWidth: 2,
694
- borderRightWidth: 2,
695
- borderColor: "#1e1e1e",
696
- transform: [{ rotate: "45deg" }],
697
- marginTop: -2,
698
- }}
699
- />
700
- </View>
701
- );
702
- }
703
-
704
- default:
705
- return null;
706
- }
707
- };
708
-
709
494
  return (
710
- <Pressable
711
- onPress={(e: any) => {
712
- e?.stopPropagation?.();
713
- onPress?.();
495
+ <View
496
+ style={{
497
+ paddingTop: layout.paddingTop,
498
+ paddingRight: layout.paddingRight,
499
+ paddingBottom: layout.paddingBottom,
500
+ paddingLeft: layout.paddingLeft,
501
+ opacity: focused ? 0.7 : 1,
714
502
  }}
715
- style={({ pressed }) => [
716
- {
717
- paddingTop: layout.paddingTop,
718
- paddingRight: layout.paddingRight,
719
- paddingBottom: layout.paddingBottom,
720
- paddingLeft: layout.paddingLeft,
721
- opacity: pressed || focused ? 0.7 : 1,
722
- },
723
- ]}
724
503
  >
725
- {renderIcon()}
726
- </Pressable>
504
+ <Image
505
+ source={{ uri: BUTTON_ASSETS[action] }}
506
+ style={{ width: layout.assetWidth, height: layout.assetHeight }}
507
+ resizeMode="contain"
508
+ />
509
+ </View>
727
510
  );
728
511
  }
729
512
 
@@ -732,12 +515,6 @@ type ItemButtonsProps = {
732
515
  trailingButton?: ItemButtonAction;
733
516
  focusedLeadingButton?: boolean;
734
517
  focusedTrailingButton?: boolean;
735
- onLeadingButtonPress?: () => void;
736
- onTrailingButtonPress?: () => void;
737
- isSelected?: boolean;
738
- renderHandle?: (element: React.ReactElement) => React.ReactElement;
739
- checkboxAssets?: CheckboxAssetsConfiguration;
740
- actionButtonAssets?: ActionButtonAssetsConfiguration;
741
518
  };
742
519
 
743
520
  function ItemButtons({
@@ -745,12 +522,6 @@ function ItemButtons({
745
522
  trailingButton,
746
523
  focusedLeadingButton = false,
747
524
  focusedTrailingButton = false,
748
- onLeadingButtonPress,
749
- onTrailingButtonPress,
750
- isSelected = false,
751
- renderHandle,
752
- checkboxAssets,
753
- actionButtonAssets,
754
525
  }: ItemButtonsProps) {
755
526
  if (!leadingButton && !trailingButton) {
756
527
  return null;
@@ -760,102 +531,42 @@ function ItemButtons({
760
531
  <View style={styles.buttonsRow}>
761
532
  {leadingButton ? (
762
533
  <>
763
- <ItemButton
764
- action={leadingButton}
765
- focused={focusedLeadingButton}
766
- onPress={onLeadingButtonPress}
767
- isSelected={isSelected}
768
- checkboxAssets={checkboxAssets}
769
- actionButtonAssets={actionButtonAssets}
770
- />
534
+ <ItemButton action={leadingButton} focused={focusedLeadingButton} />
771
535
  <View style={{ width: BUTTONS_CONTAINER_HORIZONTAL_GUTTER }} />
772
536
  </>
773
537
  ) : null}
774
538
  {trailingButton ? (
775
- trailingButton === "drag" ? (
776
- renderHandle ? (
777
- renderHandle(
778
- <ItemButton
779
- action={trailingButton}
780
- focused={focusedTrailingButton}
781
- onPress={onTrailingButtonPress}
782
- isSelected={isSelected}
783
- checkboxAssets={checkboxAssets}
784
- actionButtonAssets={actionButtonAssets}
785
- />
786
- )
787
- ) : (
788
- <ItemButton
789
- action={trailingButton}
790
- focused={focusedTrailingButton}
791
- onPress={onTrailingButtonPress}
792
- isSelected={isSelected}
793
- checkboxAssets={checkboxAssets}
794
- actionButtonAssets={actionButtonAssets}
795
- />
796
- )
797
- ) : (
798
- <ItemButton
799
- action={trailingButton}
800
- focused={focusedTrailingButton}
801
- onPress={onTrailingButtonPress}
802
- isSelected={isSelected}
803
- checkboxAssets={checkboxAssets}
804
- actionButtonAssets={actionButtonAssets}
805
- />
806
- )
539
+ <ItemButton action={trailingButton} focused={focusedTrailingButton} />
807
540
  ) : null}
808
541
  </View>
809
542
  );
810
543
  }
811
544
 
812
545
  // ---------------------------------------------------------------------------
813
- // AudioPlayerTrackItem
546
+ // Item
814
547
  // ---------------------------------------------------------------------------
815
548
 
816
- export function AudioPlayerTrackItem({
549
+ export function Item({
817
550
  configuration,
818
551
  data,
819
552
  focused = false,
820
553
  focusedLeadingButton = false,
821
554
  focusedTrailingButton = false,
822
- onPress,
823
- onLeadingButtonPress,
824
- onTrailingButtonPress,
825
- renderHandle,
826
- }: AudioPlayerTrackItemProps) {
827
- const modalBlocksStyle = useModalBlocksStyle();
828
- const showNowPlaying = !!data.nowPlayingLabel;
829
-
830
- const itemBlock =
831
- showNowPlaying && modalBlocksStyle?.nowPlayingItem
832
- ? modalBlocksStyle.nowPlayingItem
833
- : modalBlocksStyle?.item;
834
-
835
- const effectiveConfig = React.useMemo(() => {
836
- return mergeItemConfiguration(configuration, itemBlock);
837
- }, [configuration, itemBlock]);
838
-
555
+ }: ItemProps) {
839
556
  const {
840
557
  background,
841
558
  image,
559
+ nowPlayingAsset,
560
+ nowPlayingLabel,
842
561
  textLabel1,
843
562
  textLabel2,
844
- nowPlayingLabel,
845
- nowPlayingAsset,
846
- checkboxAssets,
847
- actionButtonAssets,
848
- } = effectiveConfig;
563
+ } = configuration;
849
564
 
850
565
  const container = resolveContainerSpec(image);
566
+ const showNowPlaying = !!data.nowPlayingLabel;
851
567
 
852
568
  return (
853
- <ItemContainer
854
- image={image}
855
- background={background}
856
- focused={focused}
857
- onPress={onPress}
858
- >
569
+ <ItemContainer image={image} background={background} focused={focused}>
859
570
  <View style={styles.row}>
860
571
  <ItemThumbnail configuration={image} imageUri={data.imageUri} />
861
572
  <View style={{ width: container.horizontalGutter }} />
@@ -883,12 +594,6 @@ export function AudioPlayerTrackItem({
883
594
  trailingButton={data.trailingButton}
884
595
  focusedLeadingButton={focusedLeadingButton}
885
596
  focusedTrailingButton={focusedTrailingButton}
886
- onLeadingButtonPress={onLeadingButtonPress}
887
- onTrailingButtonPress={onTrailingButtonPress}
888
- isSelected={data.isSelected}
889
- renderHandle={renderHandle}
890
- checkboxAssets={checkboxAssets}
891
- actionButtonAssets={actionButtonAssets}
892
597
  />
893
598
  </View>
894
599
  </ItemContainer>
@@ -958,3 +663,47 @@ export const VARIANT_PLAYLIST_ITEM: ItemConfiguration = {
958
663
  textLabel1: DEFAULT_TEXT_LABEL_1_CONFIGURATION,
959
664
  textLabel2: DEFAULT_TEXT_LABEL_2_CONFIGURATION,
960
665
  };
666
+
667
+ export default function App() {
668
+ // Hardcoded core mock data objects matching user types framework
669
+ const sharedMockItem: MenuItem = {
670
+ title: "Content Title",
671
+ summary: "Artist",
672
+ icon: "https://picsum.photos/200",
673
+ action: { type: "PLAY_AUDIO" },
674
+ secondaryAction: { action: { type: "OPEN_CONTEXT_MENU" } },
675
+ };
676
+
677
+ const playlistMockItem: MenuItem = {
678
+ title: "Playlist Name",
679
+ summary: "12 Songs",
680
+ icon: "https://picsum.photos/201",
681
+ isSelected: true,
682
+ action: { type: "NAVIGATE_PLAYLIST" },
683
+ };
684
+
685
+ return (
686
+ <View style={styles.demoScreen}>
687
+ <Text style={styles.demoHeading}>Modal Item Building Block</Text>
688
+
689
+ <Text style={styles.demoLabel}>Now Playing</Text>
690
+ <Item
691
+ configuration={VARIANT_NOW_PLAYING}
692
+ data={mapMenuItemToNowPlayingData(sharedMockItem)}
693
+ />
694
+
695
+ <Text style={styles.demoLabel}>Queued Item</Text>
696
+ <Item
697
+ configuration={VARIANT_QUEUED_ITEM}
698
+ data={mapMenuItemToQueuedData(sharedMockItem)}
699
+ focused
700
+ />
701
+
702
+ <Text style={styles.demoLabel}>Playlist Item</Text>
703
+ <Item
704
+ configuration={VARIANT_PLAYLIST_ITEM}
705
+ data={mapMenuItemToPlaylistData(playlistMockItem)}
706
+ />
707
+ </View>
708
+ );
709
+ }