@applicaster/zapp-react-native-utils 13.0.0-alpha.6095951301 → 13.0.0-alpha.6234681660

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 (83) hide show
  1. package/README.md +0 -10
  2. package/actionsExecutor/ActionExecutor.ts +16 -9
  3. package/actionsExecutor/ActionExecutorContext.tsx +136 -9
  4. package/analyticsUtils/currentScreenProperities.ts +6 -4
  5. package/appUtils/HooksManager/Hook.ts +2 -2
  6. package/appUtils/HooksManager/index.ts +1 -1
  7. package/appUtils/HooksManager/types.ts +5 -2
  8. package/appUtils/contextKeysManager/contextResolver.ts +7 -14
  9. package/appUtils/contextKeysManager/index.ts +2 -2
  10. package/appUtils/contextKeysManager/utils/index.ts +2 -1
  11. package/appUtils/focusManager/__tests__/__snapshots__/focusManager.test.js.snap +1 -0
  12. package/appUtils/focusManager/index.ts +11 -12
  13. package/appUtils/focusManagerAux/utils/index.ts +4 -3
  14. package/appUtils/keyCodes/index.ts +11 -7
  15. package/appUtils/orientationHelper.ts +11 -13
  16. package/appUtils/platform/const.ts +14 -0
  17. package/appUtils/platform/platformUtils.ts +47 -4
  18. package/appUtils/playerManager/index.ts +1 -1
  19. package/appUtils/playerManager/player.ts +26 -14
  20. package/appUtils/playerManager/playerNative.ts +18 -3
  21. package/equalUtils/__tests__/isEqual/combination.test.ts +263 -0
  22. package/equalUtils/index.ts +49 -30
  23. package/focusManager/FocusManager.ts +11 -1
  24. package/focusManager/index.ts +49 -4
  25. package/functionUtils/index.ts +21 -8
  26. package/idleUtils/__tests__/withTimeout$.test.ts +37 -0
  27. package/idleUtils/index.ts +1 -1
  28. package/idleUtils/withTimeout.ts +15 -2
  29. package/logger/const.ts +9 -67
  30. package/manifestUtils/__tests__/createConfig.test.js +0 -2
  31. package/manifestUtils/defaultManifestConfigurations/player.js +8 -0
  32. package/manifestUtils/fonts/index.js +5 -6
  33. package/manifestUtils/sharedConfiguration/screenPicker/__tests__/utils.test.js +304 -0
  34. package/manifestUtils/sharedConfiguration/screenPicker/stylesFields.js +875 -0
  35. package/manifestUtils/sharedConfiguration/screenPicker/utils.js +130 -0
  36. package/navigationUtils/index.ts +3 -3
  37. package/numberUtils/index.ts +7 -5
  38. package/package.json +4 -10
  39. package/playerUtils/configurationGenerator.ts +8 -0
  40. package/reactHooks/autoscrolling/__tests__/useTrackedView.test.tsx +5 -7
  41. package/reactHooks/autoscrolling/useTrackedView.ts +12 -1
  42. package/reactHooks/cell-click/__tests__/index.test.js +5 -0
  43. package/reactHooks/cell-click/index.ts +7 -1
  44. package/reactHooks/feed/useFeedLoader.tsx +5 -3
  45. package/reactHooks/hookModal/hooks/useHookModalScreenData.ts +39 -0
  46. package/reactHooks/layout/useDimensions/helpers/__tests__/getInitialDimensions.test.js +1 -1
  47. package/reactHooks/layout/useDimensions/useDimensions.ts +8 -0
  48. package/reactHooks/navigation/__mocks__/useNavigation.ts +3 -0
  49. package/reactHooks/navigation/__tests__/index.test.tsx +6 -17
  50. package/reactHooks/navigation/index.ts +13 -23
  51. package/reactHooks/navigation/useGetTabBarHeight.ts +1 -3
  52. package/reactHooks/navigation/useProfilerLogging.ts +15 -0
  53. package/reactHooks/navigation/useRoute.ts +2 -4
  54. package/reactHooks/state/useRefWithInitialValue.ts +14 -0
  55. package/reactHooks/state/useStateFromSubscribe.ts +23 -0
  56. package/reactHooks/usePluginConfiguration.ts +1 -1
  57. package/reactHooks/useSubscriberFor.ts +4 -3
  58. package/reactUtils/__tests__/__snapshots__/reactUtilsHelpers.test.js.snap +16 -4
  59. package/reactUtils/__tests__/reactUtils.test.js +1 -19
  60. package/reactUtils/__tests__/reactUtilsHelpers.test.js +72 -71
  61. package/reactUtils/createContext/__tests__/__snapshots__/helpers.test.js.snap +6 -72
  62. package/reactUtils/createContext/__tests__/__snapshots__/provider.test.js.snap +3 -28
  63. package/reactUtils/createContext/__tests__/__snapshots__/withConsumer.test.js.snap +3 -4
  64. package/reactUtils/createContext/__tests__/__snapshots__/withProvider.test.js.snap +7 -3
  65. package/reactUtils/createContext/__tests__/helpers.test.js +107 -121
  66. package/reactUtils/createContext/__tests__/{index.test.js → index.test.ts} +2 -2
  67. package/reactUtils/createContext/__tests__/provider.test.js +4 -6
  68. package/reactUtils/createContext/__tests__/withConsumer.test.js +12 -12
  69. package/reactUtils/createContext/__tests__/withProvider.test.js +4 -4
  70. package/reactUtils/createContext/helpers.ts +6 -1
  71. package/reactUtils/createContext/index.ts +11 -25
  72. package/reactUtils/index.ts +0 -11
  73. package/screenState/index.ts +24 -10
  74. package/services/js2native.ts +673 -0
  75. package/testUtils/index.tsx +0 -10
  76. package/theme/index.ts +1 -1
  77. package/time/BackgroundTimer.ts +55 -0
  78. package/time/Timer.ts +9 -6
  79. package/types.ts +1 -0
  80. package/zappFrameworkUtils/loginPluginUtils.ts +6 -2
  81. package/zappFrameworkUtils/presentPluginOneTime.ts +2 -3
  82. package/reactUtils/createContext/__tests__/index-no-react.test.js +0 -27
  83. /package/reactUtils/createContext/__tests__/__snapshots__/{index.test.js.snap → index.test.ts.snap} +0 -0
package/README.md CHANGED
@@ -376,16 +376,6 @@ useEffect(() => {
376
376
  }, []);
377
377
  ```
378
378
 
379
- ### testUtils
380
-
381
- `@applicaster/zapp-react-native-utils/testUtils`
382
-
383
- - `testIDEquals: (testId: any) => boolean | { width: number, height: number }` - Function to be used in tandem with enzyme findWhere
384
-
385
- ```javascript
386
- wrapper.findWhere(testIDEquals("text"));
387
- ```
388
-
389
379
  ### appUtils - contextKeysManager
390
380
 
391
381
  `@applicaster/zapp-react-native-utils/appUtils/contextKeyManager`
@@ -17,9 +17,10 @@ class ActionExecutor {
17
17
 
18
18
  handleAction = async (
19
19
  action: ActionType,
20
- entry: ZappEntry = null
20
+ context?: Record<string, any>
21
21
  ): Promise<ActionResult> => {
22
22
  const handler = this.registeredActions[action.type];
23
+ const entry = context?.entry as ZappEntry;
23
24
 
24
25
  if (!handler) {
25
26
  log_error(
@@ -38,11 +39,11 @@ class ActionExecutor {
38
39
  );
39
40
 
40
41
  try {
41
- return handler(action, entry);
42
+ return handler(action, context);
42
43
  } catch (error) {
43
44
  log_error(
44
45
  `handleAction: error handling action type: ${action.type}, message: ${error.message}`,
45
- { action, entry, error }
46
+ { action, context, error }
46
47
  );
47
48
 
48
49
  throw error;
@@ -51,11 +52,11 @@ class ActionExecutor {
51
52
 
52
53
  handleActions = async (
53
54
  actionTypes: ActionType[],
54
- entry: ZappEntry = null
55
+ context?: Record<string, any>
55
56
  ): Promise<ActionResult> => {
56
57
  for (const action of actionTypes) {
57
58
  // TODO: Handle action result error
58
- const result = await this.handleAction(action, entry);
59
+ const result = await this.handleAction(action, context);
59
60
 
60
61
  if (result === ActionResult.Cancel) {
61
62
  log_info(`handleActions: action: ${action.type} canceled`);
@@ -67,7 +68,10 @@ class ActionExecutor {
67
68
  return ActionResult.Success;
68
69
  };
69
70
 
70
- handleEntryActions = async (entry: ZappEntry): Promise<ActionResult> => {
71
+ handleEntryActions = async (
72
+ entry: ZappEntry,
73
+ context?: Record<string, any>
74
+ ): Promise<ActionResult> => {
71
75
  const tapActions = entry.extensions?.tap_actions?.actions;
72
76
 
73
77
  if (!tapActions) {
@@ -77,7 +81,7 @@ class ActionExecutor {
77
81
  if (!Array.isArray(tapActions)) {
78
82
  log_error(
79
83
  `handleEntryActions: tapActions is not an array for id: ${entry.id} title: ${entry.title}`,
80
- { entry }
84
+ { context, entry }
81
85
  );
82
86
 
83
87
  return;
@@ -87,7 +91,7 @@ class ActionExecutor {
87
91
  return;
88
92
  }
89
93
 
90
- await this.handleActions(tapActions, entry);
94
+ await this.handleActions(tapActions, { ...context, entry });
91
95
  };
92
96
 
93
97
  unregisterAction = (actionType: string) => {
@@ -96,7 +100,10 @@ class ActionExecutor {
96
100
 
97
101
  registerAction = (
98
102
  type: string,
99
- handler: (action: ActionType, entry?: ZappEntry) => Promise<ActionResult>
103
+ handler: (
104
+ action: ActionType,
105
+ context?: Record<string, any>
106
+ ) => Promise<ActionResult>
100
107
  ) => {
101
108
  if (this.registeredActions[type]) {
102
109
  log_error(`registerAction: action type: ${type} already registered`);
@@ -1,6 +1,6 @@
1
1
  /// <reference types="@applicaster/applicaster-types" />
2
2
  import { localStorage } from "@applicaster/zapp-react-native-bridge/ZappStorage/LocalStorage";
3
- import React, { createContext, useMemo } from "react";
3
+ import React, { createContext, useEffect, useMemo } from "react";
4
4
  import {
5
5
  actionExecutor as _actionExecutor,
6
6
  ActionResult,
@@ -13,12 +13,21 @@ import { createCloudEvent, sendCloudEvent } from "../cloudEventsUtils";
13
13
  import { createLogger } from "../logger";
14
14
  import { StorageMultiSelectProvider } from "@applicaster/zapp-react-native-bridge/ZappStorage/StorageMultiSelectProvider";
15
15
  import { ACTIVE_LAYOUT_ID_STORAGE_KEY } from "@applicaster/quick-brick-core/App/remoteContextReloader/consts";
16
+ import { appStore } from "@applicaster/zapp-react-native-redux/AppStore";
17
+ import { loadPipesData } from "@applicaster/zapp-react-native-redux/ZappPipes";
16
18
  import {
17
19
  EntryResolver,
18
20
  resolveObjectValues,
19
21
  } from "../appUtils/contextKeysManager/contextResolver";
22
+ import { useNavigation } from "../reactHooks";
23
+ import { get } from "lodash";
20
24
 
21
- const { log_error, log_info } = createLogger({
25
+ import {
26
+ useContentTypes,
27
+ usePickFromState,
28
+ } from "@applicaster/zapp-react-native-redux/hooks";
29
+
30
+ export const { log_error, log_info, log_debug } = createLogger({
22
31
  subsystem: "ActionExecutorContext",
23
32
  category: "General",
24
33
  });
@@ -26,20 +35,45 @@ const { log_error, log_info } = createLogger({
26
35
  type ActionExecutorContextType = {
27
36
  registerAction: (
28
37
  type: string,
29
- handler: (action: ActionType, entry: ZappEntry) => Promise<ActionResult>
38
+ handler: (
39
+ action: ActionType,
40
+ context?: Record<string, any>
41
+ ) => Promise<ActionResult>
30
42
  ) => void;
31
43
  unregisterAction: (type: string) => void;
32
- handleAction: (action: ActionType, entry: ZappEntry) => Promise<ActionResult>;
44
+ handleAction: (
45
+ action: ActionType,
46
+ context?: Record<string, any>
47
+ ) => Promise<ActionResult>;
33
48
  handleActions: (
34
49
  actions: ActionType[],
35
- entry: ZappEntry
50
+ context: Record<string, any>
51
+ ) => Promise<ActionResult>;
52
+ handleEntryActions: (
53
+ entry: ZappEntry,
54
+ context?: Record<string, any>
36
55
  ) => Promise<ActionResult>;
37
- handleEntryActions: (entry: ZappEntry) => Promise<ActionResult>;
38
56
  };
39
57
  type Props = {
40
58
  children: React.ReactNode;
41
59
  };
42
60
 
61
+ function findParentComponent(
62
+ childId: string,
63
+ parent: ZappRiver | ZappUIComponent
64
+ ): ZappRiver | ZappUIComponent | null {
65
+ for (const child of parent.ui_components) {
66
+ if (child.id === childId) return parent;
67
+
68
+ if (child.ui_components) {
69
+ const found = findParentComponent(childId, child);
70
+ if (found) return found;
71
+ }
72
+ }
73
+
74
+ return null;
75
+ }
76
+
43
77
  const prepareDefaultActions = (actionExecutor) => {
44
78
  actionExecutor.registerAction("localStorageSet", async (action) => {
45
79
  const namespaces = action.options.content;
@@ -49,6 +83,33 @@ const prepareDefaultActions = (actionExecutor) => {
49
83
  return ActionResult.Success;
50
84
  });
51
85
 
86
+ actionExecutor.registerAction(
87
+ "refreshComponent",
88
+ async (_action, context) => {
89
+ const dispatch = appStore.getDispatch();
90
+
91
+ const dataSource =
92
+ context?.component?.data?.source ||
93
+ findParentComponent(context?.component.id, context?.screenData)?.data
94
+ ?.source;
95
+
96
+ log_info(`handleAction: refreshComponent for dataSource:${dataSource}`);
97
+
98
+ // TODO: In theory we should wait callback to complete, before completing the action, but now it's not needed
99
+ // TODO: handle focused item removal
100
+ dispatch(
101
+ loadPipesData(dataSource, {
102
+ silentRefresh: false,
103
+ clearCache: true,
104
+ callback: (_data) => {},
105
+ riverId: context?.screenData?.id,
106
+ })
107
+ );
108
+
109
+ return ActionResult.Success;
110
+ }
111
+ );
112
+
52
113
  actionExecutor.registerAction("switchLayout", async (action) => {
53
114
  log_info("handleAction: switchLayout event");
54
115
 
@@ -84,10 +145,11 @@ const prepareDefaultActions = (actionExecutor) => {
84
145
  return confirmationPromise;
85
146
  });
86
147
 
87
- actionExecutor.registerAction("sendCloudEvent", async (action, entry) => {
148
+ actionExecutor.registerAction("sendCloudEvent", async (action, context) => {
88
149
  try {
89
150
  const options = action.options;
90
151
 
152
+ const entry = context?.entry || {};
91
153
  const entryResolver = new EntryResolver(entry);
92
154
 
93
155
  const data =
@@ -128,9 +190,33 @@ const prepareDefaultActions = (actionExecutor) => {
128
190
 
129
191
  actionExecutor.registerAction(
130
192
  "localStorageToggleFlag",
131
- async (action: ActionType, entry?: ZappEntry): Promise<ActionResult> => {
193
+ async (
194
+ action: ActionType,
195
+ context?: Record<string, any>
196
+ ): Promise<ActionResult> => {
197
+ if (!context) {
198
+ log_error(
199
+ "handleAction: localStorageToggleFlag action missing context"
200
+ );
201
+
202
+ return ActionResult.Error;
203
+ }
204
+
205
+ const entry = context?.entry as ZappEntry;
206
+
207
+ if (!entry) {
208
+ log_error(
209
+ "handleAction: localStorageToggleFlag action missing entry. Entry is required to get the tag."
210
+ );
211
+
212
+ return ActionResult.Error;
213
+ }
214
+
215
+ const tag = action.options?.selector
216
+ ? get(entry, action.options.selector)
217
+ : (entry.extensions?.tag ?? entry.id);
218
+
132
219
  const keyNamespace = action.options?.key;
133
- const tag = entry?.extensions?.tag;
134
220
 
135
221
  if (keyNamespace && tag) {
136
222
  const multiSelectProvider =
@@ -171,6 +257,10 @@ export function withActionExecutor(Component) {
171
257
  prepareDefaultActions(_actionExecutor);
172
258
 
173
259
  return function ActionExecutorComponent(props: Props) {
260
+ const navigator = useNavigation();
261
+ const { rivers } = usePickFromState(["rivers"]);
262
+ const contentTypes = useContentTypes();
263
+
174
264
  const handlers = useMemo(() => {
175
265
  return {
176
266
  unregisterAction: _actionExecutor.unregisterAction,
@@ -181,6 +271,43 @@ export function withActionExecutor(Component) {
181
271
  };
182
272
  }, []);
183
273
 
274
+ useEffect(() => {
275
+ return _actionExecutor.registerAction(
276
+ "navigateToScreen",
277
+ async (action: ActionType, _context?: Record<string, any>) => {
278
+ const screenType = action.options?.typeMapping;
279
+
280
+ if (!screenType) {
281
+ log_error("navigateToScreen: typeMapping option is missing");
282
+
283
+ return ActionResult.Error;
284
+ }
285
+
286
+ const screenId = contentTypes?.[screenType]?.screen_id || null;
287
+
288
+ if (!screenId) {
289
+ log_error(
290
+ `navigateToScreen: can not resolve screen type mapping: ${screenType}`
291
+ );
292
+
293
+ return ActionResult.Error;
294
+ }
295
+
296
+ const river = rivers[screenId];
297
+
298
+ if (!river) {
299
+ log_error("navigateToScreen: can not resolve river");
300
+
301
+ return ActionResult.Error;
302
+ }
303
+
304
+ navigator.replace(river);
305
+
306
+ return ActionResult.Success;
307
+ }
308
+ );
309
+ }, [navigator, rivers, contentTypes]);
310
+
184
311
  return (
185
312
  <ActionExecutorContext.Provider value={handlers}>
186
313
  <Component {...props} />
@@ -72,12 +72,14 @@ const mappedScreenPropertiesScreen = (
72
72
  screenData
73
73
  ): AnalyticsScreenProperties => {
74
74
  return {
75
- screen_name: screenData?.targetScreen?.name,
75
+ screen_name: screenData?.targetScreen?.name || screenData?.name,
76
76
  screen_entry_title: screenData?.title,
77
77
  screen_entry_id: R.isNil(screenData?.type) ? null : screenData?.id,
78
- screen_layout_id: screenData?.targetScreen?.id,
79
- screen_type: screenData?.targetScreen?.type,
80
- home_screen: screenData?.targetScreen?.home,
78
+ screen_layout_id: screenData?.targetScreen?.id || screenData?.id,
79
+ screen_type: screenData?.targetScreen?.type || screenData?.type,
80
+ home_screen: !R.isNil(screenData?.targetScreen?.home)
81
+ ? screenData?.targetScreen?.home
82
+ : screenData?.home,
81
83
  };
82
84
  };
83
85
 
@@ -16,7 +16,7 @@ const BASE_HOOK_PROPERTIES = ["screen_id", "identifier", "weight"];
16
16
  * @returns {number} index
17
17
  */
18
18
  const hookState: (
19
- arg0: typeof HOOKS_EVENTS[keyof typeof HOOKS_EVENTS]
19
+ arg0: (typeof HOOKS_EVENTS)[keyof typeof HOOKS_EVENTS]
20
20
  ) => number = R.indexOf(R.__, R.values(HOOKS_EVENTS));
21
21
 
22
22
  /**
@@ -62,7 +62,7 @@ export class Hook implements HookInterface {
62
62
  * @param {Array<Any>} args variadic arguments to invoke the handler with
63
63
  */
64
64
  setStateAndNotify(
65
- event: typeof HOOKS_EVENTS[keyof typeof HOOKS_EVENTS],
65
+ event: (typeof HOOKS_EVENTS)[keyof typeof HOOKS_EVENTS],
66
66
  ...args
67
67
  ) {
68
68
  this.state = hookState(event);
@@ -84,7 +84,7 @@ export function HooksManager({
84
84
  plugins,
85
85
  startUpHooksData = {},
86
86
  }: HookManagerArgs): HookManager {
87
- hooksManagerLogger.addContext({ targetScreen });
87
+ hooksManagerLogger.addContext({ targetScreenId: targetScreen.id });
88
88
 
89
89
  function logHookEvent(func, message, data) {
90
90
  func({
@@ -4,6 +4,8 @@ import { HOOKS_EVENTS } from "./constants";
4
4
  export interface HookConfiguration {}
5
5
 
6
6
  /* existing Hook Plugn props: sample */
7
+
8
+ /*
7
9
  interface _HookModulePlugin {
8
10
  Component:
9
11
  | React.FC<HookPluginProps>
@@ -23,6 +25,7 @@ interface _HookModulePlugin {
23
25
  presentUI: (payload?: HookPluginProps["payload"]) => void
24
26
  ) => any;
25
27
  }
28
+ */
26
29
 
27
30
  //* Derived from usage */
28
31
  export interface HookModule {
@@ -100,7 +103,7 @@ export interface Hook<T extends HookModule = HookModule> {
100
103
  identifier: string;
101
104
  configuration: T["configuration"];
102
105
  setStateAndNotify(
103
- event: typeof HOOKS_EVENTS[keyof typeof HOOKS_EVENTS],
106
+ event: (typeof HOOKS_EVENTS)[keyof typeof HOOKS_EVENTS],
104
107
  opts: {
105
108
  error?: typeof Error;
106
109
  route?: string;
@@ -109,7 +112,7 @@ export interface Hook<T extends HookModule = HookModule> {
109
112
  }
110
113
  );
111
114
  general?: {
112
- transition_type: typeof HOOKS_EVENTS[keyof typeof HOOKS_EVENTS];
115
+ transition_type: (typeof HOOKS_EVENTS)[keyof typeof HOOKS_EVENTS];
113
116
  allow_screen_plugin_presentation: boolean;
114
117
  is_flow_blocker: boolean;
115
118
  };
@@ -1,12 +1,6 @@
1
- import { createLogger } from "../../logger";
2
1
  import { ContextKeysManager } from "./index";
3
2
  import * as R from "ramda";
4
3
 
5
- const { log_error } = createLogger({
6
- subsystem: "contextResolver",
7
- category: "General",
8
- });
9
-
10
4
  interface IResolver {
11
5
  resolve: (string) => Promise<string | number | object>;
12
6
  }
@@ -42,12 +36,16 @@ export const resolveObjectValues = async (
42
36
 
43
37
  const resolvedEntries = await Promise.all(
44
38
  entries.map(async ([key, value]) => {
45
- const regex = /@{([^/]+)\/([^}]*)}/;
46
-
47
39
  if (typeof value !== "string") {
48
40
  return [key, value];
49
41
  }
50
42
 
43
+ if (!value.startsWith("@")) {
44
+ return [key, value];
45
+ }
46
+
47
+ const regex = /@{([^/]+)\/([^}]*)}/;
48
+
51
49
  const match = (value as string).match(regex);
52
50
 
53
51
  if (match) {
@@ -60,12 +58,7 @@ export const resolveObjectValues = async (
60
58
  return [key, resolvedValue];
61
59
  }
62
60
 
63
- log_error("resolveObjectValues: invalid context string", {
64
- key,
65
- value,
66
- });
67
-
68
- return [key, null];
61
+ return [key, value];
69
62
  })
70
63
  );
71
64
 
@@ -16,12 +16,12 @@ import {
16
16
 
17
17
  export { StorageLevel };
18
18
 
19
- type KeyNameObj = {
19
+ export type KeyNameObj = {
20
20
  namespace: string;
21
21
  key: string;
22
22
  };
23
23
 
24
- type KeyName = string | KeyNameObj;
24
+ export type KeyName = string | KeyNameObj;
25
25
 
26
26
  type ParsedKeyAndNamespace = {
27
27
  namespace?: string;
@@ -1,10 +1,11 @@
1
1
  import * as R from "ramda";
2
2
  import { DEFAULT_NAMESPACE } from "../consts";
3
+ import { KeyName, KeyNameObj } from "../index";
3
4
 
4
5
  const lastDotRegex = /\.([^.]+)$/;
5
6
  const splitByLastDot = R.compose(R.init, R.split(lastDotRegex));
6
7
 
7
- export function getNamespaceAndKey(namespacedKey) {
8
+ export function getNamespaceAndKey(namespacedKey: KeyName): KeyNameObj {
8
9
  if (typeof namespacedKey !== "string") return namespacedKey;
9
10
 
10
11
  const namespacedKeyProps = namespacedKey.includes(".")
@@ -28,6 +28,7 @@ exports[`focusManager should be defined 1`] = `
28
28
  "moveFocus": [Function],
29
29
  "on": [Function],
30
30
  "press": [Function],
31
+ "pressIn": [Function],
31
32
  "pressOut": [Function],
32
33
  "recoverFocus": [Function],
33
34
  "register": [Function],
@@ -13,6 +13,7 @@ import {
13
13
  import { subscriber } from "../../functionUtils";
14
14
  import { coreLogger } from "../../logger";
15
15
  import { ACTION } from "./utils/enums";
16
+
16
17
  const logger = coreLogger.addSubsystem("focusManager");
17
18
 
18
19
  const isFocusEnabled = (focusableItem): boolean => {
@@ -325,8 +326,6 @@ export const focusManager = (function () {
325
326
  },
326
327
  });
327
328
 
328
- currentFocusNode = focusCandidate;
329
-
330
329
  focusableItem && setFocus(focusCandidate.id, null);
331
330
 
332
331
  return { success: true };
@@ -335,15 +334,14 @@ export const focusManager = (function () {
335
334
  return { success: false };
336
335
  }
337
336
 
338
- function treeLoaded(val, node) {
339
- logger.log({
340
- message: "treeLoaded",
341
- data: {
342
- val,
343
- node,
344
- currentFocusNode,
345
- },
346
- });
337
+ function treeLoaded(_val, _node) {}
338
+
339
+ function pressIn() {
340
+ const currentFocusable = getCurrentFocus();
341
+
342
+ if (currentFocusable) {
343
+ currentFocusable.pressIn(null);
344
+ }
347
345
  }
348
346
 
349
347
  /**
@@ -477,7 +475,7 @@ export const focusManager = (function () {
477
475
  function isCurrentFocusOnTheTopScreen() {
478
476
  const routes = R.pathOr([], ["root", "children"], focusableTree);
479
477
 
480
- if (routes.length <= 1) {
478
+ if (currentFocusNode && routes.length <= 1) {
481
479
  // there is only one or zero routes
482
480
  return true;
483
481
  }
@@ -553,6 +551,7 @@ export const focusManager = (function () {
553
551
  invokeHandler,
554
552
  removeHandler,
555
553
  longPress,
554
+ pressIn,
556
555
  pressOut,
557
556
  enableFocus,
558
557
  setInitialFocus,
@@ -1,8 +1,8 @@
1
1
  import { isNotNil } from "@applicaster/zapp-react-native-utils/reactUtils/helpers";
2
- import { find, last, startsWith, pathOr } from "ramda";
2
+ import { find, last, pathOr, startsWith } from "ramda";
3
3
  import {
4
- QUICK_BRICK_NAVBAR,
5
4
  QUICK_BRICK_CONTENT,
5
+ QUICK_BRICK_NAVBAR,
6
6
  } from "@applicaster/quick-brick-core/const";
7
7
 
8
8
  // run check each 300 ms
@@ -66,7 +66,8 @@ export const getContentNode = (focusableTree) => {
66
66
  const content = find(
67
67
  (child) =>
68
68
  startsWith(QUICK_BRICK_CONTENT, child.id) ||
69
- startsWith("player", child.id),
69
+ startsWith("player", child.id) ||
70
+ startsWith("/hooks", child?.parent?.id), // For startup hooks case
70
71
  getActiveScreenChildren(focusableTree)
71
72
  );
72
73
 
@@ -1,5 +1,3 @@
1
- import * as R from "ramda";
2
-
3
1
  // more keys can be added here. Simply make sure
4
2
  // the key matches the code value
5
3
 
@@ -34,12 +32,18 @@ export function keyCode(key) {
34
32
  keyCode(keyEvent).matchesAny("Enter", "Backspace", KEYS.ArrowLeft, ...)
35
33
  */
36
34
 
37
- const matches = R.compose(
38
- R.either(R.eqProps("code", key), R.eqProps("keyCode", key)),
39
- R.when(R.is(String), R.prop(R.__, KEYS))
40
- );
35
+ const matches = (compareKey) => {
36
+ // If compareKey is a string, look it up in KEYS object
37
+ const keyToCompare =
38
+ typeof compareKey === "string" ? KEYS[compareKey] : compareKey;
39
+
40
+ // Compare either code or keyCode properties
41
+ return (
42
+ keyToCompare?.code === key.code || keyToCompare?.keyCode === key.keyCode
43
+ );
44
+ };
41
45
 
42
- const matchesAny = (...args) => R.any(matches, args);
46
+ const matchesAny = (...args) => args.some(matches);
43
47
 
44
48
  const direction = () =>
45
49
  matchesAny(...ARROW_KEYS) ? directionHelper(key) : null;
@@ -1,8 +1,8 @@
1
- /// <reference types="@types/react-native" />
2
1
  import * as ReactNative from "react-native";
3
- import { isTV, platformSelect } from "../reactUtils";
4
2
  import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
5
- import { useIsTablet } from "@applicaster/zapp-react-native-utils/reactHooks/device/useIsTablet";
3
+
4
+ import { isTV, platformSelect } from "../reactUtils";
5
+ import { useIsTablet } from "../reactHooks";
6
6
 
7
7
  import {
8
8
  QUICK_BRICK_EVENTS,
@@ -121,8 +121,15 @@ export const removeOrientationChangeListener = (listener: any): void => {
121
121
  */
122
122
  export const isOrientationCompatible = ({
123
123
  orientation,
124
- layoutData: { width, height },
124
+ layoutData: { width, height, isTablet, isTabletPortrait },
125
125
  }) => {
126
+ // We count portrait as compatible, because if default in zapp for mobile layout
127
+ // We count landscape as compatible, because if isTabletPortrait is false,
128
+ // it defaults for device
129
+ if (isTablet && !isTabletPortrait) {
130
+ return true;
131
+ }
132
+
126
133
  const isLandscape = width > height;
127
134
 
128
135
  if (
@@ -146,15 +153,6 @@ export const isOrientationCompatible = ({
146
153
  return true;
147
154
  };
148
155
 
149
- export const useIsOrientationCompatible = (orientation) => {
150
- const { height, width } = ReactNative.useWindowDimensions();
151
-
152
- return isOrientationCompatible({
153
- orientation,
154
- layoutData: { width, height },
155
- });
156
- };
157
-
158
156
  /**
159
157
  * Determine final screen orientation based on device type,
160
158
  * settings and orientation value provided by screen data settings
@@ -23,3 +23,17 @@ export const PLATFORMS = {
23
23
  export const PLATFORM_KEYS = {
24
24
  deviceClosedCaptioningEnabled: "device_closed_captioning_enabled",
25
25
  };
26
+
27
+ export enum ZappPlatform {
28
+ Android = "android",
29
+ AndroidTV = "android_tv",
30
+ AmazonFireTV = "amazon",
31
+ iOS = "ios",
32
+ tvOS = "tvos",
33
+ Roku = "roku",
34
+ Tizen = "tizen",
35
+ Web = "web",
36
+ WebOS = "webos",
37
+ Vizio = "vizio",
38
+ Unknown = "unknown",
39
+ }