@applicaster/zapp-react-native-ui-components 15.1.14 → 15.1.15-rc.0
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/GeneralContentScreen/GeneralContentScreenHookAdapter.tsx +15 -0
- package/Components/MasterCell/DefaultComponents/ActionButton.tsx +4 -1
- package/Components/ModalComponent/ActionsBottomSheet/ActionButton.tsx +56 -0
- package/Components/ModalComponent/ActionsBottomSheet/__tests__/openActionsBottomSheet.test.ts +38 -0
- package/Components/ModalComponent/ActionsBottomSheet/boundActionButton.tsx +24 -0
- package/Components/ModalComponent/ActionsBottomSheet/index.ts +9 -0
- package/Components/ModalComponent/ActionsBottomSheet/openActionsBottomSheet.ts +61 -0
- package/Components/ModalComponent/AudioPlayer/Components/Button.tsx +58 -97
- package/Components/ModalComponent/AudioPlayer/Components/Header.tsx +142 -142
- package/Components/ModalComponent/AudioPlayer/Components/Input.tsx +628 -0
- package/Components/ModalComponent/AudioPlayer/Components/Item.tsx +448 -175
- package/Components/ModalComponent/AudioPlayer/Components/NowPlayingHeaderSection.tsx +94 -0
- package/Components/ModalComponent/AudioPlayer/Components/__tests__/Item.test.tsx +113 -0
- package/Components/ModalComponent/AudioPlayer/Components/index.ts +6 -4
- package/Components/ModalComponent/AudioPlayer/utils/__tests__/mergeStyles.test.ts +248 -0
- package/Components/ModalComponent/AudioPlayer/utils/mergeStyles.ts +386 -0
- package/Components/ModalComponent/BottomSheetModalContent.tsx +425 -66
- package/Components/ModalComponent/Button/index.tsx +5 -3
- package/Components/ModalComponent/Header/index.tsx +20 -7
- package/Components/ModalComponent/Header/utils.ts +1 -1
- package/Components/ModalComponent/ModalBlocksStyleContext.tsx +10 -0
- package/Components/ModalComponent/SortableList.tsx +157 -0
- package/Components/ModalComponent/SortableList.web.tsx +102 -0
- package/Components/ModalComponent/TextInputContent.tsx +112 -0
- package/Components/ModalComponent/__tests__/BottomSheetModalContent.test.tsx +255 -0
- package/Components/ModalComponent/__tests__/TextInputContent.test.tsx +156 -0
- package/Components/ModalComponent/__tests__/showTextInput.test.ts +95 -0
- package/Components/ModalComponent/index.tsx +18 -9
- package/Components/ModalComponent/presets/__tests__/getCell.test.ts +90 -0
- package/Components/ModalComponent/presets/dynamicCollectionCell.tsx +78 -0
- package/Components/ModalComponent/presets/index.ts +27 -0
- package/Components/ModalComponent/presets/selectableCell.tsx +28 -0
- package/Components/ModalComponent/presets/standardCell.tsx +41 -0
- package/Components/ModalComponent/presets/types.ts +35 -0
- package/Components/ModalComponent/showTextInput.ts +43 -0
- package/Components/ModalComponent/utils.ts +82 -21
- package/Components/River/ComponentsMap/ComponentsMap.tsx +87 -60
- package/Components/River/__tests__/__snapshots__/componentsMap.test.js.snap +139 -75
- package/Components/River/__tests__/componentsMap.test.js +8 -3
- package/Components/Screen/navigationHandler.ts +8 -8
- package/Contexts/ModalNavigationContext/__tests__/index.test.tsx +15 -0
- package/Contexts/ModalNavigationContext/index.tsx +2 -2
- package/Hooks/useEntryActionsExpander.ts +63 -0
- package/package.json +6 -5
- package/Components/ModalComponent/AudioPlayer/Components/Action.tsx +0 -368
- /package/Decorators/ZappPipesDataConnector/__tests__/{Hero.js → Hero.tsx} +0 -0
|
@@ -1,16 +1,65 @@
|
|
|
1
|
-
import React, {
|
|
2
|
-
|
|
1
|
+
import React, {
|
|
2
|
+
memo,
|
|
3
|
+
useCallback,
|
|
4
|
+
useDeferredValue,
|
|
5
|
+
useEffect,
|
|
6
|
+
useMemo,
|
|
7
|
+
useRef,
|
|
8
|
+
} from "react";
|
|
9
|
+
import {
|
|
10
|
+
ActivityIndicator,
|
|
11
|
+
ScrollView,
|
|
12
|
+
StyleSheet,
|
|
13
|
+
Text,
|
|
14
|
+
View,
|
|
15
|
+
} from "react-native";
|
|
3
16
|
import { Button } from "./Button";
|
|
4
17
|
import { ItemIconProps } from "./Button/ItemIcon";
|
|
5
18
|
import { ItemProps } from "./Button/Item";
|
|
6
19
|
import { ItemLabelProps } from "./Button/ItemLabel";
|
|
7
20
|
import { getItemIconProps, getItemLabelProps, getItemProps } from "./utils";
|
|
8
21
|
import { useTheme } from "@applicaster/zapp-react-native-utils/theme";
|
|
22
|
+
import {
|
|
23
|
+
ContentViewModel,
|
|
24
|
+
OPERATIONS,
|
|
25
|
+
hasOperation,
|
|
26
|
+
useBottomSheetContent,
|
|
27
|
+
} from "@applicaster/zapp-react-native-utils/modalState";
|
|
28
|
+
import { getCell } from "./presets";
|
|
9
29
|
import type { PluginConfiguration } from "./";
|
|
10
|
-
|
|
11
30
|
import { ModalHeader as DefaultModalHeader } from "./Header";
|
|
12
31
|
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
|
32
|
+
import { SortableList } from "./SortableList";
|
|
33
|
+
import {
|
|
34
|
+
AudioPlayerButton,
|
|
35
|
+
NowPlayingHeaderSection,
|
|
36
|
+
VARIANT_WITH_ICON,
|
|
37
|
+
} from "./AudioPlayer/Components";
|
|
13
38
|
import { BottomSheetDragArea } from "./BottomSheetDragArea";
|
|
39
|
+
import { ModalBlocksStyleContext } from "./ModalBlocksStyleContext";
|
|
40
|
+
import { usePlugins } from "@applicaster/zapp-react-native-redux/hooks";
|
|
41
|
+
import {
|
|
42
|
+
ModalBlocksConfig,
|
|
43
|
+
parseModalBlocksConfiguration,
|
|
44
|
+
} from "@applicaster/zapp-react-native-utils/configurationUtils/modalBlocksParser";
|
|
45
|
+
import { useLocalizedStrings } from "@applicaster/zapp-react-native-utils/localizationUtils";
|
|
46
|
+
|
|
47
|
+
const styles = StyleSheet.create({
|
|
48
|
+
centered: {
|
|
49
|
+
justifyContent: "center",
|
|
50
|
+
alignItems: "center",
|
|
51
|
+
padding: 16,
|
|
52
|
+
},
|
|
53
|
+
errorText: {
|
|
54
|
+
color: "#ff453a",
|
|
55
|
+
fontSize: 14,
|
|
56
|
+
textAlign: "center",
|
|
57
|
+
},
|
|
58
|
+
scrollView: {
|
|
59
|
+
flexShrink: 1,
|
|
60
|
+
},
|
|
61
|
+
someStyles: { paddingHorizontal: 20, paddingTop: 8, paddingBottom: 12 },
|
|
62
|
+
});
|
|
14
63
|
|
|
15
64
|
type ModalComponentProps = {
|
|
16
65
|
items: any[];
|
|
@@ -22,13 +71,7 @@ type ModalComponentProps = {
|
|
|
22
71
|
title?: string;
|
|
23
72
|
maxHeight?: number;
|
|
24
73
|
dismiss: () => void;
|
|
25
|
-
headerComponent?: React.ComponentType
|
|
26
|
-
|
|
27
|
-
scrollViewContent?: {
|
|
28
|
-
renderItem: (item: any, index: number) => React.ReactNode;
|
|
29
|
-
items: any[];
|
|
30
|
-
} | null;
|
|
31
|
-
|
|
74
|
+
headerComponent?: React.ComponentType<any>;
|
|
32
75
|
buttonComponent?: React.ComponentType;
|
|
33
76
|
iconProps?: ItemIconProps | ((theme: PluginConfiguration) => ItemIconProps);
|
|
34
77
|
itemProps?:
|
|
@@ -37,16 +80,22 @@ type ModalComponentProps = {
|
|
|
37
80
|
labelProps?:
|
|
38
81
|
| ItemLabelProps
|
|
39
82
|
| ((theme: PluginConfiguration, width: number) => ItemLabelProps);
|
|
40
|
-
getSelectedItemIcon
|
|
83
|
+
getSelectedItemIcon?: (
|
|
41
84
|
theme: PluginConfiguration
|
|
42
85
|
) => ItemIconProps["asset"] | null;
|
|
43
|
-
getDefaultItemIcon
|
|
86
|
+
getDefaultItemIcon?: (
|
|
44
87
|
theme: PluginConfiguration
|
|
45
88
|
) => ItemIconProps["asset"] | null;
|
|
46
89
|
iconPlacement?: "left" | "right";
|
|
90
|
+
viewModel?: ContentViewModel;
|
|
91
|
+
/** Optional body that replaces the items list (header stays DefaultModalHeader). */
|
|
92
|
+
contentComponent?: React.ComponentType<any>;
|
|
93
|
+
contentComponentProps?: Record<string, any>;
|
|
94
|
+
styleOverrides?: ModalBlocksConfig | Record<string, any>;
|
|
95
|
+
measurementPhase?: boolean;
|
|
47
96
|
};
|
|
48
97
|
|
|
49
|
-
|
|
98
|
+
function _BottomSheetModalContent(props: ModalComponentProps) {
|
|
50
99
|
const {
|
|
51
100
|
items,
|
|
52
101
|
currentRoute,
|
|
@@ -55,23 +104,110 @@ export function BottomSheetModalContent(props: ModalComponentProps) {
|
|
|
55
104
|
dismiss,
|
|
56
105
|
summary,
|
|
57
106
|
title,
|
|
58
|
-
headerComponent
|
|
59
|
-
|
|
60
|
-
|
|
107
|
+
headerComponent,
|
|
108
|
+
viewModel = null,
|
|
61
109
|
buttonComponent: ButtonComponent = Button,
|
|
62
110
|
getSelectedItemIcon = ({
|
|
63
111
|
modal_bottom_sheet_item_selected_icon,
|
|
64
112
|
}: BaseThemePropertiesMobile) => modal_bottom_sheet_item_selected_icon,
|
|
65
113
|
getDefaultItemIcon = () => null,
|
|
66
114
|
iconPlacement,
|
|
115
|
+
contentComponent: ContentComponent,
|
|
116
|
+
contentComponentProps = {},
|
|
117
|
+
styleOverrides: propStyleOverrides,
|
|
118
|
+
measurementPhase = false,
|
|
67
119
|
} = props;
|
|
68
120
|
|
|
69
121
|
const route = useRef(currentRoute);
|
|
70
122
|
const theme = useTheme<BaseThemePropertiesMobile>();
|
|
123
|
+
const bottomInset = useSafeAreaInsets().bottom;
|
|
71
124
|
const paddingTop = Number(theme.modal_bottom_sheet_padding_top);
|
|
72
125
|
const paddingBottom = Number(theme.modal_bottom_sheet_padding_bottom);
|
|
73
126
|
|
|
74
|
-
const
|
|
127
|
+
const calculatedcontentContainerStyle = useMemo(() => {
|
|
128
|
+
return {
|
|
129
|
+
paddingBottom: paddingBottom + bottomInset,
|
|
130
|
+
};
|
|
131
|
+
}, [paddingBottom, bottomInset]);
|
|
132
|
+
|
|
133
|
+
const {
|
|
134
|
+
items: fetchedItems,
|
|
135
|
+
showCentralLoading,
|
|
136
|
+
error,
|
|
137
|
+
handleItemPress,
|
|
138
|
+
role,
|
|
139
|
+
behavior,
|
|
140
|
+
editableCollection,
|
|
141
|
+
themePluginId,
|
|
142
|
+
} = useBottomSheetContent({
|
|
143
|
+
onPress,
|
|
144
|
+
viewModel,
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
const plugins = usePlugins();
|
|
148
|
+
|
|
149
|
+
const plugin = useMemo(
|
|
150
|
+
() => plugins?.find((p) => p.identifier === themePluginId),
|
|
151
|
+
[plugins, themePluginId]
|
|
152
|
+
);
|
|
153
|
+
|
|
154
|
+
const styleOverrides = useMemo(() => {
|
|
155
|
+
if (propStyleOverrides) {
|
|
156
|
+
return propStyleOverrides;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const configuration =
|
|
160
|
+
plugin?.configuration || (plugin as any)?.configuration_json;
|
|
161
|
+
|
|
162
|
+
if (!configuration || !themePluginId) return null;
|
|
163
|
+
|
|
164
|
+
return parseModalBlocksConfiguration(configuration, themePluginId);
|
|
165
|
+
}, [propStyleOverrides, plugin, themePluginId]);
|
|
166
|
+
|
|
167
|
+
const pluginLocalizations = useLocalizedStrings({
|
|
168
|
+
localizations:
|
|
169
|
+
plugin?.configuration?.localizations ||
|
|
170
|
+
(plugin as any)?.configuration_json?.localizations,
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
const normalizedPluginId = themePluginId?.replace(/-/g, "_");
|
|
174
|
+
|
|
175
|
+
const localizedHeaderTitle = normalizedPluginId
|
|
176
|
+
? pluginLocalizations?.[`${normalizedPluginId}_header_title`]
|
|
177
|
+
: undefined;
|
|
178
|
+
|
|
179
|
+
const createPlaylistTitle =
|
|
180
|
+
pluginLocalizations?.create_new_playlist_title || "Create New Playlist";
|
|
181
|
+
|
|
182
|
+
const nextUpTitle =
|
|
183
|
+
pluginLocalizations?.next_up_title ||
|
|
184
|
+
(normalizedPluginId
|
|
185
|
+
? pluginLocalizations?.[`${normalizedPluginId}_next_up_title`]
|
|
186
|
+
: undefined) ||
|
|
187
|
+
"Next Up";
|
|
188
|
+
|
|
189
|
+
const nowPlayingTitle =
|
|
190
|
+
pluginLocalizations?.now_playing_title ||
|
|
191
|
+
(normalizedPluginId
|
|
192
|
+
? pluginLocalizations?.[`${normalizedPluginId}_now_playing_title`]
|
|
193
|
+
: undefined) ||
|
|
194
|
+
"Now Playing";
|
|
195
|
+
|
|
196
|
+
const resolvedTitle = props.title || localizedHeaderTitle || title;
|
|
197
|
+
|
|
198
|
+
const itemsToRender = viewModel ? fetchedItems : items;
|
|
199
|
+
const operations = editableCollection?.operations || [];
|
|
200
|
+
|
|
201
|
+
const isSortable = useDeferredValue(
|
|
202
|
+
!measurementPhase && hasOperation(operations, OPERATIONS.REORDER)
|
|
203
|
+
);
|
|
204
|
+
|
|
205
|
+
const cell = getCell(
|
|
206
|
+
viewModel ? role : undefined,
|
|
207
|
+
viewModel ? behavior : undefined
|
|
208
|
+
);
|
|
209
|
+
|
|
210
|
+
const Header = headerComponent ?? DefaultModalHeader;
|
|
75
211
|
|
|
76
212
|
useEffect(() => {
|
|
77
213
|
if (currentRoute !== route.current) {
|
|
@@ -84,14 +220,24 @@ export function BottomSheetModalContent(props: ModalComponentProps) {
|
|
|
84
220
|
}, [theme, props.iconProps]);
|
|
85
221
|
|
|
86
222
|
const itemBaseProps = useMemo<ItemProps>(() => {
|
|
87
|
-
return getItemProps(
|
|
88
|
-
|
|
223
|
+
return getItemProps(
|
|
224
|
+
theme,
|
|
225
|
+
props.width,
|
|
226
|
+
props.itemProps,
|
|
227
|
+
styleOverrides?.item
|
|
228
|
+
);
|
|
229
|
+
}, [theme, props.width, props.itemProps, styleOverrides?.item]);
|
|
89
230
|
|
|
90
231
|
const labelBaseProps = useMemo<ItemLabelProps>(() => {
|
|
91
|
-
return getItemLabelProps(
|
|
92
|
-
|
|
232
|
+
return getItemLabelProps(
|
|
233
|
+
theme,
|
|
234
|
+
props.width,
|
|
235
|
+
props.labelProps,
|
|
236
|
+
styleOverrides?.item
|
|
237
|
+
);
|
|
238
|
+
}, [theme, props.width, props.labelProps, styleOverrides?.item]);
|
|
93
239
|
|
|
94
|
-
const
|
|
240
|
+
const handleStaticPress = useCallback(
|
|
95
241
|
(item: any) => {
|
|
96
242
|
onPress(item);
|
|
97
243
|
dismiss();
|
|
@@ -99,58 +245,271 @@ export function BottomSheetModalContent(props: ModalComponentProps) {
|
|
|
99
245
|
[onPress, dismiss]
|
|
100
246
|
);
|
|
101
247
|
|
|
102
|
-
const
|
|
248
|
+
const onItemPress = viewModel ? handleItemPress : handleStaticPress;
|
|
249
|
+
|
|
250
|
+
const handleDragEnd = useCallback(
|
|
251
|
+
(params: any) => {
|
|
252
|
+
const from = params?.fromIndex ?? params?.from;
|
|
253
|
+
const to = params?.toIndex ?? params?.to;
|
|
254
|
+
|
|
255
|
+
const reorderedItemIds = Array.isArray(params?.data)
|
|
256
|
+
? params.data
|
|
257
|
+
.filter((item: any) => !item?.isHeader)
|
|
258
|
+
.map((item: any) => item?.id)
|
|
259
|
+
.filter(Boolean)
|
|
260
|
+
: undefined;
|
|
261
|
+
|
|
262
|
+
if (
|
|
263
|
+
(reorderedItemIds?.length ||
|
|
264
|
+
(typeof from === "number" &&
|
|
265
|
+
typeof to === "number" &&
|
|
266
|
+
from !== to)) &&
|
|
267
|
+
editableCollection?.move
|
|
268
|
+
) {
|
|
269
|
+
editableCollection.move(reorderedItemIds || []);
|
|
270
|
+
}
|
|
271
|
+
},
|
|
272
|
+
[editableCollection]
|
|
273
|
+
);
|
|
274
|
+
|
|
275
|
+
const renderContext = useMemo(
|
|
276
|
+
() => ({
|
|
277
|
+
theme,
|
|
278
|
+
ButtonComponent,
|
|
279
|
+
current_selection,
|
|
280
|
+
iconBaseProps,
|
|
281
|
+
itemBaseProps,
|
|
282
|
+
labelBaseProps,
|
|
283
|
+
getSelectedItemIcon,
|
|
284
|
+
getDefaultItemIcon,
|
|
285
|
+
iconPlacement,
|
|
286
|
+
editableCollection,
|
|
287
|
+
behavior,
|
|
288
|
+
}),
|
|
289
|
+
[
|
|
290
|
+
theme,
|
|
291
|
+
ButtonComponent,
|
|
292
|
+
current_selection,
|
|
293
|
+
iconBaseProps,
|
|
294
|
+
itemBaseProps,
|
|
295
|
+
labelBaseProps,
|
|
296
|
+
getSelectedItemIcon,
|
|
297
|
+
getDefaultItemIcon,
|
|
298
|
+
iconPlacement,
|
|
299
|
+
editableCollection,
|
|
300
|
+
behavior,
|
|
301
|
+
]
|
|
302
|
+
);
|
|
303
|
+
|
|
304
|
+
const sortableListRenderItem = useCallback(
|
|
305
|
+
({ item, index, renderHandle }) =>
|
|
306
|
+
cell.renderItem({
|
|
307
|
+
item,
|
|
308
|
+
index,
|
|
309
|
+
onPress: onItemPress,
|
|
310
|
+
context: renderContext,
|
|
311
|
+
renderHandle,
|
|
312
|
+
}),
|
|
313
|
+
[cell, onItemPress, renderContext]
|
|
314
|
+
);
|
|
315
|
+
|
|
316
|
+
const hasNowPlaying = hasOperation(operations, OPERATIONS.NOW_PLAYING);
|
|
317
|
+
const hasClearAll = hasOperation(operations, OPERATIONS.CLEAR_ALL);
|
|
318
|
+
const hasAdd = hasOperation(operations, OPERATIONS.ADD);
|
|
319
|
+
|
|
320
|
+
const handleDeleteCollection = useCallback(() => {
|
|
321
|
+
editableCollection?.deleteCollection?.();
|
|
322
|
+
}, [editableCollection]);
|
|
323
|
+
|
|
324
|
+
const handleCreatePlaylist = useCallback(() => {
|
|
325
|
+
editableCollection?.add?.({
|
|
326
|
+
id: "create_new_playlist",
|
|
327
|
+
title: createPlaylistTitle,
|
|
328
|
+
});
|
|
329
|
+
}, [editableCollection, createPlaylistTitle]);
|
|
330
|
+
|
|
331
|
+
const headers = useMemo(() => {
|
|
332
|
+
const list: Array<{ index: number; component: () => React.ReactElement }> =
|
|
333
|
+
[];
|
|
334
|
+
|
|
335
|
+
if (hasNowPlaying) {
|
|
336
|
+
list.push({
|
|
337
|
+
index: list.length,
|
|
338
|
+
component: () => (
|
|
339
|
+
<NowPlayingHeaderSection
|
|
340
|
+
onClear={hasClearAll ? handleDeleteCollection : undefined}
|
|
341
|
+
nextUpTitle={nextUpTitle}
|
|
342
|
+
nowPlayingTitle={nowPlayingTitle}
|
|
343
|
+
/>
|
|
344
|
+
),
|
|
345
|
+
});
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
if (hasAdd) {
|
|
349
|
+
list.push({
|
|
350
|
+
index: list.length,
|
|
351
|
+
component: () => (
|
|
352
|
+
<View
|
|
353
|
+
style={{ paddingHorizontal: 20, paddingTop: 8, paddingBottom: 12 }}
|
|
354
|
+
>
|
|
355
|
+
<AudioPlayerButton
|
|
356
|
+
configuration={VARIANT_WITH_ICON}
|
|
357
|
+
data={{ title: createPlaylistTitle }}
|
|
358
|
+
onPress={handleCreatePlaylist}
|
|
359
|
+
/>
|
|
360
|
+
</View>
|
|
361
|
+
),
|
|
362
|
+
});
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
return list.length > 0 ? list : undefined;
|
|
366
|
+
}, [
|
|
367
|
+
hasNowPlaying,
|
|
368
|
+
hasClearAll,
|
|
369
|
+
handleDeleteCollection,
|
|
370
|
+
nextUpTitle,
|
|
371
|
+
nowPlayingTitle,
|
|
372
|
+
hasAdd,
|
|
373
|
+
handleCreatePlaylist,
|
|
374
|
+
createPlaylistTitle,
|
|
375
|
+
]);
|
|
376
|
+
|
|
377
|
+
const _items = useMemo(() => {
|
|
378
|
+
return (itemsToRender || []).map((item, index) =>
|
|
379
|
+
cell.renderItem({
|
|
380
|
+
item,
|
|
381
|
+
index,
|
|
382
|
+
onPress: onItemPress,
|
|
383
|
+
context: renderContext,
|
|
384
|
+
})
|
|
385
|
+
);
|
|
386
|
+
}, [itemsToRender, cell, onItemPress, renderContext]);
|
|
387
|
+
|
|
388
|
+
const _styles = useMemo(() => {
|
|
389
|
+
return {
|
|
390
|
+
maxHeight: props.maxHeight,
|
|
391
|
+
paddingTop: paddingTop,
|
|
392
|
+
};
|
|
393
|
+
}, [props.maxHeight, paddingTop]);
|
|
394
|
+
|
|
395
|
+
const renderedBody = (() => {
|
|
396
|
+
if (ContentComponent) {
|
|
397
|
+
const shouldWrapInScrollView =
|
|
398
|
+
!contentComponentProps?.disableScrollViewWrap &&
|
|
399
|
+
!(ContentComponent as any)?.disableScrollViewWrap;
|
|
400
|
+
|
|
401
|
+
if (shouldWrapInScrollView) {
|
|
402
|
+
return (
|
|
403
|
+
<ScrollView
|
|
404
|
+
keyboardShouldPersistTaps="handled"
|
|
405
|
+
contentContainerStyle={calculatedcontentContainerStyle}
|
|
406
|
+
>
|
|
407
|
+
<ContentComponent
|
|
408
|
+
{...contentComponentProps}
|
|
409
|
+
dismiss={dismiss}
|
|
410
|
+
width={props.width}
|
|
411
|
+
maxHeight={props.maxHeight}
|
|
412
|
+
/>
|
|
413
|
+
</ScrollView>
|
|
414
|
+
);
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
return (
|
|
418
|
+
<View style={[styles.scrollView, calculatedcontentContainerStyle]}>
|
|
419
|
+
<ContentComponent
|
|
420
|
+
{...contentComponentProps}
|
|
421
|
+
dismiss={dismiss}
|
|
422
|
+
width={props.width}
|
|
423
|
+
maxHeight={props.maxHeight}
|
|
424
|
+
/>
|
|
425
|
+
</View>
|
|
426
|
+
);
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
if (showCentralLoading) {
|
|
430
|
+
const loaderColor =
|
|
431
|
+
(theme as any)?.modal_bottom_sheet_activity_indicator_color ||
|
|
432
|
+
(theme as any)?.cell_title_color ||
|
|
433
|
+
"#ffffff";
|
|
434
|
+
|
|
435
|
+
return (
|
|
436
|
+
<View
|
|
437
|
+
style={[
|
|
438
|
+
styles.centered,
|
|
439
|
+
{ backgroundColor: theme.modal_bottom_sheet_background_color },
|
|
440
|
+
]}
|
|
441
|
+
>
|
|
442
|
+
<ActivityIndicator color={loaderColor} />
|
|
443
|
+
</View>
|
|
444
|
+
);
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
if (error) {
|
|
448
|
+
return (
|
|
449
|
+
<View style={styles.centered}>
|
|
450
|
+
<Text style={styles.errorText}>
|
|
451
|
+
{typeof error === "string" ? error : error.message}
|
|
452
|
+
</Text>
|
|
453
|
+
</View>
|
|
454
|
+
);
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
if (isSortable) {
|
|
458
|
+
return (
|
|
459
|
+
<SortableList
|
|
460
|
+
sortableData={itemsToRender}
|
|
461
|
+
headers={headers}
|
|
462
|
+
scrollViewStyle={styles.scrollView}
|
|
463
|
+
contentContainerStyle={calculatedcontentContainerStyle}
|
|
464
|
+
onDragEnd={handleDragEnd}
|
|
465
|
+
renderItem={sortableListRenderItem}
|
|
466
|
+
/>
|
|
467
|
+
);
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
return (
|
|
471
|
+
<ScrollView
|
|
472
|
+
keyboardShouldPersistTaps="handled"
|
|
473
|
+
overScrollMode="never"
|
|
474
|
+
bounces={false}
|
|
475
|
+
contentContainerStyle={calculatedcontentContainerStyle}
|
|
476
|
+
>
|
|
477
|
+
{hasNowPlaying ? (
|
|
478
|
+
<NowPlayingHeaderSection
|
|
479
|
+
onClear={hasClearAll ? handleDeleteCollection : undefined}
|
|
480
|
+
nextUpTitle={nextUpTitle}
|
|
481
|
+
nowPlayingTitle={nowPlayingTitle}
|
|
482
|
+
/>
|
|
483
|
+
) : null}
|
|
484
|
+
{hasAdd ? (
|
|
485
|
+
<View style={styles.someStyles}>
|
|
486
|
+
<AudioPlayerButton
|
|
487
|
+
configuration={VARIANT_WITH_ICON}
|
|
488
|
+
data={{ title: createPlaylistTitle }}
|
|
489
|
+
onPress={handleCreatePlaylist}
|
|
490
|
+
/>
|
|
491
|
+
</View>
|
|
492
|
+
) : null}
|
|
493
|
+
{_items}
|
|
494
|
+
</ScrollView>
|
|
495
|
+
);
|
|
496
|
+
})();
|
|
103
497
|
|
|
104
498
|
return (
|
|
105
|
-
<
|
|
106
|
-
style={
|
|
107
|
-
maxHeight: props.maxHeight,
|
|
108
|
-
paddingTop: paddingTop,
|
|
109
|
-
}}
|
|
110
|
-
>
|
|
111
|
-
{Header ? (
|
|
499
|
+
<ModalBlocksStyleContext.Provider value={styleOverrides as any}>
|
|
500
|
+
<View style={_styles}>
|
|
112
501
|
<BottomSheetDragArea>
|
|
113
502
|
<Header
|
|
114
503
|
dismiss={dismiss}
|
|
115
504
|
configuration={theme}
|
|
116
505
|
summary={summary}
|
|
117
|
-
title={
|
|
506
|
+
title={resolvedTitle}
|
|
118
507
|
/>
|
|
119
508
|
</BottomSheetDragArea>
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
bounces={false}
|
|
124
|
-
showsVerticalScrollIndicator={false}
|
|
125
|
-
contentContainerStyle={{
|
|
126
|
-
paddingBottom: paddingBottom + bottomInset,
|
|
127
|
-
}}
|
|
128
|
-
>
|
|
129
|
-
{scrollViewContent
|
|
130
|
-
? scrollViewContent.items.map((item, index) =>
|
|
131
|
-
scrollViewContent.renderItem(item, index)
|
|
132
|
-
)
|
|
133
|
-
: null}
|
|
134
|
-
{!scrollViewContent &&
|
|
135
|
-
items.map((item, index) =>
|
|
136
|
-
item ? (
|
|
137
|
-
<ButtonComponent
|
|
138
|
-
key={index}
|
|
139
|
-
configuration={theme}
|
|
140
|
-
selectedItem={current_selection}
|
|
141
|
-
item={item}
|
|
142
|
-
onPress={handlePress}
|
|
143
|
-
label={theme[item?.label] ?? item?.label}
|
|
144
|
-
iconBaseProps={iconBaseProps}
|
|
145
|
-
itemBaseProps={itemBaseProps}
|
|
146
|
-
labelBaseProps={labelBaseProps}
|
|
147
|
-
selectedItemIcon={getSelectedItemIcon(theme)}
|
|
148
|
-
defaultItemIcon={getDefaultItemIcon(theme)}
|
|
149
|
-
iconPlacement={iconPlacement}
|
|
150
|
-
/>
|
|
151
|
-
) : null
|
|
152
|
-
)}
|
|
153
|
-
</ScrollView>
|
|
154
|
-
</View>
|
|
509
|
+
{renderedBody}
|
|
510
|
+
</View>
|
|
511
|
+
</ModalBlocksStyleContext.Provider>
|
|
155
512
|
);
|
|
156
513
|
}
|
|
514
|
+
|
|
515
|
+
export const BottomSheetModalContent = memo(_BottomSheetModalContent);
|
|
@@ -43,11 +43,13 @@ export function Button({
|
|
|
43
43
|
}: ButtonProps) {
|
|
44
44
|
const [focused, setFocused] = useState(false);
|
|
45
45
|
|
|
46
|
-
const selected = selectedItem && item
|
|
46
|
+
const selected = selectedItem && item?.value === selectedItem?.value;
|
|
47
47
|
|
|
48
48
|
const itemIconPropsAssets = useMemo<ItemIconProps["asset"]>(
|
|
49
|
-
() =>
|
|
50
|
-
|
|
49
|
+
() =>
|
|
50
|
+
(item ? (configuration[item.asset] ?? item.asset) : undefined) ??
|
|
51
|
+
defaultItemIcon,
|
|
52
|
+
[item?.asset, defaultItemIcon]
|
|
51
53
|
);
|
|
52
54
|
|
|
53
55
|
const selectedItemIconPropsAssets = useMemo<ItemIconProps["asset"]>(
|
|
@@ -4,6 +4,7 @@ import { Title, TitleProps } from "./Title";
|
|
|
4
4
|
import { CloseButton, CloseButtonProps } from "./CloseButton";
|
|
5
5
|
import { getCloseButtonProps, getTitleProps } from "./utils";
|
|
6
6
|
import { PluginConfiguration } from "../index";
|
|
7
|
+
import { useModalBlocksStyle } from "../ModalBlocksStyleContext";
|
|
7
8
|
|
|
8
9
|
type Props = {
|
|
9
10
|
dismiss: () => void;
|
|
@@ -28,6 +29,14 @@ const styles = StyleSheet.create({
|
|
|
28
29
|
|
|
29
30
|
export function ModalHeader(props: Props) {
|
|
30
31
|
const { configuration, dismiss, onLayout, summary, title } = props;
|
|
32
|
+
const modalBlocksStyle = useModalBlocksStyle();
|
|
33
|
+
const headerBlock = modalBlocksStyle?.header;
|
|
34
|
+
|
|
35
|
+
const containerStyle = useMemo(() => {
|
|
36
|
+
const bg = headerBlock?.container?.default?.backgroundColor;
|
|
37
|
+
|
|
38
|
+
return [styles.container, bg ? { backgroundColor: bg } : null];
|
|
39
|
+
}, [headerBlock?.container?.default?.backgroundColor]);
|
|
31
40
|
|
|
32
41
|
const closeButtonProps = useMemo<CloseButtonProps>(
|
|
33
42
|
() => ({
|
|
@@ -37,13 +46,17 @@ export function ModalHeader(props: Props) {
|
|
|
37
46
|
[configuration, dismiss]
|
|
38
47
|
);
|
|
39
48
|
|
|
40
|
-
const titleProps = useMemo<TitleProps>(
|
|
41
|
-
|
|
42
|
-
|
|
49
|
+
const titleProps = useMemo<TitleProps>(() => {
|
|
50
|
+
const baseProps = getTitleProps(configuration, "title");
|
|
51
|
+
const titleOverride = headerBlock?.title?.default;
|
|
52
|
+
|
|
53
|
+
return {
|
|
54
|
+
...baseProps,
|
|
43
55
|
text: title,
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
56
|
+
...(titleOverride?.fontColor ? { color: titleOverride.fontColor } : {}),
|
|
57
|
+
...(titleOverride?.fontSize ? { fontSize: titleOverride.fontSize } : {}),
|
|
58
|
+
};
|
|
59
|
+
}, [configuration, title, headerBlock?.title?.default]);
|
|
47
60
|
|
|
48
61
|
const summaryProps = useMemo<TitleProps>(
|
|
49
62
|
() => ({
|
|
@@ -59,7 +72,7 @@ export function ModalHeader(props: Props) {
|
|
|
59
72
|
configuration.modal_bottom_sheet_close_margin_right;
|
|
60
73
|
|
|
61
74
|
return (
|
|
62
|
-
<View onLayout={onLayout} style={
|
|
75
|
+
<View onLayout={onLayout} style={containerStyle}>
|
|
63
76
|
<View style={styles.flex}>
|
|
64
77
|
{title ? <Title {...titleProps} /> : null}
|
|
65
78
|
{summary ? <Title {...summaryProps} /> : null}
|
|
@@ -18,7 +18,7 @@ export function getCloseButtonProps(config: PluginConfiguration) {
|
|
|
18
18
|
return {
|
|
19
19
|
asset: modal_bottom_sheet_close_asset,
|
|
20
20
|
assetFocused: modal_bottom_sheet_close_focus_asset,
|
|
21
|
-
enabled: modal_bottom_sheet_close_switch,
|
|
21
|
+
enabled: modal_bottom_sheet_close_switch !== false,
|
|
22
22
|
width: modal_bottom_sheet_close_width,
|
|
23
23
|
height: modal_bottom_sheet_close_height,
|
|
24
24
|
marginTop: modal_bottom_sheet_close_margin_top,
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import React, { useContext } from "react";
|
|
2
|
+
import type { ModalBlocksConfig } from "@applicaster/zapp-react-native-utils/configurationUtils/modalBlocksParser";
|
|
3
|
+
|
|
4
|
+
export const ModalBlocksStyleContext = React.createContext<
|
|
5
|
+
ModalBlocksConfig | Record<string, any> | undefined
|
|
6
|
+
>(undefined);
|
|
7
|
+
|
|
8
|
+
export const useModalBlocksStyle = () => {
|
|
9
|
+
return useContext(ModalBlocksStyleContext);
|
|
10
|
+
};
|