@applicaster/zapp-react-native-ui-components 12.0.0-alpha.7725319213 → 12.0.0-alpha.7855034103

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 (111) 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 +6 -3
  15. package/Components/GeneralContentScreen/utils/__tests__/useCurationAPI.test.js +13 -6
  16. package/Components/GeneralContentScreen/utils/useCurationAPI.ts +1 -1
  17. package/Components/HookRenderer/index.tsx +1 -6
  18. package/Components/Image/Image.android.tsx +3 -25
  19. package/Components/Image/Image.tsx +18 -2
  20. package/Components/Image/utils/index.ts +39 -0
  21. package/Components/Layout/TV/__tests__/index.test.tsx +1 -34
  22. package/Components/Layout/TV/index.tsx +28 -41
  23. package/Components/MasterCell/DefaultComponents/ActionButton.tsx +2 -0
  24. package/Components/MasterCell/DefaultComponents/BorderContainerView/index.tsx +80 -109
  25. package/Components/MasterCell/DefaultComponents/DynamicBadge.tsx +4 -2
  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/Text/index.tsx +14 -2
  33. package/Components/MasterCell/DefaultComponents/Toggle.tsx +5 -1
  34. package/Components/MasterCell/DefaultComponents/__tests__/image.test.js +1 -1
  35. package/Components/MasterCell/DefaultComponents/__tests__/text.test.tsx +24 -9
  36. package/Components/MasterCell/SharedUI/CollapsibleTextContainer/index.ts +6 -14
  37. package/Components/MasterCell/hooks/useAsyncRendering/index.ts +1 -1
  38. package/Components/MasterCell/utils/index.ts +16 -5
  39. package/Components/MeasurmentsPortal/BasicMeasurementsPortal.tsx +11 -7
  40. package/Components/MeasurmentsPortal/MeasurementsPortal.tsx +10 -1
  41. package/Components/ModalComponent/BottomSheetModalContent.tsx +121 -0
  42. package/Components/ModalComponent/Button/Item.tsx +82 -0
  43. package/Components/ModalComponent/Button/ItemIcon.tsx +60 -0
  44. package/Components/ModalComponent/Button/ItemLabel.tsx +101 -0
  45. package/Components/ModalComponent/Button/assets.ts +4 -0
  46. package/Components/ModalComponent/Button/index.tsx +111 -0
  47. package/Components/ModalComponent/Header/CloseButton.tsx +59 -0
  48. package/Components/ModalComponent/Header/Title.tsx +70 -0
  49. package/Components/ModalComponent/Header/assets.ts +4 -0
  50. package/Components/ModalComponent/Header/index.tsx +71 -0
  51. package/Components/ModalComponent/Header/utils.ts +79 -0
  52. package/Components/ModalComponent/index.tsx +38 -0
  53. package/Components/ModalComponent/utils.ts +126 -0
  54. package/Components/PlayerContainer/PlayerContainer.tsx +60 -31
  55. package/Components/PlayerContainer/ProgramInfo/index.tsx +3 -1
  56. package/Components/PlayerImageBackground/index.tsx +34 -8
  57. package/Components/River/ComponentsMap/ComponentsMap.tsx +97 -2
  58. package/Components/River/RefreshControl.tsx +55 -1
  59. package/Components/River/TV/River.tsx +2 -2
  60. package/Components/River/__tests__/__snapshots__/componentsMap.test.js.snap +1 -1
  61. package/Components/River/__tests__/componentsMap.test.js +7 -0
  62. package/Components/River/useScreenConfiguration.ts +2 -2
  63. package/Components/RouteManager/__tests__/__snapshots__/routeManager.test.js.snap +1 -0
  64. package/Components/RouteManager/__tests__/routeManager.test.js +9 -2
  65. package/Components/RouteManager/index.tsx +4 -2
  66. package/Components/Screen/__tests__/Screen.test.tsx +88 -74
  67. package/Components/Screen/__tests__/__snapshots__/Screen.test.tsx.snap +24 -6
  68. package/Components/Screen/__tests__/navigationHandler.test.ts +1 -178
  69. package/Components/Screen/index.tsx +103 -43
  70. package/Components/Screen/navigationHandler.ts +0 -82
  71. package/Components/ScreenResolver/index.tsx +1 -1
  72. package/Components/Tabs/TV/styles.ts +1 -1
  73. package/Components/Transitioner/Scene.tsx +24 -19
  74. package/Components/Transitioner/Transitioner.tsx +9 -2
  75. package/Components/Transitioner/__tests__/__snapshots__/Scene.test.js.snap +6 -2
  76. package/Components/Transitioner/__tests__/__snapshots__/transitioner.test.js.snap +1 -0
  77. package/Components/VideoLive/LiveImageManager.ts +5 -2
  78. package/Components/VideoLive/PlayerLiveImageComponent.tsx +31 -28
  79. package/Components/VideoLive/__tests__/PlayerLiveImageComponent.test.tsx +45 -3
  80. package/Components/VideoLive/__tests__/__snapshots__/PlayerLiveImageComponent.test.tsx.snap +18 -28
  81. package/Components/VideoModal/ModalAnimation/AnimatedPlayerModalWrapper.tsx +78 -0
  82. package/Components/VideoModal/ModalAnimation/AnimatedScrollModal.tsx +342 -0
  83. package/Components/VideoModal/ModalAnimation/AnimatedVideoPlayerComponent.tsx +151 -0
  84. package/Components/VideoModal/ModalAnimation/AnimationComponent.tsx +438 -0
  85. package/Components/VideoModal/ModalAnimation/ModalAnimationContext.tsx +154 -0
  86. package/Components/VideoModal/ModalAnimation/index.ts +15 -0
  87. package/Components/VideoModal/ModalAnimation/utils.ts +299 -0
  88. package/Components/VideoModal/PlayerDetails.tsx +6 -3
  89. package/Components/VideoModal/PlayerWrapper.tsx +78 -48
  90. package/Components/VideoModal/VideoModal.tsx +25 -42
  91. package/Components/VideoModal/__tests__/PlayerDetails.test.tsx +0 -2
  92. package/Components/VideoModal/__tests__/PlayerWrapper.test.tsx +12 -1
  93. package/Components/VideoModal/__tests__/__snapshots__/PlayerWrapper.test.tsx.snap +246 -166
  94. package/Components/VideoModal/utils.ts +3 -3
  95. package/Components/Viewport/ViewportAware/__tests__/viewportAware.test.js +26 -21
  96. package/Components/Viewport/ViewportTracker/ViewportTracker.tsx +31 -40
  97. package/Components/Viewport/ViewportTracker/__tests__/viewportTracker.test.js +4 -5
  98. package/Components/Viewport/ViewportTracker/index.tsx +1 -0
  99. package/Components/Viewport/utils.js +1 -1
  100. package/Components/ZappUIComponent/index.tsx +22 -12
  101. package/Components/index.js +2 -0
  102. package/Contexts/MenuToggleContext/{index.js → index.ts} +16 -0
  103. package/Contexts/ScreenContext/__tests__/__snapshots__/index.test.tsx.snap +3 -0
  104. package/Contexts/ScreenContext/__tests__/index.test.tsx +27 -0
  105. package/Contexts/ScreenContext/index.tsx +95 -29
  106. package/Contexts/ScreenDataContext/index.ts +3 -0
  107. package/Decorators/ComponentsMapWrapper/withComponentsMapProvider.tsx +7 -2
  108. package/events/index.ts +1 -0
  109. package/package.json +5 -5
  110. package/Components/VideoModal/hooks/usePosition.ts +0 -50
  111. /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={{
@@ -1,7 +1,6 @@
1
1
  import * as React from "react";
2
2
  import { Text } from "react-native";
3
3
  import { omit } from "ramda";
4
- import { isNilOrEmpty } from "@applicaster/zapp-react-native-utils/reactUtils/helpers";
5
4
  import {
6
5
  textTransform,
7
6
  dateFormat,
@@ -9,6 +8,9 @@ import {
9
8
 
10
9
  import { useTextLabel, withFocusedStyles } from "./hooks";
11
10
  import { withScaledLineHeight } from "./utils";
11
+ import { toNumber } from "@applicaster/zapp-react-native-utils/numberUtils";
12
+ import { MeasurementPortalContext } from "../../../MeasurmentsPortal";
13
+ import { isNilOrEmpty } from "@applicaster/zapp-react-native-utils/reactUtils/helpers";
12
14
 
13
15
  type Props = {
14
16
  style: any;
@@ -32,14 +34,24 @@ const _Text = ({
32
34
  ...otherProps
33
35
  }: Props) => {
34
36
  const _label = useTextLabel({ label, entry });
37
+ const isMeasurement = React.useContext(MeasurementPortalContext);
35
38
 
36
39
  if (isNilOrEmpty(_label)) {
37
40
  return null;
38
41
  }
39
42
 
43
+ // set maximum possible height for the text in case of measurement
44
+ const height =
45
+ isMeasurement && otherProps.numberOfLines && style.lineHeight
46
+ ? toNumber(otherProps.numberOfLines) * toNumber(style.lineHeight)
47
+ : undefined;
48
+
40
49
  return (
41
50
  <Text
42
- style={withScaledLineHeight(withFocusedStyles({ style, otherProps }))}
51
+ style={[
52
+ withScaledLineHeight(withFocusedStyles({ style, otherProps })),
53
+ { height },
54
+ ]}
43
55
  {...withoutLabel(otherProps)}
44
56
  >
45
57
  {dateTransformEnabled
@@ -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,11 +1,23 @@
1
1
  import React from "react";
2
- import { Text } from "react-native";
2
+ import RN from "react-native";
3
3
  import { Provider } from "react-redux";
4
4
  import TestRenderer from "react-test-renderer";
5
- import configureStore from "redux-mock-store";
6
- import CustomText from "../Text";
5
+ import configureStoreFn from "redux-mock-store";
7
6
 
8
- const mockStore = configureStore();
7
+ const mockUseIsRTL = jest.fn(() => true);
8
+ const mockGetIsRTL = jest.fn(() => true);
9
+ const mockUseLocalizedStrings = jest.fn(() => ({}));
10
+ const mockGetUILanguage = jest.fn(() => "he-HE");
11
+
12
+ jest.mock("@applicaster/zapp-react-native-utils/localizationUtils", () => ({
13
+ useIsRTL: mockUseIsRTL,
14
+ getIsRTL: mockGetIsRTL,
15
+ useLocalizedStrings: mockUseLocalizedStrings,
16
+ getUILanguage: mockGetUILanguage,
17
+ }));
18
+
19
+ const CustomText = require("../Text").default;
20
+ const mockStore = configureStoreFn();
9
21
 
10
22
  const defaultProps = {
11
23
  entry: {},
@@ -22,7 +34,7 @@ const getRenderedText = (label: string, store: any) => {
22
34
  </Provider>
23
35
  );
24
36
 
25
- return testRenderer.root.findByType(Text).props.children;
37
+ return testRenderer.root.findByType(RN.Text).props.children;
26
38
  };
27
39
 
28
40
  describe("RTL app: Hebrew text contains english word", () => {
@@ -34,7 +46,7 @@ describe("RTL app: Hebrew text contains english word", () => {
34
46
  remoteConfigurations: { localizations: { he: {} } },
35
47
  appData: {
36
48
  languageCode: "he",
37
- countryCode: "HE",
49
+ countryCode: "IL",
38
50
  },
39
51
  });
40
52
 
@@ -47,18 +59,22 @@ describe("RTL app: Hebrew text contains english word", () => {
47
59
 
48
60
  it("Hebrew text contains not first english word", () => {
49
61
  const renderedText = getRenderedText(textWithNotFirstEnglishWord, store);
50
-
51
62
  expect(renderedText).toEqual(textWithNotFirstEnglishWord);
52
63
  });
53
64
 
54
65
  it("Hebrew text doesn't contain english word", () => {
55
66
  const renderedText = getRenderedText(textWithoutEnglishWord, store);
56
-
57
67
  expect(renderedText).toEqual(textWithoutEnglishWord);
58
68
  });
59
69
  });
60
70
 
61
71
  describe("LTR app: English text", () => {
72
+ beforeAll(() => {
73
+ mockUseIsRTL.mockReturnValue(false);
74
+ mockGetIsRTL.mockReturnValue(false);
75
+ mockGetUILanguage.mockReturnValue("en-US");
76
+ });
77
+
62
78
  const englishText = "Test sentence";
63
79
 
64
80
  const store = mockStore({
@@ -71,7 +87,6 @@ describe("LTR app: English text", () => {
71
87
 
72
88
  it("English text", () => {
73
89
  const renderedText = getRenderedText(englishText, store);
74
-
75
90
  expect(renderedText).toEqual(englishText);
76
91
  });
77
92
  });
@@ -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,19 +49,10 @@ export const CollapsibleTextContainer = ({
48
49
  ]),
49
50
  {
50
51
  func: (data) => {
51
- const value = getValue("background_color");
52
-
53
- const valueFromData = pathOr(value, value.split("."), data);
54
-
55
- if (
56
- valueFromData &&
57
- (valueFromData.startsWith("#") || valueFromData.startsWith("rgba("))
58
- ) {
59
- return valueFromData;
60
- }
61
-
62
- // return default value
63
- return additionalStyles.backgroundColor;
52
+ return getColorFromData({
53
+ data,
54
+ valueFromLayout: additionalStyles.backgroundColor,
55
+ });
64
56
  },
65
57
  propName: "backgroundColor",
66
58
  },
@@ -53,7 +53,7 @@ export const useAsyncRendering = (viewRef: React.RefObject<View>): Return => {
53
53
  measure(viewRef?.current, ({ width, height }) => {
54
54
  setDimensions({
55
55
  width,
56
- height,
56
+ height: Math.ceil(height),
57
57
  });
58
58
  });
59
59
  })
@@ -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;
@@ -1,5 +1,6 @@
1
1
  import React from "react";
2
2
  import { View, StyleSheet } from "react-native";
3
+ import { MeasurementPortalContext } from "./MeasurementsPortal";
3
4
 
4
5
  type Props = {
5
6
  Component: React.ElementType;
@@ -19,13 +20,16 @@ const _MeasurementsPortal = (
19
20
  { Component, onLayout, componentProps, containerStyle }: Props,
20
21
  ref
21
22
  ) => (
22
- <View
23
- onLayout={onLayout}
24
- style={[styles.container, containerStyle]}
25
- ref={ref}
26
- >
27
- <Component {...componentProps} />
28
- </View>
23
+ // hack for cell to determine if cell is in measurement mode
24
+ <MeasurementPortalContext.Provider value={{}}>
25
+ <View
26
+ onLayout={onLayout}
27
+ style={[styles.container, containerStyle]}
28
+ ref={ref}
29
+ >
30
+ <Component {...componentProps} />
31
+ </View>
32
+ </MeasurementPortalContext.Provider>
29
33
  );
30
34
 
31
35
  export const MeasurementsPortal = React.forwardRef(_MeasurementsPortal);
@@ -35,7 +35,16 @@ const MeasurementsPortal = ({ Component, onLayout, componentProps }: Props) => {
35
35
  );
36
36
  };
37
37
 
38
- const MeasurementPortalContext = React.createContext(null);
38
+ type MeasurementPortalContextType = {
39
+ measureComponent?: (
40
+ comp: React.ElementType,
41
+ props: Record<any, any>
42
+ ) => Promise<any>;
43
+ measuringInProgress?: boolean;
44
+ };
45
+
46
+ const MeasurementPortalContext =
47
+ React.createContext<null | MeasurementPortalContextType>(null);
39
48
 
40
49
  const MeasurementsPortalContextProvider = ({ children }) => {
41
50
  const Component = React.useRef(View);
@@ -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
+ }