@applicaster/zapp-react-native-utils 15.1.0-rc.8 → 16.0.0-alpha.1833861900

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 (147) hide show
  1. package/README.md +0 -6
  2. package/actionUtils/index.ts +7 -0
  3. package/actionsExecutor/ActionExecutorContext.tsx +43 -12
  4. package/actionsExecutor/feedDecorator.ts +6 -6
  5. package/adsUtils/__tests__/createVMAP.test.ts +419 -0
  6. package/adsUtils/index.ts +2 -2
  7. package/analyticsUtils/PlayerAnalyticsManager.ts +11 -1
  8. package/analyticsUtils/README.md +1 -1
  9. package/analyticsUtils/playerAnalyticsTracker.ts +26 -3
  10. package/appDataUtils/__tests__/urlScheme.test.ts +678 -0
  11. package/appUtils/HooksManager/__tests__/__snapshots__/hooksManager.test.js.snap +0 -188
  12. package/appUtils/HooksManager/__tests__/hooksManager.test.js +16 -2
  13. package/appUtils/HooksManager/index.ts +15 -26
  14. package/appUtils/RiverFocusManager/{index.js → index.ts} +25 -18
  15. package/appUtils/accessibilityManager/const.ts +4 -0
  16. package/appUtils/accessibilityManager/utils.ts +0 -1
  17. package/appUtils/contextKeysManager/__tests__/getKeys/failure.test.ts +7 -2
  18. package/appUtils/contextKeysManager/__tests__/getKeys/success.test.ts +48 -0
  19. package/appUtils/contextKeysManager/contextResolver.ts +51 -22
  20. package/appUtils/contextKeysManager/index.ts +65 -10
  21. package/appUtils/contextKeysManager/utils/index.ts +38 -25
  22. package/appUtils/focusManager/__tests__/__snapshots__/focusManager.test.js.snap +3 -0
  23. package/appUtils/focusManager/index.ios.ts +43 -4
  24. package/appUtils/focusManager/treeDataStructure/Tree/__tests__/Tree.test.js +46 -0
  25. package/appUtils/focusManager/treeDataStructure/Tree/index.js +18 -18
  26. package/appUtils/focusManagerAux/utils/index.ios.ts +122 -0
  27. package/appUtils/focusManagerAux/utils/index.ts +11 -3
  28. package/appUtils/focusManagerAux/utils/utils.ios.ts +202 -3
  29. package/appUtils/keyCodes/keys/keys.web.ts +1 -4
  30. package/appUtils/orientationHelper.ts +2 -4
  31. package/appUtils/platform/platformUtils.ts +12 -1
  32. package/appUtils/playerManager/player.ts +4 -0
  33. package/appUtils/playerManager/playerNative.ts +30 -21
  34. package/appUtils/playerManager/usePlayerState.tsx +14 -2
  35. package/cloudEventsUtils/__tests__/index.test.ts +529 -0
  36. package/cloudEventsUtils/index.ts +65 -1
  37. package/componentsUtils/index.ts +8 -0
  38. package/configurationUtils/__tests__/manifestKeyParser.test.ts +26 -26
  39. package/enumUtils/__tests__/getEnumKeyByEnumValue.test.ts +207 -0
  40. package/errorUtils/__tests__/GeneralError.test.ts +97 -0
  41. package/errorUtils/__tests__/HttpStatusCode.test.ts +344 -0
  42. package/errorUtils/__tests__/MissingPluginError.test.ts +113 -0
  43. package/errorUtils/__tests__/NetworkError.test.ts +202 -0
  44. package/errorUtils/__tests__/getParsedResponse.test.ts +188 -0
  45. package/errorUtils/__tests__/invariant.test.ts +112 -0
  46. package/focusManager/aux/index.ts +1 -1
  47. package/headersUtils/__tests__/headersUtils.test.js +11 -1
  48. package/headersUtils/index.ts +2 -1
  49. package/manifestUtils/_internals/__tests__/index.test.js +41 -0
  50. package/manifestUtils/_internals/index.js +33 -0
  51. package/manifestUtils/defaultManifestConfigurations/player.js +59 -1
  52. package/manifestUtils/fieldUtils/__tests__/fieldUtils.test.js +49 -0
  53. package/manifestUtils/fieldUtils/index.js +54 -0
  54. package/manifestUtils/index.js +3 -1
  55. package/manifestUtils/keys.js +228 -0
  56. package/manifestUtils/mobileAction/button/__tests__/mobileActionButton.test.js +168 -0
  57. package/manifestUtils/mobileAction/button/index.js +140 -0
  58. package/manifestUtils/mobileAction/container/__tests__/mobileActionButtonsContainer.test.js +102 -0
  59. package/manifestUtils/mobileAction/container/index.js +73 -0
  60. package/manifestUtils/mobileAction/groups/__tests__/buildMobileActionButtonGroups.test.js +127 -0
  61. package/manifestUtils/mobileAction/groups/defaults.js +76 -0
  62. package/manifestUtils/mobileAction/groups/index.js +80 -0
  63. package/manifestUtils/tvAction/container/index.js +1 -1
  64. package/numberUtils/__tests__/toNumber.test.ts +27 -0
  65. package/numberUtils/__tests__/toPositiveNumber.test.ts +193 -0
  66. package/numberUtils/index.ts +23 -1
  67. package/package.json +4 -4
  68. package/playerUtils/index.ts +4 -2
  69. package/pluginUtils/index.ts +4 -0
  70. package/reactHooks/advertising/index.ts +2 -2
  71. package/reactHooks/analytics/__tests__/useSendAnalyticsOnPress.test.ts +537 -0
  72. package/reactHooks/app/__tests__/useAppState.test.ts +1 -1
  73. package/reactHooks/autoscrolling/__tests__/useTrackCurrentAutoScrollingElement.test.ts +1 -1
  74. package/reactHooks/autoscrolling/__tests__/useTrackedView.test.tsx +1 -2
  75. package/reactHooks/cell-click/__tests__/index.test.js +1 -3
  76. package/reactHooks/cell-click/index.ts +2 -1
  77. package/reactHooks/configuration/__tests__/index.test.tsx +1 -1
  78. package/reactHooks/connection/__tests__/index.test.js +1 -1
  79. package/reactHooks/debugging/__tests__/index.test.js +4 -4
  80. package/reactHooks/dev/__tests__/useReRenderLog.test.ts +188 -0
  81. package/reactHooks/device/useIsTablet.tsx +14 -19
  82. package/reactHooks/device/useMemoizedIsTablet.ts +3 -3
  83. package/reactHooks/feed/__tests__/useBatchLoading.test.tsx +32 -23
  84. package/reactHooks/feed/__tests__/useBuildPipesUrl.test.tsx +19 -19
  85. package/reactHooks/feed/__tests__/useEntryScreenId.test.tsx +4 -1
  86. package/reactHooks/feed/__tests__/useFeedLoader.test.tsx +42 -30
  87. package/reactHooks/feed/__tests__/useInflatedUrl.test.tsx +1 -1
  88. package/reactHooks/feed/index.ts +0 -2
  89. package/reactHooks/feed/useBatchLoading.ts +7 -1
  90. package/reactHooks/feed/useEntryScreenId.ts +2 -2
  91. package/reactHooks/feed/usePipesCacheReset.ts +3 -1
  92. package/reactHooks/flatList/useLoadNextPageIfNeeded.ts +13 -16
  93. package/reactHooks/layout/__tests__/index.test.tsx +1 -1
  94. package/reactHooks/layout/__tests__/useLayoutVersion.test.tsx +1 -1
  95. package/reactHooks/layout/useDimensions/__tests__/{useDimensions.test.ts → useDimensions.test.tsx} +105 -25
  96. package/reactHooks/layout/useDimensions/useDimensions.ts +2 -2
  97. package/reactHooks/navigation/__tests__/index.test.tsx +2 -4
  98. package/reactHooks/navigation/index.ts +7 -6
  99. package/reactHooks/navigation/useRoute.ts +8 -6
  100. package/reactHooks/player/TVSeekControlller/TVSeekController.ts +27 -10
  101. package/reactHooks/player/__tests__/useAutoSeek._test.tsx +1 -1
  102. package/reactHooks/player/__tests__/useTapSeek._test.ts +1 -1
  103. package/reactHooks/resolvers/__tests__/useCellResolver.test.tsx +1 -1
  104. package/reactHooks/resolvers/__tests__/useComponentResolver.test.tsx +1 -1
  105. package/reactHooks/resolvers/useCellResolver.ts +6 -2
  106. package/reactHooks/resolvers/useComponentResolver.ts +8 -2
  107. package/reactHooks/screen/__tests__/useCurrentScreenData.test.tsx +2 -2
  108. package/reactHooks/screen/__tests__/useIsStandaloneFullscreen.test.ts +114 -0
  109. package/reactHooks/screen/__tests__/useScreenBackgroundColor.test.tsx +1 -1
  110. package/reactHooks/screen/__tests__/useScreenData.test.tsx +1 -1
  111. package/reactHooks/screen/__tests__/useTargetScreenData.test.tsx +12 -4
  112. package/reactHooks/screen/useTargetScreenData.ts +4 -2
  113. package/reactHooks/state/useRivers.ts +1 -1
  114. package/reactHooks/ui/__tests__/useFadeOutWhenBlurred.test.ts +580 -0
  115. package/reactHooks/usePluginConfiguration.ts +2 -2
  116. package/reactHooks/utils/__tests__/index.test.js +1 -1
  117. package/rectUtils/__tests__/index.test.ts +549 -0
  118. package/rectUtils/index.ts +2 -2
  119. package/refreshUtils/RefreshCoordinator/__tests__/refreshCoordinator.test.ts +206 -0
  120. package/refreshUtils/RefreshCoordinator/index.ts +245 -0
  121. package/refreshUtils/RefreshCoordinator/utils/__tests__/getDataRefreshConfig.test.ts +104 -0
  122. package/refreshUtils/RefreshCoordinator/utils/index.ts +29 -0
  123. package/screenPickerUtils/__tests__/index.test.ts +333 -0
  124. package/screenState/__tests__/index.test.ts +1 -1
  125. package/screenUtils/index.ts +3 -0
  126. package/searchUtils/const.ts +7 -0
  127. package/searchUtils/index.ts +3 -0
  128. package/stringUtils/index.ts +1 -1
  129. package/testUtils/index.tsx +30 -21
  130. package/time/__tests__/BackgroundTimer.test.ts +156 -0
  131. package/time/__tests__/Timer.test.ts +236 -0
  132. package/typeGuards/__tests__/isString.test.ts +21 -0
  133. package/typeGuards/index.ts +4 -0
  134. package/utils/__tests__/mergeRight.test.ts +48 -0
  135. package/utils/__tests__/path.test.ts +7 -0
  136. package/utils/__tests__/selectors.test.ts +124 -0
  137. package/utils/index.ts +13 -0
  138. package/utils/mergeRight.ts +5 -0
  139. package/utils/path.ts +6 -3
  140. package/utils/pathOr.ts +5 -1
  141. package/utils/selectors.ts +46 -0
  142. package/zappFrameworkUtils/HookCallback/callbackNavigationAction.ts +1 -1
  143. package/zappFrameworkUtils/HookCallback/hookCallbackManifestExtensions.config.js +1 -1
  144. package/zappFrameworkUtils/loginPluginUtils.ts +1 -1
  145. package/reactHooks/componentsMap/index.ts +0 -55
  146. package/reactHooks/feed/__tests__/useFeedRefresh.test.tsx +0 -75
  147. package/reactHooks/feed/useFeedRefresh.tsx +0 -65
@@ -1,4 +1,4 @@
1
- import { renderHook } from "@testing-library/react-hooks";
1
+ import { renderHook } from "@testing-library/react-native";
2
2
  import * as R from "ramda";
3
3
  import * as zappPipesModule from "@applicaster/zapp-react-native-redux/ZappPipes";
4
4
  import * as reactReduxModules from "react-redux";
@@ -50,6 +50,16 @@ const mockZappPipesData = {
50
50
  url: "test://testfakeurl",
51
51
  };
52
52
 
53
+ const createWrapper = (
54
+ getStore: () => any
55
+ ): React.FC<{ children: React.ReactNode }> => {
56
+ const Wrapper: React.FC<{ children: React.ReactNode }> = ({ children }) => (
57
+ <WrappedWithProviders store={getStore()}>{children}</WrappedWithProviders>
58
+ );
59
+
60
+ return Wrapper;
61
+ };
62
+
53
63
  describe("useFeedLoader", () => {
54
64
  describe("with cached feed url", () => {
55
65
  const store = {
@@ -57,11 +67,7 @@ describe("useFeedLoader", () => {
57
67
  zappPipes: { "test://testfakeurl": mockZappPipesData },
58
68
  };
59
69
 
60
- const wrapper: React.FC<any> = ({ children, ...props }) => (
61
- <WrappedWithProviders store={props.store || store}>
62
- {children}
63
- </WrappedWithProviders>
64
- );
70
+ const wrapper = createWrapper(() => store);
65
71
 
66
72
  it("returns cached feed", () => {
67
73
  const { result } = renderHook(
@@ -109,12 +115,6 @@ describe("useFeedLoader", () => {
109
115
  describe("without cached feeds", () => {
110
116
  const feedUrl = "test://testfakeurl2";
111
117
 
112
- const wrapper: React.FC<any> = ({ children, ...props }) => (
113
- <WrappedWithProviders store={props.store}>
114
- {children}
115
- </WrappedWithProviders>
116
- );
117
-
118
118
  it("It loads data for new url and returns it", () => {
119
119
  const useDispatchSpy = jest
120
120
  .spyOn(reactReduxModules, "useDispatch")
@@ -129,9 +129,12 @@ describe("useFeedLoader", () => {
129
129
  zappPipes: { "test://testfakeurl": "foobar" },
130
130
  };
131
131
 
132
+ let store = initialStore;
133
+ const wrapper = createWrapper(() => store);
134
+
132
135
  const { result, rerender } = renderHook(
133
- () => useFeedLoader({ feedUrl: "test://testfakeurl2" }),
134
- { wrapper, initialProps: { store: initialStore } }
136
+ ({ feedUrl: url }) => useFeedLoader({ feedUrl: url }),
137
+ { wrapper, initialProps: { feedUrl } }
135
138
  );
136
139
 
137
140
  expect(result.current.data).toBeNull();
@@ -150,7 +153,8 @@ describe("useFeedLoader", () => {
150
153
  zappPipes: { "test://testfakeurl2": mockZappPipesData },
151
154
  };
152
155
 
153
- rerender({ store: store2 });
156
+ store = store2;
157
+ rerender({ feedUrl });
154
158
 
155
159
  expect(R.omit(["reloadData", "loadNext"], result.current)).toEqual(
156
160
  mockZappPipesData
@@ -174,9 +178,12 @@ describe("useFeedLoader", () => {
174
178
  zappPipes: { "test://testfakeurl": "foobar" },
175
179
  };
176
180
 
181
+ let store = initialStore;
182
+ const wrapper = createWrapper(() => store);
183
+
177
184
  const { result, rerender } = renderHook(
178
- () => useFeedLoader({ feedUrl: "test://testfakeurl2" }),
179
- { wrapper, initialProps: { store: initialStore } }
185
+ ({ feedUrl: url }) => useFeedLoader({ feedUrl: url }),
186
+ { wrapper, initialProps: { feedUrl } }
180
187
  );
181
188
 
182
189
  expect(result.current.data).toBeNull();
@@ -198,7 +205,8 @@ describe("useFeedLoader", () => {
198
205
  zappPipes: { "test://testfakeurl2": mockZappPipesData },
199
206
  };
200
207
 
201
- rerender({ store: store2 });
208
+ store = store2;
209
+ rerender({ feedUrl });
202
210
 
203
211
  loadPipesDataSpy.mockRestore();
204
212
  useDispatchSpy.mockRestore();
@@ -209,12 +217,6 @@ describe("useFeedLoader", () => {
209
217
  const feedUrl = "test://testfakeurl";
210
218
  const feedUrlWithNext = "test://withnexttestfakeurl";
211
219
 
212
- const wrapper: React.FC<any> = ({ children, ...props }) => (
213
- <WrappedWithProviders store={props.store || {}}>
214
- {children}
215
- </WrappedWithProviders>
216
- );
217
-
218
220
  describe("reloadData", () => {
219
221
  it("Tries to reload data in the redux store", () => {
220
222
  const loadPipesDataSpy = jest
@@ -230,10 +232,17 @@ describe("useFeedLoader", () => {
230
232
  zappPipes: { [feedUrl]: "foobar" },
231
233
  };
232
234
 
233
- const { result } = renderHook(() => useFeedLoader({ feedUrl }), {
234
- wrapper,
235
- initialProps: { store: initialStore },
236
- });
235
+ const store = initialStore;
236
+
237
+ const wrapper = createWrapper(() => store);
238
+
239
+ const { result } = renderHook(
240
+ ({ feedUrl: url }) => useFeedLoader({ feedUrl: url }),
241
+ {
242
+ wrapper,
243
+ initialProps: { feedUrl },
244
+ }
245
+ );
237
246
 
238
247
  const { reloadData } = result.current;
239
248
 
@@ -279,11 +288,14 @@ describe("useFeedLoader", () => {
279
288
  zappPipes: { [feedUrlWithNext]: { data: { next: nextUrl } } },
280
289
  };
281
290
 
291
+ const store = initialStore;
292
+ const wrapper = createWrapper(() => store);
293
+
282
294
  const { result } = renderHook(
283
- () => useFeedLoader({ feedUrl: feedUrlWithNext }),
295
+ ({ feedUrl: url }) => useFeedLoader({ feedUrl: url }),
284
296
  {
285
297
  wrapper,
286
- initialProps: { store: initialStore },
298
+ initialProps: { feedUrl: feedUrlWithNext },
287
299
  }
288
300
  );
289
301
 
@@ -214,7 +214,7 @@ describe("getSearchContext", () => {
214
214
  });
215
215
 
216
216
  describe("useGetUrlInflater", () => {
217
- const { renderHook } = require("@testing-library/react-hooks");
217
+ const { renderHook } = require("@testing-library/react-native");
218
218
 
219
219
  it("returns original url when mapping is not provided", () => {
220
220
  const { result } = renderHook(() => useGetUrlInflater(), {
@@ -1,5 +1,3 @@
1
- export { useFeedRefresh, feedRefreshLogger } from "./useFeedRefresh";
2
-
3
1
  export { useFeedLoader } from "./useFeedLoader";
4
2
 
5
3
  export { getSearchContext, getInflatedDataSourceUrl } from "./useInflatedUrl";
@@ -151,7 +151,13 @@ export const useBatchLoading = (
151
151
  }
152
152
  }
153
153
  });
154
- }, [feedUrls, feeds, loadPipesDataDispatcher]);
154
+ }, [
155
+ batchComponents,
156
+ feeds,
157
+ getUrl,
158
+ loadPipesDataDispatcher,
159
+ options.riverId,
160
+ ]);
155
161
 
156
162
  React.useEffect(() => {
157
163
  runBatchLoading();
@@ -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;
@@ -34,7 +34,9 @@ export const usePipesCacheReset = (riverId, riverComponents) => {
34
34
  component
35
35
  );
36
36
 
37
- dispatch(clearPipesData(url, { riverId }));
37
+ if (url) {
38
+ dispatch(clearPipesData(url, { riverId }));
39
+ }
38
40
  }
39
41
  });
40
42
  };
@@ -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,6 +1,6 @@
1
1
  import React from "react";
2
2
 
3
- import { cleanup, renderHook } from "@testing-library/react-hooks";
3
+ import { cleanup, renderHook } from "@testing-library/react-native";
4
4
  import { Provider } from "react-redux";
5
5
  import configureStore from "redux-mock-store";
6
6
 
@@ -1,4 +1,4 @@
1
- import { renderHook } from "@testing-library/react-hooks";
1
+ import { renderHook } from "@testing-library/react-native";
2
2
  import configureStore from "redux-mock-store";
3
3
 
4
4
  const mockStore = configureStore();
@@ -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
@@ -1,6 +1,6 @@
1
1
  import React from "react";
2
2
  import { PathnameContext } from "@applicaster/zapp-react-native-ui-components/Contexts/PathnameContext";
3
- import { renderHook } from "@testing-library/react-hooks";
3
+ import { renderHook } from "@testing-library/react-native";
4
4
  import { isNavBarVisible, useRoute } from "../";
5
5
  import { Provider } from "react-redux";
6
6
  import configureMockStore from "redux-mock-store";
@@ -86,11 +86,11 @@ const hookModalContextState = {
86
86
  };
87
87
 
88
88
  const hooksModalPathname = `${ROUTE_TYPES.HOOKS_MODAL}/${hookModalContextState.state.screenData.payload.id}`;
89
+ const videoModalPathname = `${ROUTE_TYPES.VIDEO_MODAL}/${videoModalNavigator.videoModalState.item.id}`;
89
90
 
90
91
  jest.mock(
91
92
  "@applicaster/zapp-react-native-ui-components/Contexts/ZappHookModalContext",
92
93
  () => {
93
- // Define state inside mock factory to avoid hoisting issues
94
94
  const mockState = {
95
95
  isRunningInBackground: false,
96
96
  setIsRunningInBackground: jest.fn(),
@@ -111,7 +111,6 @@ jest.mock(
111
111
  return selector ? selector(mockState) : mockState;
112
112
  }) as jest.MockedFunction<any> & { getState: () => typeof mockState };
113
113
 
114
- // Add getState method to the mock hook (Zustand stores have this)
115
114
  mockHook.getState = jest.fn(() => mockState);
116
115
 
117
116
  return {
@@ -121,7 +120,6 @@ jest.mock(
121
120
  }
122
121
  );
123
122
 
124
- const videoModalPathname = `${ROUTE_TYPES.VIDEO_MODAL}/${videoModalNavigator.videoModalState.item.id}`;
125
123
  const mockStore = configureMockStore();
126
124
 
127
125
  const store = mockStore({
@@ -4,7 +4,7 @@ import { shallow } from "zustand/shallow";
4
4
 
5
5
  import {
6
6
  useContentTypes,
7
- usePickFromState,
7
+ usePlugins,
8
8
  } from "@applicaster/zapp-react-native-redux/hooks";
9
9
  import { HooksManager } from "@applicaster/zapp-react-native-utils/appUtils/HooksManager";
10
10
 
@@ -17,6 +17,8 @@ import { useConnectionInfo } from "../connection";
17
17
  import { isTV, isWeb } from "@applicaster/zapp-react-native-utils/reactUtils";
18
18
  import { pick } from "@applicaster/zapp-react-native-utils/utils";
19
19
  import { useNavbarState } from "../screen";
20
+ import { useRivers } from "../state";
21
+ import { useLayoutVersion } from "../layout";
20
22
 
21
23
  export { useNavigation } from "./useNavigation";
22
24
 
@@ -179,11 +181,10 @@ export const useZappHooksForEntry = (
179
181
  shallow
180
182
  );
181
183
 
182
- const {
183
- appData: { layoutVersion },
184
- rivers,
185
- plugins,
186
- } = usePickFromState(["appData", "rivers", "plugins"]);
184
+ const plugins = usePlugins();
185
+ const rivers = useRivers();
186
+
187
+ const layoutVersion = useLayoutVersion();
187
188
 
188
189
  const contentTypes = useContentTypes();
189
190
 
@@ -3,7 +3,10 @@
3
3
 
4
4
  import { useContext } from "react";
5
5
 
6
- import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
6
+ import {
7
+ useContentTypes,
8
+ usePlugins,
9
+ } from "@applicaster/zapp-react-native-redux/hooks";
7
10
 
8
11
  import { legacyScreenData } from "@applicaster/quick-brick-core/App/NavigationProvider/utils";
9
12
 
@@ -14,6 +17,7 @@ import { useNavigation } from "./useNavigation";
14
17
  import { useModalStoreState } from "../../modalState";
15
18
  import { ScreenDataContext } from "@applicaster/zapp-react-native-ui-components/Contexts/ScreenDataContext";
16
19
  import { usePathname } from "./usePathname";
20
+ import { useRivers } from "../state";
17
21
 
18
22
  // starts with modal/
19
23
  const isModalPathname = (pathname: string) => /^modal\//.test(pathname);
@@ -42,11 +46,9 @@ export const useRoute = (
42
46
  ? legacyScreenData(screenContext)
43
47
  : screenContext;
44
48
 
45
- const { plugins, contentTypes, rivers } = usePickFromState([
46
- "plugins",
47
- "rivers",
48
- "contentTypes",
49
- ]);
49
+ const plugins = usePlugins();
50
+ const rivers = useRivers();
51
+ const contentTypes = useContentTypes();
50
52
 
51
53
  const modalState = useModalStoreState();
52
54
 
@@ -147,17 +147,34 @@ export class TVSeekController
147
147
 
148
148
  let targetPos = currentPos;
149
149
 
150
- if (this.currentSeekType === SEEK_TYPE.FORWARD) {
151
- targetPos = Math.min(
152
- currentPos + offset,
153
- this.playerController.getSeekableDuration()
154
- );
155
- } else if (this.currentSeekType === SEEK_TYPE.REWIND) {
156
- targetPos = Math.max(0, currentPos - offset);
150
+ const isLive = this.playerController.isLive();
151
+
152
+ if (isLive) {
153
+ if (this.currentSeekType === SEEK_TYPE.REWIND) {
154
+ targetPos = Math.min(
155
+ currentPos + offset,
156
+ this.playerController.getSeekableDuration()
157
+ );
158
+ } else if (this.currentSeekType === SEEK_TYPE.FORWARD) {
159
+ targetPos = Math.max(0, currentPos - offset);
160
+ } else {
161
+ log_warning(
162
+ `TVSeekController: handleDelayedSeek - invalid seek type: ${this.currentSeekType}`
163
+ );
164
+ }
157
165
  } else {
158
- log_warning(
159
- `TVSeekController: handleDelayedSeek - invalid seek type: ${this.currentSeekType}`
160
- );
166
+ if (this.currentSeekType === SEEK_TYPE.FORWARD) {
167
+ targetPos = Math.min(
168
+ currentPos + offset,
169
+ this.playerController.getSeekableDuration()
170
+ );
171
+ } else if (this.currentSeekType === SEEK_TYPE.REWIND) {
172
+ targetPos = Math.max(0, currentPos - offset);
173
+ } else {
174
+ log_warning(
175
+ `TVSeekController: handleDelayedSeek - invalid seek type: ${this.currentSeekType}`
176
+ );
177
+ }
161
178
  }
162
179
 
163
180
  log_debug(
@@ -1,4 +1,4 @@
1
- import { act, renderHook } from "@testing-library/react-hooks";
1
+ import { act, renderHook } from "@testing-library/react-native";
2
2
  import { playerManager } from "@applicaster/zapp-react-native-utils/appUtils/playerManager";
3
3
 
4
4
  import { ON_HOLD_INTERVAL, SEEK_TYPE, SKIP_TIME_BASE } from "../const";
@@ -1,4 +1,4 @@
1
- import { renderHook } from "@testing-library/react-hooks";
1
+ import { renderHook } from "@testing-library/react-native";
2
2
  import { playerManager } from "@applicaster/zapp-react-native-utils/appUtils/playerManager";
3
3
  import { useTapSeek } from "../useTapSeek";
4
4
 
@@ -1,6 +1,6 @@
1
1
  import * as React from "react";
2
2
  import { View } from "react-native";
3
- import { cleanup, renderHook } from "@testing-library/react-hooks";
3
+ import { cleanup, renderHook } from "@testing-library/react-native";
4
4
  import configureStore from "redux-mock-store";
5
5
  import { Provider } from "react-redux";
6
6