@applicaster/zapp-react-native-utils 12.0.0-rc.10 → 12.0.0-rc.101

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 (111) hide show
  1. package/actionsExecutor/ActionExecutorContext.tsx +16 -8
  2. package/analyticsUtils/AnalyticsEvents/index.ts +13 -0
  3. package/analyticsUtils/AnalyticsEvents/searchEvents.ts +21 -0
  4. package/analyticsUtils/AnalyticsEvents/sendShareEvent.ts +21 -0
  5. package/analyticsUtils/__tests__/analyticsManager.test.js +75 -73
  6. package/analyticsUtils/analyticsPlugins.ts +25 -0
  7. package/analyticsUtils/events.ts +12 -0
  8. package/analyticsUtils/helpers/hooks.ts +1 -1
  9. package/analyticsUtils/index.tsx +12 -0
  10. package/appUtils/HooksManager/index.js +3 -1
  11. package/appUtils/accessibilityManager/const.ts +50 -0
  12. package/appUtils/accessibilityManager/hooks.ts +40 -0
  13. package/appUtils/accessibilityManager/index.ts +155 -0
  14. package/appUtils/accessibilityManager/logger.ts +5 -0
  15. package/appUtils/focusManager/__tests__/__snapshots__/focusManager.test.js.snap +2 -3
  16. package/appUtils/focusManager/__tests__/focusManager.test.js +4 -24
  17. package/appUtils/focusManager/__tests__/index.test.ts +2 -3
  18. package/appUtils/focusManager/index.ts +76 -57
  19. package/appUtils/focusManager/treeDataStructure/Utils/index.js +75 -35
  20. package/appUtils/focusManager/utils/index.ts +100 -0
  21. package/appUtils/focusManagerAux/index.ts +76 -0
  22. package/appUtils/focusManagerAux/utils/index.ts +100 -0
  23. package/appUtils/index.js +2 -0
  24. package/appUtils/keyCodes/__tests__/__snapshots__/keyCodes.test.js.snap +1 -1
  25. package/appUtils/keyCodes/__tests__/keyCodes.test.js +80 -85
  26. package/appUtils/keyCodes/keys.web.js +9 -0
  27. package/appUtils/keyCodes/keysByPlatform.js +11 -1
  28. package/appUtils/platform/const.ts +25 -0
  29. package/appUtils/platform/index.ts +3 -0
  30. package/appUtils/platform/platformUtils.ts +185 -0
  31. package/appUtils/playerManager/OverlayObserver/OverlaysObserver.ts +53 -0
  32. package/appUtils/playerManager/conts.ts +6 -0
  33. package/appUtils/playerManager/index.ts +11 -5
  34. package/appUtils/playerManager/nativePlayerManager.ts +12 -0
  35. package/appUtils/playerManager/player.ts +56 -7
  36. package/appUtils/playerManager/playerFactory.ts +15 -1
  37. package/appUtils/playerManager/playerNative.ts +40 -14
  38. package/appUtils/playerManager/usePlayerControllerSetup.tsx +7 -1
  39. package/appUtils/playerManager/usePlayerState.tsx +13 -1
  40. package/appUtils/playerManager/usePlayerTitleSummaryOverlay.tsx +50 -0
  41. package/arrayUtils/__tests__/isFilledArray.test.ts +63 -0
  42. package/arrayUtils/index.ts +5 -0
  43. package/booleanUtils/index.ts +4 -4
  44. package/cellUtils/__tests__/cellUtils.test.ts +48 -0
  45. package/cellUtils/__tests__/fixtures.ts +13 -0
  46. package/cellUtils/index.ts +45 -7
  47. package/dateUtils/index.ts +11 -0
  48. package/focusManager/index.ts +1 -1
  49. package/functionUtils/__tests__/__snapshots__/functionUtils.test.js.snap +2 -2
  50. package/functionUtils/__tests__/functionUtils.test.js +244 -248
  51. package/headersUtils/index.ts +1 -0
  52. package/index.d.ts +15 -0
  53. package/inflatedUrlUtils/index.ts +4 -4
  54. package/keyboardState/index.ts +0 -0
  55. package/localizationUtils/__tests__/localizationUtils.test.ts +78 -55
  56. package/localizationUtils/index.ts +13 -19
  57. package/logger/index.ts +1 -1
  58. package/manifestUtils/defaultManifestConfigurations/generalContent.js +6 -0
  59. package/manifestUtils/defaultManifestConfigurations/player.js +10 -1
  60. package/manifestUtils/index.js +5 -1
  61. package/manifestUtils/secondaryImage/index.js +18 -15
  62. package/modalState/index.ts +57 -0
  63. package/navigationUtils/index.ts +104 -7
  64. package/numberUtils/__tests__/isLikeNumber.test.ts +18 -0
  65. package/numberUtils/__tests__/toNumber.test.ts +2 -2
  66. package/numberUtils/index.ts +9 -18
  67. package/package.json +3 -2
  68. package/playerUtils/configurationGenerator.ts +11 -1
  69. package/pluginUtils/index.ts +20 -7
  70. package/reactHooks/autoscrolling/__tests__/useTrackCurrentAutoScrollingElement.test.ts +2 -0
  71. package/reactHooks/autoscrolling/__tests__/{useTrackedView.test.ts → useTrackedView.test.tsx} +18 -1
  72. package/reactHooks/cell-click/__tests__/index.test.js +16 -3
  73. package/reactHooks/cell-click/index.ts +14 -14
  74. package/reactHooks/feed/__tests__/useBuildPipesUrl.test.tsx +30 -70
  75. package/reactHooks/feed/__tests__/useFeedRefresh.test.tsx +6 -2
  76. package/reactHooks/feed/__tests__/useInflatedUrl.test.ts +18 -3
  77. package/reactHooks/feed/useBuildPipesUrl.ts +7 -10
  78. package/reactHooks/feed/useFeedRefresh.tsx +9 -7
  79. package/reactHooks/feed/useInflatedUrl.ts +44 -15
  80. package/reactHooks/flatList/useLoadNextPageIfNeeded.ts +16 -9
  81. package/reactHooks/index.ts +2 -0
  82. package/reactHooks/layout/__tests__/{index.test.js → index.test.tsx} +66 -59
  83. package/reactHooks/layout/getDeviceInfo/index.ts +4 -2
  84. package/reactHooks/layout/types/index.ts +2 -0
  85. package/reactHooks/layout/useDimensions/helpers/__tests__/getInitialDimensions.native.test.js +11 -16
  86. package/reactHooks/layout/useDimensions/helpers/__tests__/getInitialDimensions.test.js +12 -14
  87. package/reactHooks/layout/useDimensions/useDimensions.ts +13 -7
  88. package/reactHooks/navigation/__mocks__/index.ts +15 -0
  89. package/reactHooks/navigation/__mocks__/useNavigation.ts +7 -0
  90. package/reactHooks/navigation/__tests__/index.test.tsx +240 -81
  91. package/reactHooks/navigation/index.ts +239 -80
  92. package/reactHooks/resolvers/__tests__/useCellResolver.test.tsx +3 -1
  93. package/reactHooks/screen/__mocks__/useScreenContext.ts +3 -1
  94. package/reactHooks/screen/__tests__/useCurrentScreenData.test.tsx +21 -23
  95. package/reactHooks/screen/index.ts +4 -0
  96. package/reactHooks/screen/useScreenBackgroundColor.ts +23 -0
  97. package/reactHooks/screen/useScreenContext.ts +4 -4
  98. package/reactHooks/screen/useScreenData.ts +1 -1
  99. package/reactHooks/screen/useTargetScreenData.ts +7 -0
  100. package/reactHooks/state/useRivers.ts +3 -1
  101. package/reactHooks/useListenEventBusEvent.ts +1 -4
  102. package/reactHooks/videoModal/hooks/useVideoModalScreenData.tsx +10 -9
  103. package/reactUtils/index.ts +105 -0
  104. package/riverComponetsMeasurementProvider/index.tsx +2 -2
  105. package/stringUtils/index.ts +5 -0
  106. package/testUtils/getByTestId.ts +14 -0
  107. package/testUtils/index.tsx +38 -23
  108. package/types.ts +4 -0
  109. package/appUtils/focusManager/FocusableEvents.ts +0 -8
  110. package/appUtils/focusManager/treeDataStructure/Utils/__tests__/Utils_android.test.js +0 -1094
  111. package/appUtils/focusManager/treeDataStructure/Utils/index.android.js +0 -261
@@ -1,55 +1,59 @@
1
- const mocked_state = {
2
- remoteConfigurations: { localizations: {} },
3
- appData: {
4
- languageCode: "en",
5
- countryCode: "US",
6
- },
7
- };
8
-
9
- let mocked_locale = ["en-US"];
1
+ import { NativeModules } from "react-native";
10
2
 
11
- jest.doMock("react-redux", () => ({
12
- useSelector: jest.fn((fn) => fn(mocked_state)),
13
- }));
3
+ const settingsManagerMock = {
4
+ getConstants: jest.fn(() => ({
5
+ settings: { AppleLanguages: ["en-US"] },
6
+ })),
7
+ };
14
8
 
15
- jest.doMock("react-native", () => ({
16
- NativeModules: {
17
- SettingsManager: {
18
- getConstants: jest.fn(() => ({
19
- settings: { AppleLanguages: mocked_locale },
20
- })),
21
- },
22
- QuickBrickCommunicationModule: {
23
- languageLocale: "en",
24
- countryLocale: "US",
25
- },
26
- },
27
- }));
9
+ const qbCommunicationModuleMock = {
10
+ languageLocale: "en",
11
+ countryLocale: "US",
12
+ uiLanguage: "en-US",
13
+ };
28
14
 
29
- const { useIsRTL } = require("../index");
15
+ NativeModules.SettingsManager = settingsManagerMock;
16
+ NativeModules.QuickBrickCommunicationModule = qbCommunicationModuleMock;
30
17
 
31
18
  describe("localizationUtils", () => {
19
+ beforeEach(() => {
20
+ jest.resetModules();
21
+ });
22
+
32
23
  describe("when the app has a single locale", () => {
33
24
  describe("when the app has only a RTL language as locale", () => {
34
25
  beforeEach(() => {
35
- mocked_state.remoteConfigurations.localizations = {
36
- he: "http://url.com",
26
+ jest.resetModules();
27
+ const RN = require("react-native");
28
+
29
+ RN.NativeModules.QuickBrickCommunicationModule = {
30
+ languageLocale: "he",
31
+ countryLocale: "IL",
32
+ uiLanguage: "he-HE",
37
33
  };
38
34
  });
39
35
 
40
36
  it("useIsRTL returns true", () => {
37
+ const { useIsRTL } = require("../index");
41
38
  expect(useIsRTL()).toBe(true);
42
39
  });
43
40
  });
44
41
 
45
42
  describe("when the app has only a LTR language as locale", () => {
46
43
  beforeEach(() => {
47
- mocked_state.remoteConfigurations.localizations = {
48
- en: "http://url.com",
44
+ jest.resetModules();
45
+
46
+ const RN = require("react-native");
47
+
48
+ RN.NativeModules.QuickBrickCommunicationModule = {
49
+ languageLocale: "en",
50
+ countryLocale: "US",
51
+ uiLanguage: "en",
49
52
  };
50
53
  });
51
54
 
52
55
  it("useIsRTL returns false", () => {
56
+ const { useIsRTL } = require("../index");
53
57
  expect(useIsRTL()).toBe(false);
54
58
  });
55
59
  });
@@ -59,45 +63,56 @@ describe("localizationUtils", () => {
59
63
  describe("when device locale is in the app's locales", () => {
60
64
  describe("when device locale is LTR", () => {
61
65
  beforeEach(() => {
62
- mocked_state.remoteConfigurations.localizations = {
63
- he: "http://url.com",
64
- en: "http://url.com",
65
- };
66
+ jest.resetModules();
67
+
68
+ const RN = require("react-native");
66
69
 
67
- mocked_locale = ["en-US"];
70
+ RN.NativeModules.QuickBrickCommunicationModule = {
71
+ languageLocale: "en",
72
+ countryLocale: "US",
73
+ uiLanguage: "en-US",
74
+ };
68
75
  });
69
76
 
70
77
  it("useIsRTL returns false", () => {
78
+ const { useIsRTL } = require("../index");
71
79
  expect(useIsRTL()).toBe(false);
72
80
  });
73
81
  });
74
82
 
75
83
  describe("when device locale is RTL", () => {
76
84
  beforeEach(() => {
77
- mocked_state.remoteConfigurations.localizations = {
78
- he: "http://url.com",
79
- en: "http://url.com",
80
- };
85
+ jest.resetModules();
86
+ const RN = require("react-native");
81
87
 
82
- mocked_locale = ["he-HE"];
88
+ RN.NativeModules.QuickBrickCommunicationModule = {
89
+ languageLocale: "he",
90
+ countryLocale: "IL",
91
+ uiLanguage: "he",
92
+ };
83
93
  });
84
94
 
85
95
  it("useIsRTL returns true", () => {
96
+ const { useIsRTL } = require("../index");
86
97
  expect(useIsRTL()).toBe(true);
87
98
  });
88
99
  });
89
100
 
90
101
  describe("when a device has a secondary language in a supported language", () => {
91
102
  beforeEach(() => {
92
- mocked_state.remoteConfigurations.localizations = {
93
- en: "http://url.com",
94
- he: "http://url.com",
95
- };
103
+ jest.resetModules();
96
104
 
97
- mocked_locale = ["es-SP", "he-HE"];
105
+ const RN = require("react-native");
106
+
107
+ RN.NativeModules.QuickBrickCommunicationModule = {
108
+ languageLocale: "he",
109
+ countryLocale: "IL",
110
+ uiLanguage: "he",
111
+ };
98
112
  });
99
113
 
100
114
  it("useIsRTL returns true", () => {
115
+ const { useIsRTL } = require("../index");
101
116
  expect(useIsRTL()).toBe(true);
102
117
  });
103
118
  });
@@ -106,30 +121,38 @@ describe("localizationUtils", () => {
106
121
  describe("when device locale is not in the app's locales", () => {
107
122
  describe("when first app locale is LTR", () => {
108
123
  beforeEach(() => {
109
- mocked_state.remoteConfigurations.localizations = {
110
- en: "http://url.com",
111
- he: "http://url.com",
112
- };
124
+ jest.resetModules();
113
125
 
114
- mocked_locale = ["fr-FR"];
126
+ const RN = require("react-native");
127
+
128
+ RN.NativeModules.QuickBrickCommunicationModule = {
129
+ languageLocale: "fr",
130
+ countryLocale: "FR",
131
+ uiLanguage: "fr-FR",
132
+ };
115
133
  });
116
134
 
117
135
  it("useIsRTL returns false", () => {
136
+ const { useIsRTL } = require("../index");
118
137
  expect(useIsRTL()).toBe(false);
119
138
  });
120
139
  });
121
140
 
122
141
  describe("when first app locale is RTL", () => {
123
142
  beforeEach(() => {
124
- mocked_state.remoteConfigurations.localizations = {
125
- he: "http://url.com",
126
- en: "http://url.com",
127
- };
143
+ jest.resetModules();
128
144
 
129
- mocked_locale = ["fr-FR"];
145
+ const RN = require("react-native");
146
+
147
+ RN.NativeModules.QuickBrickCommunicationModule = {
148
+ languageLocale: "he",
149
+ countryLocale: "HE",
150
+ uiLanguage: "he",
151
+ };
130
152
  });
131
153
 
132
154
  it("useIsRTL returns true", () => {
155
+ const { useIsRTL } = require("../index");
133
156
  expect(useIsRTL()).toBe(true);
134
157
  });
135
158
  });
@@ -1,10 +1,9 @@
1
1
  import * as R from "ramda";
2
2
  import { ViewStyle } from "react-native";
3
- import { useSelector } from "react-redux";
4
3
 
5
- import { getDeviceLocales } from "./deviceLocales";
6
4
  import { useMemo } from "react";
7
5
  import { getUILanguage } from "../appUtils/localizationsHelper";
6
+ import { utilsLogger } from "../logger";
8
7
 
9
8
  export {
10
9
  getLocale,
@@ -45,31 +44,26 @@ export function useLocalizedStrings({ localizations }) {
45
44
  return result;
46
45
  }
47
46
 
48
- function getLocaleToUse(languageCodes, localizations) {
49
- const matchingLanguages = languageCodes.filter(
50
- R.contains(R.__, localizations)
51
- );
47
+ export function getIsRTL(): boolean {
48
+ const uiLanguage = getUILanguage();
49
+
50
+ if (!uiLanguage) {
51
+ utilsLogger.error({ message: "getUILanguage returned null or undefined" });
52
52
 
53
- if (matchingLanguages?.length) {
54
- return R.head(matchingLanguages);
53
+ return false;
55
54
  }
56
55
 
57
- return R.head(localizations);
58
- }
56
+ const [languageCode] = uiLanguage.split("-");
59
57
 
60
- export function getIsRTLFromLocalizations(localizations): boolean {
61
- const deviceLocales = getDeviceLocales() || [];
62
- const localeToUse = getLocaleToUse(deviceLocales, R.keys(localizations));
58
+ const lowerCaseLanguageCode = languageCode.toLocaleLowerCase();
63
59
 
64
- return R.contains(localeToUse, RTL_LOCALES);
60
+ const isRTL = R.contains(lowerCaseLanguageCode, RTL_LOCALES);
61
+
62
+ return isRTL;
65
63
  }
66
64
 
67
65
  export function useIsRTL(): boolean {
68
- const localizations = useSelector(
69
- R.path(["remoteConfigurations", "localizations"])
70
- );
71
-
72
- return getIsRTLFromLocalizations(localizations);
66
+ return getIsRTL();
73
67
  }
74
68
 
75
69
  export const applyRTLStylesIfNeeded = (
package/logger/index.ts CHANGED
@@ -72,7 +72,7 @@ const { quickBrickLogger, coreLogger, logger, logLevels, utilsLogger } =
72
72
  function useLogger(
73
73
  logger: XRayLoggerI,
74
74
  eventData: UseLoggerHookArgs,
75
- deps = []
75
+ deps: string[] = []
76
76
  ) {
77
77
  const {
78
78
  level = logLevels.verbose,
@@ -245,6 +245,12 @@ const generalContent = () => ({
245
245
  ],
246
246
  initial_value: "reloading...",
247
247
  },
248
+ {
249
+ type: "text_input",
250
+ label: "Navigation Bar Screen Title",
251
+ key: "screen_title",
252
+ initial_value: null,
253
+ },
248
254
  ],
249
255
  },
250
256
  advertising: {
@@ -41,6 +41,14 @@ function getPlayerConfiguration({ platform }) {
41
41
  label_tooltip:
42
42
  "Enable if you want to have adaptive background gradient based on audio background image.",
43
43
  },
44
+ {
45
+ key: "audio_player_background_image_query",
46
+ label: "Audio Player Image Query",
47
+ initial_value: "",
48
+ type: "text_input",
49
+ label_tooltip:
50
+ "Set the query params which control the size of the image e.g width, height. This will help to optimize the loading time, when magic background is enabled.",
51
+ },
44
52
  ],
45
53
  };
46
54
 
@@ -1655,7 +1663,8 @@ function getPlayerConfiguration({ platform }) {
1655
1663
  platform.includes("lg") ||
1656
1664
  platform.includes("samsung") ||
1657
1665
  platform.includes("android_tv") ||
1658
- platform.includes("amazon")
1666
+ platform.includes("amazon") ||
1667
+ platform.includes("vizio")
1659
1668
  ) {
1660
1669
  styles.fields.push(
1661
1670
  // Captions Menu
@@ -22,7 +22,11 @@ const {
22
22
  const { buttonKey } = require("./buttons");
23
23
  const { tvBadges } = require("./tvBadges");
24
24
  const { mobileProgressBar, tvProgressBar } = require("./progressBar");
25
- const { secondaryImage, getUpdatedSecondaryImageKeys } = require("./secondaryImage");
25
+
26
+ const {
27
+ secondaryImage,
28
+ getUpdatedSecondaryImageKeys,
29
+ } = require("./secondaryImage");
26
30
 
27
31
  module.exports = {
28
32
  fontKey,
@@ -132,29 +132,32 @@ function secondaryImage({
132
132
 
133
133
  const POSITION_OVER_IMAGE = toSnakeCase(position_over_image);
134
134
 
135
- const getUpdatedSecondaryImageKeys = (secondaryImageManifest) => secondaryImageManifest.fields.reduce((acc, item) => {
136
- const key = item.key;
135
+ const getUpdatedSecondaryImageKeys = (secondaryImageManifest) =>
136
+ secondaryImageManifest.fields.reduce((acc, item) => {
137
+ const key = item.key;
137
138
 
138
- const conditionalFields = (item.conditional_fields || []).map((field) => field.key);
139
+ const conditionalFields = (item.conditional_fields || []).map(
140
+ (field) => field.key
141
+ );
139
142
 
140
- const updatedConditionalFields = conditionalFields.reduce((acc, field) => {
141
- const updatedKey = field.replace("secondary_image_", "nested_image_");
143
+ const updatedConditionalFields = conditionalFields.reduce((acc, field) => {
144
+ const updatedKey = field.replace("secondary_image_", "nested_image_");
145
+
146
+ return {
147
+ ...acc,
148
+ [updatedKey]: field,
149
+ };
150
+ }, {});
151
+
152
+ const updatedKey = key.replace("secondary_image_", "nested_image_");
142
153
 
143
154
  return {
144
155
  ...acc,
145
- [updatedKey]: field,
156
+ ...updatedConditionalFields,
157
+ [updatedKey]: key,
146
158
  };
147
159
  }, {});
148
160
 
149
- const updatedKey = key.replace("secondary_image_", "nested_image_");
150
-
151
- return {
152
- ...acc,
153
- ...updatedConditionalFields,
154
- [updatedKey]: key,
155
- };
156
- }, {});
157
-
158
161
  module.exports = {
159
162
  secondaryImage,
160
163
  getUpdatedSecondaryImageKeys,
@@ -0,0 +1,57 @@
1
+ import { create } from "zustand";
2
+
3
+ interface ModalState {
4
+ visible: boolean;
5
+ screen: any;
6
+ options: Record<string, unknown>;
7
+ props: Record<string, unknown>;
8
+ }
9
+
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
+ }
20
+
21
+ const initialModalState: ModalState = {
22
+ visible: false,
23
+ screen: null,
24
+ options: {},
25
+ props: {},
26
+ };
27
+
28
+ export const useModalStore = create<ModalStore>((set) => ({
29
+ modalState: initialModalState,
30
+ setModalState: (newState) =>
31
+ set((state) => ({
32
+ modalState: { ...state.modalState, ...newState },
33
+ })),
34
+ openModal: ({
35
+ item,
36
+ options = {},
37
+ props = { screenData: {} },
38
+ }: OpenModalArg) =>
39
+ set({
40
+ modalState: {
41
+ visible: true,
42
+ screen: item,
43
+ options: {
44
+ animated: true,
45
+ animationType: "slide",
46
+ onShow: () => {},
47
+ presentationStyle: "overFullScreen",
48
+ transparent: true,
49
+ ...options,
50
+ onDismiss: () => set({ modalState: initialModalState }),
51
+ onRequestClose: () => set({ modalState: initialModalState }),
52
+ },
53
+ props,
54
+ },
55
+ }),
56
+ dismissModal: () => set(() => ({ modalState: initialModalState })),
57
+ }));
@@ -93,19 +93,68 @@ export function resolveNavigationPlugin({
93
93
  * @param {Object} navigator to look for navigation props
94
94
  * @param {String} category to look for in screen navigations
95
95
  * @returns {Object} props
96
+ * @deprecated use getNavigationPropsV2 instead
96
97
  */
97
98
  export function getNavigationProps({
98
- navigator: { activeRiver },
99
+ navigator,
99
100
  title = "",
100
101
  category,
101
102
  }: {
102
103
  navigator: QuickBrickAppNavigator;
103
104
  title: string;
104
105
  category: string;
105
- }): Nullable<
106
- Partial<ZappNavigation> & { selected: string; title: string; home: boolean }
107
- > {
108
- const { navigations, id: selected, home } = activeRiver;
106
+ }): {
107
+ selected: string;
108
+ title: string;
109
+ home: boolean;
110
+ styles: unknown;
111
+ assets: ZappNavBarAssets;
112
+ rules: ZappNavBarRules;
113
+ nav_items: NavBarItem[];
114
+ } | null {
115
+ const { activeRiver } = navigator;
116
+ const { navigations, id: selected, home } = activeRiver; // use useRiver hook instead
117
+
118
+ const navigation: ZappNavigation = R.find(
119
+ R.propEq("category", category),
120
+ navigations
121
+ );
122
+
123
+ if (!navigation) {
124
+ return null;
125
+ }
126
+
127
+ const { styles, assets, nav_items, rules } = navigation;
128
+
129
+ return {
130
+ selected,
131
+ title,
132
+ home,
133
+ styles,
134
+ assets: assets as ZappNavBarAssets,
135
+ nav_items: nav_items as any as NavBarItem[],
136
+ rules: rules as any as ZappNavBarRules,
137
+ };
138
+ }
139
+
140
+ export function getNavigationPropsV2({
141
+ currentRiver,
142
+ title = "",
143
+ category,
144
+ }: {
145
+ currentRiver: ZappRiver;
146
+ title: string;
147
+ category: string;
148
+ }): {
149
+ selected: string;
150
+ title: string;
151
+ home: boolean;
152
+ styles: unknown;
153
+ assets: ZappNavBarAssets;
154
+ rules: ZappNavBarRules;
155
+ nav_items: NavBarItem[];
156
+ } | null {
157
+ const { navigations, id: selected, home } = currentRiver; // use useRiver hook instead
109
158
  const navigation = R.find(R.propEq("category", category), navigations);
110
159
 
111
160
  if (!navigation) {
@@ -170,7 +219,7 @@ export function getScreenIdForContentType(payload, contentTypes) {
170
219
  export function getItemTargetId(
171
220
  item: ZappEntry | ZappRiver,
172
221
  screenType?: string, // todo: creat screen types enum
173
- contentTypes?: ZappContentTypes,
222
+ contentTypes?: ZappContentTypes | null,
174
223
  rivers?: Record<string, ZappRiver>
175
224
  ) {
176
225
  // Pipes v2 resolution
@@ -217,7 +266,7 @@ export function getTargetRoute(
217
266
  layoutVersion = undefined,
218
267
  rivers = {},
219
268
  }: {
220
- contentTypes?: ZappContentTypes;
269
+ contentTypes?: ZappContentTypes | null;
221
270
  layoutVersion?: Maybe<ZappLayoutVersions>;
222
271
  rivers?: Record<string, ZappRiver>;
223
272
  } = {}
@@ -543,3 +592,51 @@ export function isMenuDisabled(
543
592
  export function routeIsPlayerScreen(currentRoute) {
544
593
  return currentRoute?.includes("/playable");
545
594
  }
595
+
596
+ export const getNavBarProps =
597
+ (currentRiver: ZappRiver, pathname: string, title: string) => () => {
598
+ const props = getNavigationPropsV2({
599
+ currentRiver,
600
+ title,
601
+ category: "nav_bar",
602
+ });
603
+
604
+ if (props) {
605
+ return {
606
+ ...props,
607
+ id: pathname,
608
+ pathname: pathname,
609
+ };
610
+ }
611
+
612
+ return null;
613
+ };
614
+
615
+ export const findMenuPlugin = (
616
+ navigations: ZappNavigation[],
617
+ plugins
618
+ ): QuickBrickPlugin => {
619
+ return resolveNavigationPlugin({
620
+ category: "menu",
621
+ navigations,
622
+ plugins,
623
+ }) as QuickBrickPlugin;
624
+ };
625
+
626
+ export const shouldNavBarDisplayMenu = (currentRiver: ZappRiver, plugins) =>
627
+ findMenuPlugin(currentRiver.navigations, plugins)?.identifier ===
628
+ "quick_brick_side_menu" ||
629
+ currentRiver?.navigations.findIndex(
630
+ (nav) => nav.category === "nav_bar" && nav.general?.override_menu_target
631
+ ) > -1;
632
+
633
+ export const getScreenId = (
634
+ screenData: LegacyNavigationScreenData,
635
+ fallbackRiver: ZappRiver
636
+ ) => {
637
+ return screenData?.targetScreen
638
+ ? screenData?.targetScreen?.id ?? fallbackRiver.id
639
+ : "screen_id" in screenData
640
+ ? screenData.screen_id
641
+ : fallbackRiver.id;
642
+ };
@@ -7,12 +7,24 @@ describe("isLikeNumber", () => {
7
7
  expect(isLikeNumber(value)).toBe(true);
8
8
  });
9
9
 
10
+ it("value is a number", () => {
11
+ const value = 123.45;
12
+
13
+ expect(isLikeNumber(value)).toBe(true);
14
+ });
15
+
10
16
  it("value is a string as number", () => {
11
17
  const value = "123";
12
18
 
13
19
  expect(isLikeNumber(value)).toBe(true);
14
20
  });
15
21
 
22
+ it("value is a string as number", () => {
23
+ const value = "123.45";
24
+
25
+ expect(isLikeNumber(value)).toBe(true);
26
+ });
27
+
16
28
  it("value is empty string", () => {
17
29
  const value = "";
18
30
 
@@ -54,4 +66,10 @@ describe("isLikeNumber", () => {
54
66
 
55
67
  expect(isLikeNumber(value)).toBe(false);
56
68
  });
69
+
70
+ it("NaN is not a number", () => {
71
+ const value = NaN;
72
+
73
+ expect(isLikeNumber(value)).toBe(false);
74
+ });
57
75
  });
@@ -2,7 +2,7 @@ import { toNumber } from "..";
2
2
 
3
3
  describe("toNumber", () => {
4
4
  it("return number if input is number", () => {
5
- const inputs = [-1, 0, 1, 100];
5
+ const inputs = [-1, 0, 1, 100, 0.2];
6
6
  expect.assertions(inputs.length);
7
7
 
8
8
  inputs.forEach((input) => {
@@ -12,7 +12,7 @@ describe("toNumber", () => {
12
12
  });
13
13
 
14
14
  it("return number if input is string as number", () => {
15
- const inputs = ["-1", "0", "1", "100"];
15
+ const inputs = ["-1", "0", "1", "100", "0.2"];
16
16
  expect.assertions(inputs.length);
17
17
 
18
18
  inputs.forEach((input) => {
@@ -50,28 +50,19 @@ export const toFiniteNumberWithDefault = (
50
50
  return possibleNumber;
51
51
  };
52
52
 
53
- export const isLikeNumber = (value: any): boolean => {
54
- if (R.isEmpty(value)) {
55
- return false;
56
- }
57
-
58
- if (R.is(Number, value)) {
59
- return true;
60
- }
53
+ export const isLikeNumber = (value: unknown): boolean => {
54
+ const possibleNumber = toNumber(value);
61
55
 
62
- if (R.is(String, value)) {
63
- const onlyDigit = value
64
- .split("")
65
- .filter((char) =>
66
- ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"].includes(char)
67
- )
68
- .join("");
69
-
70
- return value === onlyDigit;
56
+ if (R.isNil(possibleNumber)) {
57
+ return false;
71
58
  }
72
59
 
73
- return false;
60
+ return true;
74
61
  };
75
62
 
76
63
  export const isZero = (value: unknown): boolean =>
77
64
  Object.is(value, -0) || Object.is(value, 0);
65
+
66
+ export const isMinusZero = (value: number) => {
67
+ return 1 / value === -Infinity;
68
+ };