@applicaster/zapp-react-native-utils 16.0.0-alpha.8901714553 → 16.0.0-alpha.9530606740

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 (60) hide show
  1. package/actionsExecutor/ActionExecutor.ts +8 -10
  2. package/actionsExecutor/ActionExecutorContext.tsx +41 -325
  3. package/actionsExecutor/actions/appRestart.ts +24 -0
  4. package/actionsExecutor/actions/confirmDialog.ts +53 -0
  5. package/actionsExecutor/actions/index.ts +30 -0
  6. package/actionsExecutor/actions/localStorageRemove.ts +27 -0
  7. package/actionsExecutor/actions/localStorageSet.ts +28 -0
  8. package/actionsExecutor/actions/localStorageToggleFlag.ts +28 -0
  9. package/actionsExecutor/actions/navigateToScreen.ts +123 -0
  10. package/actionsExecutor/actions/openBottomSheet.ts +177 -0
  11. package/actionsExecutor/actions/refreshComponent.ts +79 -0
  12. package/actionsExecutor/actions/screenSetVariable.ts +35 -0
  13. package/actionsExecutor/actions/screenToggleFlag.ts +38 -0
  14. package/actionsExecutor/actions/sendCloudEvent.ts +88 -0
  15. package/actionsExecutor/actions/sessionStorageRemove.ts +19 -0
  16. package/actionsExecutor/actions/sessionStorageSet.ts +20 -0
  17. package/actionsExecutor/actions/sessionStorageToggleFlag.ts +15 -0
  18. package/actionsExecutor/actions/switchLayout.ts +40 -0
  19. package/actionsExecutor/types.ts +59 -0
  20. package/appUtils/contextKeysManager/__tests__/getKey/failure.test.ts +1 -1
  21. package/appUtils/contextKeysManager/__tests__/removeKey/failure.test.ts +1 -1
  22. package/appUtils/contextKeysManager/__tests__/setKey/failure/invalidKey.test.ts +4 -4
  23. package/appUtils/contextKeysManager/index.ts +1 -1
  24. package/cellUtils/index.ts +3 -5
  25. package/colorUtils/__tests__/isTransparentColor.test.ts +76 -0
  26. package/colorUtils/__tests__/isValidColor.test.ts +70 -0
  27. package/colorUtils/index.ts +50 -0
  28. package/manifestUtils/_internals/index.js +6 -0
  29. package/manifestUtils/fieldUtils/__tests__/fieldUtils.test.js +84 -0
  30. package/manifestUtils/fieldUtils/index.js +125 -0
  31. package/manifestUtils/keys.js +9 -0
  32. package/manifestUtils/mobileAction/button/index.js +16 -0
  33. package/manifestUtils/mobileAction/container/index.js +3 -1
  34. package/manifestUtils/mobileAction/groups/defaults.js +3 -1
  35. package/manifestUtils/platformIsTV.js +1 -0
  36. package/modalState/ContentViewModel.ts +59 -0
  37. package/modalState/ModalOrchestrator.ts +204 -0
  38. package/modalState/__tests__/ContentViewModel.test.ts +107 -0
  39. package/modalState/components/ActionItem.tsx +155 -0
  40. package/modalState/components/BottomSheetHeader.tsx +245 -0
  41. package/modalState/components/PrimaryButton.tsx +54 -0
  42. package/modalState/components/TrackItem.tsx +241 -0
  43. package/modalState/index.ts +25 -74
  44. package/modalState/store.ts +102 -0
  45. package/modalState/types.ts +55 -0
  46. package/package.json +2 -2
  47. package/pipesUtils/__tests__/buildUrlWithQuery.test.ts +33 -0
  48. package/pipesUtils/__tests__/withPipesEndpoint.test.tsx +56 -0
  49. package/pipesUtils/index.ts +1 -0
  50. package/pipesUtils/withPipesEndpoint.tsx +54 -0
  51. package/reactHooks/actions/index.ts +51 -1
  52. package/reactHooks/cell-click/index.ts +3 -3
  53. package/reactHooks/feed/__mocks__/useMarkPipesDataStale.ts +4 -0
  54. package/reactHooks/feed/index.ts +5 -1
  55. package/reactHooks/feed/useBatchLoading.ts +9 -1
  56. package/reactHooks/feed/{usePipesCacheReset.ts → useMarkPipesDataStale.ts} +12 -4
  57. package/reactHooks/utils/index.ts +3 -2
  58. package/riverComponetsMeasurementProvider/index.tsx +12 -8
  59. package/uiActionsRegistrator/index.ts +203 -0
  60. package/reactHooks/feed/__mocks__/usePipesCacheReset.ts +0 -1
@@ -0,0 +1,245 @@
1
+ import React from "react";
2
+ import {
3
+ View,
4
+ Text,
5
+ StyleSheet,
6
+ Pressable,
7
+ ActivityIndicator,
8
+ } from "react-native";
9
+
10
+ const styles = StyleSheet.create({
11
+ headerContainer: {
12
+ flexDirection: "row",
13
+ alignItems: "center",
14
+ justifyContent: "space-between",
15
+ backgroundColor: "#262626",
16
+ paddingVertical: 12,
17
+ },
18
+ navBarBorder: {
19
+ borderBottomWidth: 1,
20
+ borderBottomColor: "#333333",
21
+ },
22
+ headerGutter16: {
23
+ paddingHorizontal: 16,
24
+ },
25
+ headerGutter12: {
26
+ paddingHorizontal: 12,
27
+ },
28
+ headerTitle: {
29
+ color: "#FFFFFF",
30
+ fontWeight: "bold",
31
+ fontSize: 16,
32
+ textAlign: "center",
33
+ },
34
+ headerTitleCenter: {
35
+ fontSize: 17,
36
+ flex: 1,
37
+ textAlign: "center",
38
+ },
39
+ headerTitleSection: {
40
+ color: "#aaaaaa",
41
+ fontSize: 13,
42
+ fontWeight: "600",
43
+ textTransform: "uppercase",
44
+ },
45
+ titleWrapper: {
46
+ flex: 1,
47
+ alignItems: "center",
48
+ justifyContent: "center",
49
+ },
50
+ subtitle: {
51
+ color: "#aaaaaa",
52
+ fontSize: 11,
53
+ marginTop: 2,
54
+ textAlign: "center",
55
+ },
56
+ backButton: {
57
+ paddingVertical: 6,
58
+ paddingHorizontal: 12,
59
+ borderRadius: 6,
60
+ backgroundColor: "#333333",
61
+ width: 70,
62
+ alignItems: "center",
63
+ justifyContent: "center",
64
+ },
65
+ backButtonText: {
66
+ color: "#ffffff",
67
+ fontSize: 14,
68
+ fontWeight: "600",
69
+ },
70
+ closeButton: {
71
+ width: 44,
72
+ height: 44,
73
+ alignItems: "center",
74
+ justifyContent: "center",
75
+ },
76
+ closeButtonText: {
77
+ color: "#FFFFFF",
78
+ fontSize: 18,
79
+ },
80
+ headerActionButton: {
81
+ backgroundColor: "#3e3e3e",
82
+ paddingVertical: 6,
83
+ paddingHorizontal: 10,
84
+ borderRadius: 16,
85
+ minWidth: 70,
86
+ alignItems: "center",
87
+ justifyContent: "center",
88
+ },
89
+ headerActionText: {
90
+ color: "#FFFFFF",
91
+ fontWeight: "600",
92
+ fontSize: 14,
93
+ },
94
+ navSpacer: {
95
+ width: 70,
96
+ alignItems: "center",
97
+ justifyContent: "center",
98
+ },
99
+ pressedState: {
100
+ opacity: 0.7,
101
+ },
102
+ });
103
+
104
+ export interface BottomSheetHeaderProps {
105
+ variant?: "single" | "actions" | "section";
106
+ title: string;
107
+ subtitle?: string;
108
+ onClose?: () => void;
109
+ onBack?: () => void;
110
+ onCancel?: () => void;
111
+ onDone?: () => void;
112
+ onClear?: () => void;
113
+ isLoading?: boolean;
114
+ }
115
+
116
+ export const BottomSheetHeader: React.FC<BottomSheetHeaderProps> = ({
117
+ variant = "single",
118
+ title,
119
+ subtitle,
120
+ onClose,
121
+ onBack,
122
+ onCancel,
123
+ onDone,
124
+ onClear,
125
+ isLoading = false,
126
+ }) => {
127
+ if (variant === "actions") {
128
+ return (
129
+ <View
130
+ style={[
131
+ styles.headerContainer,
132
+ styles.headerGutter12,
133
+ styles.navBarBorder,
134
+ ]}
135
+ >
136
+ <Pressable
137
+ style={({ pressed }) => [
138
+ styles.headerActionButton,
139
+ pressed && styles.pressedState,
140
+ ]}
141
+ onPress={onCancel}
142
+ >
143
+ <Text style={styles.headerActionText}>Cancel</Text>
144
+ </Pressable>
145
+ <View style={styles.titleWrapper}>
146
+ <Text
147
+ numberOfLines={1}
148
+ style={[styles.headerTitle, styles.headerTitleCenter]}
149
+ >
150
+ {title}
151
+ </Text>
152
+ {subtitle ? (
153
+ <Text numberOfLines={1} style={styles.subtitle}>
154
+ {subtitle}
155
+ </Text>
156
+ ) : null}
157
+ </View>
158
+ <Pressable
159
+ style={({ pressed }) => [
160
+ styles.headerActionButton,
161
+ pressed && styles.pressedState,
162
+ ]}
163
+ onPress={onDone}
164
+ >
165
+ <Text style={styles.headerActionText}>Done</Text>
166
+ </Pressable>
167
+ </View>
168
+ );
169
+ }
170
+
171
+ if (variant === "section") {
172
+ return (
173
+ <View style={[styles.headerContainer, styles.headerGutter12]}>
174
+ <Text style={[styles.headerTitle, styles.headerTitleSection]}>
175
+ {title}
176
+ </Text>
177
+ {onClear ? (
178
+ <Pressable
179
+ style={({ pressed }) => [
180
+ styles.headerActionButton,
181
+ pressed && styles.pressedState,
182
+ ]}
183
+ onPress={onClear}
184
+ >
185
+ <Text style={styles.headerActionText}>Clear</Text>
186
+ </Pressable>
187
+ ) : null}
188
+ </View>
189
+ );
190
+ }
191
+
192
+ // Default: Single Line with Back and Close button options
193
+ return (
194
+ <View
195
+ style={[
196
+ styles.headerContainer,
197
+ styles.headerGutter16,
198
+ styles.navBarBorder,
199
+ ]}
200
+ >
201
+ {onBack ? (
202
+ <Pressable
203
+ onPress={onBack}
204
+ style={({ pressed }) => [
205
+ styles.backButton,
206
+ pressed && styles.pressedState,
207
+ ]}
208
+ >
209
+ <Text style={styles.backButtonText}>‹ Back</Text>
210
+ </Pressable>
211
+ ) : (
212
+ <View style={styles.navSpacer} />
213
+ )}
214
+
215
+ <View style={styles.titleWrapper}>
216
+ <Text numberOfLines={1} style={styles.headerTitle}>
217
+ {title}
218
+ </Text>
219
+ {subtitle ? (
220
+ <Text numberOfLines={1} style={styles.subtitle}>
221
+ {subtitle}
222
+ </Text>
223
+ ) : null}
224
+ </View>
225
+
226
+ {isLoading ? (
227
+ <View style={styles.navSpacer}>
228
+ <ActivityIndicator size="small" color="#aaaaaa" />
229
+ </View>
230
+ ) : onClose ? (
231
+ <Pressable
232
+ style={({ pressed }) => [
233
+ styles.closeButton,
234
+ pressed && styles.pressedState,
235
+ ]}
236
+ onPress={onClose}
237
+ >
238
+ <Text style={styles.closeButtonText}>✕</Text>
239
+ </Pressable>
240
+ ) : (
241
+ <View style={styles.navSpacer} />
242
+ )}
243
+ </View>
244
+ );
245
+ };
@@ -0,0 +1,54 @@
1
+ import React from "react";
2
+ import { Text, StyleSheet, Pressable } from "react-native";
3
+
4
+ const styles = StyleSheet.create({
5
+ primaryButton: {
6
+ flexDirection: "row",
7
+ backgroundColor: "#FFFFFF",
8
+ borderRadius: 12,
9
+ padding: 12,
10
+ marginHorizontal: 16,
11
+ alignItems: "center",
12
+ justifyContent: "center",
13
+ marginTop: 16,
14
+ marginBottom: 8,
15
+ },
16
+ primaryButtonText: {
17
+ color: "#000000",
18
+ fontSize: 15,
19
+ fontWeight: "bold",
20
+ },
21
+ primaryButtonIcon: {
22
+ color: "#000000",
23
+ fontSize: 18,
24
+ marginRight: 8,
25
+ },
26
+ pressedState: {
27
+ opacity: 0.8,
28
+ },
29
+ });
30
+
31
+ export interface PrimaryButtonProps {
32
+ title: string;
33
+ icon?: string;
34
+ onPress?: () => void;
35
+ }
36
+
37
+ export const PrimaryButton: React.FC<PrimaryButtonProps> = ({
38
+ title,
39
+ icon,
40
+ onPress,
41
+ }) => {
42
+ return (
43
+ <Pressable
44
+ style={({ pressed }) => [
45
+ styles.primaryButton,
46
+ pressed && styles.pressedState,
47
+ ]}
48
+ onPress={onPress}
49
+ >
50
+ {icon ? <Text style={styles.primaryButtonIcon}>{icon}</Text> : null}
51
+ <Text style={styles.primaryButtonText}>{title}</Text>
52
+ </Pressable>
53
+ );
54
+ };
@@ -0,0 +1,241 @@
1
+ import React, { useState } from "react";
2
+ import { View, Text, StyleSheet, Pressable, Image } from "react-native";
3
+
4
+ const styles = StyleSheet.create({
5
+ trackItem: {
6
+ flexDirection: "row",
7
+ alignItems: "center",
8
+ paddingVertical: 10,
9
+ paddingHorizontal: 12,
10
+ borderBottomWidth: 1,
11
+ borderBottomColor: "#2a2a2a",
12
+ backgroundColor: "#1e1e1e",
13
+ },
14
+ trackItemFocused: {
15
+ backgroundColor: "#2d2d2d",
16
+ },
17
+ trackImage: {
18
+ width: 48,
19
+ height: 48,
20
+ borderRadius: 6,
21
+ marginRight: 12,
22
+ backgroundColor: "#2a2a2a",
23
+ },
24
+ trackImagePlaceholder: {
25
+ width: 48,
26
+ height: 48,
27
+ borderRadius: 6,
28
+ borderWidth: 1,
29
+ borderColor: "rgba(255, 255, 255, 0.1)",
30
+ backgroundColor: "#333",
31
+ marginRight: 12,
32
+ alignItems: "center",
33
+ justifyContent: "center",
34
+ },
35
+ trackImageText: {
36
+ color: "#fff",
37
+ fontSize: 20,
38
+ },
39
+ trackTextContainer: {
40
+ flex: 1,
41
+ justifyContent: "center",
42
+ },
43
+ nowPlayingLabel: {
44
+ color: "#30d158",
45
+ fontSize: 11,
46
+ fontWeight: "600",
47
+ marginBottom: 2,
48
+ textTransform: "uppercase",
49
+ },
50
+ trackTitle: {
51
+ color: "#FFFFFF",
52
+ fontSize: 15,
53
+ fontWeight: "600",
54
+ },
55
+ trackSubtitle: {
56
+ color: "#999999",
57
+ fontSize: 13,
58
+ fontWeight: "500",
59
+ marginTop: 2,
60
+ },
61
+ trackActions: {
62
+ flexDirection: "row",
63
+ alignItems: "center",
64
+ },
65
+ queuedActionsContainer: {
66
+ flexDirection: "row",
67
+ alignItems: "center",
68
+ },
69
+ trackActionButton: {
70
+ padding: 10,
71
+ marginLeft: 4,
72
+ },
73
+ trackActionIcon: {
74
+ color: "#FFFFFF",
75
+ fontSize: 18,
76
+ },
77
+ playPauseButton: {
78
+ width: 36,
79
+ height: 36,
80
+ backgroundColor: "#FFFFFF",
81
+ borderRadius: 18,
82
+ alignItems: "center",
83
+ justifyContent: "center",
84
+ marginLeft: 8,
85
+ },
86
+ playPauseText: {
87
+ color: "#000000",
88
+ fontWeight: "bold",
89
+ fontSize: 12,
90
+ },
91
+ radioContainer: {
92
+ padding: 10,
93
+ },
94
+ radioUnselected: {
95
+ width: 24,
96
+ height: 24,
97
+ borderRadius: 12,
98
+ borderWidth: 1,
99
+ borderColor: "#999",
100
+ },
101
+ radioSelected: {
102
+ width: 24,
103
+ height: 24,
104
+ borderRadius: 12,
105
+ backgroundColor: "#FFFFFF",
106
+ alignItems: "center",
107
+ justifyContent: "center",
108
+ },
109
+ radioCheck: {
110
+ color: "#000000",
111
+ fontSize: 14,
112
+ fontWeight: "bold",
113
+ },
114
+ pressedState: {
115
+ opacity: 0.7,
116
+ },
117
+ });
118
+
119
+ export interface TrackItemProps {
120
+ variant: "nowPlaying" | "queued" | "playlist";
121
+ title: string;
122
+ subtitle?: string;
123
+ icon?: string;
124
+ isSelected?: boolean;
125
+ isPlaying?: boolean;
126
+ onPress?: () => void;
127
+ onSecondaryPress?: () => void;
128
+ onRemovePress?: () => void;
129
+ onPlayPausePress?: () => void;
130
+ }
131
+
132
+ export const TrackItem: React.FC<TrackItemProps> = ({
133
+ variant,
134
+ title,
135
+ subtitle,
136
+ icon,
137
+ isSelected = false,
138
+ isPlaying = false,
139
+ onPress,
140
+ onSecondaryPress,
141
+ onRemovePress,
142
+ onPlayPausePress,
143
+ }) => {
144
+ const [isFocused, setIsFocused] = useState(false);
145
+
146
+ const isIconUri =
147
+ icon &&
148
+ (icon.startsWith("http") ||
149
+ icon.startsWith("file") ||
150
+ icon.includes("/") ||
151
+ icon.includes("."));
152
+
153
+ return (
154
+ <Pressable
155
+ style={({ pressed }) => [
156
+ styles.trackItem,
157
+ (pressed || isFocused) && styles.trackItemFocused,
158
+ ]}
159
+ onPress={onPress}
160
+ onPressIn={() => setIsFocused(true)}
161
+ onPressOut={() => setIsFocused(false)}
162
+ >
163
+ {icon ? (
164
+ isIconUri ? (
165
+ <Image source={{ uri: icon }} style={styles.trackImage} />
166
+ ) : (
167
+ <View style={styles.trackImagePlaceholder}>
168
+ <Text style={styles.trackImageText}>{icon}</Text>
169
+ </View>
170
+ )
171
+ ) : (
172
+ <View style={styles.trackImagePlaceholder} />
173
+ )}
174
+
175
+ <View style={styles.trackTextContainer}>
176
+ {variant === "nowPlaying" ? (
177
+ <Text style={styles.nowPlayingLabel}>♪ Now Playing</Text>
178
+ ) : null}
179
+ <Text numberOfLines={1} style={styles.trackTitle}>
180
+ {title}
181
+ </Text>
182
+ {subtitle ? (
183
+ <Text numberOfLines={1} style={styles.trackSubtitle}>
184
+ {subtitle}
185
+ </Text>
186
+ ) : null}
187
+ </View>
188
+
189
+ <View style={styles.trackActions}>
190
+ {variant === "nowPlaying" ? (
191
+ <Pressable
192
+ style={({ pressed }) => [
193
+ styles.playPauseButton,
194
+ pressed && styles.pressedState,
195
+ ]}
196
+ onPress={onPlayPausePress || onPress}
197
+ >
198
+ <Text style={styles.playPauseText}>{isPlaying ? "II" : "▶"}</Text>
199
+ </Pressable>
200
+ ) : null}
201
+
202
+ {variant === "queued" ? (
203
+ <View style={styles.queuedActionsContainer}>
204
+ {onRemovePress ? (
205
+ <Pressable
206
+ style={({ pressed }) => [
207
+ styles.trackActionButton,
208
+ pressed && styles.pressedState,
209
+ ]}
210
+ onPress={onRemovePress}
211
+ >
212
+ <Text style={styles.trackActionIcon}>⊖</Text>
213
+ </Pressable>
214
+ ) : null}
215
+ <Pressable
216
+ style={({ pressed }) => [
217
+ styles.trackActionButton,
218
+ pressed && styles.pressedState,
219
+ ]}
220
+ onPress={onSecondaryPress || onPress}
221
+ >
222
+ <Text style={styles.trackActionIcon}>≡</Text>
223
+ </Pressable>
224
+ </View>
225
+ ) : null}
226
+
227
+ {variant === "playlist" ? (
228
+ <View style={styles.radioContainer}>
229
+ {isSelected ? (
230
+ <View style={styles.radioSelected}>
231
+ <Text style={styles.radioCheck}>✓</Text>
232
+ </View>
233
+ ) : (
234
+ <View style={styles.radioUnselected} />
235
+ )}
236
+ </View>
237
+ ) : null}
238
+ </View>
239
+ </Pressable>
240
+ );
241
+ };
@@ -1,83 +1,34 @@
1
- import { useStore, createStore } from "zustand";
1
+ export {
2
+ modalStore,
3
+ useModalStore,
4
+ openModal,
5
+ dismissModal,
6
+ openBottomSheetModal,
7
+ useModalStoreState,
8
+ } from "./store";
2
9
 
3
- interface ModalState {
4
- visible: boolean;
5
- screen: any;
6
- options: Record<string, unknown>;
7
- props: Record<string, unknown>;
8
- }
10
+ export type { ModalState, ModalStore } from "./store";
9
11
 
10
- interface ModalStore {
11
- modalState: ModalState;
12
- setModalState: (newState: Partial<ModalState>) => void;
13
- openModal: (
14
- item: any,
15
- options?: Record<string, unknown>,
16
- props?: Record<string, unknown>
17
- ) => void;
18
- dismissModal: () => void;
19
- }
12
+ export { modalOrchestrator } from "./ModalOrchestrator";
20
13
 
21
- const initialModalState: ModalState = {
22
- visible: false,
23
- screen: null,
24
- options: {},
25
- props: {},
26
- };
14
+ export { ContentViewModel } from "./ContentViewModel";
27
15
 
28
- export const modalStore = createStore<ModalStore>((set) => ({
29
- modalState: initialModalState,
30
- setModalState: (newState) =>
31
- set((state) => ({
32
- modalState: { ...state.modalState, ...newState },
33
- })),
34
- openModal: ({ item, options = {}, props }: OpenModalArg) =>
35
- set({
36
- modalState: {
37
- visible: true,
38
- screen: item,
39
- options: {
40
- animated: true,
41
- animationType: "slide",
42
- onShow: () => {},
43
- presentationStyle: "overFullScreen",
44
- transparent: true,
45
- ...options,
46
- onDismiss: () => set({ modalState: initialModalState }),
47
- onRequestClose: () => set({ modalState: initialModalState }),
48
- },
49
- props,
50
- },
51
- }),
52
- dismissModal: () => set(() => ({ modalState: initialModalState })),
53
- }));
16
+ export { BottomSheetHeader } from "./components/BottomSheetHeader";
54
17
 
55
- export const useModalStore = <T>(selector: (state: ModalStore) => T) =>
56
- useStore(modalStore, selector);
18
+ export { ActionItem } from "./components/ActionItem";
57
19
 
58
- export const openModal = modalStore.getInitialState().openModal;
20
+ export { TrackItem } from "./components/TrackItem";
59
21
 
60
- export const dismissModal = modalStore.getInitialState().dismissModal;
22
+ export { PrimaryButton } from "./components/PrimaryButton";
61
23
 
62
- export const openBottomSheetModal = ({
63
- ModalBottomSheetContent,
64
- modalBottomSheetContentProps,
65
- props = {},
66
- options = {},
67
- }: OpenModalBottomSheetArgs) => {
68
- openModal({
69
- item: {
70
- ModalBottomSheetContent,
71
- modalBottomSheetContentProps,
72
- },
73
- props,
74
- options: {
75
- animationType: "none",
76
- animated: false,
77
- ...options,
78
- },
79
- });
80
- };
24
+ export type {
25
+ Menu,
26
+ MenuItem,
27
+ Header,
28
+ Content,
29
+ Action,
30
+ PresentSubMenuAction,
31
+ SecondaryAction,
32
+ } from "./types";
81
33
 
82
- export const useModalStoreState = (): ModalState =>
83
- useModalStore<ModalState>((state) => state.modalState);
34
+ export { isPresentSubMenuAction } from "./types";