@applicaster/zapp-react-native-ui-components 12.0.0-alpha.5114122134 → 12.0.0-alpha.5208030571

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 (104) 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/BaseFocusable/index.tsx +1 -1
  5. package/Components/Cell/Cell.tsx +7 -3
  6. package/Components/Cell/CellWithFocusable.tsx +38 -19
  7. package/Components/Cell/TvOSCellComponent.tsx +2 -2
  8. package/Components/ErrorScreen/index.tsx +1 -1
  9. package/Components/FocusableCell/index.tsx +7 -7
  10. package/Components/FocusableGroup/index.tsx +1 -0
  11. package/Components/FocusableList/FocusableChild.ts +24 -14
  12. package/Components/FocusableList/FocusableItem.tsx +1 -1
  13. package/Components/FocusableList/FocusableListItemWrapper.tsx +76 -0
  14. package/Components/FocusableList/hooks/useCellState.android.ts +3 -1
  15. package/Components/FocusableList/index.tsx +26 -25
  16. package/Components/GeneralContentScreen/GeneralContentScreen.tsx +11 -8
  17. package/Components/GeneralContentScreen/utils/__tests__/useCurationAPI.test.js +13 -6
  18. package/Components/GeneralContentScreen/utils/useCurationAPI.ts +1 -1
  19. package/Components/HandlePlayable/HandlePlayable.tsx +4 -1
  20. package/Components/HookRenderer/index.tsx +1 -6
  21. package/Components/Image/Image.android.tsx +3 -25
  22. package/Components/Image/Image.tsx +18 -2
  23. package/Components/Image/utils/index.ts +39 -0
  24. package/Components/Layout/TV/ScreenLayoutContextProvider.tsx +2 -2
  25. package/Components/Layout/TV/__tests__/index.test.tsx +1 -34
  26. package/Components/Layout/TV/index.tsx +141 -58
  27. package/Components/MasterCell/DefaultComponents/BorderContainerView/index.tsx +0 -1
  28. package/Components/MasterCell/DefaultComponents/CellBadge/index.tsx +21 -8
  29. package/Components/MasterCell/DefaultComponents/Image/Image.android.tsx +9 -26
  30. package/Components/MasterCell/DefaultComponents/Image/Image.ios.tsx +5 -3
  31. package/Components/MasterCell/DefaultComponents/Image/hooks/useImageSize.ts +65 -0
  32. package/Components/MasterCell/DefaultComponents/LiveImage/index.tsx +17 -2
  33. package/Components/MasterCell/DefaultComponents/SecondaryImage/Image.tsx +3 -2
  34. package/Components/MasterCell/DefaultComponents/Toggle.tsx +5 -1
  35. package/Components/MasterCell/DefaultComponents/__tests__/image.test.js +1 -1
  36. package/Components/MasterCell/SharedUI/CollapsibleTextContainer/index.ts +8 -10
  37. package/Components/MasterCell/utils/index.ts +16 -5
  38. package/Components/ModalComponent/BottomSheetModalContent.tsx +121 -0
  39. package/Components/ModalComponent/Button/Item.tsx +82 -0
  40. package/Components/ModalComponent/Button/ItemIcon.tsx +60 -0
  41. package/Components/ModalComponent/Button/ItemLabel.tsx +101 -0
  42. package/Components/ModalComponent/Button/assets.ts +4 -0
  43. package/Components/ModalComponent/Button/index.tsx +111 -0
  44. package/Components/ModalComponent/Header/CloseButton.tsx +59 -0
  45. package/Components/ModalComponent/Header/Title.tsx +70 -0
  46. package/Components/ModalComponent/Header/assets.ts +4 -0
  47. package/Components/ModalComponent/Header/index.tsx +71 -0
  48. package/Components/ModalComponent/Header/utils.ts +79 -0
  49. package/Components/ModalComponent/index.tsx +38 -0
  50. package/Components/ModalComponent/utils.ts +126 -0
  51. package/Components/PlayerContainer/PlayerContainer.tsx +63 -31
  52. package/Components/PlayerContainer/ProgramInfo/index.tsx +3 -1
  53. package/Components/PlayerImageBackground/index.tsx +34 -8
  54. package/Components/River/ComponentsMap/ComponentsMap.tsx +90 -2
  55. package/Components/River/TV/River.tsx +2 -3
  56. package/Components/River/__tests__/__snapshots__/componentsMap.test.js.snap +1 -1
  57. package/Components/River/__tests__/componentsMap.test.js +7 -0
  58. package/Components/River/useScreenConfiguration.ts +2 -2
  59. package/Components/RouteManager/__tests__/__snapshots__/routeManager.test.js.snap +1 -0
  60. package/Components/RouteManager/__tests__/routeManager.test.js +9 -2
  61. package/Components/RouteManager/index.tsx +5 -3
  62. package/Components/Screen/TV/index.web.tsx +151 -0
  63. package/Components/Screen/__tests__/Screen.test.tsx +88 -74
  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 -43
  67. package/Components/Screen/navigationHandler.ts +0 -82
  68. package/Components/ScreenResolver/index.tsx +4 -2
  69. package/Components/Tabs/TV/styles.ts +1 -1
  70. package/Components/TrackedView/index.tsx +6 -3
  71. package/Components/VideoLive/LiveImageManager.ts +37 -10
  72. package/Components/VideoLive/PlayerLiveImageComponent.tsx +81 -72
  73. package/Components/VideoLive/__tests__/PlayerLiveImageComponent.test.tsx +45 -3
  74. package/Components/VideoLive/__tests__/__snapshots__/PlayerLiveImageComponent.test.tsx.snap +18 -28
  75. package/Components/VideoModal/ModalAnimation/AnimatedPlayerModalWrapper.tsx +78 -0
  76. package/Components/VideoModal/ModalAnimation/AnimatedScrollModal.tsx +342 -0
  77. package/Components/VideoModal/ModalAnimation/AnimatedVideoPlayerComponent.tsx +151 -0
  78. package/Components/VideoModal/ModalAnimation/AnimationComponent.tsx +438 -0
  79. package/Components/VideoModal/ModalAnimation/ModalAnimationContext.tsx +143 -0
  80. package/Components/VideoModal/ModalAnimation/index.ts +15 -0
  81. package/Components/VideoModal/ModalAnimation/utils.ts +299 -0
  82. package/Components/VideoModal/PlayerDetails.tsx +3 -0
  83. package/Components/VideoModal/PlayerWrapper.tsx +65 -42
  84. package/Components/VideoModal/VideoModal.tsx +8 -25
  85. package/Components/VideoModal/__tests__/PlayerDetails.test.tsx +0 -2
  86. package/Components/VideoModal/__tests__/PlayerWrapper.test.tsx +5 -1
  87. package/Components/VideoModal/__tests__/__snapshots__/PlayerWrapper.test.tsx.snap +246 -166
  88. package/Components/VideoModal/utils.ts +3 -3
  89. package/Components/Viewport/ViewportAware/__tests__/viewportAware.test.js +26 -21
  90. package/Components/Viewport/ViewportTracker/ViewportTracker.tsx +1 -1
  91. package/Components/Viewport/ViewportTracker/__tests__/viewportTracker.test.js +4 -5
  92. package/Components/Viewport/ViewportTracker/index.tsx +1 -0
  93. package/Components/Viewport/utils.js +1 -1
  94. package/Components/ZappUIComponent/index.tsx +22 -12
  95. package/Components/index.js +2 -0
  96. package/Contexts/MenuToggleContext/{index.js → index.ts} +16 -0
  97. package/Contexts/ScreenContext/__tests__/__snapshots__/index.test.tsx.snap +3 -0
  98. package/Contexts/ScreenContext/__tests__/index.test.tsx +27 -0
  99. package/Contexts/ScreenContext/index.tsx +95 -29
  100. package/Contexts/ZappPipesContext/ZappPipesEntryContext.ts +1 -1
  101. package/Decorators/ComponentsMapWrapper/withComponentsMapProvider.tsx +7 -2
  102. package/package.json +5 -5
  103. package/Components/VideoModal/hooks/usePosition.ts +0 -50
  104. /package/Contexts/{index.js → index.ts} +0 -0
@@ -18,6 +18,7 @@ type LiveImageProps = {
18
18
  imageKey?: string;
19
19
  state: "focused" | "unfocused" | "selected";
20
20
  audio_muted_by_default?: boolean;
21
+ uri: string; // cover image url
21
22
  };
22
23
 
23
24
  const DEFAULT_PLAYER_IDENTIFIER = "QuickBrickPlayerPlugin";
@@ -176,10 +177,23 @@ const getPlayerConfig = (player_screen_id, actionIdentifier) => {
176
177
  const positionAbsolute: ViewStyle = { position: "absolute" };
177
178
 
178
179
  const LiveImageComponent = (props: LiveImageProps) => {
179
- const { item, style, cellUUID, imageKey, actionIdentifier, state } = props;
180
+ const {
181
+ item,
182
+ style: componentStyle,
183
+ cellUUID,
184
+ imageKey,
185
+ actionIdentifier,
186
+ state,
187
+ } = props;
180
188
 
181
189
  const component = useUIComponentContext();
182
190
 
191
+ // Fix for blinking on state change
192
+ const style = React.useMemo(
193
+ () => ({ ...componentStyle, backgroundColor: "transparent" }),
194
+ [componentStyle]
195
+ );
196
+
183
197
  const componentType = React.useMemo(
184
198
  () => getPropComponentType(component),
185
199
  [component?.id]
@@ -209,10 +223,11 @@ const LiveImageComponent = (props: LiveImageProps) => {
209
223
 
210
224
  return (
211
225
  <>
212
- <Image {...props} />
226
+ <Image {...props} applyMaxSize />
213
227
  {isShouldRender && (
214
228
  <View style={[style, positionAbsolute]}>
215
229
  <PlayerLiveImage
230
+ uri={props.uri}
216
231
  playerId={cellUUID}
217
232
  playerPluginId={playerPluginId}
218
233
  screenConfig={screenConfig}
@@ -1,11 +1,12 @@
1
1
  import * as React from "react";
2
2
  import { isNil } from "ramda";
3
- import { Image as RNImage, ImageStyle, View } from "react-native";
3
+ import { ImageStyle, View } from "react-native";
4
4
  import {
5
5
  FIT_POSITION,
6
6
  IMAGE_SIZING_FIT,
7
7
  IMAGE_SIZING_FILL,
8
8
  } from "@applicaster/zapp-react-native-utils/manifestUtils/secondaryImage";
9
+ import { QBImage as Image } from "@applicaster/zapp-react-native-ui-components/Components/Image";
9
10
 
10
11
  import { useGetImageDimensions } from "./hooks";
11
12
  import {
@@ -59,7 +60,7 @@ const SecondaryImageComponent = (props: Props) => {
59
60
 
60
61
  return (
61
62
  <View style={style} onLayout={onAsyncRender}>
62
- <RNImage
63
+ <Image
63
64
  {...props}
64
65
  source={{ uri }}
65
66
  style={{
@@ -23,7 +23,11 @@ export const Toggle = (props: Props) => {
23
23
  iosBackgroundColor,
24
24
  } = style;
25
25
 
26
- const isSelected = React.useMemo(() => (cellState === "selected"), [item?.id, cellState]);
26
+ const isSelected = React.useMemo(
27
+ () => cellState === "selected",
28
+ [item?.id, cellState]
29
+ );
30
+
27
31
  const actionContext = useActions(action?.identifier);
28
32
 
29
33
  const [actionState, setActionState] = useState(
@@ -39,6 +39,6 @@ describe("image with no source", () => {
39
39
  );
40
40
 
41
41
  const testInstance = testRenderer.root;
42
- expect(testInstance.findByType(Image).props.source).toEqual({ uri: "" });
42
+ expect(testInstance.findByType(Image).props.source).toBeUndefined();
43
43
  });
44
44
  });
@@ -1,6 +1,7 @@
1
- import { path, pathOr } from "ramda";
1
+ import { path } from "ramda";
2
2
  import { isNilOrEmpty } from "@applicaster/zapp-react-native-utils/reactUtils/helpers";
3
3
  import {
4
+ getColorFromData,
4
5
  getKeyForLabel,
5
6
  mapSelfAlignment,
6
7
  } from "@applicaster/zapp-react-native-utils/cellUtils";
@@ -48,15 +49,12 @@ export const CollapsibleTextContainer = ({
48
49
  ]),
49
50
  {
50
51
  func: (data) => {
51
- const value = getValue("background_color");
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;
59
- }
52
+ return getColorFromData({
53
+ data,
54
+ getValue,
55
+ key: "background_color",
56
+ defaultColor: additionalStyles.backgroundColor,
57
+ });
60
58
  },
61
59
  propName: "backgroundColor",
62
60
  },
@@ -125,13 +125,24 @@ export const useFilterChildren = <
125
125
 
126
126
  const filteredChildren = children.filter((child) => {
127
127
  const item = child.props.item;
128
- const action = actions.actions[child.props.pluginIdentifier];
128
+ const actionIdentifier = child.props.pluginIdentifier;
129
+ const action = actions.actions[actionIdentifier];
130
+
129
131
  // context value of specific plugin
130
- const currentValue = action.module.context._currentValue;
132
+ if (action?.module && action.module.context) {
133
+ const currentValue = action.module.context._currentValue;
134
+
135
+ return currentValue?.isActionAvailable
136
+ ? currentValue.isActionAvailable(item)
137
+ : true;
138
+ }
131
139
 
132
- return currentValue?.isActionAvailable
133
- ? currentValue.isActionAvailable(item)
134
- : true;
140
+ masterCellLogger.error({
141
+ message: `Action plugin for ${actionIdentifier} could not be found, check the configuration of your action button`,
142
+ data: { item, action: child.props.pluginIdentifier },
143
+ });
144
+
145
+ return false;
135
146
  });
136
147
 
137
148
  return filteredChildren;
@@ -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
+ }