@applicaster/zapp-react-native-ui-components 12.0.0-rc.6 → 12.0.0-rc.60

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 (108) hide show
  1. package/Components/AudioPlayer/AudioPlayer.tsx +9 -1
  2. package/Components/AudioPlayer/__tests__/__snapshots__/audioPlayer.test.js.snap +5 -0
  3. package/Components/AudioPlayer/helpers.tsx +1 -0
  4. package/Components/Cell/Cell.tsx +2 -2
  5. package/Components/Cell/CellWithFocusable.tsx +21 -14
  6. package/Components/Cell/TvOSCellComponent.tsx +2 -2
  7. package/Components/ErrorScreen/index.tsx +1 -1
  8. package/Components/FocusableCell/index.tsx +7 -7
  9. package/Components/FocusableList/FocusableChild.ts +24 -14
  10. package/Components/FocusableList/FocusableItem.tsx +1 -1
  11. package/Components/FocusableList/FocusableListItemWrapper.tsx +76 -0
  12. package/Components/FocusableList/hooks/useCellState.android.ts +3 -1
  13. package/Components/FocusableList/index.tsx +26 -25
  14. package/Components/GeneralContentScreen/GeneralContentScreen.tsx +11 -8
  15. package/Components/GeneralContentScreen/utils/__tests__/useCurationAPI.test.js +13 -6
  16. package/Components/GeneralContentScreen/utils/useCurationAPI.ts +1 -1
  17. package/Components/HandlePlayable/HandlePlayable.tsx +1 -1
  18. package/Components/HookRenderer/index.tsx +1 -6
  19. package/Components/Image/Image.android.tsx +3 -26
  20. package/Components/Image/Image.tsx +18 -2
  21. package/Components/Image/utils/index.ts +39 -0
  22. package/Components/Layout/TV/__tests__/index.test.tsx +1 -34
  23. package/Components/Layout/TV/index.tsx +20 -36
  24. package/Components/MasterCell/DefaultComponents/BorderContainerView/index.tsx +0 -1
  25. package/Components/MasterCell/DefaultComponents/CellBadge/index.tsx +21 -8
  26. package/Components/MasterCell/DefaultComponents/Image/Image.android.tsx +9 -26
  27. package/Components/MasterCell/DefaultComponents/Image/Image.ios.tsx +5 -3
  28. package/Components/MasterCell/DefaultComponents/Image/hooks/useImageSize.ts +65 -0
  29. package/Components/MasterCell/DefaultComponents/ImageContainer/index.tsx +5 -1
  30. package/Components/MasterCell/DefaultComponents/LiveImage/index.tsx +17 -2
  31. package/Components/MasterCell/DefaultComponents/SecondaryImage/Image.tsx +3 -2
  32. package/Components/MasterCell/DefaultComponents/Toggle.tsx +5 -1
  33. package/Components/MasterCell/DefaultComponents/__tests__/image.test.js +1 -1
  34. package/Components/MasterCell/SharedUI/CollapsibleTextContainer/index.ts +6 -10
  35. package/Components/MasterCell/hooks/useAsyncRendering/index.ts +1 -1
  36. package/Components/MasterCell/utils/index.ts +16 -5
  37. package/Components/ModalComponent/BottomSheetModalContent.tsx +121 -0
  38. package/Components/ModalComponent/Button/Item.tsx +82 -0
  39. package/Components/ModalComponent/Button/ItemIcon.tsx +60 -0
  40. package/Components/ModalComponent/Button/ItemLabel.tsx +101 -0
  41. package/Components/ModalComponent/Button/assets.ts +4 -0
  42. package/Components/ModalComponent/Button/index.tsx +111 -0
  43. package/Components/ModalComponent/Header/CloseButton.tsx +59 -0
  44. package/Components/ModalComponent/Header/Title.tsx +70 -0
  45. package/Components/ModalComponent/Header/assets.ts +4 -0
  46. package/Components/ModalComponent/Header/index.tsx +71 -0
  47. package/Components/ModalComponent/Header/utils.ts +79 -0
  48. package/Components/ModalComponent/index.tsx +38 -0
  49. package/Components/ModalComponent/utils.ts +126 -0
  50. package/Components/PlayerContainer/PlayerContainer.tsx +61 -30
  51. package/Components/PlayerContainer/ProgramInfo/index.tsx +3 -1
  52. package/Components/PlayerImageBackground/index.tsx +34 -8
  53. package/Components/River/ComponentsMap/ComponentsMap.tsx +91 -2
  54. package/Components/River/RefreshControl.tsx +55 -1
  55. package/Components/River/River.tsx +8 -5
  56. package/Components/River/TV/River.tsx +2 -2
  57. package/Components/River/__tests__/__snapshots__/componentsMap.test.js.snap +1 -1
  58. package/Components/River/__tests__/componentsMap.test.js +7 -0
  59. package/Components/River/useScreenConfiguration.ts +5 -6
  60. package/Components/RouteManager/__tests__/__snapshots__/routeManager.test.js.snap +1 -0
  61. package/Components/RouteManager/__tests__/routeManager.test.js +9 -2
  62. package/Components/RouteManager/index.tsx +5 -3
  63. package/Components/Screen/__tests__/Screen.test.tsx +48 -36
  64. package/Components/Screen/__tests__/__snapshots__/Screen.test.tsx.snap +24 -6
  65. package/Components/Screen/__tests__/navigationHandler.test.ts +1 -178
  66. package/Components/Screen/index.tsx +103 -44
  67. package/Components/Screen/navigationHandler.ts +0 -82
  68. package/Components/Screen/orientationHandler.ts +1 -1
  69. package/Components/ScreenResolver/index.tsx +1 -1
  70. package/Components/Tabs/TV/styles.ts +1 -1
  71. package/Components/TrackedView/index.tsx +6 -3
  72. package/Components/VideoLive/LiveImageManager.ts +42 -13
  73. package/Components/VideoLive/PlayerLiveImageComponent.tsx +81 -72
  74. package/Components/VideoLive/__tests__/PlayerLiveImageComponent.test.tsx +45 -3
  75. package/Components/VideoLive/__tests__/__snapshots__/PlayerLiveImageComponent.test.tsx.snap +18 -28
  76. package/Components/VideoModal/ModalAnimation/AnimatedPlayerModalWrapper.tsx +78 -0
  77. package/Components/VideoModal/ModalAnimation/AnimatedScrollModal.tsx +342 -0
  78. package/Components/VideoModal/ModalAnimation/AnimatedVideoPlayerComponent.tsx +151 -0
  79. package/Components/VideoModal/ModalAnimation/AnimationComponent.tsx +438 -0
  80. package/Components/VideoModal/ModalAnimation/ModalAnimationContext.tsx +154 -0
  81. package/Components/VideoModal/ModalAnimation/index.ts +15 -0
  82. package/Components/VideoModal/ModalAnimation/utils.ts +299 -0
  83. package/Components/VideoModal/PlayerDetails.tsx +3 -0
  84. package/Components/VideoModal/PlayerWrapper.tsx +69 -44
  85. package/Components/VideoModal/VideoModal.tsx +25 -42
  86. package/Components/VideoModal/__tests__/PlayerDetails.test.tsx +0 -2
  87. package/Components/VideoModal/__tests__/PlayerWrapper.test.tsx +5 -1
  88. package/Components/VideoModal/__tests__/__snapshots__/PlayerWrapper.test.tsx.snap +246 -166
  89. package/Components/VideoModal/hooks/useModalSize.ts +13 -4
  90. package/Components/VideoModal/utils.ts +3 -3
  91. package/Components/Viewport/ViewportAware/__tests__/viewportAware.test.js +26 -21
  92. package/Components/Viewport/ViewportTracker/ViewportTracker.tsx +1 -1
  93. package/Components/Viewport/ViewportTracker/__tests__/viewportTracker.test.js +4 -5
  94. package/Components/Viewport/ViewportTracker/index.tsx +1 -0
  95. package/Components/Viewport/utils.js +1 -1
  96. package/Components/ZappUIComponent/index.tsx +22 -12
  97. package/Components/index.js +2 -0
  98. package/Contexts/MenuToggleContext/{index.js → index.ts} +16 -0
  99. package/Contexts/ScreenContext/__tests__/__snapshots__/index.test.tsx.snap +3 -0
  100. package/Contexts/ScreenContext/__tests__/index.test.tsx +27 -0
  101. package/Contexts/ScreenContext/index.tsx +95 -29
  102. package/Decorators/ComponentsMapWrapper/withComponentsMapProvider.tsx +7 -2
  103. package/Decorators/RiverResolver/index.tsx +0 -4
  104. package/Decorators/index.tsx +0 -4
  105. package/events/index.ts +1 -0
  106. package/package.json +5 -6
  107. package/Components/VideoModal/hooks/usePosition.ts +0 -50
  108. /package/Contexts/{index.js → index.ts} +0 -0
@@ -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
+ }
@@ -0,0 +1,70 @@
1
+ import * as React from "react";
2
+ import { View, Text } from "react-native";
3
+ import { useIsRTL } from "@applicaster/zapp-react-native-utils/localizationUtils";
4
+
5
+ import { textTransform } from "@applicaster/zapp-react-native-utils/cellUtils/";
6
+
7
+ export type TitleProps = {
8
+ text: string;
9
+ letterSpacing: number;
10
+ lineHeight: number;
11
+ fontFamily: string;
12
+ fontSize: number;
13
+ color: string;
14
+ marginTop: number;
15
+ marginLeft: number;
16
+ marginRight: number;
17
+ marginBottom: number;
18
+ transform: string;
19
+ numberOfLines: number;
20
+ };
21
+
22
+ export function Title(props: TitleProps) {
23
+ const {
24
+ text,
25
+ letterSpacing,
26
+ lineHeight,
27
+ fontFamily,
28
+ fontSize,
29
+ color,
30
+ marginTop,
31
+ marginBottom,
32
+ marginLeft,
33
+ marginRight,
34
+ numberOfLines,
35
+ transform,
36
+ } = props;
37
+
38
+ const isRTL = useIsRTL();
39
+ const writingDirection = isRTL ? "rtl" : "ltr";
40
+
41
+ if (!text) return null;
42
+
43
+ return (
44
+ <View
45
+ style={{
46
+ marginTop,
47
+ marginBottom,
48
+ marginLeft,
49
+ marginRight,
50
+ }}
51
+ >
52
+ {!!text?.length && (
53
+ <Text
54
+ style={{
55
+ letterSpacing,
56
+ fontFamily,
57
+ fontSize,
58
+ lineHeight,
59
+ color,
60
+ writingDirection,
61
+ }}
62
+ numberOfLines={numberOfLines}
63
+ ellipsizeMode="tail"
64
+ >
65
+ {textTransform(transform, text)}
66
+ </Text>
67
+ )}
68
+ </View>
69
+ );
70
+ }
@@ -0,0 +1,4 @@
1
+ /* eslint-disable max-len */
2
+
3
+ export const defaultCloseAsset: string =
4
+ "data:image/png;base64,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";
@@ -0,0 +1,71 @@
1
+ import React, { useMemo } from "react";
2
+ import { View, StyleSheet, LayoutChangeEvent } from "react-native";
3
+ import { Title, TitleProps } from "./Title";
4
+ import { CloseButton, CloseButtonProps } from "./CloseButton";
5
+ import { getCloseButtonProps, getTitleProps } from "./utils";
6
+ import { PluginConfiguration } from "../index";
7
+
8
+ type Props = {
9
+ dismiss: () => void;
10
+ configuration: PluginConfiguration;
11
+ width: number;
12
+ onLayout?: (event: LayoutChangeEvent) => void;
13
+ summary?: string;
14
+ title?: string;
15
+ };
16
+
17
+ const styles = StyleSheet.create({
18
+ container: {
19
+ flexDirection: "row",
20
+ alignItems: "center",
21
+ },
22
+ });
23
+
24
+ export function ModalHeader(props: Props) {
25
+ const { configuration, dismiss, width, onLayout, summary, title } = props;
26
+
27
+ const closeButtonProps = useMemo<CloseButtonProps>(
28
+ () => ({
29
+ ...getCloseButtonProps(configuration),
30
+ close: dismiss,
31
+ }),
32
+ [configuration, dismiss]
33
+ );
34
+
35
+ const titleProps = useMemo<TitleProps>(
36
+ () => ({
37
+ ...getTitleProps(configuration, "title"),
38
+ text: title,
39
+ }),
40
+ [configuration, title]
41
+ );
42
+
43
+ const summaryProps = useMemo<TitleProps>(
44
+ () => ({
45
+ ...getTitleProps(configuration, "summary"),
46
+ text: summary,
47
+ }),
48
+ [configuration, summary]
49
+ );
50
+
51
+ const buttonsContainerWidth =
52
+ configuration.modal_bottom_sheet_close_width +
53
+ configuration.modal_bottom_sheet_close_margin_left +
54
+ configuration.modal_bottom_sheet_close_margin_right;
55
+
56
+ return (
57
+ <View onLayout={onLayout} style={styles.container}>
58
+ <View
59
+ style={{
60
+ width: width - buttonsContainerWidth,
61
+ }}
62
+ >
63
+ {title && <Title {...titleProps} />}
64
+ {summary && <Title {...summaryProps} />}
65
+ </View>
66
+ <View style={{ width: buttonsContainerWidth }}>
67
+ <CloseButton {...closeButtonProps} />
68
+ </View>
69
+ </View>
70
+ );
71
+ }