@applicaster/zapp-react-native-ui-components 13.0.0-alpha.1724095599 → 13.0.0-alpha.1731130113

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 (92) hide show
  1. package/Components/AudioPlayer/AudioPlayer.tsx +5 -9
  2. package/Components/AudioPlayer/AudioPlayerLayout.tsx +8 -9
  3. package/Components/AudioPlayer/helpers.tsx +1 -2
  4. package/Components/Cell/Cell.tsx +3 -13
  5. package/Components/Cell/CellWithFocusable.tsx +21 -15
  6. package/Components/Cell/CellWrapper.tsx +18 -0
  7. package/Components/Cell/styles.ts +17 -0
  8. package/Components/CellRendererResolver/index.ts +2 -1
  9. package/Components/ErrorScreen/index.tsx +8 -0
  10. package/Components/FocusableCell/index.tsx +1 -1
  11. package/Components/FocusableGroup/FocusableTvOS.tsx +34 -86
  12. package/Components/FocusableGroup/index.tsx +0 -3
  13. package/Components/GeneralContentScreen/GeneralContentScreen.tsx +3 -0
  14. package/Components/GeneralContentScreen/utils/useCurationAPI.ts +4 -2
  15. package/Components/GeneralContentScreen/utils/useEventAlerts.ts +30 -0
  16. package/Components/HandlePlayable/HandlePlayable.tsx +21 -27
  17. package/Components/Layout/TV/LayoutBackground.tsx +28 -0
  18. package/Components/Layout/TV/NavBarContainer.tsx +2 -1
  19. package/Components/Layout/TV/ScreenContainer.tsx +8 -2
  20. package/Components/Layout/TV/ScreenLayoutContextProvider.tsx +5 -0
  21. package/Components/Layout/TV/__tests__/ScreenContainer.test.tsx +2 -1
  22. package/Components/Layout/TV/__tests__/__snapshots__/NavBarContainer.test.tsx.snap +1 -0
  23. package/Components/Layout/TV/__tests__/__snapshots__/ScreenContainer.test.tsx.snap +1 -0
  24. package/Components/Layout/TV/__tests__/__snapshots__/index.test.tsx.snap +15 -10
  25. package/Components/Layout/TV/__tests__/index.test.tsx +8 -2
  26. package/Components/Layout/TV/index.tsx +6 -20
  27. package/Components/Layout/TV/index.web.tsx +4 -1
  28. package/Components/MasterCell/DefaultComponents/ActionButton.tsx +2 -3
  29. package/Components/MasterCell/DefaultComponents/Image/Image.ios.tsx +4 -3
  30. package/Components/MasterCell/DefaultComponents/Image/hooks/useImage.ts +11 -7
  31. package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/const.ts +3 -0
  32. package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/index.ts +6 -6
  33. package/Components/MasterCell/SharedUI/ProgressBar/hooks/useFillInPercent.ts +2 -8
  34. package/Components/MasterCell/utils/behaviorProvider.ts +136 -0
  35. package/Components/MasterCell/utils/index.ts +8 -134
  36. package/Components/ModalComponent/BottomSheetModalContent.tsx +66 -54
  37. package/Components/ModalComponent/Button/Item.tsx +6 -5
  38. package/Components/ModalComponent/Button/assets.ts +1 -1
  39. package/Components/ModalComponent/Button/index.tsx +45 -62
  40. package/Components/ModalComponent/Header/index.tsx +9 -8
  41. package/Components/ModalComponent/utils.ts +55 -7
  42. package/Components/OfflineHandler/utils/index.ts +1 -1
  43. package/Components/PlayerContainer/PlayerContainer.tsx +55 -46
  44. package/Components/PlayerImageBackground/index.tsx +1 -1
  45. package/Components/River/ComponentsMap/ComponentsMap.tsx +14 -3
  46. package/Components/River/ComponentsMap/hooks/useLoadingState.ts +3 -3
  47. package/Components/River/RiverItem.tsx +8 -3
  48. package/Components/River/__tests__/__snapshots__/componentsMap.test.js.snap +7 -1
  49. package/Components/RouteManager/TestId.tsx +1 -5
  50. package/Components/RouteManager/__tests__/__snapshots__/routeManager.test.js.snap +0 -1
  51. package/Components/RouteManager/__tests__/testId.test.js +0 -4
  52. package/Components/Screen/TV/__tests__/index.web.test.tsx +26 -0
  53. package/Components/Screen/TV/index.web.tsx +5 -6
  54. package/Components/Screen/__tests__/Screen.test.tsx +22 -14
  55. package/Components/Screen/__tests__/__snapshots__/Screen.test.tsx.snap +2 -2
  56. package/Components/Screen/hooks.ts +3 -6
  57. package/Components/TopMarginApplicator/TopMarginApplicator.tsx +2 -3
  58. package/Components/TrackedView/index.tsx +1 -0
  59. package/Components/Transitioner/AnimationManager.js +15 -15
  60. package/Components/VideoLive/PlayerLiveImageComponent.tsx +4 -0
  61. package/Components/VideoLive/__tests__/__snapshots__/PlayerLiveImageComponent.test.tsx.snap +1 -0
  62. package/Components/VideoModal/ModalAnimation/AnimatedPlayerModalWrapper.tsx +1 -1
  63. package/Components/VideoModal/ModalAnimation/AnimatedScrollModal.tsx +35 -19
  64. package/Components/VideoModal/ModalAnimation/AnimatedVideoPlayerComponent.tsx +3 -3
  65. package/Components/VideoModal/ModalAnimation/AnimationComponent.tsx +38 -14
  66. package/Components/VideoModal/ModalAnimation/ModalAnimationContext.tsx +11 -3
  67. package/Components/VideoModal/ModalAnimation/__tests__/getMoveUpValue.test.ts +108 -0
  68. package/Components/VideoModal/ModalAnimation/const.ts +5 -0
  69. package/Components/VideoModal/ModalAnimation/index.ts +2 -0
  70. package/Components/VideoModal/ModalAnimation/utils.ts +30 -0
  71. package/Components/VideoModal/PlayerDetails.tsx +13 -5
  72. package/Components/VideoModal/PlayerWrapper.tsx +35 -22
  73. package/Components/VideoModal/VideoModal.tsx +19 -4
  74. package/Components/VideoModal/__tests__/__snapshots__/PlayerDetails.test.tsx.snap +2 -40
  75. package/Components/VideoModal/utils.ts +3 -4
  76. package/Components/ZappUIComponent/index.tsx +4 -4
  77. package/Contexts/FocusableGroupContext/withFocusableContext.tsx +4 -10
  78. package/Contexts/HeaderOffsetContext/index.tsx +4 -6
  79. package/Contexts/ScreenContext/index.tsx +3 -10
  80. package/Contexts/ScreenLayoutContext/index.tsx +5 -3
  81. package/Decorators/RiverResolver/index.tsx +5 -7
  82. package/Decorators/ZappPipesDataConnector/index.tsx +4 -30
  83. package/package.json +5 -9
  84. package/tsconfig.json +2 -3
  85. package/.babelrc +0 -8
  86. package/Components/Cell/CellStyles/FallbackCellStyle/index.js +0 -157
  87. package/Components/Cell/CellStyles/Hero/index.js +0 -111
  88. package/Components/Cell/CellStyles/ScreenSelector/index.js +0 -68
  89. package/Components/Cell/CellStyles/cellStylesResolver.ts +0 -19
  90. package/Components/Cell/CellStyles/colors.js +0 -40
  91. package/Components/Cell/CellStyles/index.js +0 -15
  92. package/Components/Cell/CellWithFocusable.ios.tsx +0 -126
@@ -1,16 +1,13 @@
1
- import React, { useEffect, useMemo } from "react";
1
+ import React, { useMemo } from "react";
2
2
  import * as R from "ramda";
3
3
  import validateColor from "validate-color";
4
4
  import { platformSelect } from "@applicaster/zapp-react-native-utils/reactUtils";
5
5
  import { useActions } from "@applicaster/zapp-react-native-utils/reactHooks/actions";
6
6
 
7
7
  import { masterCellLogger } from "../logger";
8
- import { playerManager } from "@applicaster/zapp-react-native-utils/appUtils";
9
- import { usePlayer } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/usePlayer";
10
- import { PushTopicManager } from "@applicaster/zapp-react-native-bridge/PushNotifications/PushTopicManager";
11
- import { StorageMultiSelectProvider } from "@applicaster/zapp-react-native-bridge/ZappStorage/StorageMultiSelectProvider";
12
8
  import { getCellState } from "../../Cell/utils";
13
9
  import { getColorFromData } from "@applicaster/zapp-react-native-utils/cellUtils";
10
+ import { isCellSelected, useBehaviorUpdate } from "./behaviorProvider";
14
11
 
15
12
  const hasElementSpecificViewType = (viewType) => (element) => {
16
13
  if (R.isNil(element)) {
@@ -193,147 +190,24 @@ export const getFocusedButtonId = (focusable) => {
193
190
  });
194
191
  };
195
192
 
196
- export const isSelected = (id: string | number, behavior?: Behavior) => {
197
- if (!behavior) {
198
- return false;
199
- }
200
-
201
- if (behavior?.selection_source === "now_playing") {
202
- const player = playerManager.getActivePlayer();
203
-
204
- if (player?.entry?.id === id) {
205
- return true;
206
- }
207
- }
208
-
209
- if (behavior?.select_mode === "single") {
210
- return behavior.current_selection === id;
211
- }
212
-
213
- if (behavior?.select_mode === "multi") {
214
- // TODO: Use generic resolver source
215
-
216
- if (behavior.selection_source === "@{push/topics}") {
217
- const tags = PushTopicManager.getInstance().getRegisteredTags();
218
-
219
- return tags.includes(String(id));
220
- }
221
-
222
- if (Array.isArray(behavior.current_selection)) {
223
- return behavior.current_selection.includes(id);
224
- }
225
-
226
- const currentSelection = String(behavior.current_selection);
227
-
228
- if (currentSelection?.startsWith("@{ctx/")) {
229
- const keyWithoutCtx = currentSelection.substring(
230
- "@{ctx/".length,
231
- currentSelection.length - 1
232
- );
233
-
234
- const selectedItems =
235
- StorageMultiSelectProvider.getProvider(
236
- keyWithoutCtx
237
- )?.getSelectedItems();
238
-
239
- return selectedItems?.includes(String(id));
240
- }
241
- }
242
-
243
- return false;
244
- };
245
-
246
- export const useBehaviorUpdate = (behavior: Behavior) => {
247
- const [lastUpdate, setLastUpdate] = React.useState(null);
248
-
249
- const player = usePlayer();
250
-
251
- const triggerUpdate = () => {
252
- setLastUpdate(Date.now());
253
- };
254
-
255
- // TODO: Create generic RX to state update
256
- useEffect(() => {
257
- // TODO: Use generic resolver source
258
- if (!behavior) {
259
- return;
260
- }
261
-
262
- const currentSelection = String(behavior.current_selection);
263
-
264
- if (currentSelection?.startsWith("@{ctx/")) {
265
- const keyWithoutCtx = currentSelection.substring(
266
- "@{ctx/".length,
267
- currentSelection.length - 1
268
- );
269
-
270
- if (keyWithoutCtx) {
271
- const subscription = StorageMultiSelectProvider.getProvider(
272
- keyWithoutCtx
273
- )
274
- .getObservable()
275
- .subscribe(() => {
276
- triggerUpdate();
277
- });
278
-
279
- return () => {
280
- subscription.unsubscribe();
281
- };
282
- }
283
- }
284
- }, [behavior]);
285
-
286
- useEffect(() => {
287
- if (!behavior) {
288
- return;
289
- }
290
-
291
- if (behavior?.selection_source === "@{push/topics}") {
292
- const subscription = PushTopicManager.getInstance()
293
- .getEntryObservable()
294
- .subscribe(() => {
295
- triggerUpdate();
296
- });
297
-
298
- return () => {
299
- subscription.unsubscribe();
300
- };
301
- }
302
- }, [behavior]);
303
-
304
- useEffect(() => {
305
- if (!behavior) {
306
- return;
307
- }
308
-
309
- if (behavior?.selection_source === "now_playing" && player) {
310
- const subscription = player.getEntryObservable().subscribe(() => {
311
- triggerUpdate();
312
- });
313
-
314
- return () => {
315
- subscription.unsubscribe();
316
- };
317
- }
318
- }, [behavior, player]);
319
-
320
- return lastUpdate;
193
+ export const isSelected = (item: ZappEntry, behavior?: Behavior) => {
194
+ return isCellSelected(item, behavior);
321
195
  };
322
196
 
323
197
  export const useCellState = ({
324
- id,
198
+ item,
325
199
  behavior,
326
200
  focused,
327
201
  }: {
328
- id: string | number;
202
+ item: ZappEntry;
329
203
  behavior: Behavior;
330
204
  focused: boolean;
331
205
  }): CellState => {
332
206
  const lastUpdate = useBehaviorUpdate(behavior);
333
207
 
334
208
  const _isSelected = useMemo(
335
- () => isSelected(id, behavior),
336
- [behavior, id, lastUpdate]
209
+ () => isSelected(item, behavior),
210
+ [behavior, item, lastUpdate]
337
211
  );
338
212
 
339
213
  return getCellState({ focused, selected: _isSelected });
@@ -1,23 +1,16 @@
1
- import React, {
2
- useCallback,
3
- useEffect,
4
- useMemo,
5
- useRef,
6
- useState,
7
- } from "react";
8
- import { View, LayoutChangeEvent, ScrollView } from "react-native";
1
+ import React, { useCallback, useEffect, useMemo, useRef } from "react";
2
+ import { View, ScrollView } from "react-native";
9
3
  import { Button } from "./Button";
10
4
  import { ItemIconProps } from "./Button/ItemIcon";
11
5
  import { ItemProps } from "./Button/Item";
12
6
  import { ItemLabelProps } from "./Button/ItemLabel";
13
- import {
14
- defaultItemIconProps,
15
- defaultItemLabelProps,
16
- defaultItemProps,
17
- } from "./utils";
7
+ import { getItemIconProps, getItemLabelProps, getItemProps } from "./utils";
18
8
  import { useTheme } from "@applicaster/zapp-react-native-utils/theme";
19
9
 
20
- import { ModalHeader } from "./Header";
10
+ import type { PluginConfiguration } from "./";
11
+
12
+ import { ModalHeader as DefaultModalHeader } from "./Header";
13
+ import { useSafeAreaInsets } from "react-native-safe-area-context";
21
14
 
22
15
  type ModalComponentProps = {
23
16
  items: any[];
@@ -29,33 +22,46 @@ type ModalComponentProps = {
29
22
  title?: string;
30
23
  maxHeight?: number;
31
24
  dismiss: () => void;
25
+ headerComponent?: React.ComponentType;
32
26
  buttonComponent?: React.ComponentType;
27
+ iconProps?: ItemIconProps | ((theme: PluginConfiguration) => ItemIconProps);
28
+ itemProps?:
29
+ | ItemProps
30
+ | ((theme: PluginConfiguration, width: number) => ItemProps);
31
+ labelProps?:
32
+ | ItemLabelProps
33
+ | ((theme: PluginConfiguration, width: number) => ItemLabelProps);
34
+ getSelectedItemIcon: (
35
+ theme: PluginConfiguration
36
+ ) => ItemIconProps["asset"] | null;
37
+ getDefaultItemIcon: (
38
+ theme: PluginConfiguration
39
+ ) => ItemIconProps["asset"] | null;
40
+ iconPlacement?: "left" | "right";
33
41
  };
34
42
 
35
43
  export function BottomSheetModalContent(props: ModalComponentProps) {
36
44
  const {
37
45
  items,
38
46
  currentRoute,
39
- maxHeight,
40
47
  current_selection = null,
41
48
  onPress,
42
49
  dismiss,
43
50
  summary,
44
51
  title,
52
+ headerComponent: ModalHeader = DefaultModalHeader,
45
53
  buttonComponent: ButtonComponent = Button,
54
+ getSelectedItemIcon = ({
55
+ modal_bottom_sheet_item_selected_icon,
56
+ }: BaseThemePropertiesMobile) => modal_bottom_sheet_item_selected_icon,
57
+ getDefaultItemIcon = () => null,
58
+ iconPlacement,
46
59
  } = props;
47
60
 
48
- const [headerHeight, setHeaderHeight] = useState(0);
49
61
  const route = useRef(currentRoute);
50
62
  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
- }, []);
63
+ const paddingTop = Number(theme.modal_bottom_sheet_padding_top);
64
+ const paddingBottom = Number(theme.modal_bottom_sheet_padding_bottom);
59
65
 
60
66
  useEffect(() => {
61
67
  if (currentRoute !== route.current) {
@@ -64,57 +70,63 @@ export function BottomSheetModalContent(props: ModalComponentProps) {
64
70
  }, [currentRoute]);
65
71
 
66
72
  const iconBaseProps = useMemo<ItemIconProps>(() => {
67
- return defaultItemIconProps(theme);
68
- }, [theme]);
73
+ return getItemIconProps(theme, props.iconProps);
74
+ }, [theme, props.iconProps]);
69
75
 
70
76
  const itemBaseProps = useMemo<ItemProps>(() => {
71
- return defaultItemProps(theme, props.width);
72
- }, [theme, props.width]);
77
+ return getItemProps(theme, props.width, props.itemProps);
78
+ }, [theme, props.width, props.itemProps]);
73
79
 
74
80
  const labelBaseProps = useMemo<ItemLabelProps>(() => {
75
- return defaultItemLabelProps(theme, props.width);
76
- }, [theme, props.width]);
81
+ return getItemLabelProps(theme, props.width, props.labelProps);
82
+ }, [theme, props.width, props.labelProps]);
83
+
84
+ const handlePress = useCallback(
85
+ (item: any) => {
86
+ onPress(item);
87
+ dismiss();
88
+ },
89
+ [onPress, dismiss]
90
+ );
77
91
 
78
- const handlePress = (item: any) => {
79
- onPress(item);
80
- dismiss();
81
- };
92
+ const bottomInset = useSafeAreaInsets().bottom;
82
93
 
83
94
  return (
84
95
  <View
85
96
  style={{
86
- paddingTop: Number(theme.modal_bottom_sheet_padding_top),
97
+ maxHeight: props.maxHeight,
98
+ paddingTop: paddingTop,
87
99
  }}
88
100
  >
89
101
  <ModalHeader
90
- width={props.width}
91
102
  dismiss={dismiss}
92
103
  configuration={theme}
93
- onLayout={onHeaderLayout}
94
104
  summary={summary}
95
105
  title={title}
96
106
  />
97
107
  <ScrollView
98
- bounces={false}
99
- style={{ maxHeight: maxContentHeight }}
100
108
  contentContainerStyle={{
101
- paddingBottom: Number(theme.modal_bottom_sheet_padding_bottom),
102
- paddingTop: Number(theme.modal_bottom_sheet_padding_top),
109
+ paddingBottom: paddingBottom + bottomInset,
103
110
  }}
104
111
  >
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
- ))}
112
+ {items.map((item, index) =>
113
+ item ? (
114
+ <ButtonComponent
115
+ key={index}
116
+ configuration={theme}
117
+ selectedItem={current_selection}
118
+ item={item}
119
+ onPress={handlePress}
120
+ label={theme[item?.label] ?? item?.label}
121
+ iconBaseProps={iconBaseProps}
122
+ itemBaseProps={itemBaseProps}
123
+ labelBaseProps={labelBaseProps}
124
+ selectedItemIcon={getSelectedItemIcon(theme)}
125
+ defaultItemIcon={getDefaultItemIcon(theme)}
126
+ iconPlacement={iconPlacement}
127
+ />
128
+ ) : null
129
+ )}
118
130
  </ScrollView>
119
131
  </View>
120
132
  );
@@ -5,7 +5,7 @@ export type ItemProps = {
5
5
  backgroundColor: string;
6
6
  focusedBackgroundColor: string;
7
7
  selectedBackgroundColor?: string;
8
- focusectedBackgroundColor?: string;
8
+ focusedSelectedBackgroundColor?: string;
9
9
  borderRadius: number;
10
10
  marginBottom: number;
11
11
  marginLeft: number;
@@ -15,6 +15,7 @@ export type ItemProps = {
15
15
  paddingBottom: number;
16
16
  paddingRight: number;
17
17
  paddingLeft: number;
18
+ maxWidth: number;
18
19
  focused?: boolean;
19
20
  selected?: boolean;
20
21
  children?: ReactChild[];
@@ -33,11 +34,11 @@ function getBackgroundColor({
33
34
  backgroundColor,
34
35
  focusedBackgroundColor,
35
36
  selectedBackgroundColor,
36
- focusectedBackgroundColor,
37
+ focusedSelectedBackgroundColor,
37
38
  }) {
38
39
  switch (true) {
39
40
  case selected && focused:
40
- return focusectedBackgroundColor;
41
+ return focusedSelectedBackgroundColor;
41
42
  case selected && !focused:
42
43
  return selectedBackgroundColor;
43
44
  case !selected && focused:
@@ -51,7 +52,7 @@ export function Item(props: ItemProps) {
51
52
  const {
52
53
  backgroundColor,
53
54
  focusedBackgroundColor,
54
- focusectedBackgroundColor,
55
+ focusedSelectedBackgroundColor,
55
56
  selectedBackgroundColor,
56
57
  children,
57
58
  focused,
@@ -68,7 +69,7 @@ export function Item(props: ItemProps) {
68
69
  backgroundColor: getBackgroundColor({
69
70
  selected,
70
71
  focused,
71
- focusectedBackgroundColor,
72
+ focusedSelectedBackgroundColor,
72
73
  focusedBackgroundColor,
73
74
  selectedBackgroundColor,
74
75
  backgroundColor,
@@ -1,4 +1,4 @@
1
1
  /* eslint-disable max-len */
2
2
 
3
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==";
4
+ "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEgAAABICAYAAABV7bNHAAAACXBIWXMAACE4AAAhOAFFljFgAAAA+0lEQVR4nO3a3QnCQBBF4ZRiSXZgKVqKnVnCQBpQwb0QJA752ZjszPlg3/JwOU8b2K4DAAAAAAAAkIOZnczsvPeOQypxHmb27Pv+sveeQxnG0SFSMRaHSIUXJ32kKXHKue+99e+I4yCOgzgO4jiI4yCOgzgO4jiajfMedd366t50nK3/b0LE2SpSqDi1I4WMUytSs3G6z/jbhOGLIzUdR7aKFCKO1I4UKo7UihQyjqyNFDqOLI2UIo7MjZQqjkyNVL7LFUdmRMoXRypEihtHVkSKH0cWRMoTR2ZEyhdHJkTKG0ecSMSRkUjE+TaIRJxfeFQJAAAAAAAANOwFT0Mt2UgcaMoAAAAASUVORK5CYII=";
@@ -3,12 +3,10 @@ import { StyleSheet, TouchableOpacity, View } from "react-native";
3
3
  import { Item, ItemProps } from "./Item";
4
4
  import { ItemIcon, ItemIconProps } from "./ItemIcon";
5
5
  import { ItemLabel, ItemLabelProps } from "./ItemLabel";
6
- import * as assets from "./assets";
7
6
  import { defaultSelectedAsset } from "./assets";
8
7
 
9
8
  type ButtonProps = {
10
9
  configuration: any;
11
- width: number;
12
10
  selectedItem?: any;
13
11
  item: any; // Adjust type as needed
14
12
  onPress: (item: any) => void; // Adjust type as needed
@@ -17,6 +15,9 @@ type ButtonProps = {
17
15
  labelBaseProps?: ItemLabelProps;
18
16
  disabled?: boolean;
19
17
  label?: string | Record<string, string>;
18
+ iconPlacement?: "left" | "right";
19
+ selectedItemIcon?: ItemIconProps["asset"];
20
+ defaultItemIcon?: ItemIconProps["asset"];
20
21
  };
21
22
 
22
23
  const styles = StyleSheet.create({
@@ -31,81 +32,63 @@ export function Button({
31
32
  item,
32
33
  onPress,
33
34
  configuration,
34
- width,
35
35
  iconBaseProps,
36
- itemBaseProps,
36
+ itemBaseProps: itemProps,
37
37
  labelBaseProps,
38
38
  label,
39
+ iconPlacement = "left",
40
+ defaultItemIcon,
41
+ selectedItemIcon,
39
42
  disabled = false,
40
43
  }: ButtonProps) {
41
44
  const [focused, setFocused] = useState(false);
42
45
 
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
- );
46
+ const selected = selectedItem && item.value === selectedItem?.value;
55
47
 
56
- const itemIconProps = useMemo<ItemIconProps>(
57
- () => ({
58
- ...iconBaseProps,
59
- asset: configuration[item.asset] ?? assets[item.asset] ?? item.asset,
60
- }),
61
- [configuration, item.asset]
48
+ const itemIconPropsAssets = useMemo<ItemIconProps["asset"]>(
49
+ () => configuration[item.asset] ?? item.asset ?? defaultItemIcon,
50
+ [item.asset, defaultItemIcon]
62
51
  );
63
52
 
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]
53
+ const selectedItemIconPropsAssets = useMemo<ItemIconProps["asset"]>(
54
+ () => selectedItemIcon || defaultSelectedAsset,
55
+ [selectedItemIcon]
73
56
  );
74
57
 
75
- const itemLabelProps = useMemo<ItemLabelProps>(
76
- () => ({
77
- ...labelBaseProps,
78
- label: label ?? configuration[item?.label] ?? item?.label ?? null,
79
- }),
80
- [configuration, item?.label]
81
- );
58
+ const renderItemIcon =
59
+ itemIconPropsAssets && itemIconPropsAssets.length > 0 ? (
60
+ <ItemIcon {...iconBaseProps} asset={itemIconPropsAssets} />
61
+ ) : null;
82
62
 
83
63
  if (disabled) return null;
84
64
 
85
65
  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
- ) : null}
98
- {itemLabelProps.label ? (
99
- <ItemLabel
100
- {...itemLabelProps}
101
- focused={focused}
102
- selected={selected}
103
- />
104
- ) : null}
105
- </View>
106
- {selected ? <ItemIcon {...selectedItemIconProps} /> : null}
107
- </Item>
108
- </TouchableOpacity>
109
- </View>
66
+ <TouchableOpacity
67
+ activeOpacity={1}
68
+ onPress={() => onPress(item)}
69
+ onPressIn={() => setFocused(true)}
70
+ onPressOut={() => setFocused(false)}
71
+ >
72
+ <Item {...itemProps} focused={focused} selected={selected}>
73
+ <View style={styles.label_icon_container}>
74
+ {iconPlacement === "left" && renderItemIcon}
75
+
76
+ {label ? (
77
+ <ItemLabel
78
+ {...labelBaseProps}
79
+ label={label ?? null}
80
+ focused={focused}
81
+ selected={selected}
82
+ />
83
+ ) : null}
84
+ </View>
85
+
86
+ {selected ? (
87
+ <ItemIcon {...iconBaseProps} asset={selectedItemIconPropsAssets} />
88
+ ) : (
89
+ iconPlacement === "right" && renderItemIcon
90
+ )}
91
+ </Item>
92
+ </TouchableOpacity>
110
93
  );
111
94
  }
@@ -8,13 +8,18 @@ import { PluginConfiguration } from "../index";
8
8
  type Props = {
9
9
  dismiss: () => void;
10
10
  configuration: PluginConfiguration;
11
- width: number;
12
11
  onLayout?: (event: LayoutChangeEvent) => void;
13
12
  summary?: string;
14
13
  title?: string;
15
14
  };
16
15
 
17
16
  const styles = StyleSheet.create({
17
+ noFlex: {
18
+ flex: 0,
19
+ },
20
+ flex: {
21
+ flex: 1,
22
+ },
18
23
  container: {
19
24
  flexDirection: "row",
20
25
  alignItems: "center",
@@ -22,7 +27,7 @@ const styles = StyleSheet.create({
22
27
  });
23
28
 
24
29
  export function ModalHeader(props: Props) {
25
- const { configuration, dismiss, width, onLayout, summary, title } = props;
30
+ const { configuration, dismiss, onLayout, summary, title } = props;
26
31
 
27
32
  const closeButtonProps = useMemo<CloseButtonProps>(
28
33
  () => ({
@@ -55,15 +60,11 @@ export function ModalHeader(props: Props) {
55
60
 
56
61
  return (
57
62
  <View onLayout={onLayout} style={styles.container}>
58
- <View
59
- style={{
60
- width: width - buttonsContainerWidth,
61
- }}
62
- >
63
+ <View style={styles.flex}>
63
64
  {title ? <Title {...titleProps} /> : null}
64
65
  {summary ? <Title {...summaryProps} /> : null}
65
66
  </View>
66
- <View style={{ width: buttonsContainerWidth }}>
67
+ <View style={[styles.noFlex, { width: buttonsContainerWidth }]}>
67
68
  <CloseButton {...closeButtonProps} />
68
69
  </View>
69
70
  </View>