@applicaster/zapp-react-native-utils 15.0.0-alpha.1327232155 → 15.0.0-alpha.1346954013

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 (58) hide show
  1. package/actionsExecutor/ActionExecutorContext.tsx +3 -6
  2. package/actionsExecutor/feedDecorator.ts +6 -6
  3. package/adsUtils/index.ts +2 -2
  4. package/analyticsUtils/README.md +1 -1
  5. package/appUtils/HooksManager/index.ts +10 -10
  6. package/appUtils/accessibilityManager/__tests__/utils.test.ts +360 -0
  7. package/appUtils/accessibilityManager/const.ts +4 -0
  8. package/appUtils/accessibilityManager/hooks.ts +20 -13
  9. package/appUtils/accessibilityManager/index.ts +28 -1
  10. package/appUtils/accessibilityManager/utils.ts +59 -8
  11. package/appUtils/focusManager/index.ios.ts +8 -2
  12. package/appUtils/focusManagerAux/utils/index.ts +1 -1
  13. package/appUtils/focusManagerAux/utils/utils.ios.ts +145 -3
  14. package/appUtils/keyCodes/keys/keys.web.ts +1 -4
  15. package/appUtils/orientationHelper.ts +2 -4
  16. package/appUtils/platform/platformUtils.ts +115 -16
  17. package/appUtils/playerManager/OverlayObserver/OverlaysObserver.ts +94 -4
  18. package/appUtils/playerManager/OverlayObserver/utils.ts +32 -20
  19. package/appUtils/playerManager/player.ts +4 -0
  20. package/appUtils/playerManager/playerNative.ts +29 -16
  21. package/appUtils/playerManager/usePlayerState.tsx +14 -2
  22. package/cellUtils/index.ts +32 -0
  23. package/configurationUtils/__tests__/manifestKeyParser.test.ts +26 -26
  24. package/focusManager/aux/index.ts +1 -1
  25. package/manifestUtils/defaultManifestConfigurations/player.js +91 -1
  26. package/manifestUtils/keys.js +21 -0
  27. package/manifestUtils/sharedConfiguration/screenPicker/utils.js +1 -0
  28. package/manifestUtils/tvAction/container/index.js +1 -1
  29. package/package.json +2 -2
  30. package/playerUtils/usePlayerTTS.ts +8 -3
  31. package/pluginUtils/index.ts +4 -0
  32. package/reactHooks/advertising/index.ts +2 -2
  33. package/reactHooks/debugging/__tests__/index.test.js +4 -4
  34. package/reactHooks/device/useMemoizedIsTablet.ts +3 -3
  35. package/reactHooks/feed/__tests__/useEntryScreenId.test.tsx +3 -0
  36. package/reactHooks/feed/__tests__/{useInflatedUrl.test.ts → useInflatedUrl.test.tsx} +62 -7
  37. package/reactHooks/feed/useEntryScreenId.ts +2 -2
  38. package/reactHooks/feed/useInflatedUrl.ts +43 -17
  39. package/reactHooks/flatList/useLoadNextPageIfNeeded.ts +13 -16
  40. package/reactHooks/layout/useDimensions/__tests__/{useDimensions.test.ts → useDimensions.test.tsx} +105 -25
  41. package/reactHooks/layout/useDimensions/useDimensions.ts +2 -2
  42. package/reactHooks/navigation/index.ts +11 -6
  43. package/reactHooks/navigation/useRoute.ts +8 -6
  44. package/reactHooks/player/TVSeekControlller/TVSeekController.ts +27 -10
  45. package/reactHooks/resolvers/useCellResolver.ts +6 -2
  46. package/reactHooks/resolvers/useComponentResolver.ts +8 -2
  47. package/reactHooks/screen/__tests__/useTargetScreenData.test.tsx +10 -2
  48. package/reactHooks/screen/useTargetScreenData.ts +4 -2
  49. package/reactHooks/state/useRivers.ts +1 -1
  50. package/reactHooks/usePluginConfiguration.ts +2 -2
  51. package/testUtils/index.tsx +29 -20
  52. package/utils/__tests__/selectors.test.ts +124 -0
  53. package/utils/index.ts +10 -0
  54. package/utils/path.ts +6 -3
  55. package/utils/pathOr.ts +5 -1
  56. package/utils/selectors.ts +46 -0
  57. package/zappFrameworkUtils/HookCallback/callbackNavigationAction.ts +34 -11
  58. package/zappFrameworkUtils/HookCallback/hookCallbackManifestExtensions.config.js +1 -1
@@ -3,6 +3,7 @@ const defaultPlatforms = {
3
3
  android_tv: "Android TV",
4
4
  lg_tv: "LG TV",
5
5
  samsung_tv: "Samsung TV",
6
+ roku: "Roku TV",
6
7
  };
7
8
 
8
9
  const global_defaults = {
@@ -38,7 +38,7 @@ function tvActionButtonsContainer({ label, description, defaults }) {
38
38
  generateFieldsFromDefaultsWithoutPrefixedLabel(
39
39
  label,
40
40
  defaults,
41
- tvActionButtonContainerFields(defaults["position"])
41
+ tvActionButtonContainerFields(defaults.position)
42
42
  )
43
43
  );
44
44
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@applicaster/zapp-react-native-utils",
3
- "version": "15.0.0-alpha.1327232155",
3
+ "version": "15.0.0-alpha.1346954013",
4
4
  "description": "Applicaster Zapp React Native utilities package",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -27,7 +27,7 @@
27
27
  },
28
28
  "homepage": "https://github.com/applicaster/quickbrick#readme",
29
29
  "dependencies": {
30
- "@applicaster/applicaster-types": "15.0.0-alpha.1327232155",
30
+ "@applicaster/applicaster-types": "15.0.0-alpha.1346954013",
31
31
  "buffer": "^5.2.1",
32
32
  "camelize": "^1.0.0",
33
33
  "dayjs": "^1.11.10",
@@ -1,14 +1,19 @@
1
1
  import * as React from "react";
2
2
  import { usePlayer } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/usePlayer";
3
- import { useAccessibilityManager } from "@applicaster/zapp-react-native-utils/appUtils/accessibilityManager/hooks";
3
+ import {
4
+ useAccessibilityManager,
5
+ useAccessibilityState,
6
+ } from "@applicaster/zapp-react-native-utils/appUtils/accessibilityManager/hooks";
4
7
  import { PlayerTTS } from "@applicaster/zapp-react-native-utils/playerUtils/PlayerTTS";
5
8
 
6
9
  export const usePlayerTTS = () => {
7
10
  const player = usePlayer();
8
11
  const accessibilityManager = useAccessibilityManager({});
12
+ const accessibilityState = useAccessibilityState();
13
+ const isScreenReaderEnabled = accessibilityState.screenReaderEnabled;
9
14
 
10
15
  React.useEffect(() => {
11
- if (player && accessibilityManager) {
16
+ if (player && accessibilityManager && isScreenReaderEnabled) {
12
17
  const playerTTS = new PlayerTTS(player, accessibilityManager);
13
18
  const unsubscribe = playerTTS.init();
14
19
 
@@ -17,5 +22,5 @@ export const usePlayerTTS = () => {
17
22
  playerTTS.destroy();
18
23
  };
19
24
  }
20
- }, [player, accessibilityManager]);
25
+ }, [player, accessibilityManager, isScreenReaderEnabled]);
21
26
  };
@@ -6,6 +6,7 @@ import { deprecationMessage } from "../appUtils";
6
6
 
7
7
  import { pluginUtilsLogger } from "./logger";
8
8
  import { platformSelect } from "../reactUtils";
9
+ import { get } from "../utils";
9
10
 
10
11
  type PluginModule = any;
11
12
  type Plugin = {
@@ -254,3 +255,6 @@ const getPluginType = R.pathOr("unknown_plugin_type", [
254
255
 
255
256
  export const isPlayerPlugin = (routeState): boolean =>
256
257
  getPluginType(routeState) === "player";
258
+
259
+ export const getPluginModuleUrlScheme = (plugin) =>
260
+ get(plugin, ["module", "urlScheme"]);
@@ -3,7 +3,7 @@ import { View } from "react-native";
3
3
  import * as R from "ramda";
4
4
 
5
5
  import { useNavigation } from "../navigation";
6
- import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
6
+ import { usePlugins } from "@applicaster/zapp-react-native-redux/hooks";
7
7
  import { platformSelect } from "@applicaster/zapp-react-native-utils/reactUtils";
8
8
  import { dismissModal, openModal } from "../../modalState";
9
9
 
@@ -16,7 +16,7 @@ const ModalContainer = platformSelect({
16
16
 
17
17
  export function useAdvertisingInterstitial() {
18
18
  const { screenData, currentRoute } = useNavigation();
19
- const { plugins } = usePickFromState();
19
+ const plugins = usePlugins();
20
20
 
21
21
  return useEffect(() => {
22
22
  // TODD: typing problem: fix any type
@@ -27,20 +27,20 @@ describe("Debug utils", () => {
27
27
  it("should create new timer if timer with a label does not exist", () => {
28
28
  performanceNowMock.mockReturnValue(1000);
29
29
  time("timer1");
30
- expect(timers["timer1"]).toBeDefined();
31
- expect(timers["timer1"].startTime).toBe(1000);
30
+ expect(timers.timer1).toBeDefined();
31
+ expect(timers.timer1.startTime).toBe(1000);
32
32
  });
33
33
 
34
34
  it("should update start time of timer if timer with a label exists", () => {
35
35
  // First call to time()
36
36
  performanceNowMock.mockReturnValue(1000);
37
37
  time("timer1");
38
- const previousStartTime = timers["timer1"].startTime;
38
+ const previousStartTime = timers.timer1.startTime;
39
39
 
40
40
  // Second call to time()
41
41
  performanceNowMock.mockReturnValue(2000);
42
42
  time("timer1");
43
- const currentStartTime = timers["timer1"].startTime;
43
+ const currentStartTime = timers.timer1.startTime;
44
44
 
45
45
  expect(previousStartTime).toBe(1000);
46
46
  expect(currentStartTime).toBe(2000);
@@ -1,6 +1,6 @@
1
1
  import * as React from "react";
2
- import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
3
2
  import { useIsTablet } from "./useIsTablet";
3
+ import { useAppData } from "@applicaster/zapp-react-native-redux";
4
4
 
5
5
  export const useMemoizedIsTablet = () => {
6
6
  const isTablet = useIsTablet();
@@ -14,9 +14,9 @@ export const useMemoizedIsTablet = () => {
14
14
  };
15
15
 
16
16
  export const useIsTabletLandscape = (): boolean => {
17
- const { appData } = usePickFromState(["appData"]);
17
+ const { isTabletPortrait } = useAppData();
18
18
 
19
19
  const isTablet = useIsTablet();
20
20
 
21
- return isTablet && !appData.isTabletPortrait;
21
+ return isTablet && !isTabletPortrait;
22
22
  };
@@ -10,6 +10,9 @@ describe("useEntryScreenId", () => {
10
10
  const mappedScreenId = "mapped-id";
11
11
 
12
12
  const initialState = {
13
+ rivers: {
14
+ [mappedScreenId]: { id: mappedScreenId, type: "any" },
15
+ },
13
16
  contentTypes: { mappedEntry: { screen_id: mappedScreenId } },
14
17
  };
15
18
 
@@ -1,3 +1,34 @@
1
+ import React from "react";
2
+
3
+ import { WrappedWithProviders } from "@applicaster/zapp-react-native-utils/testUtils";
4
+
5
+ import {
6
+ getInflatedDataSourceUrl,
7
+ getSearchContext,
8
+ useGetUrlInflater,
9
+ } from "../useInflatedUrl";
10
+
11
+ import { reactHooksLogger } from "../../logger";
12
+
13
+ jest.mock("../../navigation", () => ({
14
+ useRoute: () => ({ pathname: "/mock/path" }),
15
+ }));
16
+
17
+ // mock contexts hooks
18
+ jest.mock("@applicaster/zapp-react-native-ui-components/Contexts", () => ({
19
+ ZappPipesEntryContext: {
20
+ useZappPipesContext: () => [
21
+ { id: "entry-1", extensions: { showId: "A123" } },
22
+ ],
23
+ },
24
+ ZappPipesSearchContext: {
25
+ useZappPipesContext: () => ["user%20query"],
26
+ },
27
+ ZappPipesScreenContext: {
28
+ useZappPipesContext: () => [{ id: "screen-1" }],
29
+ },
30
+ }));
31
+
1
32
  jest.mock("../../logger", () => ({
2
33
  reactHooksLogger: {
3
34
  warning: jest.fn(),
@@ -5,13 +36,6 @@ jest.mock("../../logger", () => ({
5
36
  },
6
37
  }));
7
38
 
8
- const {
9
- getInflatedDataSourceUrl,
10
- getSearchContext,
11
- } = require("../useInflatedUrl");
12
-
13
- const { reactHooksLogger } = require("../../logger");
14
-
15
39
  let mockStore;
16
40
 
17
41
  describe("getInflatedDataSourceUrl", () => {
@@ -188,3 +212,34 @@ describe("getSearchContext", () => {
188
212
  expect(result).toHaveProperty(mapping.queryParam.property, searchContext);
189
213
  });
190
214
  });
215
+
216
+ describe("useGetUrlInflater", () => {
217
+ const { renderHook } = require("@testing-library/react-hooks");
218
+
219
+ it("returns original url when mapping is not provided", () => {
220
+ const { result } = renderHook(() => useGetUrlInflater(), {
221
+ wrapper: WrappedWithProviders,
222
+ });
223
+
224
+ const src = "https://foo.com/feed";
225
+ expect(result.current(src)).toBe(src);
226
+ });
227
+
228
+ it("inflates url using entry/search/screen contexts when mapping provided", () => {
229
+ const { result } = renderHook(() => useGetUrlInflater(), {
230
+ wrapper: ({ children }) => (
231
+ <WrappedWithProviders>{children}</WrappedWithProviders>
232
+ ),
233
+ });
234
+
235
+ const source = "https://foo.com/shows/{{showId}}?q={{q}}";
236
+
237
+ const mapping = {
238
+ showId: { source: "entry", property: "extensions.showId" },
239
+ q: { source: "search", property: "q" },
240
+ };
241
+
242
+ const url = result.current(source, mapping);
243
+ expect(url).toBe("https://foo.com/shows/A123?q=user%20query");
244
+ });
245
+ });
@@ -1,7 +1,7 @@
1
- import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
1
+ import { useContentTypes } from "@applicaster/zapp-react-native-redux";
2
2
 
3
3
  export const useEntryScreenId = (entry?: ZappEntry): string | undefined => {
4
- const { contentTypes } = usePickFromState("contentTypes");
4
+ const contentTypes = useContentTypes();
5
5
 
6
6
  if (!entry) {
7
7
  return;
@@ -1,4 +1,4 @@
1
- import { useMemo } from "react";
1
+ import { useCallback, useMemo, useRef } from "react";
2
2
  import * as R from "ramda";
3
3
 
4
4
  import {
@@ -169,7 +169,7 @@ const encodeIfNeeded: (string) => string = R.tryCatch(
169
169
 
170
170
  export function getSearchContext(
171
171
  searchContext: string,
172
- mapping: ZappTypeMapping
172
+ mapping: Nullable<ZappTypeMapping>
173
173
  ) {
174
174
  if (!mapping) {
175
175
  return {};
@@ -183,31 +183,57 @@ export function getSearchContext(
183
183
  return { [property]: encodeIfNeeded(searchContext) };
184
184
  }
185
185
 
186
- export function useInflatedUrl({
187
- feedUrl,
188
- mapping,
189
- }: {
190
- feedUrl?: string;
191
- mapping?: ZappTypeMapping;
192
- }) {
186
+ /**
187
+ * Hook returns a function that replace placeholders with context values
188
+ * @returns function that inflates urls based on contexts
189
+ */
190
+ export const useGetUrlInflater = () => {
193
191
  const { pathname } = useRoute();
194
192
 
195
193
  const [entryContext] = ZappPipesEntryContext.useZappPipesContext(pathname);
196
194
  const [searchContext] = ZappPipesSearchContext.useZappPipesContext();
197
195
  const [screenContext] = ZappPipesScreenContext.useZappPipesContext();
198
196
 
199
- const url = useMemo(
200
- () =>
201
- getInflatedDataSourceUrl({
197
+ const entryContextRef = useRef(entryContext);
198
+ entryContextRef.current = entryContext;
199
+
200
+ const screenContextRef = useRef(screenContext);
201
+ screenContextRef.current = screenContext;
202
+
203
+ const searchContextRef = useRef(searchContext);
204
+ searchContextRef.current = searchContext;
205
+
206
+ return useCallback(
207
+ (
208
+ feedUrl: Nullable<string>,
209
+ mapping?: Nullable<ZappTypeMapping>
210
+ ): Nullable<string> => {
211
+ return getInflatedDataSourceUrl({
202
212
  source: feedUrl,
203
213
  contexts: {
204
- entry: entryContext,
205
- screen: screenContext,
206
- search: getSearchContext(searchContext, mapping),
214
+ entry: entryContextRef.current,
215
+ screen: screenContextRef.current,
216
+ search: getSearchContext(searchContextRef.current, mapping),
207
217
  },
208
218
  mapping,
209
- }),
210
- [entryContext, feedUrl, mapping, screenContext, searchContext]
219
+ });
220
+ },
221
+ []
222
+ );
223
+ };
224
+
225
+ export function useInflatedUrl({
226
+ feedUrl,
227
+ mapping,
228
+ }: {
229
+ feedUrl?: string;
230
+ mapping?: ZappTypeMapping;
231
+ }) {
232
+ const urlInflater = useGetUrlInflater();
233
+
234
+ const url = useMemo(
235
+ () => urlInflater(feedUrl, mapping),
236
+ [urlInflater, feedUrl, mapping]
211
237
  );
212
238
 
213
239
  return url;
@@ -1,10 +1,8 @@
1
1
  import { noop } from "@applicaster/zapp-react-native-utils/functionUtils";
2
2
  import React from "react";
3
3
 
4
- type Return = (index: number) => void;
5
-
6
4
  type Predicate = (
7
- entry: ZappUIComponentProps["zappPipesData"]["data"]["entry"],
5
+ entryLength: number,
8
6
  index: number,
9
7
  numberOfColumns: number
10
8
  ) => boolean;
@@ -12,19 +10,15 @@ type Predicate = (
12
10
  type Props = {
13
11
  ifNeeded: Predicate;
14
12
  loadNextData: () => void;
15
- entry: ZappUIComponentProps["zappPipesData"]["data"]["entry"];
13
+ entryLength: number;
16
14
  numberOfColumns?: number;
17
15
  };
18
16
 
19
17
  const handleLoadNextPage =
20
18
  (
21
- ifNeeded: (
22
- entry: ZappEntry[],
23
- index: number,
24
- numberOfColumns?: number
25
- ) => boolean,
19
+ ifNeeded: Predicate,
26
20
  loadNextData: () => void,
27
- entry: ZappEntry[],
21
+ entryLength: number,
28
22
  numberOfColumns
29
23
  ) =>
30
24
  (index: number) => {
@@ -32,7 +26,7 @@ const handleLoadNextPage =
32
26
  * Lazy-Loading, invoke nextLoadData if we reach the end of the List
33
27
  */
34
28
 
35
- if (ifNeeded(entry, index, numberOfColumns)) {
29
+ if (ifNeeded(entryLength, index, numberOfColumns)) {
36
30
  loadNextData();
37
31
  }
38
32
  };
@@ -40,11 +34,14 @@ const handleLoadNextPage =
40
34
  export const useLoadNextPageIfNeeded = ({
41
35
  ifNeeded,
42
36
  loadNextData = noop,
43
- entry,
37
+ entryLength,
44
38
  numberOfColumns = 0,
45
- }: Props): Return => {
46
- return React.useCallback(
47
- handleLoadNextPage(ifNeeded, loadNextData, entry, numberOfColumns),
48
- [ifNeeded, loadNextData, entry, numberOfColumns]
39
+ }: Props) => {
40
+ const memoFn = React.useMemo(
41
+ () =>
42
+ handleLoadNextPage(ifNeeded, loadNextData, entryLength, numberOfColumns),
43
+ [ifNeeded, loadNextData, entryLength, numberOfColumns]
49
44
  );
45
+
46
+ return memoFn;
50
47
  };
@@ -1,16 +1,10 @@
1
- import { renderHook } from "@testing-library/react-hooks";
1
+ import React from "react";
2
+ import { renderHook } from "@testing-library/react-native";
2
3
  import { Dimensions, StatusBar } from "react-native";
3
4
  import { useDimensions } from "../useDimensions";
4
- import { usePickFromState } from "@applicaster/zapp-react-native-redux";
5
5
 
6
6
  import { useIsScreenActive } from "@applicaster/zapp-react-native-utils/reactHooks/navigation/useIsScreenActive";
7
-
8
- jest.mock("@applicaster/zapp-react-native-redux/hooks", () => {
9
- return {
10
- ...jest.requireActual("@applicaster/zapp-react-native-redux/hooks"),
11
- usePickFromState: jest.fn(),
12
- };
13
- });
7
+ import { WrappedWithProviders } from "@applicaster/zapp-react-native-utils/testUtils";
14
8
 
15
9
  jest.mock(
16
10
  "@applicaster/zapp-react-native-utils/reactHooks/navigation/useIsScreenActive",
@@ -42,12 +36,22 @@ describe("useDimensions", () => {
42
36
 
43
37
  beforeEach(() => {
44
38
  StatusBar.currentHeight = 20;
45
- (usePickFromState as jest.Mock).mockReturnValue({ appData: mockAppData });
46
39
  });
47
40
 
48
41
  it("returns correct initial dimensions", () => {
49
- const { result } = renderHook(() =>
50
- useDimensions("window", { fullDimensions: false })
42
+ const { result } = renderHook(
43
+ () => useDimensions("window", { fullDimensions: false }),
44
+ {
45
+ wrapper: ({ children }) => (
46
+ <WrappedWithProviders
47
+ store={{
48
+ appData: mockAppData,
49
+ }}
50
+ >
51
+ {children}
52
+ </WrappedWithProviders>
53
+ ),
54
+ }
51
55
  );
52
56
 
53
57
  expect(result.current).toMatchObject({
@@ -56,7 +60,17 @@ describe("useDimensions", () => {
56
60
  });
57
61
 
58
62
  it("calls handler on mount", () => {
59
- renderHook(() => useDimensions("window", { fullDimensions: false }));
63
+ renderHook(() => useDimensions("window", { fullDimensions: false }), {
64
+ wrapper: ({ children }) => (
65
+ <WrappedWithProviders
66
+ store={{
67
+ appData: mockAppData,
68
+ }}
69
+ >
70
+ {children}
71
+ </WrappedWithProviders>
72
+ ),
73
+ });
60
74
 
61
75
  expect(Dimensions.addEventListener).toHaveBeenCalledWith(
62
76
  "change",
@@ -65,12 +79,23 @@ describe("useDimensions", () => {
65
79
  });
66
80
 
67
81
  it("calls handler on isActive change", () => {
68
- const { rerender } = renderHook(() =>
69
- useDimensions("window", { fullDimensions: false })
82
+ const { rerender } = renderHook(
83
+ () => useDimensions("window", { fullDimensions: false }),
84
+ {
85
+ wrapper: ({ children }) => (
86
+ <WrappedWithProviders
87
+ store={{
88
+ appData: mockAppData,
89
+ }}
90
+ >
91
+ {children}
92
+ </WrappedWithProviders>
93
+ ),
94
+ }
70
95
  );
71
96
 
72
97
  (useIsScreenActive as jest.Mock).mockReturnValue(false);
73
- rerender();
98
+ rerender({});
74
99
 
75
100
  expect(Dimensions.addEventListener).toHaveBeenCalledWith(
76
101
  "change",
@@ -79,8 +104,19 @@ describe("useDimensions", () => {
79
104
  });
80
105
 
81
106
  it("handles fullDimensions option", () => {
82
- const { result } = renderHook(() =>
83
- useDimensions("window", { fullDimensions: true })
107
+ const { result } = renderHook(
108
+ () => useDimensions("window", { fullDimensions: true }),
109
+ {
110
+ wrapper: ({ children }) => (
111
+ <WrappedWithProviders
112
+ store={{
113
+ appData: mockAppData,
114
+ }}
115
+ >
116
+ {children}
117
+ </WrappedWithProviders>
118
+ ),
119
+ }
84
120
  );
85
121
 
86
122
  expect(result.current).toMatchObject({
@@ -91,8 +127,19 @@ describe("useDimensions", () => {
91
127
  });
92
128
 
93
129
  it("handles excludeStatusBar option", () => {
94
- const { result } = renderHook(() =>
95
- useDimensions("window", { excludeStatusBar: true })
130
+ const { result } = renderHook(
131
+ () => useDimensions("window", { excludeStatusBar: true }),
132
+ {
133
+ wrapper: ({ children }) => (
134
+ <WrappedWithProviders
135
+ store={{
136
+ appData: mockAppData,
137
+ }}
138
+ >
139
+ {children}
140
+ </WrappedWithProviders>
141
+ ),
142
+ }
96
143
  );
97
144
 
98
145
  expect(result.current.height).toBe(
@@ -101,8 +148,19 @@ describe("useDimensions", () => {
101
148
  });
102
149
 
103
150
  it("handles rounded option", () => {
104
- const { result } = renderHook(() =>
105
- useDimensions("window", { rounded: true })
151
+ const { result } = renderHook(
152
+ () => useDimensions("window", { rounded: true }),
153
+ {
154
+ wrapper: ({ children }) => (
155
+ <WrappedWithProviders
156
+ store={{
157
+ appData: mockAppData,
158
+ }}
159
+ >
160
+ {children}
161
+ </WrappedWithProviders>
162
+ ),
163
+ }
106
164
  );
107
165
 
108
166
  expect(result.current.width).toBe(Math.ceil(mockDimensions.width));
@@ -110,8 +168,19 @@ describe("useDimensions", () => {
110
168
  });
111
169
 
112
170
  it("handles deviceInfo option", () => {
113
- const { result } = renderHook(() =>
114
- useDimensions("window", { deviceInfo: true })
171
+ const { result } = renderHook(
172
+ () => useDimensions("window", { deviceInfo: true }),
173
+ {
174
+ wrapper: ({ children }) => (
175
+ <WrappedWithProviders
176
+ store={{
177
+ appData: mockAppData,
178
+ }}
179
+ >
180
+ {children}
181
+ </WrappedWithProviders>
182
+ ),
183
+ }
115
184
  );
116
185
 
117
186
  expect(result.current.deviceInfo).toMatchObject({
@@ -121,7 +190,18 @@ describe("useDimensions", () => {
121
190
 
122
191
  it("logs deprecation warning when fullDimensions is boolean", () => {
123
192
  const consoleWarnSpy = jest.spyOn(console, "warn").mockImplementation();
124
- renderHook(() => useDimensions("window", true));
193
+
194
+ renderHook(() => useDimensions("window", true), {
195
+ wrapper: ({ children }) => (
196
+ <WrappedWithProviders
197
+ store={{
198
+ appData: mockAppData,
199
+ }}
200
+ >
201
+ {children}
202
+ </WrappedWithProviders>
203
+ ),
204
+ });
125
205
 
126
206
  expect(consoleWarnSpy).toHaveBeenCalledWith(
127
207
  "Deprecation Warning\nSecond argument is now the options object. {fullDimensions: boolean, ...}"
@@ -3,7 +3,7 @@ import { useLayoutEffect, useMemo, useRef, useState } from "react";
3
3
  import * as R from "ramda";
4
4
 
5
5
  import { Dimensions, Platform, StatusBar } from "react-native";
6
- import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
6
+ import { useAppData } from "@applicaster/zapp-react-native-redux/hooks";
7
7
 
8
8
  import { isTV } from "../../../reactUtils";
9
9
 
@@ -37,7 +37,7 @@ export const useDimensions: UseDimensions = (
37
37
  ) => {
38
38
  const statusBarHeight = StatusBar?.currentHeight;
39
39
  const isActive = useIsScreenActive();
40
- const { appData } = usePickFromState(["appData"]);
40
+ const appData = useAppData();
41
41
 
42
42
  if (typeof fullDimensions === "boolean") {
43
43
  // eslint-disable-next-line no-console
@@ -3,7 +3,7 @@ import { BackHandler } from "react-native";
3
3
 
4
4
  import {
5
5
  useContentTypes,
6
- usePickFromState,
6
+ usePlugins,
7
7
  } from "@applicaster/zapp-react-native-redux/hooks";
8
8
  import { HooksManager } from "@applicaster/zapp-react-native-utils/appUtils/HooksManager";
9
9
 
@@ -16,6 +16,8 @@ import { useConnectionInfo } from "../connection";
16
16
 
17
17
  import { isTV, isWeb } from "@applicaster/zapp-react-native-utils/reactUtils";
18
18
  import { useNavbarState } from "../screen";
19
+ import { useRivers } from "../state";
20
+ import { useLayoutVersion } from "../layout";
19
21
 
20
22
  export { useNavigation } from "./useNavigation";
21
23
 
@@ -86,6 +88,10 @@ export function isNavBarVisible(
86
88
  if (route.startsWith("/hooks/")) {
87
89
  const module = screenData?.module;
88
90
 
91
+ if (module === undefined) {
92
+ return showNavBar;
93
+ }
94
+
89
95
  if (module?.presentFullScreen) {
90
96
  return false;
91
97
  }
@@ -164,11 +170,10 @@ export const useZappHooksForEntry = (
164
170
  setIsRunningInBackground,
165
171
  }: HookModalContextT = useContext(ZappHookModalContext.ReactContext);
166
172
 
167
- const {
168
- appData: { layoutVersion },
169
- rivers,
170
- plugins,
171
- } = usePickFromState(["appData", "rivers", "plugins"]);
173
+ const plugins = usePlugins();
174
+ const rivers = useRivers();
175
+
176
+ const layoutVersion = useLayoutVersion();
172
177
 
173
178
  const contentTypes = useContentTypes();
174
179