@applicaster/zapp-react-native-ui-components 13.0.0-alpha.6179233127 → 13.0.0-alpha.6400875052

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/Components/Cell/Cell.tsx +3 -13
  2. package/Components/Cell/CellWithFocusable.tsx +18 -14
  3. package/Components/Cell/CellWrapper.ts +5 -0
  4. package/Components/Cell/styles.ts +17 -0
  5. package/Components/ErrorScreen/index.tsx +8 -0
  6. package/Components/FocusableCell/index.tsx +1 -1
  7. package/Components/HandlePlayable/HandlePlayable.tsx +21 -27
  8. package/Components/MasterCell/DefaultComponents/Image/Image.ios.tsx +4 -3
  9. package/Components/MasterCell/DefaultComponents/Image/hooks/useImage.ts +11 -7
  10. package/Components/MasterCell/utils/behaviorProvider.ts +4 -1
  11. package/Components/MasterCell/utils/index.ts +6 -6
  12. package/Components/ModalComponent/BottomSheetModalContent.tsx +38 -15
  13. package/Components/ModalComponent/Button/Item.tsx +1 -0
  14. package/Components/ModalComponent/Button/assets.ts +1 -1
  15. package/Components/ModalComponent/Button/index.tsx +29 -42
  16. package/Components/ModalComponent/utils.ts +52 -4
  17. package/Components/OfflineHandler/utils/index.ts +1 -1
  18. package/Components/PlayerContainer/PlayerContainer.tsx +11 -1
  19. package/Components/River/ComponentsMap/ComponentsMap.tsx +3 -0
  20. package/Components/Screen/TV/index.web.tsx +5 -6
  21. package/Components/VideoModal/ModalAnimation/AnimationComponent.tsx +4 -0
  22. package/Components/VideoModal/PlayerDetails.tsx +4 -4
  23. package/Components/VideoModal/PlayerWrapper.tsx +26 -3
  24. package/Components/VideoModal/VideoModal.tsx +19 -4
  25. package/Components/ZappUIComponent/index.tsx +4 -4
  26. package/Decorators/RiverResolver/index.tsx +5 -7
  27. package/Decorators/ZappPipesDataConnector/index.tsx +2 -1
  28. package/package.json +5 -6
  29. package/.babelrc +0 -8
  30. package/Components/Cell/CellStyles/FallbackCellStyle/index.js +0 -157
  31. package/Components/Cell/CellStyles/Hero/index.js +0 -111
  32. package/Components/Cell/CellStyles/ScreenSelector/index.js +0 -68
  33. package/Components/Cell/CellStyles/cellStylesResolver.ts +0 -19
  34. package/Components/Cell/CellStyles/colors.js +0 -40
  35. package/Components/Cell/CellStyles/index.js +0 -15
@@ -12,6 +12,7 @@ import { noop } from "@applicaster/zapp-react-native-utils/functionUtils";
12
12
  import { CellWithFocusable } from "./CellWithFocusable";
13
13
  import { BaseFocusable } from "../BaseFocusable";
14
14
  import { AccessibilityManager } from "@applicaster/zapp-react-native-utils/appUtils/accessibilityManager";
15
+ import { styles } from "./styles";
15
16
 
16
17
  type Props = {
17
18
  item: ZappEntry;
@@ -68,17 +69,6 @@ type State = {
68
69
  hasFocusableInside: boolean;
69
70
  };
70
71
 
71
- const baseCellStyles = {
72
- height: "100%",
73
- display: "flex",
74
- flex: 1,
75
- } as const;
76
-
77
- const touchableStyles = {
78
- flex: 1,
79
- height: "100%",
80
- } as const;
81
-
82
72
  export class CellComponent extends React.Component<Props, State> {
83
73
  constructor(props) {
84
74
  super(props);
@@ -252,7 +242,7 @@ export class CellComponent extends React.Component<Props, State> {
252
242
  <View
253
243
  testID={`${component?.id}-${id}`}
254
244
  accessible={false}
255
- style={touchableStyles}
245
+ style={styles.touchableCell}
256
246
  >
257
247
  <Focusable
258
248
  id={focusableId}
@@ -264,7 +254,7 @@ export class CellComponent extends React.Component<Props, State> {
264
254
  hasReceivedFocus={hasReceivedFocus || this.hasReceivedFocus}
265
255
  preferredFocus={preferredFocus}
266
256
  offsetUpdater={offsetUpdater}
267
- style={baseCellStyles}
257
+ style={styles.baseCell}
268
258
  isFocusable={isFocusable}
269
259
  skipFocusManagerRegistration={skipFocusManagerRegistration}
270
260
  >
@@ -5,6 +5,8 @@ import { toBooleanWithDefaultFalse } from "@applicaster/zapp-react-native-utils/
5
5
 
6
6
  import { useCellState } from "../MasterCell/utils";
7
7
  import { FocusableGroup } from "../FocusableGroup";
8
+ import { CellWrapper } from "./CellWrapper";
9
+ import { styles } from "./styles";
8
10
 
9
11
  type Props = {
10
12
  item: ZappEntry;
@@ -40,7 +42,7 @@ export function CellWithFocusable(props: Props) {
40
42
  const [isFocused, setIsFocused] = React.useState(false);
41
43
 
42
44
  const state = useCellState({
43
- id: item.id,
45
+ item,
44
46
  behavior,
45
47
  focused: isFocused || toBooleanWithDefaultFalse(focused),
46
48
  });
@@ -88,19 +90,21 @@ export function CellWithFocusable(props: Props) {
88
90
  onBlur={onGroupBlur}
89
91
  skipFocusManagerRegistration={skipFocusManagerRegistration}
90
92
  >
91
- <CellRenderer
92
- testID={"cell-with-focusable-cell-renderer"}
93
- item={item}
94
- groupId={`focusable-cell-wrapper-${id}`}
95
- onToggleFocus={handleToggleFocus}
96
- state={state}
97
- prefixId={id}
98
- focusedButtonId={focusedButtonId}
99
- preferredFocus={true}
100
- skipFocusManagerRegistration={skipFocusManagerRegistration}
101
- isFocusable={isFocusable}
102
- focused={focused}
103
- />
93
+ <CellWrapper style={styles.cellWrapper}>
94
+ <CellRenderer
95
+ testID={"cell-with-focusable-cell-renderer"}
96
+ item={item}
97
+ groupId={`focusable-cell-wrapper-${id}`}
98
+ onToggleFocus={handleToggleFocus}
99
+ state={state}
100
+ prefixId={id}
101
+ focusedButtonId={focusedButtonId}
102
+ preferredFocus={true}
103
+ skipFocusManagerRegistration={skipFocusManagerRegistration}
104
+ isFocusable={isFocusable}
105
+ focused={focused}
106
+ />
107
+ </CellWrapper>
104
108
  </FocusableGroup>
105
109
  );
106
110
  }
@@ -0,0 +1,5 @@
1
+ import { isTvOSPlatform } from "@applicaster/zapp-react-native-utils/reactUtils";
2
+ import React from "react";
3
+ import { View } from "react-native";
4
+
5
+ export const CellWrapper = isTvOSPlatform() ? View : React.Fragment;
@@ -0,0 +1,17 @@
1
+ import { StyleSheet } from "react-native";
2
+
3
+ export const styles = StyleSheet.create({
4
+ cellWrapper: {
5
+ flex: 0,
6
+ height: "100%",
7
+ },
8
+ baseCell: {
9
+ height: "100%",
10
+ display: "flex",
11
+ flex: 1,
12
+ },
13
+ touchableCell: {
14
+ flex: 1,
15
+ height: "100%",
16
+ },
17
+ });
@@ -105,6 +105,11 @@ const defaultProps = {
105
105
  alignItems: "center",
106
106
  justifyContent: "center",
107
107
  },
108
+ focusedButton: {
109
+ backgroundColor: "#3a3a3a",
110
+ borderColor: "#ffffff",
111
+ borderWidth: 2,
112
+ },
108
113
  buttonText: {
109
114
  fontFamily: platformSelect({
110
115
  ios: "SFProText-Medium",
@@ -116,6 +121,9 @@ const defaultProps = {
116
121
  color: "rgba(255, 255, 255, 1)",
117
122
  textTransform: "uppercase",
118
123
  },
124
+ focusedText: {
125
+ color: "#ffffff",
126
+ },
119
127
  },
120
128
  };
121
129
 
@@ -23,7 +23,7 @@ export function FocusableCell(props: Props) {
23
23
  behavior,
24
24
  } = props;
25
25
 
26
- const state = useCellState({ id: item.id, behavior, focused });
26
+ const state = useCellState({ item, behavior, focused });
27
27
 
28
28
  React.useEffect(() => {
29
29
  if (focused && scrollTo && !isAndroid) {
@@ -1,17 +1,18 @@
1
1
  import * as React from "react";
2
2
  import * as R from "ramda";
3
- import { ViewStyle } from "react-native";
4
3
  import {
5
4
  findPluginByType,
6
5
  findPluginByIdentifier,
7
6
  } from "@applicaster/zapp-react-native-utils/pluginUtils";
8
- import { useDimensions } from "@applicaster/zapp-react-native-utils/reactHooks/layout";
9
7
  import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
10
- import { useNavigation } from "@applicaster/zapp-react-native-utils/reactHooks";
11
- import { platformSelect } from "@applicaster/zapp-react-native-utils/reactUtils";
8
+ import {
9
+ useDimensions,
10
+ useNavigation,
11
+ } from "@applicaster/zapp-react-native-utils/reactHooks";
12
12
 
13
13
  import { BufferAnimation } from "../PlayerContainer/BufferAnimation";
14
14
  import { PlayerContainer } from "../PlayerContainer";
15
+ import { useModalSize } from "../VideoModal/hooks";
15
16
 
16
17
  type Props = {
17
18
  item: ZappEntry;
@@ -78,12 +79,6 @@ const getPlayer = (
78
79
  return getPlayerWithModuleProperties(PlayerModule);
79
80
  };
80
81
 
81
- const dimensionsContext: "window" | "screen" = platformSelect({
82
- android_tv: "window",
83
- amazon: "window",
84
- default: "screen",
85
- });
86
-
87
82
  type PlayableComponent = {
88
83
  Component: React.ComponentType<any>;
89
84
  };
@@ -91,16 +86,11 @@ type PlayableComponent = {
91
86
  export function HandlePlayable({
92
87
  item,
93
88
  isModal,
94
- modalHeight,
95
- modalWidth,
96
89
  mode,
97
90
  groupId,
98
91
  }: Props): React.ReactElement | null {
99
92
  const state = usePickFromState();
100
93
 
101
- const { width: screenWidth, height: screenHeight } =
102
- useDimensions(dimensionsContext);
103
-
104
94
  const { closeVideoModal } = useNavigation();
105
95
 
106
96
  const [Player, playerModuleProperties] = getPlayer(item, state);
@@ -118,9 +108,7 @@ export function HandlePlayable({
118
108
  if (!isModal) {
119
109
  closeVideoModal();
120
110
  }
121
- }, []);
122
111
 
123
- React.useEffect(() => {
124
112
  const castStateHandler = async () => {
125
113
  const castState = await CastPlugin?.getCastState();
126
114
  setCasting(castState === "Connected");
@@ -142,23 +130,29 @@ export function HandlePlayable({
142
130
  }, []);
143
131
 
144
132
  React.useEffect(() => {
145
- if (casting) {
146
- setPlayable({ Component: CastPlugin?.CastHandler });
147
- } else {
148
- setPlayable({ Component: PlayerContainer });
149
- }
133
+ setPlayable({
134
+ Component: casting ? CastPlugin?.CastHandler : PlayerContainer,
135
+ });
150
136
  }, [casting]);
151
137
 
152
- const Component = playable?.Component;
138
+ const { width: screenWidth, height: screenHeight } = useDimensions("window");
139
+
140
+ const modalSize = useModalSize();
153
141
 
154
142
  const style = React.useMemo(
155
143
  () => ({
156
- width: isModal ? modalWidth : mode === "PIP" ? "100%" : screenWidth,
157
- height: isModal ? modalHeight : mode === "PIP" ? "100%" : screenHeight,
144
+ width: isModal ? modalSize.width : mode === "PIP" ? "100%" : screenWidth,
145
+ height: isModal
146
+ ? modalSize.height
147
+ : mode === "PIP"
148
+ ? "100%"
149
+ : screenHeight,
158
150
  }),
159
- [screenWidth, screenHeight, modalHeight, modalWidth, isModal, mode]
151
+ [screenWidth, screenHeight, modalSize, isModal, mode]
160
152
  );
161
153
 
154
+ const Component = playable?.Component;
155
+
162
156
  if (Component) {
163
157
  return (
164
158
  <Component
@@ -174,5 +168,5 @@ export function HandlePlayable({
174
168
  );
175
169
  }
176
170
 
177
- return !isModal ? <BufferAnimation videoStyle={style as ViewStyle} /> : null;
171
+ return !isModal ? <BufferAnimation videoStyle={style} /> : null;
178
172
  }
@@ -1,6 +1,6 @@
1
1
  import * as React from "react";
2
2
  import { Image as RnImage, ImageStyle } from "react-native";
3
- import * as R from "ramda";
3
+ import { equals, omit } from "ramda";
4
4
 
5
5
  import { useImageSource } from "./hooks";
6
6
 
@@ -17,7 +17,7 @@ type Props = Record<string, any> & {
17
17
  withDimensions: (source: Source) => Source;
18
18
  };
19
19
 
20
- const MemoizedImage = React.memo(RnImage, R.equals);
20
+ const MemoizedImage = React.memo(RnImage, equals);
21
21
 
22
22
  function Image({
23
23
  style,
@@ -44,11 +44,12 @@ function Image({
44
44
 
45
45
  return (
46
46
  <MemoizedImage
47
+ key={_source?.uri || "no-image"}
47
48
  style={style as ImageStyle}
48
49
  onError={React.useCallback(() => setErrorState(true), [])}
49
50
  // as we have defaults as "" for placeholder image, we need to pass undefined to source to not throw warnings
50
51
  source={_source?.uri ? _source : undefined}
51
- {...R.omit(["source"], otherProps)}
52
+ {...omit(["source"], otherProps)}
52
53
  />
53
54
  );
54
55
  }
@@ -1,5 +1,5 @@
1
1
  import * as React from "react";
2
- import * as R from "ramda";
2
+ import { path } from "ramda";
3
3
 
4
4
  import { isTV } from "@applicaster/zapp-react-native-utils/reactUtils";
5
5
  import { useActions } from "@applicaster/zapp-react-native-utils/reactHooks/actions";
@@ -7,9 +7,13 @@ import { extractAsset } from "./utils";
7
7
 
8
8
  type Return = { uri: string } | null;
9
9
 
10
+ const getSourceContext = path(["source", "context"]);
11
+ const getSourceUri = path(["source", "uri"]);
12
+ const getState = path(["state"]);
13
+
10
14
  export const useImageSource = ({ uri, entry, otherProps }): Return => {
11
- const uriContext = R.path(["source", "context"], otherProps);
12
- const uriState = R.path(["state"], otherProps);
15
+ const uriContext = getSourceContext(otherProps);
16
+ const uriState = getState(otherProps);
13
17
 
14
18
  const action = useActions(uriContext);
15
19
 
@@ -34,7 +38,7 @@ export const useImageSource = ({ uri, entry, otherProps }): Return => {
34
38
  return { uri };
35
39
  }
36
40
 
37
- const uriFromSource = R.path(["source", "uri"], otherProps);
41
+ const uriFromSource = getSourceUri(otherProps);
38
42
 
39
43
  if (uriFromSource) {
40
44
  return { uri: uriFromSource };
@@ -56,7 +60,7 @@ const getSource = (uri, showDefault, placeholderImage, otherProps) => {
56
60
  return { uri };
57
61
  }
58
62
 
59
- const uriFromSource = R.path(["source", "uri"], otherProps);
63
+ const uriFromSource = getSourceUri(otherProps);
60
64
 
61
65
  if (uriFromSource) {
62
66
  return { uri: uriFromSource };
@@ -72,8 +76,8 @@ export const useImageSourceWithDefault = ({
72
76
  placeholderImage,
73
77
  otherProps,
74
78
  }): Return => {
75
- const uriContext = R.path(["source", "context"], otherProps);
76
- const uriState = R.path(["state"], otherProps);
79
+ const uriContext = getSourceContext(otherProps);
80
+ const uriState = getState(otherProps);
77
81
 
78
82
  const action = useActions(uriContext);
79
83
 
@@ -6,6 +6,7 @@ import React, { useEffect } from "react";
6
6
  import { usePlayer } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/usePlayer";
7
7
  import { BehaviorSubject } from "rxjs";
8
8
  import { masterCellLogger } from "../logger";
9
+ import get from "lodash/get";
9
10
 
10
11
  const parseContextKey = (key: string): string | null => {
11
12
  if (!key?.startsWith("@{ctx/")) return null;
@@ -72,11 +73,13 @@ export const useBehaviorUpdate = (behavior: Behavior) => {
72
73
  // We cant use async in this function (its inside render),
73
74
  // so we rely on useBehaviorUpdate to update current value and trigger re-render
74
75
  export const isCellSelected = (
75
- id: string | number,
76
+ item: ZappEntry,
76
77
  behavior?: Behavior
77
78
  ): boolean => {
78
79
  if (!behavior) return false;
79
80
 
81
+ const id = behavior.selector ? get(item, behavior.selector) : item.id;
82
+
80
83
  if (behavior.selection_source === "now_playing") {
81
84
  const player = playerManager.getActivePlayer();
82
85
 
@@ -190,24 +190,24 @@ export const getFocusedButtonId = (focusable) => {
190
190
  });
191
191
  };
192
192
 
193
- export const isSelected = (id: string | number, behavior?: Behavior) => {
194
- return isCellSelected(id, behavior);
193
+ export const isSelected = (item: ZappEntry, behavior?: Behavior) => {
194
+ return isCellSelected(item, behavior);
195
195
  };
196
196
 
197
197
  export const useCellState = ({
198
- id,
198
+ item,
199
199
  behavior,
200
200
  focused,
201
201
  }: {
202
- id: string | number;
202
+ item: ZappEntry;
203
203
  behavior: Behavior;
204
204
  focused: boolean;
205
205
  }): CellState => {
206
206
  const lastUpdate = useBehaviorUpdate(behavior);
207
207
 
208
208
  const _isSelected = useMemo(
209
- () => isSelected(id, behavior),
210
- [behavior, id, lastUpdate]
209
+ () => isSelected(item, behavior),
210
+ [behavior, item, lastUpdate]
211
211
  );
212
212
 
213
213
  return getCellState({ focused, selected: _isSelected });
@@ -10,13 +10,11 @@ import { Button } from "./Button";
10
10
  import { ItemIconProps } from "./Button/ItemIcon";
11
11
  import { ItemProps } from "./Button/Item";
12
12
  import { ItemLabelProps } from "./Button/ItemLabel";
13
- import {
14
- defaultItemIconProps,
15
- defaultItemLabelProps,
16
- defaultItemProps,
17
- } from "./utils";
13
+ import { getItemIconProps, getItemLabelProps, getItemProps } from "./utils";
18
14
  import { useTheme } from "@applicaster/zapp-react-native-utils/theme";
19
15
 
16
+ import type { PluginConfiguration } from "./";
17
+
20
18
  import { ModalHeader } from "./Header";
21
19
 
22
20
  type ModalComponentProps = {
@@ -30,6 +28,20 @@ type ModalComponentProps = {
30
28
  maxHeight?: number;
31
29
  dismiss: () => void;
32
30
  buttonComponent?: React.ComponentType;
31
+ iconProps?: ItemIconProps | ((theme: PluginConfiguration) => ItemIconProps);
32
+ itemProps?:
33
+ | ItemProps
34
+ | ((theme: PluginConfiguration, width: number) => ItemProps);
35
+ labelProps?:
36
+ | ItemLabelProps
37
+ | ((theme: PluginConfiguration, width: number) => ItemLabelProps);
38
+ getSelectedItemIcon: (
39
+ theme: PluginConfiguration
40
+ ) => ItemIconProps["asset"] | null;
41
+ getDefaultItemIcon: (
42
+ theme: PluginConfiguration
43
+ ) => ItemIconProps["asset"] | null;
44
+ iconPlacement?: "left" | "right";
33
45
  };
34
46
 
35
47
  export function BottomSheetModalContent(props: ModalComponentProps) {
@@ -43,6 +55,10 @@ export function BottomSheetModalContent(props: ModalComponentProps) {
43
55
  summary,
44
56
  title,
45
57
  buttonComponent: ButtonComponent = Button,
58
+ getSelectedItemIcon = (theme) =>
59
+ theme.modal_bottom_sheet_item_selected_icon,
60
+ getDefaultItemIcon = () => null,
61
+ iconPlacement,
46
62
  } = props;
47
63
 
48
64
  const [headerHeight, setHeaderHeight] = useState(0);
@@ -64,21 +80,24 @@ export function BottomSheetModalContent(props: ModalComponentProps) {
64
80
  }, [currentRoute]);
65
81
 
66
82
  const iconBaseProps = useMemo<ItemIconProps>(() => {
67
- return defaultItemIconProps(theme);
68
- }, [theme]);
83
+ return getItemIconProps(theme, props.iconProps);
84
+ }, [theme, props.iconProps]);
69
85
 
70
86
  const itemBaseProps = useMemo<ItemProps>(() => {
71
- return defaultItemProps(theme, props.width);
72
- }, [theme, props.width]);
87
+ return getItemProps(theme, props.width, props.itemProps);
88
+ }, [theme, props.width, props.itemProps]);
73
89
 
74
90
  const labelBaseProps = useMemo<ItemLabelProps>(() => {
75
- return defaultItemLabelProps(theme, props.width);
76
- }, [theme, props.width]);
91
+ return getItemLabelProps(theme, props.width, props.labelProps);
92
+ }, [theme, props.width, props.labelProps]);
77
93
 
78
- const handlePress = (item: any) => {
79
- onPress(item);
80
- dismiss();
81
- };
94
+ const handlePress = useCallback(
95
+ (item: any) => {
96
+ onPress(item);
97
+ dismiss();
98
+ },
99
+ [onPress, dismiss]
100
+ );
82
101
 
83
102
  return (
84
103
  <View
@@ -110,9 +129,13 @@ export function BottomSheetModalContent(props: ModalComponentProps) {
110
129
  selectedItem={current_selection}
111
130
  item={item}
112
131
  onPress={handlePress}
132
+ label={theme[item?.label] ?? item?.label}
113
133
  iconBaseProps={iconBaseProps}
114
134
  itemBaseProps={itemBaseProps}
115
135
  labelBaseProps={labelBaseProps}
136
+ selectedItemIcon={getSelectedItemIcon(theme)}
137
+ defaultItemIcon={getDefaultItemIcon(theme)}
138
+ iconPlacement={iconPlacement}
116
139
  />
117
140
  ))}
118
141
  </ScrollView>
@@ -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[];
@@ -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,7 +3,6 @@ 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 = {
@@ -17,6 +16,9 @@ type ButtonProps = {
17
16
  labelBaseProps?: ItemLabelProps;
18
17
  disabled?: boolean;
19
18
  label?: string | Record<string, string>;
19
+ iconPlacement?: "left" | "right";
20
+ selectedItemIcon?: ItemIconProps["asset"];
21
+ defaultItemIcon?: ItemIconProps["asset"];
20
22
  };
21
23
 
22
24
  const styles = StyleSheet.create({
@@ -33,52 +35,32 @@ export function Button({
33
35
  configuration,
34
36
  width,
35
37
  iconBaseProps,
36
- itemBaseProps,
38
+ itemBaseProps: itemProps,
37
39
  labelBaseProps,
38
40
  label,
41
+ iconPlacement = "left",
42
+ defaultItemIcon,
43
+ selectedItemIcon,
39
44
  disabled = false,
40
45
  }: ButtonProps) {
41
46
  const [focused, setFocused] = useState(false);
42
47
 
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
- );
48
+ const selected = selectedItem && item.value === selectedItem?.value;
55
49
 
56
- const itemIconProps = useMemo<ItemIconProps>(
57
- () => ({
58
- ...iconBaseProps,
59
- asset: configuration[item.asset] ?? assets[item.asset] ?? item.asset,
60
- }),
61
- [configuration, item.asset]
50
+ const itemIconPropsAssets = useMemo<ItemIconProps["asset"]>(
51
+ () => configuration[item.asset] ?? item.asset ?? defaultItemIcon,
52
+ [item.asset, defaultItemIcon]
62
53
  );
63
54
 
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]
55
+ const selectedItemIconPropsAssets = useMemo<ItemIconProps["asset"]>(
56
+ () => selectedItemIcon || defaultSelectedAsset,
57
+ [selectedItemIcon]
73
58
  );
74
59
 
75
- const itemLabelProps = useMemo<ItemLabelProps>(
76
- () => ({
77
- ...labelBaseProps,
78
- label: label ?? configuration[item?.label] ?? item?.label ?? null,
79
- }),
80
- [configuration, item?.label]
81
- );
60
+ const renderItemIcon =
61
+ itemIconPropsAssets && itemIconPropsAssets.length > 0 ? (
62
+ <ItemIcon {...iconBaseProps} asset={itemIconPropsAssets} />
63
+ ) : null;
82
64
 
83
65
  if (disabled) return null;
84
66
 
@@ -92,18 +74,23 @@ export function Button({
92
74
  >
93
75
  <Item {...itemProps} focused={focused} selected={selected}>
94
76
  <View style={styles.label_icon_container}>
95
- {itemIconProps.asset && itemIconProps.asset.length > 0 ? (
96
- <ItemIcon {...itemIconProps} />
97
- ) : null}
98
- {itemLabelProps.label ? (
77
+ {iconPlacement === "left" && renderItemIcon}
78
+
79
+ {label ? (
99
80
  <ItemLabel
100
- {...itemLabelProps}
81
+ {...labelBaseProps}
82
+ label={label ?? null}
101
83
  focused={focused}
102
84
  selected={selected}
103
85
  />
104
86
  ) : null}
105
87
  </View>
106
- {selected ? <ItemIcon {...selectedItemIconProps} /> : null}
88
+
89
+ {selected ? (
90
+ <ItemIcon {...iconBaseProps} asset={selectedItemIconPropsAssets} />
91
+ ) : (
92
+ iconPlacement === "right" && renderItemIcon
93
+ )}
107
94
  </Item>
108
95
  </TouchableOpacity>
109
96
  </View>