@applicaster/zapp-react-native-ui-components 13.0.0-alpha.1240837114 → 13.0.0-alpha.1244047241
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.
- package/Components/AudioPlayer/AudioPlayer.tsx +0 -11
- package/Components/AudioPlayer/helpers.tsx +0 -2
- package/Components/Cell/CellWithFocusable.tsx +4 -2
- package/Components/Cell/CellWrapper.tsx +18 -0
- package/Components/CellRendererResolver/index.ts +2 -1
- package/Components/GeneralContentScreen/GeneralContentScreen.tsx +3 -0
- package/Components/GeneralContentScreen/utils/useCurationAPI.ts +4 -2
- package/Components/GeneralContentScreen/utils/useEventAlerts.ts +30 -0
- package/Components/HandlePlayable/HandlePlayable.tsx +10 -3
- package/Components/Layout/TV/LayoutBackground.tsx +28 -0
- package/Components/Layout/TV/ScreenContainer.tsx +0 -1
- package/Components/Layout/TV/__tests__/__snapshots__/index.test.tsx.snap +15 -10
- package/Components/Layout/TV/__tests__/index.test.tsx +8 -2
- package/Components/Layout/TV/index.tsx +6 -20
- package/Components/Layout/TV/index.web.tsx +4 -1
- package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/const.ts +3 -0
- package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/index.ts +6 -6
- package/Components/ModalComponent/BottomSheetModalContent.tsx +49 -41
- package/Components/ModalComponent/Button/Item.tsx +6 -5
- package/Components/ModalComponent/Button/index.tsx +45 -62
- package/Components/ModalComponent/Header/index.tsx +9 -8
- package/Components/ModalComponent/utils.ts +55 -7
- package/Components/PlayerContainer/PlayerContainer.tsx +25 -2
- package/Components/River/ComponentsMap/ComponentsMap.tsx +11 -3
- package/Components/River/RiverItem.tsx +8 -3
- package/Components/River/__tests__/__snapshots__/componentsMap.test.js.snap +7 -1
- package/Components/Screen/TV/__tests__/index.web.test.tsx +26 -0
- package/Components/Screen/__tests__/Screen.test.tsx +22 -14
- package/Components/Screen/__tests__/__snapshots__/Screen.test.tsx.snap +2 -2
- package/Components/TopMarginApplicator/TopMarginApplicator.tsx +2 -3
- package/Components/VideoModal/ModalAnimation/AnimatedScrollModal.tsx +12 -2
- package/Components/VideoModal/ModalAnimation/AnimationComponent.tsx +21 -10
- package/Components/VideoModal/ModalAnimation/ModalAnimationContext.tsx +8 -1
- package/Components/VideoModal/ModalAnimation/__tests__/getMoveUpValue.test.ts +108 -0
- package/Components/VideoModal/ModalAnimation/const.ts +5 -0
- package/Components/VideoModal/ModalAnimation/index.ts +2 -0
- package/Components/VideoModal/ModalAnimation/utils.ts +30 -0
- package/Components/VideoModal/PlayerDetails.tsx +9 -4
- package/Components/VideoModal/PlayerWrapper.tsx +35 -22
- package/Components/VideoModal/VideoModal.tsx +19 -4
- package/Components/VideoModal/__tests__/__snapshots__/PlayerDetails.test.tsx.snap +2 -40
- package/Components/VideoModal/utils.ts +3 -4
- package/package.json +5 -5
- package/Components/Cell/CellWrapper.ts +0 -5
|
@@ -22,8 +22,6 @@ type Props = {
|
|
|
22
22
|
audio_player_title_color?: string;
|
|
23
23
|
audio_player_summary_color?: string;
|
|
24
24
|
audio_player_rtl?: boolean;
|
|
25
|
-
magic_background?: boolean;
|
|
26
|
-
audio_player_background_image_query?: string;
|
|
27
25
|
audio_player_background_image_default_color?: string;
|
|
28
26
|
start_time?: string;
|
|
29
27
|
end_time?: string;
|
|
@@ -34,8 +32,6 @@ type Props = {
|
|
|
34
32
|
audio_player_title_color?: string;
|
|
35
33
|
audio_player_summary_color?: string;
|
|
36
34
|
audio_player_rtl?: string;
|
|
37
|
-
magic_background?: string;
|
|
38
|
-
audio_player_background_image_query?: string;
|
|
39
35
|
audio_player_background_image_default_color?: string;
|
|
40
36
|
audio_player_background_image?: string;
|
|
41
37
|
audio_player_artwork_aspect_ratio?: string;
|
|
@@ -76,11 +72,6 @@ export function AudioPlayer(props: Props) {
|
|
|
76
72
|
const artworkAspectRatio = getProp("audio_player_artwork_aspect_ratio");
|
|
77
73
|
const channelIcon = getProp("audio_player_channel_icon");
|
|
78
74
|
const rtlFlag = getProp("audio_player_rtl");
|
|
79
|
-
const magicBackground = getProp("magic_background");
|
|
80
|
-
|
|
81
|
-
const audioPlayerBackgroundImageQuery = getProp(
|
|
82
|
-
"audio_player_background_image_query"
|
|
83
|
-
);
|
|
84
75
|
|
|
85
76
|
const audioPlayerBackgroundImageDefaultColor = getProp(
|
|
86
77
|
"audio_player_background_image_default_color"
|
|
@@ -162,8 +153,6 @@ export function AudioPlayer(props: Props) {
|
|
|
162
153
|
runTimeFontSize,
|
|
163
154
|
artworkAspectRatio,
|
|
164
155
|
channelIcon,
|
|
165
|
-
magicBackground,
|
|
166
|
-
audioPlayerBackgroundImageQuery,
|
|
167
156
|
audioPlayerBackgroundImageDefaultColor,
|
|
168
157
|
};
|
|
169
158
|
}, [getProp]);
|
|
@@ -23,6 +23,8 @@ type Props = {
|
|
|
23
23
|
focused?: boolean;
|
|
24
24
|
};
|
|
25
25
|
|
|
26
|
+
const addPrefix = (id: string) => `focusable-cell-wrapper-${id}`;
|
|
27
|
+
|
|
26
28
|
export function CellWithFocusable(props: Props) {
|
|
27
29
|
const {
|
|
28
30
|
index,
|
|
@@ -81,7 +83,7 @@ export function CellWithFocusable(props: Props) {
|
|
|
81
83
|
|
|
82
84
|
return (
|
|
83
85
|
<FocusableGroup
|
|
84
|
-
id={
|
|
86
|
+
id={addPrefix(id)}
|
|
85
87
|
testID={"cell-with-focusable-cell-renderer-focusable-group"}
|
|
86
88
|
groupId={groupId}
|
|
87
89
|
preferredFocus={preferredFocus}
|
|
@@ -94,7 +96,7 @@ export function CellWithFocusable(props: Props) {
|
|
|
94
96
|
<CellRenderer
|
|
95
97
|
testID={"cell-with-focusable-cell-renderer"}
|
|
96
98
|
item={item}
|
|
97
|
-
groupId={
|
|
99
|
+
groupId={addPrefix(id)}
|
|
98
100
|
onToggleFocus={handleToggleFocus}
|
|
99
101
|
state={state}
|
|
100
102
|
prefixId={id}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { View, ViewStyle } from "react-native";
|
|
3
|
+
import { isTvOSPlatform } from "@applicaster/zapp-react-native-utils/reactUtils";
|
|
4
|
+
|
|
5
|
+
const isTvOS = isTvOSPlatform();
|
|
6
|
+
|
|
7
|
+
type Props = {
|
|
8
|
+
style: ViewStyle;
|
|
9
|
+
children: React.ReactNode;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export const CellWrapper = ({ style, children }: Props) => {
|
|
13
|
+
if (isTvOS) {
|
|
14
|
+
return <View style={style}>{children}</View>;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
return <>{children}</>;
|
|
18
|
+
};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { findPluginByIdentifier } from "@applicaster/zapp-react-native-utils/pluginUtils";
|
|
2
|
+
import { isGroup } from "@applicaster/zapp-react-native-utils/componentsUtils";
|
|
2
3
|
|
|
3
4
|
import { componentsLogger } from "../../Helpers/logger";
|
|
4
5
|
import defaultCellRenderer from "../default-cell-renderer";
|
|
@@ -80,7 +81,7 @@ export function CellRendererResolver({
|
|
|
80
81
|
}: Props) {
|
|
81
82
|
const cellRendererPlugin = getRendererPlugin(component, plugins, cellStyles);
|
|
82
83
|
|
|
83
|
-
if (!cellRendererPlugin && component
|
|
84
|
+
if (!cellRendererPlugin && !isGroup(component)) {
|
|
84
85
|
logger.warning({
|
|
85
86
|
message: "Could not resolve cell builder plugin",
|
|
86
87
|
data: { component },
|
|
@@ -11,6 +11,7 @@ import { allSettled } from "promise";
|
|
|
11
11
|
import { createLogger } from "@applicaster/zapp-react-native-utils/logger";
|
|
12
12
|
import { isNilOrEmpty } from "@applicaster/zapp-react-native-utils/reactUtils/helpers";
|
|
13
13
|
import { ScreenTrackedViewPositionsContext } from "@applicaster/zapp-react-native-ui-components/Contexts/ScreenTrackedViewPositionsContext";
|
|
14
|
+
import { useEventAlerts } from "./utils/useEventAlerts";
|
|
14
15
|
|
|
15
16
|
const { log_info } = createLogger({
|
|
16
17
|
category: "ScreenContainer",
|
|
@@ -103,6 +104,8 @@ export const GeneralContentScreen = ({
|
|
|
103
104
|
[typeof cellTapAction === "function" ? cellTapAction : onCellTapAction]
|
|
104
105
|
);
|
|
105
106
|
|
|
107
|
+
useEventAlerts(screenData);
|
|
108
|
+
|
|
106
109
|
if (!isReady || isNilOrEmpty(components || uiComponents)) return null;
|
|
107
110
|
|
|
108
111
|
return (
|
|
@@ -3,8 +3,10 @@ import { all, equals, path, prop, isEmpty, pluck, values } from "ramda";
|
|
|
3
3
|
import { useEffect, useMemo } from "react";
|
|
4
4
|
import { useDispatch } from "react-redux";
|
|
5
5
|
|
|
6
|
-
import {
|
|
7
|
-
|
|
6
|
+
import {
|
|
7
|
+
useLayoutPresets,
|
|
8
|
+
useZappPipesFeeds,
|
|
9
|
+
} from "@applicaster/zapp-react-native-redux/hooks";
|
|
8
10
|
import { loadPipesData } from "@applicaster/zapp-react-native-redux/ZappPipes";
|
|
9
11
|
import { isEmptyOrNil } from "@applicaster/zapp-react-native-utils/cellUtils";
|
|
10
12
|
import { Categories } from "./logger";
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { showAlertDialog } from "@applicaster/zapp-react-native-utils/alertUtils";
|
|
3
|
+
import { TOGGLE_FLAG_MAX_ITEMS_REACHED_EVENT } from "@applicaster/zapp-react-native-utils/actionsExecutor/consts";
|
|
4
|
+
import { useLocalizedStrings } from "@applicaster/zapp-react-native-utils/localizationUtils";
|
|
5
|
+
import { useIsScreenActive } from "@applicaster/zapp-react-native-utils/reactHooks";
|
|
6
|
+
import { useSubscriberFor } from "@applicaster/zapp-react-native-utils/reactHooks/useSubscriberFor";
|
|
7
|
+
|
|
8
|
+
export const useEventAlerts = (screenData: ZappRiver) => {
|
|
9
|
+
const localizations = useLocalizedStrings({
|
|
10
|
+
localizations: screenData?.localizations || {},
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
const isActive = useIsScreenActive();
|
|
14
|
+
|
|
15
|
+
const onMaxTagsReached = React.useCallback(() => {
|
|
16
|
+
// We can't skip subscribe hook call, so we have to check.
|
|
17
|
+
if (!isActive || !localizations?.msg_maximum_selection_reached_message) {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
showAlertDialog({
|
|
22
|
+
title: "",
|
|
23
|
+
message: localizations.msg_maximum_selection_reached_message,
|
|
24
|
+
okButtonText:
|
|
25
|
+
localizations.msg_maximum_selection_reached_message_ok_button || "OK",
|
|
26
|
+
});
|
|
27
|
+
}, [localizations, isActive]);
|
|
28
|
+
|
|
29
|
+
useSubscriberFor(TOGGLE_FLAG_MAX_ITEMS_REACHED_EVENT, onMaxTagsReached);
|
|
30
|
+
};
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
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;
|
|
@@ -136,12 +137,18 @@ export function HandlePlayable({
|
|
|
136
137
|
|
|
137
138
|
const { width: screenWidth, height: screenHeight } = useDimensions("window");
|
|
138
139
|
|
|
140
|
+
const modalSize = useModalSize();
|
|
141
|
+
|
|
139
142
|
const style = React.useMemo(
|
|
140
143
|
() => ({
|
|
141
|
-
width: isModal ?
|
|
142
|
-
height: isModal
|
|
144
|
+
width: isModal ? modalSize.width : mode === "PIP" ? "100%" : screenWidth,
|
|
145
|
+
height: isModal
|
|
146
|
+
? modalSize.height
|
|
147
|
+
: mode === "PIP"
|
|
148
|
+
? "100%"
|
|
149
|
+
: screenHeight,
|
|
143
150
|
}),
|
|
144
|
-
[screenWidth, screenHeight, isModal, mode]
|
|
151
|
+
[screenWidth, screenHeight, modalSize, isModal, mode]
|
|
145
152
|
);
|
|
146
153
|
|
|
147
154
|
const Component = playable?.Component;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks/usePickFromState";
|
|
3
|
+
import { getBackgroundImageUrl } from "../utils";
|
|
4
|
+
import { useTheme } from "@applicaster/zapp-react-native-utils/theme";
|
|
5
|
+
|
|
6
|
+
export const LayoutBackground = ({
|
|
7
|
+
Background,
|
|
8
|
+
children,
|
|
9
|
+
}: {
|
|
10
|
+
Background: React.ComponentType<any>;
|
|
11
|
+
children: React.ReactNode;
|
|
12
|
+
}) => {
|
|
13
|
+
const theme = useTheme();
|
|
14
|
+
|
|
15
|
+
const { remoteConfigurations } = usePickFromState(["remoteConfigurations"]);
|
|
16
|
+
|
|
17
|
+
const backgroundColor = theme.app_background_color;
|
|
18
|
+
const backgroundImageUrl = getBackgroundImageUrl(remoteConfigurations);
|
|
19
|
+
|
|
20
|
+
return (
|
|
21
|
+
<Background
|
|
22
|
+
backgroundColor={backgroundColor}
|
|
23
|
+
backgroundImageUrl={backgroundImageUrl}
|
|
24
|
+
>
|
|
25
|
+
{children}
|
|
26
|
+
</Background>
|
|
27
|
+
);
|
|
28
|
+
};
|
|
@@ -2,18 +2,23 @@
|
|
|
2
2
|
|
|
3
3
|
exports[`Layout TV renders 1`] = `
|
|
4
4
|
<View
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
preferredFocus={true}
|
|
5
|
+
backgroundColor="#000000"
|
|
6
|
+
testID="background-component"
|
|
8
7
|
>
|
|
9
8
|
<View
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
9
|
+
excludeFromFocusSearching={true}
|
|
10
|
+
id="/river/A1234"
|
|
11
|
+
preferredFocus={true}
|
|
12
|
+
>
|
|
13
|
+
<View
|
|
14
|
+
Components={
|
|
15
|
+
{
|
|
16
|
+
"Background": [Function],
|
|
17
|
+
"NavBar": [Function],
|
|
18
|
+
}
|
|
14
19
|
}
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
20
|
+
route="/river/A1234"
|
|
21
|
+
/>
|
|
22
|
+
</View>
|
|
18
23
|
</View>
|
|
19
24
|
`;
|
|
@@ -5,6 +5,14 @@ import { render } from "@testing-library/react-native";
|
|
|
5
5
|
import { Provider } from "react-redux";
|
|
6
6
|
import { NavigationContext } from "@applicaster/zapp-react-native-ui-components/Contexts/NavigationContext";
|
|
7
7
|
import configureStore from "redux-mock-store";
|
|
8
|
+
import Layout from "../index.web";
|
|
9
|
+
|
|
10
|
+
// mock useTheme to provide app_background_color
|
|
11
|
+
jest.mock("@applicaster/zapp-react-native-utils/theme", () => ({
|
|
12
|
+
useTheme: () => ({
|
|
13
|
+
app_background_color: "#000000",
|
|
14
|
+
}),
|
|
15
|
+
}));
|
|
8
16
|
|
|
9
17
|
const withoutChildren = omit(["children"]);
|
|
10
18
|
|
|
@@ -16,8 +24,6 @@ jest.mock("../../../Screen/TV/index.web", () => {
|
|
|
16
24
|
};
|
|
17
25
|
});
|
|
18
26
|
|
|
19
|
-
const Layout = require("../index.web").default;
|
|
20
|
-
|
|
21
27
|
const mockStore = configureStore()({
|
|
22
28
|
appState: { appReady: true },
|
|
23
29
|
});
|
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import * as R from "ramda";
|
|
3
2
|
import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
|
|
4
3
|
import { useNavigation } from "@applicaster/zapp-react-native-utils/reactHooks/navigation";
|
|
5
|
-
import { useTheme } from "@applicaster/zapp-react-native-utils/theme";
|
|
6
4
|
|
|
7
|
-
import { getBackgroundImageUrl } from "../utils";
|
|
8
5
|
import { LayoutContainer } from "./LayoutContainer";
|
|
9
6
|
import { ScreenContainer } from "./ScreenContainer";
|
|
10
7
|
|
|
@@ -12,6 +9,7 @@ import { ScreenLayoutContextProvider } from "./ScreenLayoutContextProvider";
|
|
|
12
9
|
import { PathnameContext } from "../../../Contexts/PathnameContext";
|
|
13
10
|
import { ScreenDataContext } from "../../../Contexts/ScreenDataContext";
|
|
14
11
|
import { ScreenContextProvider } from "../../../Contexts/ScreenContext";
|
|
12
|
+
import { LayoutBackground } from "./LayoutBackground";
|
|
15
13
|
|
|
16
14
|
type Components = {
|
|
17
15
|
NavBar: React.ComponentType<any>;
|
|
@@ -19,7 +17,6 @@ type Components = {
|
|
|
19
17
|
};
|
|
20
18
|
|
|
21
19
|
type ComponentsExtraProps = {
|
|
22
|
-
Background?: Record<string, any>;
|
|
23
20
|
NavBar?: Record<string, any>;
|
|
24
21
|
};
|
|
25
22
|
|
|
@@ -31,17 +28,10 @@ type Props = {
|
|
|
31
28
|
|
|
32
29
|
const Layout = ({ Components, ComponentsExtraProps, children }: Props) => {
|
|
33
30
|
const navigator = useNavigation();
|
|
34
|
-
const theme = useTheme();
|
|
35
31
|
|
|
36
|
-
const { appState: { appReady = false } = {}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
const backgroundColor = React.useMemo(() => theme.app_background_color, []);
|
|
40
|
-
|
|
41
|
-
const backgroundImageUrl = React.useMemo(
|
|
42
|
-
() => getBackgroundImageUrl(remoteConfigurations),
|
|
43
|
-
[remoteConfigurations]
|
|
44
|
-
);
|
|
32
|
+
const { appState: { appReady = false } = {} } = usePickFromState([
|
|
33
|
+
"appState",
|
|
34
|
+
]);
|
|
45
35
|
|
|
46
36
|
if (!appReady) {
|
|
47
37
|
return null;
|
|
@@ -50,11 +40,7 @@ const Layout = ({ Components, ComponentsExtraProps, children }: Props) => {
|
|
|
50
40
|
return (
|
|
51
41
|
<LayoutContainer>
|
|
52
42
|
<ScreenLayoutContextProvider>
|
|
53
|
-
<Components.Background
|
|
54
|
-
backgroundColor={backgroundColor}
|
|
55
|
-
backgroundImageUrl={backgroundImageUrl}
|
|
56
|
-
{...R.omit(["ref"])(ComponentsExtraProps?.Background)}
|
|
57
|
-
>
|
|
43
|
+
<LayoutBackground Background={Components.Background}>
|
|
58
44
|
<ScreenDataContext.Provider value={navigator.data}>
|
|
59
45
|
<PathnameContext.Provider value={navigator.currentRoute}>
|
|
60
46
|
<ScreenContextProvider pathname={navigator.currentRoute}>
|
|
@@ -67,7 +53,7 @@ const Layout = ({ Components, ComponentsExtraProps, children }: Props) => {
|
|
|
67
53
|
</ScreenContextProvider>
|
|
68
54
|
</PathnameContext.Provider>
|
|
69
55
|
</ScreenDataContext.Provider>
|
|
70
|
-
</
|
|
56
|
+
</LayoutBackground>
|
|
71
57
|
</ScreenLayoutContextProvider>
|
|
72
58
|
</LayoutContainer>
|
|
73
59
|
);
|
|
@@ -5,6 +5,7 @@ import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
|
|
|
5
5
|
|
|
6
6
|
import { ScreenLayoutContextProvider } from "./ScreenLayoutContextProvider";
|
|
7
7
|
import { StackNavigator } from "../../Navigator";
|
|
8
|
+
import { LayoutBackground } from "./LayoutBackground";
|
|
8
9
|
|
|
9
10
|
type Components = {
|
|
10
11
|
NavBar: React.ComponentType<any>;
|
|
@@ -25,7 +26,9 @@ const Layout = ({ Components }: Props) => {
|
|
|
25
26
|
|
|
26
27
|
return (
|
|
27
28
|
<ScreenLayoutContextProvider>
|
|
28
|
-
<
|
|
29
|
+
<LayoutBackground Background={Components.Background}>
|
|
30
|
+
<StackNavigator Components={Components} />
|
|
31
|
+
</LayoutBackground>
|
|
29
32
|
</ScreenLayoutContextProvider>
|
|
30
33
|
);
|
|
31
34
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { times } from "@applicaster/zapp-react-native-utils/utils";
|
|
2
2
|
import { toNumberWithDefaultZero } from "@applicaster/zapp-react-native-utils/numberUtils";
|
|
3
3
|
|
|
4
4
|
import { Button } from "./Button";
|
|
@@ -9,13 +9,14 @@ import {
|
|
|
9
9
|
} from "./utils";
|
|
10
10
|
|
|
11
11
|
import { compact } from "@applicaster/zapp-react-native-utils/cellUtils";
|
|
12
|
+
import { PREFIX, BUTTON_PREFIX } from "./const";
|
|
12
13
|
|
|
13
14
|
export {
|
|
14
15
|
insertButtonsBetweenLabels,
|
|
15
16
|
insertButtonsBetweenLabelContainers,
|
|
16
17
|
} from "./utils";
|
|
17
18
|
|
|
18
|
-
const
|
|
19
|
+
const buttonId = (index: number) => `${BUTTON_PREFIX}_${index}`;
|
|
19
20
|
|
|
20
21
|
type Props = {
|
|
21
22
|
value: Function;
|
|
@@ -42,7 +43,6 @@ export const TvActionButtons = ({
|
|
|
42
43
|
return null;
|
|
43
44
|
}
|
|
44
45
|
|
|
45
|
-
const prefix1Button = `${PREFIX}_button_1`;
|
|
46
46
|
const independentStyles = value(`${PREFIX}_container_independent_styles`);
|
|
47
47
|
|
|
48
48
|
return {
|
|
@@ -73,11 +73,11 @@ export const TvActionButtons = ({
|
|
|
73
73
|
buttonsCount,
|
|
74
74
|
},
|
|
75
75
|
elements: compact(
|
|
76
|
-
|
|
77
|
-
const prefixSpecificButton =
|
|
76
|
+
times((index) => {
|
|
77
|
+
const prefixSpecificButton = buttonId(index + 1);
|
|
78
78
|
|
|
79
79
|
return Button({
|
|
80
|
-
prefix: independentStyles ? prefixSpecificButton :
|
|
80
|
+
prefix: independentStyles ? prefixSpecificButton : buttonId(1),
|
|
81
81
|
value,
|
|
82
82
|
platformValue,
|
|
83
83
|
pluginIdentifier: getPluginIdentifier(configuration, PREFIX, index),
|
|
@@ -1,23 +1,16 @@
|
|
|
1
|
-
import React, {
|
|
2
|
-
|
|
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, Platform } 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
|
|
|
10
|
+
import type { PluginConfiguration } from "./";
|
|
11
|
+
|
|
20
12
|
import { ModalHeader } from "./Header";
|
|
13
|
+
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
|
21
14
|
|
|
22
15
|
type ModalComponentProps = {
|
|
23
16
|
items: any[];
|
|
@@ -30,32 +23,42 @@ type ModalComponentProps = {
|
|
|
30
23
|
maxHeight?: number;
|
|
31
24
|
dismiss: () => void;
|
|
32
25
|
buttonComponent?: React.ComponentType;
|
|
26
|
+
iconProps?: ItemIconProps | ((theme: PluginConfiguration) => ItemIconProps);
|
|
27
|
+
itemProps?:
|
|
28
|
+
| ItemProps
|
|
29
|
+
| ((theme: PluginConfiguration, width: number) => ItemProps);
|
|
30
|
+
labelProps?:
|
|
31
|
+
| ItemLabelProps
|
|
32
|
+
| ((theme: PluginConfiguration, width: number) => ItemLabelProps);
|
|
33
|
+
getSelectedItemIcon: (
|
|
34
|
+
theme: PluginConfiguration
|
|
35
|
+
) => ItemIconProps["asset"] | null;
|
|
36
|
+
getDefaultItemIcon: (
|
|
37
|
+
theme: PluginConfiguration
|
|
38
|
+
) => ItemIconProps["asset"] | null;
|
|
39
|
+
iconPlacement?: "left" | "right";
|
|
33
40
|
};
|
|
34
41
|
|
|
35
42
|
export function BottomSheetModalContent(props: ModalComponentProps) {
|
|
36
43
|
const {
|
|
37
44
|
items,
|
|
38
45
|
currentRoute,
|
|
39
|
-
maxHeight,
|
|
40
46
|
current_selection = null,
|
|
41
47
|
onPress,
|
|
42
48
|
dismiss,
|
|
43
49
|
summary,
|
|
44
50
|
title,
|
|
45
51
|
buttonComponent: ButtonComponent = Button,
|
|
52
|
+
getSelectedItemIcon = (theme) =>
|
|
53
|
+
theme.modal_bottom_sheet_item_selected_icon,
|
|
54
|
+
getDefaultItemIcon = () => null,
|
|
55
|
+
iconPlacement,
|
|
46
56
|
} = props;
|
|
47
57
|
|
|
48
|
-
const [headerHeight, setHeaderHeight] = useState(0);
|
|
49
58
|
const route = useRef(currentRoute);
|
|
50
59
|
const theme = useTheme<BaseThemePropertiesMobile>();
|
|
51
|
-
|
|
52
|
-
const
|
|
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
|
-
}, []);
|
|
60
|
+
const paddingTop = Number(theme.modal_bottom_sheet_padding_top);
|
|
61
|
+
const paddingBottom = Number(theme.modal_bottom_sheet_padding_bottom);
|
|
59
62
|
|
|
60
63
|
useEffect(() => {
|
|
61
64
|
if (currentRoute !== route.current) {
|
|
@@ -64,55 +67,60 @@ export function BottomSheetModalContent(props: ModalComponentProps) {
|
|
|
64
67
|
}, [currentRoute]);
|
|
65
68
|
|
|
66
69
|
const iconBaseProps = useMemo<ItemIconProps>(() => {
|
|
67
|
-
return
|
|
68
|
-
}, [theme]);
|
|
70
|
+
return getItemIconProps(theme, props.iconProps);
|
|
71
|
+
}, [theme, props.iconProps]);
|
|
69
72
|
|
|
70
73
|
const itemBaseProps = useMemo<ItemProps>(() => {
|
|
71
|
-
return
|
|
72
|
-
}, [theme, props.width]);
|
|
74
|
+
return getItemProps(theme, props.width, props.itemProps);
|
|
75
|
+
}, [theme, props.width, props.itemProps]);
|
|
73
76
|
|
|
74
77
|
const labelBaseProps = useMemo<ItemLabelProps>(() => {
|
|
75
|
-
return
|
|
76
|
-
}, [theme, props.width]);
|
|
78
|
+
return getItemLabelProps(theme, props.width, props.labelProps);
|
|
79
|
+
}, [theme, props.width, props.labelProps]);
|
|
80
|
+
|
|
81
|
+
const handlePress = useCallback(
|
|
82
|
+
(item: any) => {
|
|
83
|
+
onPress(item);
|
|
84
|
+
dismiss();
|
|
85
|
+
},
|
|
86
|
+
[onPress, dismiss]
|
|
87
|
+
);
|
|
77
88
|
|
|
78
|
-
const
|
|
79
|
-
onPress(item);
|
|
80
|
-
dismiss();
|
|
81
|
-
};
|
|
89
|
+
const bottomInset = useSafeAreaInsets().bottom;
|
|
82
90
|
|
|
83
91
|
return (
|
|
84
92
|
<View
|
|
85
93
|
style={{
|
|
86
|
-
|
|
94
|
+
maxHeight: props.maxHeight,
|
|
95
|
+
paddingTop: paddingTop,
|
|
87
96
|
}}
|
|
88
97
|
>
|
|
89
98
|
<ModalHeader
|
|
90
|
-
width={props.width}
|
|
91
99
|
dismiss={dismiss}
|
|
92
100
|
configuration={theme}
|
|
93
|
-
onLayout={onHeaderLayout}
|
|
94
101
|
summary={summary}
|
|
95
102
|
title={title}
|
|
96
103
|
/>
|
|
97
104
|
<ScrollView
|
|
98
|
-
bounces={false}
|
|
99
|
-
style={{ maxHeight: maxContentHeight }}
|
|
100
105
|
contentContainerStyle={{
|
|
101
|
-
paddingBottom:
|
|
102
|
-
|
|
106
|
+
paddingBottom:
|
|
107
|
+
paddingBottom + (Platform.OS === "ios" ? bottomInset : 0),
|
|
103
108
|
}}
|
|
104
109
|
>
|
|
105
110
|
{items.map((item, index) => (
|
|
106
111
|
<ButtonComponent
|
|
107
112
|
key={index}
|
|
108
|
-
width={props.width}
|
|
109
113
|
configuration={theme}
|
|
110
114
|
selectedItem={current_selection}
|
|
111
115
|
item={item}
|
|
112
116
|
onPress={handlePress}
|
|
117
|
+
label={theme[item?.label] ?? item?.label}
|
|
113
118
|
iconBaseProps={iconBaseProps}
|
|
114
119
|
itemBaseProps={itemBaseProps}
|
|
115
120
|
labelBaseProps={labelBaseProps}
|
|
121
|
+
selectedItemIcon={getSelectedItemIcon(theme)}
|
|
122
|
+
defaultItemIcon={getDefaultItemIcon(theme)}
|
|
123
|
+
iconPlacement={iconPlacement}
|
|
116
124
|
/>
|
|
117
125
|
))}
|
|
118
126
|
</ScrollView>
|
|
@@ -5,7 +5,7 @@ export type ItemProps = {
|
|
|
5
5
|
backgroundColor: string;
|
|
6
6
|
focusedBackgroundColor: string;
|
|
7
7
|
selectedBackgroundColor?: string;
|
|
8
|
-
|
|
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
|
-
|
|
37
|
+
focusedSelectedBackgroundColor,
|
|
37
38
|
}) {
|
|
38
39
|
switch (true) {
|
|
39
40
|
case selected && focused:
|
|
40
|
-
return
|
|
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
|
-
|
|
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
|
-
|
|
72
|
+
focusedSelectedBackgroundColor,
|
|
72
73
|
focusedBackgroundColor,
|
|
73
74
|
selectedBackgroundColor,
|
|
74
75
|
backgroundColor,
|