@applicaster/zapp-react-native-ui-components 12.0.0-alpha.5882013252 → 12.0.0-alpha.9151207838
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/AnimatedInOut/index.tsx +18 -10
- package/Components/AudioPlayer/AudioPlayer.tsx +9 -1
- package/Components/AudioPlayer/__tests__/__snapshots__/audioPlayer.test.js.snap +5 -0
- package/Components/AudioPlayer/helpers.tsx +1 -0
- package/Components/Image/Image.android.tsx +4 -0
- package/Components/MasterCell/utils/index.ts +2 -2
- package/Components/ModalComponent/BottomSheetModalContent.tsx +121 -0
- package/Components/ModalComponent/Button/Item.tsx +82 -0
- package/Components/ModalComponent/Button/ItemIcon.tsx +60 -0
- package/Components/ModalComponent/Button/ItemLabel.tsx +101 -0
- package/Components/ModalComponent/Button/assets.ts +4 -0
- package/Components/ModalComponent/Button/index.tsx +111 -0
- package/Components/ModalComponent/Header/CloseButton.tsx +59 -0
- package/Components/ModalComponent/Header/Title.tsx +70 -0
- package/Components/ModalComponent/Header/assets.ts +4 -0
- package/Components/ModalComponent/Header/index.tsx +71 -0
- package/Components/ModalComponent/Header/utils.ts +79 -0
- package/Components/ModalComponent/index.tsx +38 -0
- package/Components/ModalComponent/utils.ts +126 -0
- package/Components/PlayerContainer/ErrorDisplay/ErrorDisplay.tsx +4 -7
- package/Components/VideoModal/PlayerDetails.tsx +3 -0
- package/Components/VideoModal/PlayerWrapper.tsx +63 -64
- package/Components/VideoModal/__tests__/PlayerWrapper.test.tsx +3 -2
- package/Components/VideoModal/__tests__/__snapshots__/PlayerWrapper.test.tsx.snap +8 -12
- package/Components/index.js +2 -0
- package/package.json +5 -5
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import { Animated, EasingFunction, StyleProp, ViewStyle } from "react-native";
|
|
3
|
-
|
|
3
|
+
import { usePrevious } from "@applicaster/zapp-react-native-utils/reactHooks/utils";
|
|
4
|
+
import { toBooleanWithDefaultFalse } from "@applicaster/zapp-react-native-utils/booleanUtils";
|
|
4
5
|
import { noop } from "@applicaster/zapp-react-native-utils/functionUtils";
|
|
5
6
|
|
|
6
7
|
type AnimatedInterpolatedStyle =
|
|
@@ -35,11 +36,16 @@ function getAnimation(config: AnimatedInConfig, phase: "in" | "out") {
|
|
|
35
36
|
return config[phase] || config;
|
|
36
37
|
}
|
|
37
38
|
|
|
38
|
-
export function AnimatedInOut(
|
|
39
|
-
|
|
40
|
-
|
|
39
|
+
export function AnimatedInOut({
|
|
40
|
+
visible,
|
|
41
|
+
animationConfig,
|
|
42
|
+
staticStyles = {},
|
|
43
|
+
children,
|
|
44
|
+
}: Props) {
|
|
41
45
|
const [animatedValue] = React.useState(new Animated.Value(visible ? 1 : 0));
|
|
42
|
-
const [animating, setAnimating] = React.useState(
|
|
46
|
+
const [animating, setAnimating] = React.useState(undefined);
|
|
47
|
+
|
|
48
|
+
const previousVisible = usePrevious(toBooleanWithDefaultFalse(visible));
|
|
43
49
|
|
|
44
50
|
function startAnimation(toValue, config) {
|
|
45
51
|
if (animating) {
|
|
@@ -55,7 +61,7 @@ export function AnimatedInOut(props: Props) {
|
|
|
55
61
|
delay,
|
|
56
62
|
useNativeDriver: true,
|
|
57
63
|
}).start(() => {
|
|
58
|
-
setAnimating(
|
|
64
|
+
setAnimating(undefined);
|
|
59
65
|
onAnimationEnd();
|
|
60
66
|
});
|
|
61
67
|
|
|
@@ -63,12 +69,14 @@ export function AnimatedInOut(props: Props) {
|
|
|
63
69
|
}
|
|
64
70
|
|
|
65
71
|
React.useEffect(() => {
|
|
66
|
-
if (visible) {
|
|
72
|
+
if (!previousVisible && visible) {
|
|
67
73
|
startAnimation(1.0, getAnimation(animationConfig, "in"));
|
|
68
|
-
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (previousVisible && !visible) {
|
|
69
77
|
startAnimation(0.0, getAnimation(animationConfig, "out"));
|
|
70
78
|
}
|
|
71
|
-
}, [visible,
|
|
79
|
+
}, [visible, previousVisible]);
|
|
72
80
|
|
|
73
81
|
const styles = visible
|
|
74
82
|
? getAnimation(animationConfig, "in").styles
|
|
@@ -77,7 +85,7 @@ export function AnimatedInOut(props: Props) {
|
|
|
77
85
|
return (
|
|
78
86
|
<Animated.View
|
|
79
87
|
renderToHardwareTextureAndroid={animating}
|
|
80
|
-
style={[styles(animatedValue),
|
|
88
|
+
style={[styles(animatedValue), staticStyles]}
|
|
81
89
|
>
|
|
82
90
|
{children}
|
|
83
91
|
</Animated.View>
|
|
@@ -23,6 +23,7 @@ type Props = {
|
|
|
23
23
|
audio_player_summary_color?: string;
|
|
24
24
|
audio_player_rtl?: boolean;
|
|
25
25
|
magic_background?: boolean;
|
|
26
|
+
audio_player_background_image_query?: string;
|
|
26
27
|
start_time?: string;
|
|
27
28
|
end_time?: string;
|
|
28
29
|
};
|
|
@@ -33,6 +34,7 @@ type Props = {
|
|
|
33
34
|
audio_player_summary_color?: string;
|
|
34
35
|
audio_player_rtl?: string;
|
|
35
36
|
magic_background?: string;
|
|
37
|
+
audio_player_background_image_query?: string;
|
|
36
38
|
audio_player_background_image?: string;
|
|
37
39
|
audio_player_artwork_aspect_ratio?: string;
|
|
38
40
|
lg_tv_audio_player_title_font_family?: string;
|
|
@@ -73,6 +75,11 @@ export function AudioPlayer(props: Props) {
|
|
|
73
75
|
const channelIcon = getProp("audio_player_channel_icon");
|
|
74
76
|
const rtlFlag = getProp("audio_player_rtl");
|
|
75
77
|
const magicBackground = getProp("magic_background");
|
|
78
|
+
|
|
79
|
+
const audioPlayerBackgroundImageQuery = getProp(
|
|
80
|
+
"audio_player_background_image_query"
|
|
81
|
+
);
|
|
82
|
+
|
|
76
83
|
const isRTL = rtlFlag === "1" || rtlFlag === "true" || rtlFlag === true;
|
|
77
84
|
|
|
78
85
|
const titleFontFamily = getProp(
|
|
@@ -149,7 +156,8 @@ export function AudioPlayer(props: Props) {
|
|
|
149
156
|
runTimeFontSize,
|
|
150
157
|
artworkAspectRatio,
|
|
151
158
|
channelIcon,
|
|
152
|
-
magicBackground
|
|
159
|
+
magicBackground,
|
|
160
|
+
audioPlayerBackgroundImageQuery,
|
|
153
161
|
};
|
|
154
162
|
}, [getProp]);
|
|
155
163
|
|
|
@@ -5,6 +5,7 @@ exports[`<AudioPlayer /> renders correctly 1`] = `
|
|
|
5
5
|
config={
|
|
6
6
|
Object {
|
|
7
7
|
"artworkAspectRatio": "1:1",
|
|
8
|
+
"audioPlayerBackgroundImageQuery": "",
|
|
8
9
|
"backgroundColor": "black",
|
|
9
10
|
"backgroundImage": "https://example.com",
|
|
10
11
|
"channelIcon": "https://example.com",
|
|
@@ -26,6 +27,7 @@ exports[`<AudioPlayer /> renders correctly 1`] = `
|
|
|
26
27
|
config={
|
|
27
28
|
Object {
|
|
28
29
|
"artworkAspectRatio": "1:1",
|
|
30
|
+
"audioPlayerBackgroundImageQuery": "",
|
|
29
31
|
"backgroundColor": "black",
|
|
30
32
|
"backgroundImage": "https://example.com",
|
|
31
33
|
"channelIcon": "https://example.com",
|
|
@@ -47,6 +49,7 @@ exports[`<AudioPlayer /> renders correctly 1`] = `
|
|
|
47
49
|
config={
|
|
48
50
|
Object {
|
|
49
51
|
"artworkAspectRatio": "1:1",
|
|
52
|
+
"audioPlayerBackgroundImageQuery": "",
|
|
50
53
|
"backgroundColor": "black",
|
|
51
54
|
"backgroundImage": "https://example.com",
|
|
52
55
|
"channelIcon": "https://example.com",
|
|
@@ -68,6 +71,7 @@ exports[`<AudioPlayer /> renders correctly 1`] = `
|
|
|
68
71
|
config={
|
|
69
72
|
Object {
|
|
70
73
|
"artworkAspectRatio": "1:1",
|
|
74
|
+
"audioPlayerBackgroundImageQuery": "",
|
|
71
75
|
"backgroundColor": "black",
|
|
72
76
|
"backgroundImage": "https://example.com",
|
|
73
77
|
"channelIcon": "https://example.com",
|
|
@@ -96,6 +100,7 @@ exports[`<AudioPlayer /> renders correctly 1`] = `
|
|
|
96
100
|
config={
|
|
97
101
|
Object {
|
|
98
102
|
"artworkAspectRatio": "1:1",
|
|
103
|
+
"audioPlayerBackgroundImageQuery": "",
|
|
99
104
|
"backgroundColor": "black",
|
|
100
105
|
"backgroundImage": "https://example.com",
|
|
101
106
|
"channelIcon": "https://example.com",
|
|
@@ -15,6 +15,8 @@ export const QBImage = (props: FastImageProps) => {
|
|
|
15
15
|
headers: props.source.headers,
|
|
16
16
|
priority: props.source.priority,
|
|
17
17
|
cache: props.source.cache,
|
|
18
|
+
maxWidth: props.source.maxWidth,
|
|
19
|
+
maxHeight: props.source.maxHeight,
|
|
18
20
|
};
|
|
19
21
|
}, [
|
|
20
22
|
...(typeof props.source === "object"
|
|
@@ -23,6 +25,8 @@ export const QBImage = (props: FastImageProps) => {
|
|
|
23
25
|
props.source?.priority,
|
|
24
26
|
props.source?.cache,
|
|
25
27
|
props.source?.headers,
|
|
28
|
+
props.source?.maxWidth,
|
|
29
|
+
props.source?.maxHeight,
|
|
26
30
|
]
|
|
27
31
|
: []),
|
|
28
32
|
]);
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import React, {
|
|
2
|
+
useCallback,
|
|
3
|
+
useEffect,
|
|
4
|
+
useMemo,
|
|
5
|
+
useRef,
|
|
6
|
+
useState,
|
|
7
|
+
} from "react";
|
|
8
|
+
import { View, LayoutChangeEvent, ScrollView } from "react-native";
|
|
9
|
+
import { Button } from "./Button";
|
|
10
|
+
import { ItemIconProps } from "./Button/ItemIcon";
|
|
11
|
+
import { ItemProps } from "./Button/Item";
|
|
12
|
+
import { ItemLabelProps } from "./Button/ItemLabel";
|
|
13
|
+
import {
|
|
14
|
+
defaultItemIconProps,
|
|
15
|
+
defaultItemLabelProps,
|
|
16
|
+
defaultItemProps,
|
|
17
|
+
} from "./utils";
|
|
18
|
+
import { useTheme } from "@applicaster/zapp-react-native-utils/theme";
|
|
19
|
+
|
|
20
|
+
import { ModalHeader } from "./Header";
|
|
21
|
+
|
|
22
|
+
type ModalComponentProps = {
|
|
23
|
+
items: any[];
|
|
24
|
+
current_selection?: any;
|
|
25
|
+
onPress: (item: any) => void;
|
|
26
|
+
width: number;
|
|
27
|
+
currentRoute: boolean;
|
|
28
|
+
summary?: string;
|
|
29
|
+
title?: string;
|
|
30
|
+
maxHeight?: number;
|
|
31
|
+
dismiss: () => void;
|
|
32
|
+
buttonComponent?: React.ComponentType;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
export function BottomSheetModalContent(props: ModalComponentProps) {
|
|
36
|
+
const {
|
|
37
|
+
items,
|
|
38
|
+
currentRoute,
|
|
39
|
+
maxHeight,
|
|
40
|
+
current_selection = null,
|
|
41
|
+
onPress,
|
|
42
|
+
dismiss,
|
|
43
|
+
summary,
|
|
44
|
+
title,
|
|
45
|
+
buttonComponent: ButtonComponent = Button,
|
|
46
|
+
} = props;
|
|
47
|
+
|
|
48
|
+
const [headerHeight, setHeaderHeight] = useState(0);
|
|
49
|
+
const route = useRef(currentRoute);
|
|
50
|
+
const theme = useTheme<BaseThemePropertiesMobile>();
|
|
51
|
+
|
|
52
|
+
const maxContentHeight = maxHeight
|
|
53
|
+
? maxHeight - headerHeight - Number(theme.modal_bottom_sheet_padding_top)
|
|
54
|
+
: undefined;
|
|
55
|
+
|
|
56
|
+
const onHeaderLayout = useCallback((event: LayoutChangeEvent) => {
|
|
57
|
+
setHeaderHeight(event.nativeEvent.layout.height);
|
|
58
|
+
}, []);
|
|
59
|
+
|
|
60
|
+
useEffect(() => {
|
|
61
|
+
if (currentRoute !== route.current) {
|
|
62
|
+
props.dismiss();
|
|
63
|
+
}
|
|
64
|
+
}, [currentRoute]);
|
|
65
|
+
|
|
66
|
+
const iconBaseProps = useMemo<ItemIconProps>(() => {
|
|
67
|
+
return defaultItemIconProps(theme);
|
|
68
|
+
}, [theme]);
|
|
69
|
+
|
|
70
|
+
const itemBaseProps = useMemo<ItemProps>(() => {
|
|
71
|
+
return defaultItemProps(theme, props.width);
|
|
72
|
+
}, [theme, props.width]);
|
|
73
|
+
|
|
74
|
+
const labelBaseProps = useMemo<ItemLabelProps>(() => {
|
|
75
|
+
return defaultItemLabelProps(theme, props.width);
|
|
76
|
+
}, [theme, props.width]);
|
|
77
|
+
|
|
78
|
+
const handlePress = (item: any) => {
|
|
79
|
+
onPress(item);
|
|
80
|
+
dismiss();
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
return (
|
|
84
|
+
<View
|
|
85
|
+
style={{
|
|
86
|
+
paddingTop: Number(theme.modal_bottom_sheet_padding_top),
|
|
87
|
+
}}
|
|
88
|
+
>
|
|
89
|
+
<ModalHeader
|
|
90
|
+
width={props.width}
|
|
91
|
+
dismiss={dismiss}
|
|
92
|
+
configuration={theme}
|
|
93
|
+
onLayout={onHeaderLayout}
|
|
94
|
+
summary={summary}
|
|
95
|
+
title={title}
|
|
96
|
+
/>
|
|
97
|
+
<ScrollView
|
|
98
|
+
bounces={false}
|
|
99
|
+
style={{ maxHeight: maxContentHeight }}
|
|
100
|
+
contentContainerStyle={{
|
|
101
|
+
paddingBottom: Number(theme.modal_bottom_sheet_padding_bottom),
|
|
102
|
+
paddingTop: Number(theme.modal_bottom_sheet_padding_top),
|
|
103
|
+
}}
|
|
104
|
+
>
|
|
105
|
+
{items.map((item, index) => (
|
|
106
|
+
<ButtonComponent
|
|
107
|
+
key={index}
|
|
108
|
+
width={props.width}
|
|
109
|
+
configuration={theme}
|
|
110
|
+
selectedItem={current_selection}
|
|
111
|
+
item={item}
|
|
112
|
+
onPress={handlePress}
|
|
113
|
+
iconBaseProps={iconBaseProps}
|
|
114
|
+
itemBaseProps={itemBaseProps}
|
|
115
|
+
labelBaseProps={labelBaseProps}
|
|
116
|
+
/>
|
|
117
|
+
))}
|
|
118
|
+
</ScrollView>
|
|
119
|
+
</View>
|
|
120
|
+
);
|
|
121
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import React, { ReactChild } from "react";
|
|
2
|
+
import { View, StyleSheet } from "react-native";
|
|
3
|
+
|
|
4
|
+
export type ItemProps = {
|
|
5
|
+
backgroundColor: string;
|
|
6
|
+
focusedBackgroundColor: string;
|
|
7
|
+
selectedBackgroundColor?: string;
|
|
8
|
+
focusectedBackgroundColor?: string;
|
|
9
|
+
borderRadius: number;
|
|
10
|
+
marginBottom: number;
|
|
11
|
+
marginLeft: number;
|
|
12
|
+
marginRight: number;
|
|
13
|
+
marginTop: number;
|
|
14
|
+
paddingTop: number;
|
|
15
|
+
paddingBottom: number;
|
|
16
|
+
paddingRight: number;
|
|
17
|
+
paddingLeft: number;
|
|
18
|
+
focused?: boolean;
|
|
19
|
+
selected?: boolean;
|
|
20
|
+
children?: ReactChild[];
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const styles = StyleSheet.create({
|
|
24
|
+
container: {
|
|
25
|
+
flexDirection: "row",
|
|
26
|
+
justifyContent: "space-between",
|
|
27
|
+
},
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
function getBackgroundColor({
|
|
31
|
+
selected,
|
|
32
|
+
focused,
|
|
33
|
+
backgroundColor,
|
|
34
|
+
focusedBackgroundColor,
|
|
35
|
+
selectedBackgroundColor,
|
|
36
|
+
focusectedBackgroundColor,
|
|
37
|
+
}) {
|
|
38
|
+
switch (true) {
|
|
39
|
+
case selected && focused:
|
|
40
|
+
return focusectedBackgroundColor;
|
|
41
|
+
case selected && !focused:
|
|
42
|
+
return selectedBackgroundColor;
|
|
43
|
+
case !selected && focused:
|
|
44
|
+
return focusedBackgroundColor;
|
|
45
|
+
default:
|
|
46
|
+
return backgroundColor;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function Item(props: ItemProps) {
|
|
51
|
+
const {
|
|
52
|
+
backgroundColor,
|
|
53
|
+
focusedBackgroundColor,
|
|
54
|
+
focusectedBackgroundColor,
|
|
55
|
+
selectedBackgroundColor,
|
|
56
|
+
children,
|
|
57
|
+
focused,
|
|
58
|
+
selected,
|
|
59
|
+
...itemStyles
|
|
60
|
+
} = props;
|
|
61
|
+
|
|
62
|
+
return (
|
|
63
|
+
<View
|
|
64
|
+
style={[
|
|
65
|
+
styles.container,
|
|
66
|
+
itemStyles,
|
|
67
|
+
{
|
|
68
|
+
backgroundColor: getBackgroundColor({
|
|
69
|
+
selected,
|
|
70
|
+
focused,
|
|
71
|
+
focusectedBackgroundColor,
|
|
72
|
+
focusedBackgroundColor,
|
|
73
|
+
selectedBackgroundColor,
|
|
74
|
+
backgroundColor,
|
|
75
|
+
}),
|
|
76
|
+
},
|
|
77
|
+
]}
|
|
78
|
+
>
|
|
79
|
+
{children}
|
|
80
|
+
</View>
|
|
81
|
+
);
|
|
82
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { View } from "react-native";
|
|
3
|
+
import { QBImage } from "@applicaster/zapp-react-native-ui-components/Components";
|
|
4
|
+
|
|
5
|
+
export type ItemIconProps = {
|
|
6
|
+
width: number;
|
|
7
|
+
height: number;
|
|
8
|
+
asset?: string | string[] | CellActionAssetComponent;
|
|
9
|
+
flavour?: "flavour_1" | "flavour_2";
|
|
10
|
+
marginTop: number;
|
|
11
|
+
marginBottom: number;
|
|
12
|
+
marginLeft: number;
|
|
13
|
+
marginRight: number;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
function isImageAsset(asset) {
|
|
17
|
+
return typeof asset === "string" || Array.isArray(asset);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function getImageAsset(asset, flavour) {
|
|
21
|
+
if (typeof asset === "string") return asset;
|
|
22
|
+
|
|
23
|
+
if (flavour) {
|
|
24
|
+
const flavourIndex = Number(flavour.replace("flavour_", ""));
|
|
25
|
+
if (flavourIndex > -1) return asset?.[flavourIndex - 1];
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return asset?.[0];
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function ItemIcon(props: ItemIconProps) {
|
|
32
|
+
const { width, height, asset, flavour, ...styles } = props;
|
|
33
|
+
|
|
34
|
+
if (isImageAsset(asset)) {
|
|
35
|
+
const imageAsset = getImageAsset(asset, flavour);
|
|
36
|
+
|
|
37
|
+
return (
|
|
38
|
+
<View style={styles}>
|
|
39
|
+
<QBImage
|
|
40
|
+
fadeDuration={0}
|
|
41
|
+
source={{ uri: imageAsset }}
|
|
42
|
+
style={{ width, height }}
|
|
43
|
+
/>
|
|
44
|
+
</View>
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const AssetComponent = asset as CellActionAssetComponent;
|
|
49
|
+
|
|
50
|
+
return (
|
|
51
|
+
<View style={styles}>
|
|
52
|
+
<AssetComponent
|
|
53
|
+
width={width}
|
|
54
|
+
height={height}
|
|
55
|
+
style={styles}
|
|
56
|
+
flavour={flavour}
|
|
57
|
+
/>
|
|
58
|
+
</View>
|
|
59
|
+
);
|
|
60
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { View, Text, StyleSheet } from "react-native";
|
|
3
|
+
import { textTransform } from "@applicaster/zapp-react-native-utils/cellUtils";
|
|
4
|
+
|
|
5
|
+
export type ItemLabelProps = {
|
|
6
|
+
label?: string | Record<string, string>;
|
|
7
|
+
fontFamily: string;
|
|
8
|
+
letterSpacing: number;
|
|
9
|
+
fontSize: number;
|
|
10
|
+
color: string;
|
|
11
|
+
focusColor: string;
|
|
12
|
+
selectedColor?: string;
|
|
13
|
+
hoverSelectedColor?: string;
|
|
14
|
+
lineHeight: number;
|
|
15
|
+
marginBottom: number;
|
|
16
|
+
marginTop: number;
|
|
17
|
+
marginLeft: number;
|
|
18
|
+
marginRight: number;
|
|
19
|
+
transform: string;
|
|
20
|
+
maxWidth: number;
|
|
21
|
+
focused?: boolean;
|
|
22
|
+
selected?: boolean;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const styles = StyleSheet.create({
|
|
26
|
+
container: {
|
|
27
|
+
justifyContent: "center",
|
|
28
|
+
},
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
function getColor({
|
|
32
|
+
selected,
|
|
33
|
+
focused,
|
|
34
|
+
color,
|
|
35
|
+
selectedColor,
|
|
36
|
+
focusColor,
|
|
37
|
+
hoverSelectedColor,
|
|
38
|
+
}) {
|
|
39
|
+
switch (true) {
|
|
40
|
+
case selected && focused:
|
|
41
|
+
return hoverSelectedColor;
|
|
42
|
+
case selected && !focused:
|
|
43
|
+
return selectedColor;
|
|
44
|
+
case !selected && focused:
|
|
45
|
+
return focusColor;
|
|
46
|
+
default:
|
|
47
|
+
return color;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function ItemLabel(props: ItemLabelProps) {
|
|
52
|
+
const {
|
|
53
|
+
label,
|
|
54
|
+
fontFamily,
|
|
55
|
+
letterSpacing,
|
|
56
|
+
fontSize,
|
|
57
|
+
color,
|
|
58
|
+
selectedColor,
|
|
59
|
+
focusColor,
|
|
60
|
+
hoverSelectedColor,
|
|
61
|
+
lineHeight,
|
|
62
|
+
marginBottom,
|
|
63
|
+
marginTop,
|
|
64
|
+
marginLeft,
|
|
65
|
+
marginRight,
|
|
66
|
+
transform,
|
|
67
|
+
maxWidth,
|
|
68
|
+
focused,
|
|
69
|
+
selected,
|
|
70
|
+
} = props;
|
|
71
|
+
|
|
72
|
+
return (
|
|
73
|
+
<View
|
|
74
|
+
style={[
|
|
75
|
+
styles.container,
|
|
76
|
+
{ marginBottom, marginLeft, marginRight, marginTop, maxWidth },
|
|
77
|
+
]}
|
|
78
|
+
>
|
|
79
|
+
<Text
|
|
80
|
+
style={{
|
|
81
|
+
fontFamily,
|
|
82
|
+
fontSize,
|
|
83
|
+
letterSpacing,
|
|
84
|
+
color: getColor({
|
|
85
|
+
selected,
|
|
86
|
+
focused,
|
|
87
|
+
color,
|
|
88
|
+
selectedColor,
|
|
89
|
+
hoverSelectedColor,
|
|
90
|
+
focusColor,
|
|
91
|
+
}),
|
|
92
|
+
lineHeight,
|
|
93
|
+
}}
|
|
94
|
+
numberOfLines={1}
|
|
95
|
+
ellipsizeMode="tail"
|
|
96
|
+
>
|
|
97
|
+
{textTransform(transform, label)}
|
|
98
|
+
</Text>
|
|
99
|
+
</View>
|
|
100
|
+
);
|
|
101
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
/* eslint-disable max-len */
|
|
2
|
+
|
|
3
|
+
export const defaultSelectedAsset: string =
|
|
4
|
+
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEgAAABICAYAAABV7bNHAAAACXBIWXMAACE4AAAhOAFFljFgAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAGsSURBVHgB7drdaYRAFIbhk2yuBTuwlXSQDrKdrOnErSSlpATBe0nOBxEMEXV+nDnjfg8MwiK4vKjMDIoQERERERERERHRY+j7vtHxJvTfb5wvHd/DMLyLpyc5IcTRw6eOZvrtcrlcq6q6i6PTBVqKM/GJdKpAa3EmrpGe5ST2xIFxHF/FwSnuoL1x1L2u66s4KD7QkXGg6EBHx4FiA6WIA0UGShUHiguUMg4UFSh1HCgmUI44UESgXHEgaCatf/wWslLeeY1GMsWBF/GEOHpodeouGkl8Vso7rtFIxjjg9YhNcea/+W4nrFyjkcxxwDnQUpxJrEhW4oBToLU4k9BIluKA60t6M6i+kzrfF7e1OODziLV6uG2d53onWYwDvi/pViJGshoHvCeKsSJZjgNBM+nQSNbjQPBSwzdSCXEgylrMNVIpcSDaYnVvJPWhA9OAZuO87HEg6mreIdIWE3Eg+nZHhEhm4sAh+0EBkUzFgcM2zDwimYsDh+4oOkQyGQcO33LdEclsHEiyJ70SyXScpBAJX3vNRif01yxSJ7SMH1USEREREREREREV7Ad//SBSU+GIIAAAAABJRU5ErkJggg==";
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import React, { useMemo, useState } from "react";
|
|
2
|
+
import { StyleSheet, TouchableOpacity, View } from "react-native";
|
|
3
|
+
import { Item, ItemProps } from "./Item";
|
|
4
|
+
import { ItemIcon, ItemIconProps } from "./ItemIcon";
|
|
5
|
+
import { ItemLabel, ItemLabelProps } from "./ItemLabel";
|
|
6
|
+
import { defaultSelectedAsset } from "./assets";
|
|
7
|
+
import * as assets from "./assets";
|
|
8
|
+
|
|
9
|
+
type ButtonProps = {
|
|
10
|
+
configuration: any;
|
|
11
|
+
width: number;
|
|
12
|
+
selectedItem?: any;
|
|
13
|
+
item: any; // Adjust type as needed
|
|
14
|
+
onPress: (item: any) => void; // Adjust type as needed
|
|
15
|
+
iconBaseProps?: ItemIconProps;
|
|
16
|
+
itemBaseProps?: ItemProps;
|
|
17
|
+
labelBaseProps?: ItemLabelProps;
|
|
18
|
+
disabled?: boolean;
|
|
19
|
+
label?: string | Record<string, string>;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const styles = StyleSheet.create({
|
|
23
|
+
label_icon_container: {
|
|
24
|
+
flexDirection: "row",
|
|
25
|
+
alignItems: "center",
|
|
26
|
+
},
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
export function Button({
|
|
30
|
+
selectedItem,
|
|
31
|
+
item,
|
|
32
|
+
onPress,
|
|
33
|
+
configuration,
|
|
34
|
+
width,
|
|
35
|
+
iconBaseProps,
|
|
36
|
+
itemBaseProps,
|
|
37
|
+
labelBaseProps,
|
|
38
|
+
label,
|
|
39
|
+
disabled = false,
|
|
40
|
+
}: ButtonProps) {
|
|
41
|
+
const [focused, setFocused] = useState(false);
|
|
42
|
+
|
|
43
|
+
const selected = useMemo(
|
|
44
|
+
() => selectedItem && item.value === selectedItem?.value,
|
|
45
|
+
[selectedItem, selectedItem]
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
const itemProps = useMemo<ItemProps>(
|
|
49
|
+
() => ({
|
|
50
|
+
...itemBaseProps,
|
|
51
|
+
width,
|
|
52
|
+
}),
|
|
53
|
+
[configuration, width]
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
const itemIconProps = useMemo<ItemIconProps>(
|
|
57
|
+
() => ({
|
|
58
|
+
...iconBaseProps,
|
|
59
|
+
asset: configuration[item.asset] ?? assets[item.asset] ?? item.asset,
|
|
60
|
+
}),
|
|
61
|
+
[configuration, item.asset]
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
const selectedItemIconProps = useMemo<ItemIconProps>(
|
|
65
|
+
() => ({
|
|
66
|
+
...iconBaseProps,
|
|
67
|
+
asset:
|
|
68
|
+
configuration["modal_bottom_sheet_item_selected_icon"] ||
|
|
69
|
+
defaultSelectedAsset,
|
|
70
|
+
marginRight: 10,
|
|
71
|
+
}),
|
|
72
|
+
[configuration]
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
const itemLabelProps = useMemo<ItemLabelProps>(
|
|
76
|
+
() => ({
|
|
77
|
+
...labelBaseProps,
|
|
78
|
+
label: label ?? configuration[item?.label] ?? item?.label ?? null,
|
|
79
|
+
}),
|
|
80
|
+
[configuration, item?.label]
|
|
81
|
+
);
|
|
82
|
+
|
|
83
|
+
if (disabled) return null;
|
|
84
|
+
|
|
85
|
+
return (
|
|
86
|
+
<View style={{ maxWidth: width }}>
|
|
87
|
+
<TouchableOpacity
|
|
88
|
+
activeOpacity={1}
|
|
89
|
+
onPress={() => onPress(item)}
|
|
90
|
+
onPressIn={() => setFocused(true)}
|
|
91
|
+
onPressOut={() => setFocused(false)}
|
|
92
|
+
>
|
|
93
|
+
<Item {...itemProps} focused={focused} selected={selected}>
|
|
94
|
+
<View style={styles.label_icon_container}>
|
|
95
|
+
{itemIconProps.asset && itemIconProps.asset.length > 0 && (
|
|
96
|
+
<ItemIcon {...itemIconProps} />
|
|
97
|
+
)}
|
|
98
|
+
{itemLabelProps.label && (
|
|
99
|
+
<ItemLabel
|
|
100
|
+
{...itemLabelProps}
|
|
101
|
+
focused={focused}
|
|
102
|
+
selected={selected}
|
|
103
|
+
/>
|
|
104
|
+
)}
|
|
105
|
+
</View>
|
|
106
|
+
{selected && <ItemIcon {...selectedItemIconProps} />}
|
|
107
|
+
</Item>
|
|
108
|
+
</TouchableOpacity>
|
|
109
|
+
</View>
|
|
110
|
+
);
|
|
111
|
+
}
|