@applicaster/zapp-react-native-utils 13.0.0-alpha.7330390362 → 13.0.0-alpha.7429912110
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/README.md +0 -10
- package/actionsExecutor/ActionExecutorContext.tsx +159 -12
- package/actionsExecutor/consts.ts +4 -0
- package/analyticsUtils/currentScreenProperities.ts +6 -4
- package/appUtils/HooksManager/Hook.ts +4 -0
- package/appUtils/HooksManager/index.ts +3 -1
- package/appUtils/__tests__/__snapshots__/localizationsHelper.test.ts.snap +151 -0
- package/appUtils/__tests__/allZappLocales.ts +79 -0
- package/appUtils/__tests__/{localizationsHelper.test.js → localizationsHelper.test.ts} +11 -0
- package/appUtils/accessibilityManager/const.ts +18 -0
- package/appUtils/contextKeysManager/contextResolver.ts +1 -12
- package/appUtils/contextKeysManager/index.ts +2 -2
- package/appUtils/contextKeysManager/utils/index.ts +2 -1
- package/appUtils/focusManager/__tests__/__snapshots__/focusManager.test.js.snap +2 -0
- package/appUtils/focusManager/index.ios.ts +14 -4
- package/appUtils/focusManager/index.ts +14 -10
- package/appUtils/focusManager/utils/__tests__/findChild.test.ts +35 -0
- package/appUtils/focusManager/utils/index.ts +5 -0
- package/appUtils/keyCodes/index.ts +11 -7
- package/appUtils/localizationsHelper.ts +31 -0
- package/appUtils/orientationHelper.ts +11 -13
- package/appUtils/playerManager/index.ts +1 -1
- package/appUtils/playerManager/player.ts +24 -12
- package/appUtils/playerManager/playerHooks/usePlayerCurrentTime.tsx +11 -7
- package/appUtils/playerManager/playerNative.ts +18 -3
- package/appUtils/playerManager/usePlayerTitleSummaryOverlay.tsx +7 -1
- package/cellUtils/index.ts +9 -5
- package/componentsUtils/__tests__/isFirstComponentGallery.test.ts +33 -0
- package/componentsUtils/__tests__/isFirstComponentScreenPicker.test.ts +33 -0
- package/componentsUtils/__tests__/isGallery.test.ts +33 -0
- package/componentsUtils/__tests__/isScreenPicker.test.ts +33 -0
- package/componentsUtils/index.ts +39 -0
- package/dateUtils/index.ts +19 -0
- package/equalUtils/__tests__/isEqual/combination.test.ts +263 -0
- package/equalUtils/index.ts +49 -30
- package/focusManager/FocusManager.ts +14 -2
- package/focusManager/index.ts +23 -4
- package/functionUtils/index.ts +46 -8
- package/index.d.ts +0 -12
- package/localizationUtils/index.ts +8 -13
- package/manifestUtils/defaultManifestConfigurations/generalContent.js +13 -0
- package/manifestUtils/defaultManifestConfigurations/player.js +9 -3
- package/manifestUtils/fonts/index.js +5 -6
- package/manifestUtils/index.js +2 -0
- package/manifestUtils/keys.js +27 -2
- package/manifestUtils/sharedConfiguration/screenPicker/__tests__/utils.test.js +304 -0
- package/manifestUtils/sharedConfiguration/screenPicker/stylesFields.js +875 -0
- package/manifestUtils/sharedConfiguration/screenPicker/utils.js +130 -0
- package/modalState/__tests__/index.test.ts +51 -0
- package/modalState/index.ts +32 -2
- package/navigationUtils/__tests__/__snapshots__/navigationUtils.test.js.snap +1 -0
- package/navigationUtils/index.ts +3 -1
- package/numberUtils/__tests__/toPositiveNumberWithDefault.test.ts +23 -3
- package/numberUtils/index.ts +4 -0
- package/package.json +4 -10
- package/playerUtils/configurationGenerator.ts +9 -11
- package/playerUtils/index.ts +23 -0
- package/reactHooks/advertising/index.ts +5 -5
- package/reactHooks/app/useAppState.ts +2 -2
- package/reactHooks/feed/useBatchLoading.ts +10 -12
- package/reactHooks/feed/useFeedLoader.tsx +17 -8
- package/reactHooks/hookModal/hooks/useHookModalScreenData.ts +39 -0
- package/reactHooks/navigation/__mocks__/useNavigation.ts +3 -0
- package/reactHooks/navigation/__tests__/index.test.tsx +6 -17
- package/reactHooks/navigation/{useGetTabBarHeight.ts → getTabBarHeight.ts} +1 -1
- package/reactHooks/navigation/index.ts +13 -23
- package/reactHooks/navigation/useGetBottomTabBarHeight.ts +10 -3
- package/reactHooks/navigation/useNavigationPluginData.ts +8 -4
- package/reactHooks/navigation/useNavigationType.ts +4 -2
- package/reactHooks/navigation/useProfilerLogging.ts +15 -0
- package/reactHooks/navigation/useRoute.ts +4 -6
- package/reactHooks/screen/__tests__/useScreenBackgroundColor.test.tsx +69 -0
- package/reactHooks/screen/useScreenBackgroundColor.ts +3 -15
- package/reactHooks/state/README.md +79 -0
- package/reactHooks/state/ZStoreProvider.tsx +71 -0
- package/reactHooks/state/__tests__/ZStoreProvider.test.tsx +66 -0
- package/reactHooks/state/index.ts +2 -0
- package/reactHooks/useListenEventBusEvent.ts +1 -1
- package/reactUtils/__tests__/__snapshots__/reactUtilsHelpers.test.js.snap +16 -4
- package/reactUtils/__tests__/reactUtils.test.js +1 -19
- package/reactUtils/__tests__/reactUtilsHelpers.test.js +72 -71
- package/reactUtils/createContext/__tests__/__snapshots__/helpers.test.js.snap +6 -72
- package/reactUtils/createContext/__tests__/__snapshots__/provider.test.js.snap +3 -28
- package/reactUtils/createContext/__tests__/__snapshots__/withConsumer.test.js.snap +3 -4
- package/reactUtils/createContext/__tests__/__snapshots__/withProvider.test.js.snap +7 -3
- package/reactUtils/createContext/__tests__/helpers.test.js +107 -121
- package/reactUtils/createContext/__tests__/{index.test.js → index.test.ts} +2 -2
- package/reactUtils/createContext/__tests__/provider.test.js +4 -6
- package/reactUtils/createContext/__tests__/withConsumer.test.js +12 -12
- package/reactUtils/createContext/__tests__/withProvider.test.js +4 -4
- package/reactUtils/createContext/helpers.ts +6 -1
- package/reactUtils/createContext/index.ts +11 -25
- package/reactUtils/index.ts +9 -11
- package/services/js2native.ts +673 -0
- package/testUtils/index.tsx +0 -10
- package/time/BackgroundTimer.ts +55 -0
- package/time/Timer.ts +6 -6
- package/typeGuards/index.ts +3 -0
- package/utils/README.md +30 -0
- package/utils/chunk.ts +5 -0
- package/utils/index.ts +5 -0
- package/utils/times.ts +5 -0
- package/zappFrameworkUtils/localStorageHelper.ts +38 -10
- package/zappFrameworkUtils/loginPluginUtils.ts +6 -2
- package/zappFrameworkUtils/types.ts +11 -0
- package/reactUtils/createContext/__tests__/index-no-react.test.js +0 -27
- /package/reactUtils/createContext/__tests__/__snapshots__/{index.test.js.snap → index.test.ts.snap} +0 -0
|
@@ -310,14 +310,14 @@ describe("navigation", () => {
|
|
|
310
310
|
expect(navBarVisible).toBe(false);
|
|
311
311
|
});
|
|
312
312
|
|
|
313
|
-
it("returns false if it's secondary nav bar and
|
|
313
|
+
it("returns false if it's secondary nav bar and show_secondary_level_menu is false", () => {
|
|
314
314
|
const navBarVisible = isNavBarVisible(
|
|
315
315
|
"",
|
|
316
316
|
{
|
|
317
317
|
navigations: [
|
|
318
318
|
{
|
|
319
319
|
styles: {
|
|
320
|
-
|
|
320
|
+
show_secondary_level_menu: false,
|
|
321
321
|
},
|
|
322
322
|
},
|
|
323
323
|
],
|
|
@@ -329,14 +329,14 @@ describe("navigation", () => {
|
|
|
329
329
|
expect(navBarVisible).toBe(false);
|
|
330
330
|
});
|
|
331
331
|
|
|
332
|
-
it("returns true if it's secondary nav bar and
|
|
332
|
+
it("returns true if it's secondary nav bar and show_secondary_level_menu is true", () => {
|
|
333
333
|
const navBarVisible = isNavBarVisible(
|
|
334
334
|
"",
|
|
335
335
|
{
|
|
336
336
|
navigations: [
|
|
337
337
|
{
|
|
338
338
|
styles: {
|
|
339
|
-
|
|
339
|
+
show_secondary_level_menu: true,
|
|
340
340
|
},
|
|
341
341
|
},
|
|
342
342
|
],
|
|
@@ -348,14 +348,14 @@ describe("navigation", () => {
|
|
|
348
348
|
expect(navBarVisible).toBe(true);
|
|
349
349
|
});
|
|
350
350
|
|
|
351
|
-
it("returns true if it's first level menu and
|
|
351
|
+
it("returns true if it's first level menu and show_secondary_level_menu is false", () => {
|
|
352
352
|
const navBarVisible = isNavBarVisible(
|
|
353
353
|
"",
|
|
354
354
|
{
|
|
355
355
|
navigations: [
|
|
356
356
|
{
|
|
357
357
|
styles: {
|
|
358
|
-
|
|
358
|
+
show_secondary_level_menu: false,
|
|
359
359
|
},
|
|
360
360
|
},
|
|
361
361
|
],
|
|
@@ -366,16 +366,5 @@ describe("navigation", () => {
|
|
|
366
366
|
|
|
367
367
|
expect(navBarVisible).toBe(true);
|
|
368
368
|
});
|
|
369
|
-
|
|
370
|
-
it("returns true otherwise", () => {
|
|
371
|
-
const navBarVisible = isNavBarVisible(
|
|
372
|
-
"",
|
|
373
|
-
{ navigations: [] } as any,
|
|
374
|
-
true,
|
|
375
|
-
true
|
|
376
|
-
);
|
|
377
|
-
|
|
378
|
-
expect(navBarVisible).toBe(true);
|
|
379
|
-
});
|
|
380
369
|
});
|
|
381
370
|
});
|
|
@@ -3,7 +3,7 @@ import { platformSelect } from "../../reactUtils";
|
|
|
3
3
|
const TAB_BAR_HEIGHT_IOS = 49;
|
|
4
4
|
const TAB_BAR_HEIGHT_ANDROID = 56;
|
|
5
5
|
|
|
6
|
-
export const
|
|
6
|
+
export const getTabBarHeight = () =>
|
|
7
7
|
platformSelect({
|
|
8
8
|
ios: TAB_BAR_HEIGHT_IOS,
|
|
9
9
|
android: TAB_BAR_HEIGHT_ANDROID,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { BackHandler
|
|
1
|
+
import { useContext, useEffect, useMemo, useRef } from "react";
|
|
2
|
+
import { BackHandler } from "react-native";
|
|
3
3
|
|
|
4
4
|
import {
|
|
5
5
|
useContentTypes,
|
|
@@ -31,6 +31,8 @@ export { useGetBottomTabBarHeight } from "./useGetBottomTabBarHeight";
|
|
|
31
31
|
|
|
32
32
|
export { useIsScreenActive } from "./useIsScreenActive";
|
|
33
33
|
|
|
34
|
+
export { useProfilerLogging } from "./useProfilerLogging";
|
|
35
|
+
|
|
34
36
|
export {
|
|
35
37
|
useUniqueRouteSuffix,
|
|
36
38
|
useNavbarId,
|
|
@@ -106,11 +108,13 @@ export function isNavBarVisible(
|
|
|
106
108
|
return false;
|
|
107
109
|
}
|
|
108
110
|
|
|
109
|
-
const
|
|
110
|
-
(
|
|
111
|
-
|
|
111
|
+
const showSecondaryLevel =
|
|
112
|
+
!isTV() ||
|
|
113
|
+
screenData?.navigations?.some(
|
|
114
|
+
(navigation) => navigation.styles?.show_secondary_level_menu
|
|
115
|
+
);
|
|
112
116
|
|
|
113
|
-
if (canGoBack &&
|
|
117
|
+
if (canGoBack && !showSecondaryLevel) {
|
|
114
118
|
return false;
|
|
115
119
|
}
|
|
116
120
|
|
|
@@ -121,10 +125,8 @@ export function isNavBarVisible(
|
|
|
121
125
|
return true;
|
|
122
126
|
}
|
|
123
127
|
|
|
124
|
-
const { ProfilerBridge } = NativeModules;
|
|
125
|
-
|
|
126
128
|
export const useBackHandler = (cb: () => boolean) => {
|
|
127
|
-
|
|
129
|
+
useEffect(() => {
|
|
128
130
|
BackHandler.addEventListener("hardwareBackPress", cb);
|
|
129
131
|
|
|
130
132
|
return () => {
|
|
@@ -158,7 +160,7 @@ export const useZappHooksForEntry = (
|
|
|
158
160
|
setIsHooksExecutionInProgress,
|
|
159
161
|
setIsPresentingFullScreen,
|
|
160
162
|
setIsRunningInBackground,
|
|
161
|
-
}: HookModalContextT =
|
|
163
|
+
}: HookModalContextT = useContext(ZappHookModalContext.ReactContext);
|
|
162
164
|
|
|
163
165
|
const {
|
|
164
166
|
appData: { layoutVersion },
|
|
@@ -256,22 +258,10 @@ export const useZappHooksForEntry = (
|
|
|
256
258
|
}, [entry.id]);
|
|
257
259
|
};
|
|
258
260
|
|
|
259
|
-
export const useProfilerLogging = () => {
|
|
260
|
-
const logTimestamp = (data: string) =>
|
|
261
|
-
InteractionManager.runAfterInteractions(() => {
|
|
262
|
-
if (ProfilerBridge && data) {
|
|
263
|
-
ProfilerBridge.updateTimer("navigation", data, Date.now());
|
|
264
|
-
}
|
|
265
|
-
});
|
|
266
|
-
|
|
267
|
-
return logTimestamp;
|
|
268
|
-
};
|
|
269
|
-
|
|
270
261
|
export const useRunIfLongPress = (
|
|
271
262
|
options = { timeout: LONG_KEY_PRESS_TIMEOUT }
|
|
272
263
|
) => {
|
|
273
|
-
const pressTimeout =
|
|
274
|
-
React.useRef<Nullable<ReturnType<typeof setTimeout>>>(null);
|
|
264
|
+
const pressTimeout = useRef<Nullable<ReturnType<typeof setTimeout>>>(null);
|
|
275
265
|
|
|
276
266
|
const resetTimeout = () => {
|
|
277
267
|
clearTimeout(pressTimeout.current as ReturnType<typeof setTimeout>);
|
|
@@ -1,12 +1,19 @@
|
|
|
1
1
|
import { useGetNavBarTopBorderWidth } from "./useGetNavBarTopBorderWidth";
|
|
2
|
-
import {
|
|
2
|
+
import { getTabBarHeight } from "./getTabBarHeight";
|
|
3
|
+
import { useNavigation } from "./useNavigation";
|
|
3
4
|
import { MenuTypes, useNavigationType } from "./useNavigationType";
|
|
5
|
+
import { useNavigationPluginData } from "./useNavigationPluginData";
|
|
4
6
|
|
|
5
7
|
export const useGetBottomTabBarHeight = (): number => {
|
|
8
|
+
const { activeRiver } = useNavigation();
|
|
9
|
+
|
|
10
|
+
const navigationPluginData = useNavigationPluginData(activeRiver);
|
|
11
|
+
const navigationType = useNavigationType(navigationPluginData);
|
|
12
|
+
|
|
6
13
|
const topBorderWidth = useGetNavBarTopBorderWidth();
|
|
7
|
-
const tabBarHeight =
|
|
14
|
+
const tabBarHeight = getTabBarHeight();
|
|
8
15
|
|
|
9
|
-
const isBottomBarNavigation =
|
|
16
|
+
const isBottomBarNavigation = navigationType === MenuTypes.bottomTabBar;
|
|
10
17
|
|
|
11
18
|
return !isBottomBarNavigation ? 0 : tabBarHeight + topBorderWidth;
|
|
12
19
|
};
|
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
import { useRoute } from "./useRoute";
|
|
2
2
|
|
|
3
|
-
export const useNavigationPluginData = (
|
|
3
|
+
export const useNavigationPluginData = (
|
|
4
|
+
screenData?: LegacyNavigationScreenData | null
|
|
5
|
+
): ZappNavigation | undefined => {
|
|
4
6
|
const {
|
|
5
7
|
screenData: useRouteScreenData,
|
|
6
8
|
}: { screenData: QuickBrickNavigationData | null } = useRoute();
|
|
7
9
|
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
|
|
10
|
+
const activeScreenData = screenData ?? useRouteScreenData;
|
|
11
|
+
|
|
12
|
+
const navigations = activeScreenData?.targetScreen
|
|
13
|
+
? (activeScreenData.targetScreen as ZappRiver).navigations
|
|
14
|
+
: (activeScreenData as ZappRiver).navigations;
|
|
11
15
|
|
|
12
16
|
const navigationMenu = navigations?.find((nav) => nav.category === "menu");
|
|
13
17
|
|
|
@@ -5,8 +5,10 @@ export enum MenuTypes {
|
|
|
5
5
|
bottomTabBar = "BOTTOM_TAB_BAR",
|
|
6
6
|
}
|
|
7
7
|
|
|
8
|
-
export const useNavigationType = (): MenuTypes => {
|
|
9
|
-
const
|
|
8
|
+
export const useNavigationType = (navigation?: ZappNavigation): MenuTypes => {
|
|
9
|
+
const navigationPluginData = useNavigationPluginData();
|
|
10
|
+
|
|
11
|
+
const navigationMenu = navigation ?? navigationPluginData;
|
|
10
12
|
|
|
11
13
|
return !navigationMenu ||
|
|
12
14
|
navigationMenu.navigation_type === "quick_brick_side_menu"
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { useCallback } from "react";
|
|
2
|
+
import { InteractionManager, NativeModules } from "react-native";
|
|
3
|
+
|
|
4
|
+
const { ProfilerBridge } = NativeModules;
|
|
5
|
+
|
|
6
|
+
export const useProfilerLogging = () =>
|
|
7
|
+
useCallback(
|
|
8
|
+
(data: string) =>
|
|
9
|
+
InteractionManager.runAfterInteractions(() => {
|
|
10
|
+
if (ProfilerBridge && data) {
|
|
11
|
+
ProfilerBridge.updateTimer("navigation", data, Date.now());
|
|
12
|
+
}
|
|
13
|
+
}),
|
|
14
|
+
[]
|
|
15
|
+
);
|
|
@@ -7,12 +7,11 @@ import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
|
|
|
7
7
|
|
|
8
8
|
import { legacyScreenData } from "@applicaster/quick-brick-core/App/NavigationProvider/utils";
|
|
9
9
|
|
|
10
|
-
import { useZappHooksModalState } from "@applicaster/zapp-react-dom-ui-components/Components/ZappHooksModal/hooks/useZappHooksModalState";
|
|
11
|
-
|
|
12
10
|
import { getTargetScreenData } from "../screen/useTargetScreenData";
|
|
11
|
+
import { useHookModalScreenData } from "../hookModal/hooks/useHookModalScreenData";
|
|
13
12
|
|
|
14
13
|
import { useNavigation } from "./useNavigation";
|
|
15
|
-
import {
|
|
14
|
+
import { useModalStoreState } from "../../modalState";
|
|
16
15
|
import { ScreenDataContext } from "@applicaster/zapp-react-native-ui-components/Contexts/ScreenDataContext";
|
|
17
16
|
import { usePathname } from "./usePathname";
|
|
18
17
|
|
|
@@ -44,12 +43,11 @@ export const useRoute = (): {
|
|
|
44
43
|
"contentTypes",
|
|
45
44
|
]);
|
|
46
45
|
|
|
47
|
-
const
|
|
48
|
-
const hookModalState = useZappHooksModalState();
|
|
46
|
+
const modalState = useModalStoreState();
|
|
49
47
|
|
|
50
48
|
const modalScreenData = modalState.screen;
|
|
51
49
|
|
|
52
|
-
const hookModalScreenData =
|
|
50
|
+
const hookModalScreenData = useHookModalScreenData();
|
|
53
51
|
|
|
54
52
|
const videoModalScreenData =
|
|
55
53
|
navigator?.videoModalState?.item &&
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { renderHook } from "@testing-library/react-hooks";
|
|
2
|
+
|
|
3
|
+
jest.mock(
|
|
4
|
+
"@applicaster/zapp-react-native-ui-components/Components/River/useScreenConfiguration",
|
|
5
|
+
() => ({
|
|
6
|
+
useScreenConfiguration: jest.fn(),
|
|
7
|
+
})
|
|
8
|
+
);
|
|
9
|
+
|
|
10
|
+
const {
|
|
11
|
+
useScreenConfiguration,
|
|
12
|
+
} = require("@applicaster/zapp-react-native-ui-components/Components/River/useScreenConfiguration");
|
|
13
|
+
|
|
14
|
+
const { useScreenBackgroundColor } = require("../useScreenBackgroundColor");
|
|
15
|
+
|
|
16
|
+
describe("useScreenBackgroundColor", () => {
|
|
17
|
+
afterEach(() => {
|
|
18
|
+
jest.clearAllMocks();
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it("should return the background color from screen configuration", () => {
|
|
22
|
+
useScreenConfiguration.mockReturnValue({
|
|
23
|
+
backgroundColor: "#FF0000",
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
// Render the hook with a screen ID
|
|
27
|
+
const { result } = renderHook(() =>
|
|
28
|
+
useScreenBackgroundColor("test-screen-id")
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
expect(result.current).toBe("#FF0000");
|
|
32
|
+
|
|
33
|
+
expect(useScreenConfiguration).toHaveBeenCalledWith("test-screen-id");
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it("should return 'transparent' when background color is empty", () => {
|
|
37
|
+
useScreenConfiguration.mockReturnValue({
|
|
38
|
+
backgroundColor: "",
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
const { result } = renderHook(() =>
|
|
42
|
+
useScreenBackgroundColor("test-screen-id")
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
expect(result.current).toBe("transparent");
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it("should return 'transparent' when background color is null", () => {
|
|
49
|
+
useScreenConfiguration.mockReturnValue({
|
|
50
|
+
backgroundColor: null,
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
const { result } = renderHook(() =>
|
|
54
|
+
useScreenBackgroundColor("test-screen-id")
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
expect(result.current).toBe("transparent");
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it("should return 'transparent' when background color is undefined", () => {
|
|
61
|
+
useScreenConfiguration.mockReturnValue({});
|
|
62
|
+
|
|
63
|
+
const { result } = renderHook(() =>
|
|
64
|
+
useScreenBackgroundColor("test-screen-id")
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
expect(result.current).toBe("transparent");
|
|
68
|
+
});
|
|
69
|
+
});
|
|
@@ -1,23 +1,11 @@
|
|
|
1
|
-
import * as React from "react";
|
|
2
|
-
import { useTheme } from "@applicaster/zapp-react-native-utils/theme";
|
|
3
1
|
import { useScreenConfiguration } from "@applicaster/zapp-react-native-ui-components/Components/River/useScreenConfiguration";
|
|
4
2
|
import { ifEmptyUseFallback } from "@applicaster/zapp-react-native-utils/cellUtils";
|
|
5
3
|
|
|
4
|
+
const DEFAULT_BACKGROUND_FALLBACK = "transparent";
|
|
5
|
+
|
|
6
6
|
export const useScreenBackgroundColor = (screenId: string): string => {
|
|
7
7
|
const { backgroundColor: screenBackgroundColor } =
|
|
8
8
|
useScreenConfiguration(screenId);
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
const themeBackgroundColor = React.useMemo(
|
|
13
|
-
() => theme.app_background_color,
|
|
14
|
-
[theme.app_background_color]
|
|
15
|
-
);
|
|
16
|
-
|
|
17
|
-
const backgroundColor = ifEmptyUseFallback(
|
|
18
|
-
screenBackgroundColor,
|
|
19
|
-
themeBackgroundColor
|
|
20
|
-
);
|
|
21
|
-
|
|
22
|
-
return backgroundColor;
|
|
10
|
+
return ifEmptyUseFallback(screenBackgroundColor, DEFAULT_BACKGROUND_FALLBACK);
|
|
23
11
|
};
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# ZStoreProvider and useZStore
|
|
2
|
+
|
|
3
|
+
This module provides a React context-based solution for managing Zustand stores with named access.
|
|
4
|
+
|
|
5
|
+
## Usage
|
|
6
|
+
|
|
7
|
+
### ZStoreProvider
|
|
8
|
+
|
|
9
|
+
The `ZStoreProvider` component creates a Zustand store from the provided value and makes it available to child components.
|
|
10
|
+
|
|
11
|
+
```tsx
|
|
12
|
+
import { ZStoreProvider } from "@applicaster/zapp-react-native-utils/reactHooks/state";
|
|
13
|
+
|
|
14
|
+
// In your component
|
|
15
|
+
<ZStoreProvider name="playerConfiguration" value={controller?.config}>
|
|
16
|
+
<YourComponent />
|
|
17
|
+
</ZStoreProvider>
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
### useZStore
|
|
21
|
+
|
|
22
|
+
The `useZStore` hook allows you to access a Zustand store by name from within a `ZStoreProvider`.
|
|
23
|
+
|
|
24
|
+
```tsx
|
|
25
|
+
import { useZStore } from "@applicaster/zapp-react-native-utils/reactHooks/state";
|
|
26
|
+
import { useStore } from "zustand";
|
|
27
|
+
|
|
28
|
+
// In your component
|
|
29
|
+
const MyComponent = () => {
|
|
30
|
+
const store = useZStore("playerConfiguration");
|
|
31
|
+
const config = useStore(store, (state) => state.someProperty);
|
|
32
|
+
|
|
33
|
+
return <Text>{config}</Text>;
|
|
34
|
+
};
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Example
|
|
38
|
+
|
|
39
|
+
```tsx
|
|
40
|
+
import React from "react";
|
|
41
|
+
import { ZStoreProvider, useZStore } from "@applicaster/zapp-react-native-utils/reactHooks/state";
|
|
42
|
+
import { useStore } from "zustand";
|
|
43
|
+
|
|
44
|
+
// Component that uses the store
|
|
45
|
+
const PlayerConfigDisplay = () => {
|
|
46
|
+
const store = useZStore("playerConfiguration");
|
|
47
|
+
const config = useStore(store, (state) => state);
|
|
48
|
+
|
|
49
|
+
return (
|
|
50
|
+
<View>
|
|
51
|
+
<Text>Player Config: {JSON.stringify(config)}</Text>
|
|
52
|
+
</View>
|
|
53
|
+
);
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
// Main component that provides the store
|
|
57
|
+
const PlayerComponent = ({ controller }) => {
|
|
58
|
+
return (
|
|
59
|
+
<ZStoreProvider name="playerConfiguration" value={controller?.config}>
|
|
60
|
+
<PlayerConfigDisplay />
|
|
61
|
+
</ZStoreProvider>
|
|
62
|
+
);
|
|
63
|
+
};
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Features
|
|
67
|
+
|
|
68
|
+
- **Named Stores**: Access stores by name instead of importing them directly
|
|
69
|
+
- **Context-based**: Uses React Context for store management
|
|
70
|
+
- **Zustand Integration**: Seamlessly works with existing Zustand stores
|
|
71
|
+
- **Type Safety**: Full TypeScript support
|
|
72
|
+
- **Error Handling**: Clear error messages when stores are not found or used outside providers
|
|
73
|
+
|
|
74
|
+
## Error Handling
|
|
75
|
+
|
|
76
|
+
The `useZStore` hook will throw errors in the following cases:
|
|
77
|
+
|
|
78
|
+
1. **Used outside provider**: "useZStore must be used within a ZStoreProvider"
|
|
79
|
+
2. **Store not found**: "Store with name 'storeName' not found. Make sure it's provided by a ZStoreProvider"
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import React, { createContext, useContext, ReactNode, useMemo } from "react";
|
|
2
|
+
import { create, UseBoundStore } from "zustand";
|
|
3
|
+
|
|
4
|
+
interface ZStoreContextType {
|
|
5
|
+
stores: Map<string, UseBoundStore<any>>;
|
|
6
|
+
registerStore: (name: string, store: UseBoundStore<any>) => void;
|
|
7
|
+
getStore: (name: string) => UseBoundStore<any> | undefined;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const ZStoreContext = createContext<ZStoreContextType | null>(null);
|
|
11
|
+
|
|
12
|
+
interface ZStoreProviderProps {
|
|
13
|
+
children: ReactNode;
|
|
14
|
+
name: string;
|
|
15
|
+
value: any;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export const ZStoreProvider: React.FC<ZStoreProviderProps> = ({
|
|
19
|
+
children,
|
|
20
|
+
name,
|
|
21
|
+
value,
|
|
22
|
+
}) => {
|
|
23
|
+
const parentContext = useContext(ZStoreContext);
|
|
24
|
+
|
|
25
|
+
const context = useMemo(() => {
|
|
26
|
+
if (parentContext) {
|
|
27
|
+
// If parent context exists, create a new store and register it
|
|
28
|
+
const store = create(() => value);
|
|
29
|
+
parentContext.registerStore(name, store);
|
|
30
|
+
|
|
31
|
+
return parentContext;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Create a new context if none exists
|
|
35
|
+
const stores = new Map<string, UseBoundStore<any>>();
|
|
36
|
+
|
|
37
|
+
// Create a store from the provided value
|
|
38
|
+
const store = create(() => value);
|
|
39
|
+
stores.set(name, store);
|
|
40
|
+
|
|
41
|
+
return {
|
|
42
|
+
stores,
|
|
43
|
+
registerStore: (storeName: string, storeInstance: UseBoundStore<any>) => {
|
|
44
|
+
stores.set(storeName, storeInstance);
|
|
45
|
+
},
|
|
46
|
+
getStore: (storeName: string) => stores.get(storeName),
|
|
47
|
+
};
|
|
48
|
+
}, [parentContext, name, value]);
|
|
49
|
+
|
|
50
|
+
return (
|
|
51
|
+
<ZStoreContext.Provider value={context}>{children}</ZStoreContext.Provider>
|
|
52
|
+
);
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
export const useZStore = (name: string): UseBoundStore<any> => {
|
|
56
|
+
const context = useContext(ZStoreContext);
|
|
57
|
+
|
|
58
|
+
if (!context) {
|
|
59
|
+
throw new Error("useZStore must be used within a ZStoreProvider");
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const store = context.getStore(name);
|
|
63
|
+
|
|
64
|
+
if (!store) {
|
|
65
|
+
throw new Error(
|
|
66
|
+
`Store with name "${name}" not found. Make sure it's provided by a ZStoreProvider.`
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return store;
|
|
71
|
+
};
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { render, screen } from "@testing-library/react-native";
|
|
3
|
+
import { Text } from "react-native";
|
|
4
|
+
import { ZStoreProvider, useZStore } from "../ZStoreProvider";
|
|
5
|
+
import { useStore } from "zustand";
|
|
6
|
+
|
|
7
|
+
interface TestState {
|
|
8
|
+
value: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
// Test component that uses the store
|
|
12
|
+
const TestComponent = ({ storeName }: { storeName: string }) => {
|
|
13
|
+
const store = useZStore(storeName);
|
|
14
|
+
const value = useStore(store, (state: any) => (state as TestState).value);
|
|
15
|
+
|
|
16
|
+
return <Text testID="test-value">{value}</Text>;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
// Test component that provides a store
|
|
20
|
+
const TestProvider = ({ children }: { children: React.ReactNode }) => {
|
|
21
|
+
return (
|
|
22
|
+
<ZStoreProvider name="testStore" value={{ value: "test-value" }}>
|
|
23
|
+
{children}
|
|
24
|
+
</ZStoreProvider>
|
|
25
|
+
);
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
describe("ZStoreProvider and useZStore", () => {
|
|
29
|
+
it("should provide a store and allow access via useZStore", () => {
|
|
30
|
+
render(
|
|
31
|
+
<TestProvider>
|
|
32
|
+
<TestComponent storeName="testStore" />
|
|
33
|
+
</TestProvider>
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
expect(screen.getByTestId("test-value").props.children).toBe("test-value");
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it("should throw error when useZStore is used outside provider", () => {
|
|
40
|
+
// Suppress console.error for this test
|
|
41
|
+
const originalError = console.error;
|
|
42
|
+
console.error = jest.fn();
|
|
43
|
+
|
|
44
|
+
expect(() => {
|
|
45
|
+
render(<TestComponent storeName="testStore" />);
|
|
46
|
+
}).toThrow("useZStore must be used within a ZStoreProvider");
|
|
47
|
+
|
|
48
|
+
console.error = originalError;
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it("should throw error when store name is not found", () => {
|
|
52
|
+
// Suppress console.error for this test
|
|
53
|
+
const originalError = console.error;
|
|
54
|
+
console.error = jest.fn();
|
|
55
|
+
|
|
56
|
+
expect(() => {
|
|
57
|
+
render(
|
|
58
|
+
<TestProvider>
|
|
59
|
+
<TestComponent storeName="nonExistentStore" />
|
|
60
|
+
</TestProvider>
|
|
61
|
+
);
|
|
62
|
+
}).toThrow('Store with name "nonExistentStore" not found');
|
|
63
|
+
|
|
64
|
+
console.error = originalError;
|
|
65
|
+
});
|
|
66
|
+
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
2
2
|
|
|
3
|
-
exports[`addLifeCycleMethods attaches the lifecycle method to the component 1`] = `
|
|
3
|
+
exports[`reactUtils helpers addLifeCycleMethods attaches the lifecycle method to the component 1`] = `
|
|
4
4
|
<View>
|
|
5
5
|
<Text>
|
|
6
6
|
I'm a class component
|
|
@@ -8,7 +8,7 @@ exports[`addLifeCycleMethods attaches the lifecycle method to the component 1`]
|
|
|
8
8
|
</View>
|
|
9
9
|
`;
|
|
10
10
|
|
|
11
|
-
exports[`attachMethodToPrototype attaches a lifecycle method to the component's prototype 1`] = `
|
|
11
|
+
exports[`reactUtils helpers attachMethodToPrototype attaches a lifecycle method to the component's prototype 1`] = `
|
|
12
12
|
<View>
|
|
13
13
|
<Text>
|
|
14
14
|
I'm a class component
|
|
@@ -16,6 +16,18 @@ exports[`attachMethodToPrototype attaches a lifecycle method to the component's
|
|
|
16
16
|
</View>
|
|
17
17
|
`;
|
|
18
18
|
|
|
19
|
-
exports[`attachMethodToPrototype preserves any existing lifecycle method 1`] =
|
|
19
|
+
exports[`reactUtils helpers attachMethodToPrototype preserves any existing lifecycle method 1`] = `
|
|
20
|
+
<View>
|
|
21
|
+
<Text>
|
|
22
|
+
I'm a stateless component
|
|
23
|
+
</Text>
|
|
24
|
+
</View>
|
|
25
|
+
`;
|
|
20
26
|
|
|
21
|
-
exports[`wrapInClass wraps the stateless component in a class 1`] =
|
|
27
|
+
exports[`reactUtils helpers wrapInClass wraps the stateless component in a class 1`] = `
|
|
28
|
+
<View>
|
|
29
|
+
<Text>
|
|
30
|
+
I'm a stateless component
|
|
31
|
+
</Text>
|
|
32
|
+
</View>
|
|
33
|
+
`;
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
componentDidMount,
|
|
8
8
|
} from "./fixtures";
|
|
9
9
|
|
|
10
|
-
import { attachLifeCycleMethods,
|
|
10
|
+
import { attachLifeCycleMethods, mergeChildrenProps } from "..";
|
|
11
11
|
|
|
12
12
|
describe("attachLifeCycleMethods", () => {
|
|
13
13
|
let addLifeCycleMethodsSpy;
|
|
@@ -41,24 +41,6 @@ describe("attachLifeCycleMethods", () => {
|
|
|
41
41
|
});
|
|
42
42
|
});
|
|
43
43
|
|
|
44
|
-
describe("createReactRef", () => {
|
|
45
|
-
it("calls the React.createRef function if it exists", () => {
|
|
46
|
-
jest.clearAllMocks();
|
|
47
|
-
|
|
48
|
-
const ref = createReactRef();
|
|
49
|
-
expect(ref).toHaveProperty("current");
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
it("calls the polyfill if React.createRef doesn't exist", () => {
|
|
53
|
-
jest.clearAllMocks();
|
|
54
|
-
const originalCreateRef = React.createRef;
|
|
55
|
-
React.createRef = undefined;
|
|
56
|
-
const ref = createReactRef();
|
|
57
|
-
expect(ref).toHaveProperty("current");
|
|
58
|
-
React.createRef = originalCreateRef;
|
|
59
|
-
});
|
|
60
|
-
});
|
|
61
|
-
|
|
62
44
|
describe("mergeChildrenProps", () => {
|
|
63
45
|
it("returns the cloned children with the merged props", () => {
|
|
64
46
|
const Egg = () => React.createElement("Egg");
|