@applicaster/zapp-react-native-ui-components 12.0.0-alpha.6602834797 → 12.0.0-alpha.7101461483

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 (35) hide show
  1. package/Components/GeneralContentScreen/GeneralContentScreen.tsx +5 -5
  2. package/Components/HandlePlayable/HandlePlayable.tsx +1 -1
  3. package/Components/Image/Image.android.tsx +0 -1
  4. package/Components/MasterCell/DefaultComponents/BorderContainerView/index.tsx +0 -1
  5. package/Components/MasterCell/DefaultComponents/CellBadge/index.tsx +21 -8
  6. package/Components/MasterCell/SharedUI/CollapsibleTextContainer/index.ts +10 -6
  7. package/Components/MasterCell/utils/index.ts +2 -2
  8. package/Components/ModalComponent/BottomSheetModalContent.tsx +121 -0
  9. package/Components/ModalComponent/Button/Item.tsx +82 -0
  10. package/Components/ModalComponent/Button/ItemIcon.tsx +60 -0
  11. package/Components/ModalComponent/Button/ItemLabel.tsx +101 -0
  12. package/Components/ModalComponent/Button/assets.ts +4 -0
  13. package/Components/ModalComponent/Button/index.tsx +111 -0
  14. package/Components/ModalComponent/Header/CloseButton.tsx +59 -0
  15. package/Components/ModalComponent/Header/Title.tsx +70 -0
  16. package/Components/ModalComponent/Header/assets.ts +4 -0
  17. package/Components/ModalComponent/Header/index.tsx +71 -0
  18. package/Components/ModalComponent/Header/utils.ts +79 -0
  19. package/Components/ModalComponent/index.tsx +38 -0
  20. package/Components/ModalComponent/utils.ts +126 -0
  21. package/Components/River/River.tsx +8 -5
  22. package/Components/River/useScreenConfiguration.ts +3 -4
  23. package/Components/Screen/__tests__/Screen.test.tsx +40 -46
  24. package/Components/Screen/index.tsx +0 -1
  25. package/Components/Screen/orientationHandler.ts +1 -1
  26. package/Components/TrackedView/index.tsx +6 -3
  27. package/Components/VideoLive/LiveImageManager.ts +42 -13
  28. package/Components/VideoLive/PlayerLiveImageComponent.tsx +79 -73
  29. package/Components/VideoModal/PlayerDetails.tsx +3 -0
  30. package/Components/VideoModal/PlayerWrapper.tsx +5 -3
  31. package/Components/VideoModal/hooks/useModalSize.ts +13 -4
  32. package/Components/index.js +2 -0
  33. package/Decorators/RiverResolver/index.tsx +0 -4
  34. package/Decorators/index.tsx +0 -4
  35. package/package.json +5 -6
@@ -52,13 +52,13 @@ export const GeneralContentScreen = ({
52
52
  React.useState(actionsInitialStateSetters.length === 0);
53
53
 
54
54
  useEffect(() => {
55
- log_info(
56
- `ScreenContainer: starting to check river action provider ready, current status: ${riverActionProvidersReady}`,
57
- { actionsInitialStateSetters }
58
- );
59
-
60
55
  if (!riverActionProvidersReady) {
61
56
  if (actionsInitialStateSetters.length > 0) {
57
+ log_info(
58
+ "ScreenContainer: starting to check river action providers to initialize",
59
+ { actionsInitialStateSetters }
60
+ );
61
+
62
62
  allSettled(actionsInitialStateSetters).finally(() => {
63
63
  log_info(
64
64
  "ScreenContainer: action provider ready, completed. Starting to present screen"
@@ -104,7 +104,7 @@ export function HandlePlayable({
104
104
  const [Player, playerModuleProperties] = getPlayer(item, state);
105
105
 
106
106
  const { module: CastPlugin } =
107
- findPluginByIdentifier(CHROMECAST_PLUGIN_ID, state.plugins) || {};
107
+ findPluginByIdentifier(CHROMECAST_PLUGIN_ID, state.plugins, true) || {};
108
108
 
109
109
  const [playable, setPlayable] =
110
110
  React.useState<Nullable<PlayableComponent>>(null);
@@ -1,5 +1,4 @@
1
1
  import React from "react";
2
-
3
2
  import FastImage, {
4
3
  FastImageProps,
5
4
  } from "@applicaster/react-native-fast-image";
@@ -152,7 +152,6 @@ export const BorderContainerView = (props: Props) => {
152
152
  ...updatedPaddings,
153
153
  width: updatedWidth,
154
154
  height: updatedHeight,
155
- ...borderStyleForMissingBorder,
156
155
  };
157
156
 
158
157
  return (
@@ -1,6 +1,7 @@
1
1
  import {
2
2
  compact,
3
3
  ifElseFocusedSelected,
4
+ ifElseSelected,
4
5
  } from "@applicaster/zapp-react-native-utils/cellUtils";
5
6
 
6
7
  import { getPositionStyles } from "./utils";
@@ -12,9 +13,15 @@ type Props = {
12
13
  value: Function;
13
14
  state: string;
14
15
  visible?: Boolean;
16
+ isMobile?: Boolean;
15
17
  };
16
18
 
17
- export const CellBadge = ({ value, state, visible = true }: Props) => {
19
+ export const CellBadge = ({
20
+ value,
21
+ state,
22
+ visible = true,
23
+ isMobile = false,
24
+ }: Props) => {
18
25
  if (!value("cell_badge_switch") || !visible) {
19
26
  return null;
20
27
  }
@@ -45,13 +52,19 @@ export const CellBadge = ({ value, state, visible = true }: Props) => {
45
52
  data: [
46
53
  {
47
54
  func: () => {
48
- return ifElseFocusedSelected(
49
- state,
50
- value("cell_badge_focused"),
51
- value("cell_badge_selected"),
52
- value("cell_badge_focused_selected"),
53
- value("cell_badge_default")
54
- );
55
+ return isMobile
56
+ ? ifElseSelected(
57
+ state,
58
+ value("cell_badge_selected"),
59
+ value("cell_badge_default")
60
+ )
61
+ : ifElseFocusedSelected(
62
+ state,
63
+ value("cell_badge_focused"),
64
+ value("cell_badge_selected"),
65
+ value("cell_badge_focused_selected"),
66
+ value("cell_badge_default")
67
+ );
55
68
  },
56
69
  args: [],
57
70
  propName: "uri",
@@ -50,13 +50,17 @@ export const CollapsibleTextContainer = ({
50
50
  func: (data) => {
51
51
  const value = getValue("background_color");
52
52
 
53
- // check if value is a reference to an extension
54
- if (value.startsWith("extensions")) {
55
- return pathOr(value, value.split("."), data);
56
- } else {
57
- // return default value
58
- return additionalStyles.backgroundColor;
53
+ const valueFromData = pathOr(value, value.split("."), data);
54
+
55
+ if (
56
+ valueFromData &&
57
+ (valueFromData.startsWith("#") || valueFromData.startsWith("rgba("))
58
+ ) {
59
+ return valueFromData;
59
60
  }
61
+
62
+ // return default value
63
+ return additionalStyles.backgroundColor;
60
64
  },
61
65
  propName: "backgroundColor",
62
66
  },
@@ -285,8 +285,8 @@ export const useBehaviorUpdate = (behavior: Behavior) => {
285
285
  }
286
286
  }
287
287
  }, [behavior]);
288
-
289
- useEffect(() => {
288
+
289
+ useEffect(() => {
290
290
  if (!behavior) {
291
291
  return;
292
292
  }
@@ -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
+ }
@@ -0,0 +1,59 @@
1
+ import React, { useMemo } from "react";
2
+ import { TouchableOpacity } from "react-native";
3
+ import { QBImage } from "@applicaster/zapp-react-native-ui-components/Components";
4
+ // @ts-ignore
5
+ import { defaultCloseAsset } from "./assets";
6
+
7
+ export type CloseButtonProps = {
8
+ enabled: boolean;
9
+ close: () => void;
10
+ asset: string | undefined;
11
+ assetFocused: string | undefined;
12
+ height: number;
13
+ width: number;
14
+ marginTop: number;
15
+ marginBottom: number;
16
+ marginLeft: number;
17
+ marginRight: number;
18
+ };
19
+
20
+ export function CloseButton(props: CloseButtonProps) {
21
+ const {
22
+ enabled,
23
+ width,
24
+ height,
25
+ marginBottom,
26
+ marginTop,
27
+ marginLeft,
28
+ marginRight,
29
+ asset,
30
+ assetFocused,
31
+ close,
32
+ } = props;
33
+
34
+ const [focused, setFocus] = React.useState(null);
35
+
36
+ const uri = useMemo(
37
+ () => (focused ? assetFocused : asset) || defaultCloseAsset,
38
+ [asset, assetFocused, focused]
39
+ );
40
+
41
+ if (!enabled) return null;
42
+
43
+ return (
44
+ <TouchableOpacity
45
+ activeOpacity={1}
46
+ style={{
47
+ marginBottom,
48
+ marginTop,
49
+ marginLeft,
50
+ marginRight,
51
+ }}
52
+ onPress={close}
53
+ onPressIn={() => setFocus(true)}
54
+ onPressOut={() => setFocus(false)}
55
+ >
56
+ <QBImage fadeDuration={0} source={{ uri }} style={{ width, height }} />
57
+ </TouchableOpacity>
58
+ );
59
+ }