@applicaster/zapp-react-native-ui-components 16.0.0-alpha.2529997432 → 16.0.0-alpha.2663208063
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.
- package/Components/AudioPlayer/tv/__tests__/audioPlayer.test.js +19 -0
- package/Components/AudioPlayer/tv/__tests__/index.test.tsx +120 -0
- package/Components/AudioPlayer/tv/index.tsx +5 -1
- package/Components/MasterCell/DefaultComponents/Image/hoc/utils/__tests__/withDimensions.test.ts +420 -125
- package/Components/MasterCell/DefaultComponents/Image/hoc/utils/index.ts +114 -19
- package/Components/MasterCell/DefaultComponents/Image/hoc/withDimensions.tsx +19 -8
- package/Components/ModalComponent/AudioPlayer/Components/Action.tsx +0 -18
- package/Components/ModalComponent/AudioPlayer/Components/Button.tsx +17 -24
- package/Components/ModalComponent/AudioPlayer/Components/Header.tsx +25 -73
- package/Components/ModalComponent/AudioPlayer/Components/Input.tsx +0 -18
- package/Components/ModalComponent/AudioPlayer/Components/Item.tsx +75 -79
- package/Components/ModalComponent/AudioPlayer/Components/NowPlayingHeaderSection.tsx +89 -0
- package/Components/ModalComponent/AudioPlayer/Components/index.ts +3 -1
- package/Components/ModalComponent/AudioPlayer/utils/mergeStyles.ts +199 -0
- package/Components/ModalComponent/BottomSheetDragArea.tsx +33 -0
- package/Components/ModalComponent/BottomSheetModalContent.tsx +385 -60
- package/Components/ModalComponent/Button/index.tsx +5 -3
- package/Components/ModalComponent/Header/index.tsx +20 -7
- package/Components/ModalComponent/Header/utils.ts +1 -1
- package/Components/ModalComponent/ModalBlocksStyleContext.tsx +10 -0
- package/Components/ModalComponent/SortableList.tsx +142 -0
- package/Components/ModalComponent/SortableList.web.tsx +102 -0
- package/Components/ModalComponent/TextInputContent.tsx +100 -0
- package/Components/ModalComponent/__tests__/BottomSheetDragArea.test.tsx +74 -0
- package/Components/ModalComponent/__tests__/BottomSheetModalContent.test.tsx +238 -0
- package/Components/ModalComponent/__tests__/TextInputContent.test.tsx +120 -0
- package/Components/ModalComponent/__tests__/showTextInput.test.ts +95 -0
- package/Components/ModalComponent/index.tsx +11 -0
- package/Components/ModalComponent/presets/__tests__/getCell.test.ts +66 -0
- package/Components/ModalComponent/presets/dynamicCollectionCell.tsx +78 -0
- package/Components/ModalComponent/presets/index.ts +27 -0
- package/Components/ModalComponent/presets/selectableCell.tsx +28 -0
- package/Components/ModalComponent/presets/standardCell.tsx +41 -0
- package/Components/ModalComponent/presets/types.ts +35 -0
- package/Components/ModalComponent/showTextInput.ts +43 -0
- package/Components/ModalComponent/utils.ts +76 -20
- package/Components/PlayerContainer/PlayerContainer.tsx +11 -7
- package/Components/PlayerContainer/ProgramInfo/index.tsx +3 -4
- package/Components/PlayerContainer/__tests__/PlayerContainer.test.tsx +66 -13
- package/Components/VideoLive/LiveImageManager.ts +1 -1
- package/package.json +6 -5
- /package/Decorators/ZappPipesDataConnector/__tests__/{Hero.js → Hero.tsx} +0 -0
|
@@ -20,6 +20,12 @@ import {
|
|
|
20
20
|
Text,
|
|
21
21
|
View,
|
|
22
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";
|
|
23
29
|
|
|
24
30
|
const styles = StyleSheet.create({
|
|
25
31
|
row: {
|
|
@@ -34,25 +40,6 @@ const styles = StyleSheet.create({
|
|
|
34
40
|
flexDirection: "row",
|
|
35
41
|
alignItems: "center",
|
|
36
42
|
},
|
|
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
43
|
});
|
|
57
44
|
|
|
58
45
|
// ---------------------------------------------------------------------------
|
|
@@ -104,51 +91,6 @@ export type ItemConfiguration = {
|
|
|
104
91
|
textLabel2: LabelConfiguration;
|
|
105
92
|
};
|
|
106
93
|
|
|
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
94
|
export const DEFAULT_TEXT_LABEL_1_CONFIGURATION: LabelConfiguration = {
|
|
153
95
|
fontColor: "#FFFFFF",
|
|
154
96
|
focusedFontColor: "#FFFFFF",
|
|
@@ -211,6 +153,7 @@ export type AudioPlayerTrackItemProps = {
|
|
|
211
153
|
onPress?: () => void;
|
|
212
154
|
onLeadingButtonPress?: () => void;
|
|
213
155
|
onTrailingButtonPress?: () => void;
|
|
156
|
+
renderHandle?: (element: React.ReactElement) => React.ReactElement;
|
|
214
157
|
};
|
|
215
158
|
|
|
216
159
|
// ---------------------------------------------------------------------------
|
|
@@ -326,14 +269,17 @@ function resolveContainerSpec(image: ImageConfiguration): ContainerSpec {
|
|
|
326
269
|
: CONTAINER_SPEC_DEFAULT;
|
|
327
270
|
}
|
|
328
271
|
|
|
329
|
-
export function mapMenuItemToNowPlayingData(
|
|
272
|
+
export function mapMenuItemToNowPlayingData(
|
|
273
|
+
item: MenuItem,
|
|
274
|
+
isPaused?: boolean
|
|
275
|
+
): ItemData {
|
|
330
276
|
return {
|
|
331
277
|
imageUri: item.icon,
|
|
332
278
|
textLabel1: item.title,
|
|
333
279
|
textLabel2: item.summary ?? "",
|
|
334
280
|
nowPlayingLabel: "Now Playing",
|
|
335
281
|
trailingButton: "playPause",
|
|
336
|
-
isSelected: item.isSelected,
|
|
282
|
+
isSelected: isPaused !== undefined ? !isPaused : item.isSelected,
|
|
337
283
|
};
|
|
338
284
|
}
|
|
339
285
|
|
|
@@ -348,12 +294,20 @@ export function mapMenuItemToQueuedData(item: MenuItem): ItemData {
|
|
|
348
294
|
};
|
|
349
295
|
}
|
|
350
296
|
|
|
351
|
-
export function mapMenuItemToPlaylistData(
|
|
297
|
+
export function mapMenuItemToPlaylistData(
|
|
298
|
+
item: MenuItem,
|
|
299
|
+
behavior?: SelectionBehavior
|
|
300
|
+
): ItemData {
|
|
301
|
+
const showSelectionWidget =
|
|
302
|
+
behavior?.selectMode !== "none" && item.trailingButton !== "none";
|
|
303
|
+
|
|
352
304
|
return {
|
|
353
305
|
imageUri: item.icon,
|
|
354
306
|
textLabel1: item.title,
|
|
355
307
|
textLabel2: item.summary ?? "",
|
|
356
|
-
trailingButton:
|
|
308
|
+
trailingButton: showSelectionWidget
|
|
309
|
+
? item.trailingButton || ("multiSelect" as ItemButtonAction)
|
|
310
|
+
: undefined,
|
|
357
311
|
isSelected: item.isSelected,
|
|
358
312
|
};
|
|
359
313
|
}
|
|
@@ -506,6 +460,10 @@ function ItemButton({
|
|
|
506
460
|
}: ItemButtonProps) {
|
|
507
461
|
const layout = BUTTON_LAYOUT_SPEC[action];
|
|
508
462
|
|
|
463
|
+
if (!layout) {
|
|
464
|
+
return null;
|
|
465
|
+
}
|
|
466
|
+
|
|
509
467
|
const renderIcon = () => {
|
|
510
468
|
switch (action) {
|
|
511
469
|
case "playPause": {
|
|
@@ -680,7 +638,10 @@ function ItemButton({
|
|
|
680
638
|
|
|
681
639
|
return (
|
|
682
640
|
<Pressable
|
|
683
|
-
onPress={
|
|
641
|
+
onPress={(e: any) => {
|
|
642
|
+
e?.stopPropagation?.();
|
|
643
|
+
onPress?.();
|
|
644
|
+
}}
|
|
684
645
|
style={({ pressed }) => [
|
|
685
646
|
{
|
|
686
647
|
paddingTop: layout.paddingTop,
|
|
@@ -704,6 +665,7 @@ type ItemButtonsProps = {
|
|
|
704
665
|
onLeadingButtonPress?: () => void;
|
|
705
666
|
onTrailingButtonPress?: () => void;
|
|
706
667
|
isSelected?: boolean;
|
|
668
|
+
renderHandle?: (element: React.ReactElement) => React.ReactElement;
|
|
707
669
|
};
|
|
708
670
|
|
|
709
671
|
function ItemButtons({
|
|
@@ -714,6 +676,7 @@ function ItemButtons({
|
|
|
714
676
|
onLeadingButtonPress,
|
|
715
677
|
onTrailingButtonPress,
|
|
716
678
|
isSelected = false,
|
|
679
|
+
renderHandle,
|
|
717
680
|
}: ItemButtonsProps) {
|
|
718
681
|
if (!leadingButton && !trailingButton) {
|
|
719
682
|
return null;
|
|
@@ -733,12 +696,32 @@ function ItemButtons({
|
|
|
733
696
|
</>
|
|
734
697
|
) : null}
|
|
735
698
|
{trailingButton ? (
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
699
|
+
trailingButton === "drag" ? (
|
|
700
|
+
renderHandle ? (
|
|
701
|
+
renderHandle(
|
|
702
|
+
<ItemButton
|
|
703
|
+
action={trailingButton}
|
|
704
|
+
focused={focusedTrailingButton}
|
|
705
|
+
onPress={onTrailingButtonPress}
|
|
706
|
+
isSelected={isSelected}
|
|
707
|
+
/>
|
|
708
|
+
)
|
|
709
|
+
) : (
|
|
710
|
+
<ItemButton
|
|
711
|
+
action={trailingButton}
|
|
712
|
+
focused={focusedTrailingButton}
|
|
713
|
+
onPress={onTrailingButtonPress}
|
|
714
|
+
isSelected={isSelected}
|
|
715
|
+
/>
|
|
716
|
+
)
|
|
717
|
+
) : (
|
|
718
|
+
<ItemButton
|
|
719
|
+
action={trailingButton}
|
|
720
|
+
focused={focusedTrailingButton}
|
|
721
|
+
onPress={onTrailingButtonPress}
|
|
722
|
+
isSelected={isSelected}
|
|
723
|
+
/>
|
|
724
|
+
)
|
|
742
725
|
) : null}
|
|
743
726
|
</View>
|
|
744
727
|
);
|
|
@@ -757,18 +740,30 @@ export function AudioPlayerTrackItem({
|
|
|
757
740
|
onPress,
|
|
758
741
|
onLeadingButtonPress,
|
|
759
742
|
onTrailingButtonPress,
|
|
743
|
+
renderHandle,
|
|
760
744
|
}: AudioPlayerTrackItemProps) {
|
|
745
|
+
const modalBlocksStyle = useModalBlocksStyle();
|
|
746
|
+
const showNowPlaying = !!data.nowPlayingLabel;
|
|
747
|
+
|
|
748
|
+
const itemBlock =
|
|
749
|
+
showNowPlaying && modalBlocksStyle?.nowPlayingItem
|
|
750
|
+
? modalBlocksStyle.nowPlayingItem
|
|
751
|
+
: modalBlocksStyle?.item;
|
|
752
|
+
|
|
753
|
+
const effectiveConfig = React.useMemo(() => {
|
|
754
|
+
return mergeItemConfiguration(configuration, itemBlock);
|
|
755
|
+
}, [configuration, itemBlock]);
|
|
756
|
+
|
|
761
757
|
const {
|
|
762
758
|
background,
|
|
763
759
|
image,
|
|
764
|
-
nowPlayingAsset,
|
|
765
|
-
nowPlayingLabel,
|
|
766
760
|
textLabel1,
|
|
767
761
|
textLabel2,
|
|
768
|
-
|
|
762
|
+
nowPlayingLabel,
|
|
763
|
+
nowPlayingAsset,
|
|
764
|
+
} = effectiveConfig;
|
|
769
765
|
|
|
770
766
|
const container = resolveContainerSpec(image);
|
|
771
|
-
const showNowPlaying = !!data.nowPlayingLabel;
|
|
772
767
|
|
|
773
768
|
return (
|
|
774
769
|
<ItemContainer
|
|
@@ -807,6 +802,7 @@ export function AudioPlayerTrackItem({
|
|
|
807
802
|
onLeadingButtonPress={onLeadingButtonPress}
|
|
808
803
|
onTrailingButtonPress={onTrailingButtonPress}
|
|
809
804
|
isSelected={data.isSelected}
|
|
805
|
+
renderHandle={renderHandle}
|
|
810
806
|
/>
|
|
811
807
|
</View>
|
|
812
808
|
</ItemContainer>
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { StyleSheet, View } from "react-native";
|
|
3
|
+
import {
|
|
4
|
+
AudioPlayerTrackItem,
|
|
5
|
+
VARIANT_NOW_PLAYING,
|
|
6
|
+
mapMenuItemToNowPlayingData,
|
|
7
|
+
} from "./Item";
|
|
8
|
+
import { AudioPlayerHeader, VARIANT_SECTION_HEADER } from "./Header";
|
|
9
|
+
import type { MenuItem } from "@applicaster/zapp-react-native-utils/modalState/types";
|
|
10
|
+
import { usePlayer } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/usePlayer";
|
|
11
|
+
import { usePlayerState } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/usePlayerState";
|
|
12
|
+
|
|
13
|
+
const styles = StyleSheet.create({
|
|
14
|
+
divider: {
|
|
15
|
+
height: StyleSheet.hairlineWidth,
|
|
16
|
+
backgroundColor: "rgba(255, 255, 255, 0.1)",
|
|
17
|
+
marginHorizontal: 20,
|
|
18
|
+
marginVertical: 8,
|
|
19
|
+
},
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
type NowPlayingHeaderSectionProps = {
|
|
23
|
+
onClear?: () => void;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export function NowPlayingHeaderSection({
|
|
27
|
+
onClear,
|
|
28
|
+
}: NowPlayingHeaderSectionProps) {
|
|
29
|
+
const player = usePlayer();
|
|
30
|
+
const playerState = usePlayerState("queue-now-playing-section");
|
|
31
|
+
|
|
32
|
+
const renderNowPlayingTrack = () => {
|
|
33
|
+
if (!player?.entry) {
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const mediaGroup = player.entry.media_group;
|
|
38
|
+
|
|
39
|
+
const imageGroup = Array.isArray(mediaGroup)
|
|
40
|
+
? mediaGroup.find((g: any) => g.type === "image")
|
|
41
|
+
: null;
|
|
42
|
+
|
|
43
|
+
const firstImage = Array.isArray(imageGroup?.media_item)
|
|
44
|
+
? imageGroup.media_item[0]?.src
|
|
45
|
+
: imageGroup?.media_item?.src;
|
|
46
|
+
|
|
47
|
+
const nowPlayingItem: MenuItem = {
|
|
48
|
+
id: String(player.entry.id ?? "now_playing"),
|
|
49
|
+
title: (player.entry.title as string) || String(player.entry.id),
|
|
50
|
+
summary: (player.entry.summary as string) ?? "",
|
|
51
|
+
icon: firstImage,
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
const data = mapMenuItemToNowPlayingData(
|
|
55
|
+
nowPlayingItem,
|
|
56
|
+
playerState?.isPaused
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
const handlePlayPause = () => {
|
|
60
|
+
if (playerState?.isPaused) {
|
|
61
|
+
player?.play();
|
|
62
|
+
} else {
|
|
63
|
+
player?.pause();
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
return (
|
|
68
|
+
<View>
|
|
69
|
+
<AudioPlayerTrackItem
|
|
70
|
+
configuration={VARIANT_NOW_PLAYING}
|
|
71
|
+
data={data}
|
|
72
|
+
onTrailingButtonPress={handlePlayPause}
|
|
73
|
+
/>
|
|
74
|
+
<View style={styles.divider} />
|
|
75
|
+
</View>
|
|
76
|
+
);
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
return (
|
|
80
|
+
<View>
|
|
81
|
+
{renderNowPlayingTrack()}
|
|
82
|
+
<AudioPlayerHeader
|
|
83
|
+
configuration={VARIANT_SECTION_HEADER}
|
|
84
|
+
data={{ title: "Next Up" }}
|
|
85
|
+
onClear={onClear}
|
|
86
|
+
/>
|
|
87
|
+
</View>
|
|
88
|
+
);
|
|
89
|
+
}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
export { AudioPlayerAction } from "./Action";
|
|
2
2
|
|
|
3
|
-
export { AudioPlayerButton } from "./Button";
|
|
3
|
+
export { AudioPlayerButton, VARIANT_WITH_ICON } from "./Button";
|
|
4
4
|
|
|
5
5
|
export { AudioPlayerHeader } from "./Header";
|
|
6
6
|
|
|
7
7
|
export { AudioPlayerTrackItem } from "./Item";
|
|
8
8
|
|
|
9
|
+
export { NowPlayingHeaderSection } from "./NowPlayingHeaderSection";
|
|
10
|
+
|
|
9
11
|
export { AudioPlayerInput } from "./Input";
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
import {
|
|
2
|
+
BackgroundConfiguration as ItemBackgroundConfiguration,
|
|
3
|
+
ImageConfiguration as ItemImageConfiguration,
|
|
4
|
+
LabelConfiguration as ItemLabelConfiguration,
|
|
5
|
+
NowPlayingAssetConfiguration as ItemNowPlayingAssetConfiguration,
|
|
6
|
+
ItemConfiguration,
|
|
7
|
+
} from "../Components/Item";
|
|
8
|
+
import {
|
|
9
|
+
TitleConfiguration as HeaderTitleConfiguration,
|
|
10
|
+
HeaderConfiguration,
|
|
11
|
+
} from "../Components/Header";
|
|
12
|
+
import {
|
|
13
|
+
BackgroundConfiguration as ButtonBackgroundConfiguration,
|
|
14
|
+
TitleConfiguration as ButtonTitleConfiguration,
|
|
15
|
+
ButtonConfiguration,
|
|
16
|
+
} from "../Components/Button";
|
|
17
|
+
|
|
18
|
+
// ---------------------------------------------------------------------------
|
|
19
|
+
// Item Merging Helpers
|
|
20
|
+
// ---------------------------------------------------------------------------
|
|
21
|
+
|
|
22
|
+
function mergeItemBackground(
|
|
23
|
+
base: ItemBackgroundConfiguration,
|
|
24
|
+
override?: Record<string, any>
|
|
25
|
+
): ItemBackgroundConfiguration {
|
|
26
|
+
if (!override) return base;
|
|
27
|
+
|
|
28
|
+
return {
|
|
29
|
+
...base,
|
|
30
|
+
...(override.backgroundColor
|
|
31
|
+
? { defaultColor: override.backgroundColor }
|
|
32
|
+
: {}),
|
|
33
|
+
...(override.focusColor || override.backgroundColor
|
|
34
|
+
? { focusedColor: override.focusColor || override.backgroundColor }
|
|
35
|
+
: {}),
|
|
36
|
+
...(override.borderRadius !== undefined
|
|
37
|
+
? { cornerRadius: override.borderRadius }
|
|
38
|
+
: {}),
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function mergeItemImage(
|
|
43
|
+
base: ItemImageConfiguration,
|
|
44
|
+
override?: Record<string, any>
|
|
45
|
+
): ItemImageConfiguration {
|
|
46
|
+
if (!override) return base;
|
|
47
|
+
|
|
48
|
+
return {
|
|
49
|
+
...base,
|
|
50
|
+
...(override.width !== undefined ? { width: override.width } : {}),
|
|
51
|
+
...(override.height !== undefined ? { height: override.height } : {}),
|
|
52
|
+
...(override.borderRadius !== undefined
|
|
53
|
+
? { cornerRadius: override.borderRadius }
|
|
54
|
+
: {}),
|
|
55
|
+
...(override.borderWidth !== undefined
|
|
56
|
+
? { borderWidth: override.borderWidth }
|
|
57
|
+
: {}),
|
|
58
|
+
...(override.borderColor ? { borderColor: override.borderColor } : {}),
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function mergeItemLabel(
|
|
63
|
+
base: ItemLabelConfiguration,
|
|
64
|
+
override?: Record<string, any>
|
|
65
|
+
): ItemLabelConfiguration {
|
|
66
|
+
if (!override) return base;
|
|
67
|
+
|
|
68
|
+
return {
|
|
69
|
+
...base,
|
|
70
|
+
...(override.fontColor ? { fontColor: override.fontColor } : {}),
|
|
71
|
+
...(override.fontSize !== undefined ? { fontSize: override.fontSize } : {}),
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function mergeItemNowPlayingAsset(
|
|
76
|
+
base: ItemNowPlayingAssetConfiguration,
|
|
77
|
+
override?: Record<string, any>
|
|
78
|
+
): ItemNowPlayingAssetConfiguration {
|
|
79
|
+
if (!override) return base;
|
|
80
|
+
|
|
81
|
+
return {
|
|
82
|
+
...base,
|
|
83
|
+
...(override.asset ? { asset: override.asset } : {}),
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export function mergeItemConfiguration(
|
|
88
|
+
base: ItemConfiguration,
|
|
89
|
+
itemBlock?: Record<string, any>
|
|
90
|
+
): ItemConfiguration {
|
|
91
|
+
if (!itemBlock) return base;
|
|
92
|
+
|
|
93
|
+
const bg = itemBlock.background?.default || itemBlock.background;
|
|
94
|
+
const img = itemBlock.image?.default || itemBlock.image;
|
|
95
|
+
const label1 = itemBlock.textLabel1?.default || itemBlock.textLabel1;
|
|
96
|
+
const label2 = itemBlock.textLabel2?.default || itemBlock.textLabel2;
|
|
97
|
+
|
|
98
|
+
const npLabel =
|
|
99
|
+
itemBlock.nowPlayingLabel?.default || itemBlock.nowPlayingLabel;
|
|
100
|
+
|
|
101
|
+
const npAsset =
|
|
102
|
+
itemBlock.nowPlayingAsset?.default || itemBlock.nowPlayingAsset;
|
|
103
|
+
|
|
104
|
+
return {
|
|
105
|
+
...base,
|
|
106
|
+
background: mergeItemBackground(base.background, bg),
|
|
107
|
+
image: mergeItemImage(base.image, img),
|
|
108
|
+
textLabel1: mergeItemLabel(base.textLabel1, label1),
|
|
109
|
+
textLabel2: mergeItemLabel(base.textLabel2, label2),
|
|
110
|
+
nowPlayingLabel: mergeItemLabel(base.nowPlayingLabel, npLabel),
|
|
111
|
+
nowPlayingAsset: mergeItemNowPlayingAsset(base.nowPlayingAsset, npAsset),
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// ---------------------------------------------------------------------------
|
|
116
|
+
// Header Merging Helpers
|
|
117
|
+
// ---------------------------------------------------------------------------
|
|
118
|
+
|
|
119
|
+
function mergeHeaderTitle(
|
|
120
|
+
base: HeaderTitleConfiguration,
|
|
121
|
+
override?: Record<string, any>
|
|
122
|
+
): HeaderTitleConfiguration {
|
|
123
|
+
if (!override) return base;
|
|
124
|
+
|
|
125
|
+
return {
|
|
126
|
+
...base,
|
|
127
|
+
...(override.fontColor ? { fontColor: override.fontColor } : {}),
|
|
128
|
+
...(override.fontSize !== undefined ? { fontSize: override.fontSize } : {}),
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export function mergeHeaderConfiguration(
|
|
133
|
+
base: HeaderConfiguration,
|
|
134
|
+
headerBlock?: Record<string, any>
|
|
135
|
+
): HeaderConfiguration & { backgroundColor?: string } {
|
|
136
|
+
if (!headerBlock) return base;
|
|
137
|
+
|
|
138
|
+
const bgOverride = headerBlock.container?.default?.backgroundColor;
|
|
139
|
+
|
|
140
|
+
return {
|
|
141
|
+
...base,
|
|
142
|
+
title: mergeHeaderTitle(base.title, headerBlock.title?.default),
|
|
143
|
+
...(bgOverride ? { backgroundColor: bgOverride } : {}),
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// ---------------------------------------------------------------------------
|
|
148
|
+
// Button Merging Helpers
|
|
149
|
+
// ---------------------------------------------------------------------------
|
|
150
|
+
|
|
151
|
+
function mergeButtonBackground(
|
|
152
|
+
base: ButtonBackgroundConfiguration,
|
|
153
|
+
override?: Record<string, any>
|
|
154
|
+
): ButtonBackgroundConfiguration {
|
|
155
|
+
if (!override) return base;
|
|
156
|
+
|
|
157
|
+
return {
|
|
158
|
+
...base,
|
|
159
|
+
...(override.backgroundColor
|
|
160
|
+
? { defaultColor: override.backgroundColor }
|
|
161
|
+
: {}),
|
|
162
|
+
...(override.borderRadius !== undefined
|
|
163
|
+
? { cornerRadius: override.borderRadius }
|
|
164
|
+
: {}),
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function mergeButtonTitle(
|
|
169
|
+
base: ButtonTitleConfiguration,
|
|
170
|
+
override?: Record<string, any>
|
|
171
|
+
): ButtonTitleConfiguration {
|
|
172
|
+
if (!override) return base;
|
|
173
|
+
|
|
174
|
+
return {
|
|
175
|
+
...base,
|
|
176
|
+
...(override.fontColor ? { fontColor: override.fontColor } : {}),
|
|
177
|
+
...(override.fontSize !== undefined ? { fontSize: override.fontSize } : {}),
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
export function mergeButtonConfiguration(
|
|
182
|
+
base: ButtonConfiguration,
|
|
183
|
+
buttonBlock?: Record<string, any>,
|
|
184
|
+
actionBlock?: Record<string, any>
|
|
185
|
+
): ButtonConfiguration {
|
|
186
|
+
if (!buttonBlock && !actionBlock) return base;
|
|
187
|
+
|
|
188
|
+
const bgOverride =
|
|
189
|
+
buttonBlock?.background?.default || actionBlock?.background?.default;
|
|
190
|
+
|
|
191
|
+
const titleOverride =
|
|
192
|
+
buttonBlock?.title?.default || actionBlock?.title?.default;
|
|
193
|
+
|
|
194
|
+
return {
|
|
195
|
+
...base,
|
|
196
|
+
background: mergeButtonBackground(base.background, bgOverride),
|
|
197
|
+
title: mergeButtonTitle(base.title, titleOverride),
|
|
198
|
+
};
|
|
199
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { PanGestureHandler } from "react-native-gesture-handler";
|
|
3
|
+
import { View } from "react-native";
|
|
4
|
+
import { useBottomSheet } from "@applicaster/zapp-react-native-utils/bottomSheet";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Turns its children into a drag zone for the enclosing DraggableBottomSheet:
|
|
8
|
+
* dragging here moves/dismisses the sheet (used for the modal header bar).
|
|
9
|
+
* Outside a sheet (no context) it renders children unchanged.
|
|
10
|
+
*/
|
|
11
|
+
export const BottomSheetDragArea = ({
|
|
12
|
+
children,
|
|
13
|
+
}: {
|
|
14
|
+
children: React.ReactElement;
|
|
15
|
+
}) => {
|
|
16
|
+
const sheet = useBottomSheet();
|
|
17
|
+
|
|
18
|
+
// Outside a sheet (no context) render children unchanged.
|
|
19
|
+
if (!sheet) return children;
|
|
20
|
+
|
|
21
|
+
return (
|
|
22
|
+
<PanGestureHandler
|
|
23
|
+
simultaneousHandlers={[sheet.masterDrawerRef]}
|
|
24
|
+
shouldCancelWhenOutside={false}
|
|
25
|
+
onGestureEvent={sheet.onDragGestureEvent}
|
|
26
|
+
onHandlerStateChange={sheet.onDragStateChange}
|
|
27
|
+
>
|
|
28
|
+
{/* Old-API PanGestureHandler needs a host-component child; children may
|
|
29
|
+
be a function component (e.g. ModalHeader), so wrap in a View. */}
|
|
30
|
+
<View>{children}</View>
|
|
31
|
+
</PanGestureHandler>
|
|
32
|
+
);
|
|
33
|
+
};
|