@applicaster/zapp-react-native-utils 15.0.0-alpha.4515904047 → 15.0.0-alpha.4920595583

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 (103) 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/AnalyticPlayerListener.ts +5 -2
  5. package/analyticsUtils/README.md +1 -1
  6. package/analyticsUtils/analyticsMapper.ts +10 -2
  7. package/appUtils/HooksManager/index.ts +10 -10
  8. package/appUtils/RiverFocusManager/{index.js → index.ts} +25 -18
  9. package/appUtils/accessibilityManager/__tests__/utils.test.ts +360 -0
  10. package/appUtils/accessibilityManager/const.ts +4 -0
  11. package/appUtils/accessibilityManager/hooks.ts +20 -13
  12. package/appUtils/accessibilityManager/index.ts +28 -1
  13. package/appUtils/accessibilityManager/utils.ts +59 -8
  14. package/appUtils/focusManager/__tests__/__snapshots__/focusManager.test.js.snap +4 -0
  15. package/appUtils/focusManager/index.ios.ts +59 -3
  16. package/appUtils/focusManagerAux/utils/index.ios.ts +122 -0
  17. package/appUtils/focusManagerAux/utils/index.ts +19 -1
  18. package/appUtils/focusManagerAux/utils/utils.ios.ts +231 -0
  19. package/appUtils/keyCodes/keys/keys.web.ts +1 -4
  20. package/appUtils/orientationHelper.ts +2 -4
  21. package/appUtils/platform/platformUtils.ts +117 -18
  22. package/appUtils/playerManager/OverlayObserver/OverlaysObserver.ts +94 -4
  23. package/appUtils/playerManager/OverlayObserver/utils.ts +32 -20
  24. package/appUtils/playerManager/conts.ts +21 -0
  25. package/appUtils/playerManager/player.ts +4 -0
  26. package/appUtils/playerManager/playerNative.ts +29 -16
  27. package/appUtils/playerManager/usePlayerState.tsx +14 -2
  28. package/arrayUtils/__tests__/allTruthy.test.ts +24 -0
  29. package/arrayUtils/__tests__/anyThruthy.test.ts +24 -0
  30. package/arrayUtils/index.ts +5 -0
  31. package/cellUtils/index.ts +32 -0
  32. package/configurationUtils/__tests__/manifestKeyParser.test.ts +26 -26
  33. package/focusManager/aux/index.ts +1 -1
  34. package/manifestUtils/defaultManifestConfigurations/player.js +96 -11
  35. package/manifestUtils/keys.js +21 -0
  36. package/manifestUtils/sharedConfiguration/screenPicker/utils.js +1 -0
  37. package/manifestUtils/tvAction/container/index.js +1 -1
  38. package/navigationUtils/index.ts +34 -21
  39. package/package.json +4 -4
  40. package/playerUtils/usePlayerTTS.ts +8 -3
  41. package/pluginUtils/index.ts +4 -0
  42. package/reactHooks/advertising/index.ts +2 -2
  43. package/reactHooks/app/__tests__/useAppState.test.ts +1 -1
  44. package/reactHooks/autoscrolling/__tests__/useTrackCurrentAutoScrollingElement.test.ts +1 -1
  45. package/reactHooks/autoscrolling/__tests__/useTrackedView.test.tsx +1 -2
  46. package/reactHooks/cell-click/__tests__/index.test.js +1 -3
  47. package/reactHooks/configuration/__tests__/index.test.tsx +1 -1
  48. package/reactHooks/connection/__tests__/index.test.js +1 -1
  49. package/reactHooks/debugging/__tests__/index.test.js +4 -4
  50. package/reactHooks/device/useMemoizedIsTablet.ts +3 -3
  51. package/reactHooks/feed/__tests__/useBatchLoading.test.tsx +32 -23
  52. package/reactHooks/feed/__tests__/useBuildPipesUrl.test.tsx +19 -19
  53. package/reactHooks/feed/__tests__/useEntryScreenId.test.tsx +4 -1
  54. package/reactHooks/feed/__tests__/useFeedLoader.test.tsx +42 -30
  55. package/reactHooks/feed/__tests__/useFeedRefresh.test.tsx +1 -1
  56. package/reactHooks/feed/__tests__/{useInflatedUrl.test.ts → useInflatedUrl.test.tsx} +62 -7
  57. package/reactHooks/feed/useBatchLoading.ts +7 -1
  58. package/reactHooks/feed/useEntryScreenId.ts +2 -2
  59. package/reactHooks/feed/useFeedLoader.tsx +0 -9
  60. package/reactHooks/feed/useInflatedUrl.ts +57 -37
  61. package/reactHooks/feed/usePipesCacheReset.ts +3 -1
  62. package/reactHooks/flatList/useLoadNextPageIfNeeded.ts +13 -16
  63. package/reactHooks/hookModal/hooks/useHookModalScreenData.ts +12 -8
  64. package/reactHooks/layout/__tests__/index.test.tsx +1 -1
  65. package/reactHooks/layout/__tests__/useLayoutVersion.test.tsx +1 -1
  66. package/reactHooks/layout/index.ts +1 -1
  67. package/reactHooks/layout/useDimensions/__tests__/{useDimensions.test.ts → useDimensions.test.tsx} +105 -25
  68. package/reactHooks/layout/useDimensions/useDimensions.ts +2 -2
  69. package/reactHooks/navigation/__tests__/index.test.tsx +40 -9
  70. package/reactHooks/navigation/index.ts +27 -11
  71. package/reactHooks/navigation/useRoute.ts +11 -7
  72. package/reactHooks/player/TVSeekControlller/TVSeekController.ts +27 -10
  73. package/reactHooks/player/__tests__/useAutoSeek._test.tsx +1 -1
  74. package/reactHooks/player/__tests__/useTapSeek._test.ts +1 -1
  75. package/reactHooks/resolvers/__tests__/useCellResolver.test.tsx +1 -1
  76. package/reactHooks/resolvers/__tests__/useComponentResolver.test.tsx +1 -1
  77. package/reactHooks/resolvers/useCellResolver.ts +6 -2
  78. package/reactHooks/resolvers/useComponentResolver.ts +8 -2
  79. package/reactHooks/screen/__tests__/useCurrentScreenData.test.tsx +2 -2
  80. package/reactHooks/screen/__tests__/useScreenBackgroundColor.test.tsx +1 -1
  81. package/reactHooks/screen/__tests__/useScreenData.test.tsx +1 -1
  82. package/reactHooks/screen/__tests__/useTargetScreenData.test.tsx +12 -4
  83. package/reactHooks/screen/useTargetScreenData.ts +4 -2
  84. package/reactHooks/state/useRivers.ts +1 -1
  85. package/reactHooks/usePluginConfiguration.ts +2 -2
  86. package/reactHooks/utils/__tests__/index.test.js +1 -1
  87. package/screenState/__tests__/index.test.ts +1 -1
  88. package/searchUtils/const.ts +7 -0
  89. package/searchUtils/index.ts +3 -0
  90. package/stringUtils/index.ts +1 -1
  91. package/testUtils/index.tsx +30 -21
  92. package/utils/__tests__/mapAccum.test.ts +73 -0
  93. package/utils/__tests__/mergeRight.test.ts +48 -0
  94. package/utils/__tests__/selectors.test.ts +124 -0
  95. package/utils/index.ts +20 -0
  96. package/utils/mapAccum.ts +23 -0
  97. package/utils/mergeRight.ts +5 -0
  98. package/utils/path.ts +6 -3
  99. package/utils/pathOr.ts +5 -1
  100. package/utils/selectors.ts +46 -0
  101. package/zappFrameworkUtils/HookCallback/callbackNavigationAction.ts +90 -38
  102. package/zappFrameworkUtils/HookCallback/hookCallbackManifestExtensions.config.js +1 -1
  103. package/zappFrameworkUtils/HookCallback/useCallbackActions.ts +1 -7
@@ -0,0 +1,23 @@
1
+ import { curry } from "lodash";
2
+
3
+ /**
4
+ * A native reimplementation of Ramda's mapAccum.
5
+ *
6
+ * @template A, B, C
7
+ * @param {(acc: A, value: B) => [A, C]} fn - Function returning [newAcc, mappedValue]
8
+ * @param {A} acc - Initial accumulator
9
+ * @param {B[]} list - List to process
10
+ * @returns {[A, C[]]} - Tuple of [final accumulator, mapped array]
11
+ */
12
+ export const mapAccum = curry((fn, acc, list) => {
13
+ const result = [];
14
+ let currentAcc = acc;
15
+
16
+ for (let i = 0; i < list.length; i++) {
17
+ const [nextAcc, mapped] = fn(currentAcc, list[i]);
18
+ currentAcc = nextAcc;
19
+ result.push(mapped);
20
+ }
21
+
22
+ return [currentAcc, result];
23
+ });
@@ -0,0 +1,5 @@
1
+ import { assign } from "lodash";
2
+
3
+ export const mergeRight = (a, b) => {
4
+ return assign({}, a, b);
5
+ };
package/utils/path.ts CHANGED
@@ -1,5 +1,8 @@
1
- import { get } from "lodash";
1
+ import { pathOr } from "./pathOr";
2
2
 
3
- export const path = (route, record) => {
4
- return get(record, route, undefined);
3
+ export const path = <T = any>(
4
+ route: (string | number) | (string | number)[],
5
+ record: any
6
+ ) => {
7
+ return pathOr<T>(undefined, route, record);
5
8
  };
package/utils/pathOr.ts CHANGED
@@ -1,5 +1,9 @@
1
1
  import { get } from "lodash";
2
2
 
3
- export const pathOr = (defaultValue, path, record) => {
3
+ export const pathOr = <T = any>(
4
+ defaultValue: T,
5
+ path: (number | string) | (number | string)[],
6
+ record: any
7
+ ): T => {
4
8
  return get(record, path, defaultValue);
5
9
  };
@@ -0,0 +1,46 @@
1
+ import { get } from "lodash";
2
+
3
+ export type Selector<T> = (state: any) => T;
4
+
5
+ /**
6
+ * Creates a selector for filtering plugins by path
7
+ * @param path - Path to check in plugin. Can be a dot notation string or array
8
+ * @returns A selector function that returns matching plugins
9
+ */
10
+ export const createPluginsByPathSelector = (
11
+ path: string | string[]
12
+ ): Selector<any[]> => {
13
+ return (state: any) => {
14
+ const plugins = state.plugins || [];
15
+
16
+ return plugins.filter((plugin: any) => get(plugin, path));
17
+ };
18
+ };
19
+
20
+ /**
21
+ * Creates a selector for filtering plugins by module path
22
+ * @param modulePath - Module path to check in plugin (e.g., "urlScheme", "player")
23
+ * @returns A selector function that returns plugins with specified module
24
+ */
25
+ export const createPluginsByModuleSelector = (
26
+ modulePath: string
27
+ ): Selector<any[]> => {
28
+ return createPluginsByPathSelector(["module", modulePath]);
29
+ };
30
+
31
+ /**
32
+ * Creates a selector that combines multiple plugin selectors
33
+ * @param selectors - Array of plugin selectors to combine
34
+ * @returns A selector function that returns plugins matching all conditions
35
+ */
36
+ export const combinePluginSelectors = (
37
+ ...selectors: Selector<any[]>[]
38
+ ): Selector<any[]> => {
39
+ return (state: any) => {
40
+ return selectors.reduce((filtered, selector) => {
41
+ const selected = selector(state);
42
+
43
+ return filtered.filter((plugin) => selected.includes(plugin));
44
+ }, state.plugins || []);
45
+ };
46
+ };
@@ -1,6 +1,6 @@
1
1
  import { useNavigation, useRivers, useScreenContext } from "../../reactHooks";
2
2
  import { createLogger } from "../../logger";
3
- import { useCallback, useMemo } from "react";
3
+ import { useCallback, useMemo, useRef, useEffect } from "react";
4
4
 
5
5
  export enum NavigationCallbackOptions {
6
6
  DEFAULT = "default",
@@ -15,8 +15,9 @@ export enum ResultType {
15
15
  }
16
16
 
17
17
  export type CallbackResult = hookCallbackArgs & {
18
- options: {
18
+ options?: {
19
19
  resultType?: ResultType;
20
+ navigator?: QuickBrickAppNavigator;
20
21
  };
21
22
  };
22
23
 
@@ -36,7 +37,7 @@ type General = Record<string, unknown>;
36
37
 
37
38
  const LogPrefix = "useCallbackNavigationAction:";
38
39
 
39
- const { log_info, log_verbose, log_error } = createLogger({
40
+ const { log_info, log_verbose, log_debug } = createLogger({
40
41
  subsystem: "hook-navigation-callback",
41
42
  });
42
43
 
@@ -45,7 +46,7 @@ const legacyMappingKeys = {
45
46
  actionType: "login_completion_action",
46
47
  targetScreen: "navigate_to_login_screen",
47
48
  },
48
- "quick-brick-user-account-ui-component": {
49
+ "quick-brick-user-account-ui-component.login": {
49
50
  actionType: "callbackAction",
50
51
  },
51
52
  "quick-brick-login-multi-login-providers.login": {
@@ -56,23 +57,40 @@ const legacyMappingKeys = {
56
57
  actionType: "logout_completion_action",
57
58
  targetScreen: "navigate_to_logout_screen",
58
59
  },
60
+ "quick-brick-storefront": {
61
+ actionType: "purchase_completion_action",
62
+ targetScreen: "navigate_to_screen_after_purchase",
63
+ },
64
+ "zapp_login_plugin_oauth_tv_2_0.login": {
65
+ actionType: "login_completion_action",
66
+ targetScreen: "navigate_to_login_screen",
67
+ },
68
+ "zapp_login_plugin_oauth_tv_2_0.logout": {
69
+ actionType: "logout_completion_action",
70
+ targetScreen: "navigate_to_logout_screen",
71
+ },
59
72
  };
60
73
 
61
- const isNonEmptyString = (v: unknown): v is string =>
62
- typeof v === "string" && v.trim().length > 0;
63
-
64
- const NAV_ACTIONS = Object.values(NavigationCallbackOptions) as string[];
74
+ const NAV_ACTIONS = (
75
+ Object.values(NavigationCallbackOptions) as string[]
76
+ ).filter((value) => value !== NavigationCallbackOptions.DEFAULT);
65
77
 
66
78
  const isNavAction = (v: unknown): v is NavigationCallbackOptions =>
67
- typeof v === "string" && NAV_ACTIONS.includes(v.trim());
79
+ typeof v === "string" && NAV_ACTIONS.includes(v);
68
80
 
69
81
  export const getNavigationKeys = (
70
82
  item?: ZappUIComponent | ZappRiver,
71
- resultType: ResultType = null
83
+ resultType: ResultType | null = null
72
84
  ): NavKeys => {
73
85
  const general = (item?.general ?? {}) as General;
74
- const pluginIdentifier = item?.type ?? "";
75
- const legacy = legacyMappingKeys[pluginIdentifier] ?? {};
86
+
87
+ const pluginIdentifier =
88
+ (item as any).identifier ?? item?.type ?? item?.component_type ?? "";
89
+
90
+ const legacy =
91
+ legacyMappingKeys[`${pluginIdentifier}.${resultType}`] ??
92
+ legacyMappingKeys[pluginIdentifier] ??
93
+ {};
76
94
 
77
95
  const actionKey = resultType
78
96
  ? `${resultType}_${CALLBACK_NAVIGATION_KEY}`
@@ -82,29 +100,27 @@ export const getNavigationKeys = (
82
100
  (general as General)[actionKey] ??
83
101
  (legacy.actionType ? (general as General)[legacy.actionType] : undefined);
84
102
 
85
- let action: NavigationCallbackOptions | null = null;
86
-
87
- if (isNonEmptyString(rawAction)) {
88
- const trimmed = rawAction.trim();
89
- action = isNavAction(trimmed) ? trimmed : null;
90
- }
103
+ const action: NavigationCallbackOptions | null = isNavAction(rawAction)
104
+ ? rawAction
105
+ : null;
91
106
 
92
107
  if (!action) return null;
93
108
 
94
109
  let targetScreenId: string | null = null;
95
110
 
96
111
  if (action === NavigationCallbackOptions.GO_TO_SCREEN) {
112
+ const screenKey = resultType
113
+ ? `${resultType}_${CALLBACK_NAVIGATION_GO_TO_SCREEN_KEY}`
114
+ : CALLBACK_NAVIGATION_GO_TO_SCREEN_KEY;
115
+
97
116
  const screenId: string | null =
98
- ((general as General)[CALLBACK_NAVIGATION_GO_TO_SCREEN_KEY] as string) ??
117
+ ((general as General)[screenKey] as string) ??
99
118
  (legacy.targetScreen
100
119
  ? ((general as General)[legacy.targetScreen] as string)
101
120
  : undefined);
102
121
 
103
122
  if (screenId) {
104
- const trimmedTargetScreenId = screenId.trim();
105
-
106
- targetScreenId =
107
- trimmedTargetScreenId.length > 0 ? trimmedTargetScreenId : null;
123
+ targetScreenId = screenId.length > 0 ? screenId : null;
108
124
  }
109
125
  }
110
126
 
@@ -113,12 +129,20 @@ export const getNavigationKeys = (
113
129
 
114
130
  export const useCallbackNavigationAction = (
115
131
  item?: ZappUIComponent | ZappRiver
116
- ): ((args: CallbackResult) => void | undefined) => {
132
+ ): ((
133
+ args: CallbackResult,
134
+ hookCallback?: hookCallback
135
+ ) => void | undefined) => {
117
136
  const navigation = useNavigation();
118
137
  const rivers = useRivers();
119
- const enabled = Boolean(item?.general?.[CALLBACK_NAVIGATION_KEY]);
120
138
  const screenContext = useScreenContext();
121
139
 
140
+ const navigationRef = useRef(navigation);
141
+
142
+ useEffect(() => {
143
+ navigationRef.current = navigation;
144
+ }, [navigation]);
145
+
122
146
  const overrideCallbackFromComponent = useMemo(() => {
123
147
  log_verbose(`${LogPrefix}: overridden callbackAction by component`);
124
148
 
@@ -131,28 +155,56 @@ export const useCallbackNavigationAction = (
131
155
  }
132
156
 
133
157
  const callbackAction = useCallback<hookCallback>(
134
- (args: CallbackResult) => {
158
+ (args: CallbackResult, hookCallback: hookCallback = null) => {
135
159
  if (!args.success) {
136
- log_error(`${LogPrefix} callback called with no success`);
160
+ log_debug(
161
+ `${LogPrefix} callback called with no success, use original callback`
162
+ );
163
+
164
+ hookCallback?.(args);
137
165
 
138
166
  return;
139
167
  }
140
168
 
141
169
  if (args.cancelled) {
142
- log_error(`${LogPrefix} callback called but cancelled`);
170
+ log_debug(
171
+ `${LogPrefix} callback called but cancelled, use original callback`
172
+ );
173
+
174
+ hookCallback?.(args);
143
175
 
144
176
  return;
145
177
  }
146
178
 
147
- const data = getNavigationKeys(item, args.options?.resultType ?? null) ?? {
148
- action: NavigationCallbackOptions.DEFAULT,
149
- targetScreenId: null,
150
- };
179
+ let data = getNavigationKeys(item, args.options?.resultType ?? null);
180
+
181
+ if (!data) {
182
+ const isScreen = !hookCallback;
183
+
184
+ if (isScreen && args.options?.resultType === ResultType.login) {
185
+ log_debug(
186
+ `${LogPrefix} no navigation data found, applying GO BACK for login screen`
187
+ );
188
+
189
+ data = {
190
+ action: NavigationCallbackOptions.GO_BACK,
191
+ targetScreenId: null,
192
+ };
193
+ } else {
194
+ hookCallback?.(args);
195
+
196
+ return;
197
+ }
198
+ }
199
+
200
+ hookCallback?.({ ...args, success: false, cancelled: true });
201
+ const currentNavigation = navigationRef.current;
151
202
 
152
203
  switch (data.action) {
153
204
  case NavigationCallbackOptions.GO_BACK: {
154
- if (navigation.canGoBack()) {
155
- navigation.goBack();
205
+ if (currentNavigation.canGoBack()) {
206
+ currentNavigation.goBack();
207
+
156
208
  log_info(`${LogPrefix} performing 'GO BACK' action`);
157
209
  } else {
158
210
  log_info(`${LogPrefix} cannot perform 'GO BACK' action — ignoring`);
@@ -162,7 +214,7 @@ export const useCallbackNavigationAction = (
162
214
  }
163
215
 
164
216
  case NavigationCallbackOptions.GO_HOME: {
165
- navigation.goHome();
217
+ currentNavigation.goHome();
166
218
  log_info(`${LogPrefix} performing 'GO HOME' action`);
167
219
  break;
168
220
  }
@@ -178,7 +230,7 @@ export const useCallbackNavigationAction = (
178
230
  const screen = rivers[screenId];
179
231
 
180
232
  if (screen) {
181
- navigation.replace(screen);
233
+ currentNavigation.replace(screen);
182
234
 
183
235
  log_info(
184
236
  `${LogPrefix} performing 'GO TO SCREEN' action to screen: ${screenId}`
@@ -195,8 +247,8 @@ export const useCallbackNavigationAction = (
195
247
  }
196
248
  }
197
249
  },
198
- [item, navigation, rivers]
250
+ [item, rivers]
199
251
  );
200
252
 
201
- return enabled ? overrideCallbackFromComponent || callbackAction : undefined;
253
+ return overrideCallbackFromComponent || callbackAction;
202
254
  };
@@ -20,7 +20,7 @@ const callbackKeyPrefix = (key, prefix, keySeparator = "_") =>
20
20
 
21
21
  const extendManifestWithHookCallback = (prefix = null) => ({
22
22
  group: true,
23
- label: "CallBack Navigation",
23
+ label: `CallBack Navigation: ${prefix}`,
24
24
  folded: true,
25
25
  fields: [
26
26
  {
@@ -12,13 +12,7 @@ export const useCallbackActions = (
12
12
 
13
13
  return useCallback(
14
14
  async (data: CallbackResult) => {
15
- if (navigationAction && data.success) {
16
- hookCallback?.({ ...data, success: false, cancelled: true });
17
-
18
- navigationAction(data);
19
- } else {
20
- hookCallback?.(data);
21
- }
15
+ navigationAction(data, hookCallback);
22
16
  },
23
17
  [navigationAction, hookCallback]
24
18
  );