@applicaster/zapp-react-native-utils 12.0.0-alpha.9233494544 → 12.0.0-alpha.9262177070

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/analyticsUtils/AnalyticsEvents/index.ts +13 -0
  2. package/analyticsUtils/AnalyticsEvents/searchEvents.ts +21 -0
  3. package/analyticsUtils/AnalyticsEvents/sendShareEvent.ts +21 -0
  4. package/analyticsUtils/analyticsPlugins.ts +25 -0
  5. package/analyticsUtils/events.ts +12 -0
  6. package/analyticsUtils/index.tsx +12 -0
  7. package/appUtils/focusManager/__tests__/__snapshots__/focusManager.test.js.snap +2 -3
  8. package/appUtils/focusManager/__tests__/focusManager.test.js +4 -24
  9. package/appUtils/focusManager/__tests__/index.test.ts +2 -3
  10. package/appUtils/focusManager/index.ts +23 -125
  11. package/appUtils/focusManager/treeDataStructure/Utils/index.js +11 -21
  12. package/appUtils/focusManager/utils/index.ts +31 -8
  13. package/appUtils/focusManagerAux/index.ts +76 -0
  14. package/appUtils/focusManagerAux/utils/index.ts +100 -0
  15. package/appUtils/keyCodes/keys.web.js +8 -0
  16. package/appUtils/keyCodes/keysByPlatform.js +11 -1
  17. package/appUtils/platform/const.ts +25 -0
  18. package/appUtils/platform/index.ts +3 -0
  19. package/appUtils/platform/platformUtils.ts +223 -0
  20. package/appUtils/playerManager/conts.ts +1 -0
  21. package/appUtils/playerManager/index.ts +11 -5
  22. package/appUtils/playerManager/nativePlayerManager.ts +12 -0
  23. package/appUtils/playerManager/player.ts +8 -3
  24. package/appUtils/playerManager/playerNative.ts +5 -14
  25. package/appUtils/playerManager/usePlayerControllerSetup.tsx +6 -1
  26. package/arrayUtils/__tests__/isFilledArray.test.ts +63 -0
  27. package/arrayUtils/index.ts +5 -0
  28. package/booleanUtils/index.ts +4 -4
  29. package/cellUtils/__tests__/cellUtils.test.ts +9 -20
  30. package/cellUtils/index.ts +6 -12
  31. package/dateUtils/index.ts +11 -0
  32. package/inflatedUrlUtils/index.ts +4 -4
  33. package/keyboardState/index.ts +0 -0
  34. package/localizationUtils/__tests__/localizationUtils.test.ts +72 -53
  35. package/localizationUtils/index.ts +13 -22
  36. package/numberUtils/__tests__/isLikeNumber.test.ts +18 -0
  37. package/numberUtils/index.ts +9 -18
  38. package/package.json +2 -2
  39. package/reactHooks/cell-click/__tests__/index.test.js +10 -1
  40. package/reactHooks/cell-click/index.ts +12 -12
  41. package/reactHooks/feed/__tests__/useBuildPipesUrl.test.tsx +30 -70
  42. package/reactHooks/feed/__tests__/useFeedRefresh.test.tsx +6 -2
  43. package/reactHooks/feed/__tests__/useInflatedUrl.test.ts +18 -3
  44. package/reactHooks/feed/useBuildPipesUrl.ts +7 -10
  45. package/reactHooks/feed/useFeedRefresh.tsx +9 -7
  46. package/reactHooks/feed/useInflatedUrl.ts +44 -15
  47. package/reactHooks/navigation/__tests__/index.test.tsx +11 -8
  48. package/reactHooks/navigation/index.ts +42 -68
  49. package/reactHooks/screen/__tests__/useCurrentScreenData.test.tsx +21 -23
  50. package/reactHooks/screen/index.ts +2 -0
  51. package/reactHooks/screen/useScreenBackgroundColor.ts +23 -0
  52. package/reactHooks/screen/useScreenContext.ts +1 -2
  53. package/reactUtils/helpers.tsx +1 -1
  54. package/reactUtils/index.ts +102 -0
  55. package/types.ts +4 -0
  56. package/appUtils/focusManager/FocusableEvents.ts +0 -8
  57. package/appUtils/focusManager/treeDataStructure/Utils/__tests__/Utils_android.test.js +0 -1094
  58. package/appUtils/focusManager/treeDataStructure/Utils/index.android.js +0 -261
@@ -7,6 +7,15 @@ import { sendHeaderClickEvent } from "./sendHeaderClickEvent";
7
7
  import { sendHardwareBackButtonClickEvent } from "./sendHardwareBackButtonClickEvent";
8
8
  import { sendDownloadsEvent } from "./sendDownloadsEvent";
9
9
  import { sendScreenEvent } from "./sendScreenEvent";
10
+ import {
11
+ sendSearchCanceledEvent,
12
+ sendSearchExecutedEvent,
13
+ } from "./searchEvents";
14
+
15
+ import {
16
+ sendShareInitiatedEvent,
17
+ sendShareSuccessEvent,
18
+ } from "./sendShareEvent";
10
19
 
11
20
  export {
12
21
  sendScreenEvent,
@@ -18,4 +27,8 @@ export {
18
27
  sendHeaderClickEvent,
19
28
  sendHardwareBackButtonClickEvent,
20
29
  sendDownloadsEvent,
30
+ sendSearchCanceledEvent,
31
+ sendSearchExecutedEvent,
32
+ sendShareInitiatedEvent,
33
+ sendShareSuccessEvent,
21
34
  };
@@ -0,0 +1,21 @@
1
+ import { log_debug } from "../logger";
2
+ import { postAnalyticEvent } from "../manager";
3
+ import { ANALYTICS_CORE_EVENTS } from "../events";
4
+
5
+ export const sendSearchCanceledEvent = (analyticsProps) => {
6
+ const eventName = ANALYTICS_CORE_EVENTS.SEARCH_CANCELED;
7
+ postAnalyticEvent(eventName, analyticsProps);
8
+
9
+ log_debug(`sendSearchCanceledEvent: send event: ${eventName}`, {
10
+ analyticsProps,
11
+ });
12
+ };
13
+
14
+ export const sendSearchExecutedEvent = (analyticsProps) => {
15
+ const eventName = ANALYTICS_CORE_EVENTS.SEARCH_EXECUTED;
16
+ postAnalyticEvent(eventName, analyticsProps);
17
+
18
+ log_debug(`sendSearchExecutedEvent: send event: ${eventName}`, {
19
+ analyticsProps,
20
+ });
21
+ };
@@ -0,0 +1,21 @@
1
+ import { log_debug } from "../logger";
2
+ import { postAnalyticEvent } from "../manager";
3
+ import { ANALYTICS_CORE_EVENTS } from "../events";
4
+
5
+ export const sendShareInitiatedEvent = (analyticsProps) => {
6
+ const eventName = ANALYTICS_CORE_EVENTS.SHARE_INITIATED;
7
+ postAnalyticEvent(eventName, analyticsProps);
8
+
9
+ log_debug(`sendShareInitiatedEvent: send event: ${eventName}`, {
10
+ analyticsProps,
11
+ });
12
+ };
13
+
14
+ export const sendShareSuccessEvent = (analyticsProps) => {
15
+ const eventName = ANALYTICS_CORE_EVENTS.SHARE_SUCCESS;
16
+ postAnalyticEvent(eventName, analyticsProps);
17
+
18
+ log_debug(`sendShareSuccessEvent: send event: ${eventName}`, {
19
+ analyticsProps,
20
+ });
21
+ };
@@ -0,0 +1,25 @@
1
+ import * as R from "ramda";
2
+ import { appStore } from "@applicaster/zapp-react-native-redux/AppStore";
3
+
4
+ export const getVideojsAnalyticPluginsConfig = async (entry: ZappEntry) => {
5
+ let videojsConfiguration = {};
6
+
7
+ const plugins = appStore.get("plugins");
8
+ const analyticPlugins = R.filter(R.propEq("type", "analytics"), plugins);
9
+
10
+ const configurations = await Promise.all(
11
+ analyticPlugins.map(async (plugin) => {
12
+ const { configuration, module } = plugin;
13
+
14
+ return module?.getPlayerConfiguration?.(configuration, entry);
15
+ })
16
+ );
17
+
18
+ configurations.forEach((analyticConfig) => {
19
+ if (typeof analyticConfig === "object" && analyticConfig !== null) {
20
+ videojsConfiguration = { ...videojsConfiguration, ...analyticConfig };
21
+ }
22
+ });
23
+
24
+ return videojsConfiguration;
25
+ };
@@ -23,10 +23,22 @@ export const TAPPING_EVENTS = {
23
23
  TAP_NAVBAR_BACK_BUTTON: "tap_navbar_back_button",
24
24
  };
25
25
 
26
+ export const SEARCH_EVENTS = {
27
+ SEARCH_EXECUTED: "search_executed",
28
+ SEARCH_CANCELED: "search_canceled",
29
+ };
30
+
31
+ export const SHARE_EVENTS = {
32
+ SHARE_INITIATED: "share_initiated",
33
+ SHARE_SUCCESS: "share_success",
34
+ };
35
+
26
36
  export const ANALYTICS_CORE_EVENTS = {
27
37
  ...LEGACY_EVENTS,
28
38
  ...SCREEN_VIEW_EVENTS,
29
39
  ...TAPPING_EVENTS,
40
+ ...SEARCH_EVENTS,
41
+ ...SHARE_EVENTS,
30
42
  };
31
43
 
32
44
  export const WEBVIEW_EVENTS = {
@@ -18,6 +18,10 @@ import {
18
18
  sendHardwareBackButtonClickEvent,
19
19
  sendDownloadsEvent,
20
20
  sendScreenEvent,
21
+ sendSearchCanceledEvent,
22
+ sendSearchExecutedEvent,
23
+ sendShareInitiatedEvent,
24
+ sendShareSuccessEvent,
21
25
  } from "./AnalyticsEvents";
22
26
 
23
27
  import { postAnalyticEvent } from "./manager";
@@ -66,6 +70,10 @@ type AnalyticsFunctions = {
66
70
  item: ZappEntry;
67
71
  state: OfflineItemState;
68
72
  }) => void;
73
+ sendSearchCanceledEvent: (props: AnalyticsDefaultProperties) => void;
74
+ sendSearchExecutedEvent: (props: AnalyticsDefaultProperties) => void;
75
+ sendShareInitiatedEvent: (props: AnalyticsDefaultProperties) => void;
76
+ sendShareSuccessEvent: (props: AnalyticsDefaultProperties) => void;
69
77
  };
70
78
 
71
79
  type GetAnalyticsFunctions = (
@@ -102,6 +110,10 @@ export function getAnalyticsFunctions({
102
110
  sendHardwareBackButtonClickEvent,
103
111
  sendScreenEvent,
104
112
  sendDownloadsEvent,
113
+ sendSearchCanceledEvent,
114
+ sendSearchExecutedEvent,
115
+ sendShareInitiatedEvent,
116
+ sendShareSuccessEvent,
105
117
  };
106
118
  }
107
119
 
@@ -3,9 +3,7 @@
3
3
  exports[`focusManager should be defined 1`] = `
4
4
  Object {
5
5
  "blur": [Function],
6
- "disableAutomaticFocus": [Function],
7
6
  "disableFocus": [Function],
8
- "enableAutomaticFocus": [Function],
9
7
  "enableFocus": [Function],
10
8
  "focusableTree": Tree {
11
9
  "loadingCounter": 0,
@@ -23,6 +21,7 @@ Object {
23
21
  "getGroupById": [Function],
24
22
  "getGroupRootById": [Function],
25
23
  "invokeHandler": [Function],
24
+ "isCurrentFocusOnTheTopScreen": [Function],
26
25
  "isFocusDisabled": [Function],
27
26
  "isGroupItemFocused": [Function],
28
27
  "longPress": [Function],
@@ -30,11 +29,11 @@ Object {
30
29
  "on": [Function],
31
30
  "press": [Function],
32
31
  "pressOut": [Function],
32
+ "recoverFocus": [Function],
33
33
  "register": [Function],
34
34
  "removeHandler": [Function],
35
35
  "setFocus": [Function],
36
36
  "setInitialFocus": [Function],
37
- "setupInitialFocus": [Function],
38
37
  "unregister": [Function],
39
38
  }
40
39
  `;
@@ -14,10 +14,8 @@ describe("focusManager", () => {
14
14
  expect(focusManager).toMatchSnapshot();
15
15
  });
16
16
 
17
- it("enableAutomaticFocus should not block setting focus", () => {
17
+ it("manages to land initial focus", () => {
18
18
  const mockSetFocus = jest.fn();
19
- focusManager.setupInitialFocus("1", true);
20
- focusManager.enableAutomaticFocus();
21
19
 
22
20
  focusManager.register({
23
21
  id: "1",
@@ -31,31 +29,13 @@ describe("focusManager", () => {
31
29
  },
32
30
  });
33
31
 
32
+ const { success } = focusManager.setInitialFocus();
33
+
34
+ expect(success).toBe(true);
34
35
  expect(mockSetFocus).toBeCalledTimes(1);
35
36
  expect(mockSetFocus).toBeCalledWith(null);
36
37
  });
37
38
 
38
- it("enableAutomaticFocus should block setting focus", () => {
39
- const mockSetFocus = jest.fn();
40
- focusManager.setupInitialFocus("1", true);
41
- focusManager.disableAutomaticFocus();
42
-
43
- focusManager.register({
44
- id: "1",
45
- component: {
46
- setFocus: mockSetFocus,
47
- willReceiveFocus: function () {},
48
- isMounted: function () {
49
- return true;
50
- },
51
- props: { groupId: "121" },
52
- },
53
- });
54
-
55
- expect(mockSetFocus).toBeCalledTimes(0);
56
- expect(mockSetFocus).not.toBeCalledWith(null);
57
- });
58
-
59
39
  describe("register", () => {});
60
40
  describe("unregister", () => {});
61
41
  describe("find", () => {});
@@ -18,7 +18,6 @@ describe("focusManager", () => {
18
18
  "on",
19
19
  "invokeHandler",
20
20
  "removeHandler",
21
- "setupInitialFocus",
22
21
  "longPress",
23
22
  "pressOut",
24
23
  "enableFocus",
@@ -27,10 +26,10 @@ describe("focusManager", () => {
27
26
  "isFocusDisabled",
28
27
  "getCurrentFocusNode",
29
28
  "focusableTree",
30
- "disableAutomaticFocus",
31
- "enableAutomaticFocus",
32
29
  "getGroupRootById",
33
30
  "isGroupItemFocused",
31
+ "recoverFocus",
32
+ "isCurrentFocusOnTheTopScreen",
34
33
  ];
35
34
 
36
35
  expectedMethods.forEach((method) => {
@@ -8,17 +8,11 @@ import { Tree } from "./treeDataStructure/Tree";
8
8
  import {
9
9
  findFocusableNode,
10
10
  findPriorityItem,
11
- isOnTheSameScreen,
11
+ haveSameParentBeforeRoot,
12
12
  } from "./treeDataStructure/Utils";
13
13
  import { subscriber } from "../../functionUtils";
14
14
  import * as FOCUS_EVENTS from "./events";
15
15
  import { coreLogger } from "../../logger";
16
- import {
17
- waitForActiveScreen,
18
- waitForContent,
19
- getContentNode,
20
- getActiveScreen,
21
- } from "./utils";
22
16
 
23
17
  const logger = coreLogger.addSubsystem("focusManager");
24
18
 
@@ -59,21 +53,9 @@ export const focusManager = (function () {
59
53
  // focusable node which currently holds the focus
60
54
  let currentFocusNode = null;
61
55
  let lastFocusedId = null;
62
- let initialFocusOnContent = null;
63
56
  let focusDisabled = false;
64
- let focusAutoEnabled = false;
65
57
  const eventHandler = subscriber();
66
58
 
67
- function disableAutomaticFocus() {
68
- logger.log({ message: "disableAutomaticFocus" });
69
- focusAutoEnabled = false;
70
- }
71
-
72
- function enableAutomaticFocus() {
73
- logger.log({ message: "focusManager: enableAutomaticFocus" });
74
- focusAutoEnabled = true;
75
- }
76
-
77
59
  function enableFocus() {
78
60
  focusDisabled = false;
79
61
  }
@@ -251,13 +233,17 @@ export const focusManager = (function () {
251
233
  const currentFocusedId = R.path(["props", "id"], getCurrentFocus());
252
234
  const nextFocusedId = R.path(["props", "id"], focusableItem);
253
235
 
254
- if (currentFocusedId === nextFocusedId) {
236
+ if (
237
+ isNotNil(currentFocusedId) &&
238
+ isNotNil(nextFocusedId) &&
239
+ currentFocusedId === nextFocusedId
240
+ ) {
255
241
  // we are going to move focus to the same node(already focused) -> nothing to do
256
242
  return { success: true };
257
243
  }
258
244
 
259
- if (preferredFocus.length === 1 && focusableItem && focusableItem.isGroup) {
260
- // we've found only one FocusableGroup as a candidate to focus, try to use fallback
245
+ if (focusableItem?.isGroup) {
246
+ // focusCandidate is a FocusableGroup, we are not able to land focus on group(only on Focusable)
261
247
  return { success: false };
262
248
  }
263
249
 
@@ -266,10 +252,7 @@ export const focusManager = (function () {
266
252
  !focusableItem.isGroup &&
267
253
  isFocusEnabled(focusableItem)
268
254
  ) {
269
- if (initialFocusOnContent) {
270
- blur();
271
- initialFocusOnContent = false;
272
- }
255
+ blur();
273
256
 
274
257
  logger.log({
275
258
  message: "setInitialFocus – currentFocusNode",
@@ -295,17 +278,8 @@ export const focusManager = (function () {
295
278
  val,
296
279
  node,
297
280
  currentFocusNode,
298
- initialFocusOnContent,
299
281
  },
300
282
  });
301
-
302
- if ((val && !currentFocusNode) || initialFocusOnContent) {
303
- logger.log({ message: `focusAutoEnabled ${focusAutoEnabled}` });
304
-
305
- if (focusAutoEnabled) {
306
- setInitialFocus(initialFocusOnContent ? node : undefined);
307
- }
308
- }
309
283
  }
310
284
 
311
285
  /**
@@ -357,8 +331,6 @@ export const focusManager = (function () {
357
331
  * @returns {React.Component} the registered component
358
332
  */
359
333
  function registerGroup(id, component) {
360
- // console.log("debug_2", "FM registerGroup", { id, component });
361
-
362
334
  focusableTree.addNode({ id, component });
363
335
 
364
336
  return component;
@@ -374,8 +346,6 @@ export const focusManager = (function () {
374
346
  * @returns {React.Component} the registered component
375
347
  */
376
348
  function registerItem(id, component) {
377
- // console.log("debug_2", "FM registerItem", { id, component });
378
-
379
349
  focusableTree.addNode({ id, component });
380
350
 
381
351
  if (!currentFocusNode && id === lastFocusedId && !id.includes("menu")) {
@@ -392,8 +362,6 @@ export const focusManager = (function () {
392
362
  * @param {String} id of the group to unregister
393
363
  */
394
364
  function unregisterGroup(id) {
395
- // console.log("debug_2", "FM unregisterGroup", { id });
396
-
397
365
  focusableTree.findAndRemoveNode(id);
398
366
  }
399
367
 
@@ -405,8 +373,6 @@ export const focusManager = (function () {
405
373
  * @param {String} id of the Focusable to unregister
406
374
  */
407
375
  function unregisterItem(id) {
408
- // console.log("debug_2", "FM unregisterItem", { id });
409
-
410
376
  focusableTree.findAndRemoveNode(id);
411
377
 
412
378
  if (currentFocusNode && currentFocusNode.id === id) {
@@ -444,80 +410,20 @@ export const focusManager = (function () {
444
410
  group ? unregisterGroup(id) : unregisterItem(id);
445
411
  }
446
412
 
447
- function setupInitialFocus(id: string, focusOnContent?: boolean) {
448
- console.log("debug_2", "FM - setupInitialFocus", { id, focusOnContent });
449
-
450
- if (focusOnContent) {
451
- initialFocusOnContent = focusOnContent;
452
- } else {
453
- setFocus(id);
454
- }
455
- }
456
-
457
- async function setFocusOnMenu(currentRoute: string) {
458
- console.log("debug_2", "FM - setFocusOnMenu", { currentRoute });
413
+ function isCurrentFocusOnTheTopScreen() {
414
+ const routes = R.pathOr([], ["root", "children"], focusableTree);
459
415
 
460
- try {
461
- await waitForActiveScreen(currentRoute, focusableTree);
462
-
463
- const navbar = R.find(
464
- (child) => R.startsWith("navbar", child.id),
465
- getActiveScreen(focusableTree).children
466
- );
467
-
468
- const selectedMenuItemId = R.find(
469
- (child) => child.component.props.selected,
470
- navbar?.children || []
471
- )?.id;
472
-
473
- if (selectedMenuItemId) {
474
- // set focus on selected menu item
475
- setFocus(selectedMenuItemId);
476
- return;
477
- }
478
-
479
- const firstMenuItemId = R.path(["children", 0, "id"], navbar);
480
-
481
- if (firstMenuItemId) {
482
- // set focus on first menu item
483
- setFocus(firstMenuItemId);
484
- }
485
- } catch (error) {
486
- // failed to put focus on top-menu => log it
416
+ if (routes.length <= 1) {
417
+ // there is only one or zero routes
418
+ return true;
487
419
  }
488
- }
489
-
490
- async function setFocusOnContent(currentRoute: string) {
491
- console.log("debug_2", "FM - setFocusOnContent", { currentRoute });
492
-
493
- // we need to put focus on content here
494
- // For doing it we have to wait registration of first focusable node into focusableTree
495
- // this is the temporary hack with waiting until content node starts having children
496
- try {
497
- await waitForActiveScreen(currentRoute, focusableTree);
498
- await waitForContent(focusableTree);
499
420
 
500
- const content = getContentNode(focusableTree);
501
-
502
- const { success } = setInitialFocus(content);
503
-
504
- if (!success) {
505
- // we've failed to put initial focus on content, re-run "setFocusOnContent" again
506
- throw Error(
507
- "we've failed to put initial focus on content, re-run 'setFocusOnContent' again"
508
- );
509
- }
510
- } catch (e) {
511
- setFocusOnContent(currentRoute);
512
- }
421
+ return haveSameParentBeforeRoot(currentFocusNode, R.last(routes));
513
422
  }
514
423
 
515
424
  function recoverFocus() {
516
- const lastRoute = R.last(focusableTree.root.children);
517
- const onSameScreen = isOnTheSameScreen(currentFocusNode, lastRoute);
518
-
519
- if (!onSameScreen) {
520
- // currentFocusedNode is not from the last route. We need to run recover focus.
425
+ if (!isCurrentFocusOnTheTopScreen()) {
426
+ // We've failed to set focused node on the new screen => run focus recovery
521
427
  setInitialFocus();
522
428
  }
523
429
  }
@@ -528,19 +434,17 @@ export const focusManager = (function () {
528
434
  * @param {Object} direction of the scroll
529
435
  */
530
436
  function moveFocus(direction) {
437
+ if (!isCurrentFocusOnTheTopScreen()) {
438
+ // We are opening new screen. We need to ignore movement of focus.
439
+ return false;
440
+ }
441
+
531
442
  if (focusDisabled) return false;
532
443
 
533
444
  if (currentFocusNode) {
534
445
  currentFocusNode.component.willLoseFocus(currentFocusNode, direction);
535
446
  const nextFocusable = findFocusableNode(direction, currentFocusNode);
536
447
 
537
- // console.log("debug_2", "FM moveFocus", {
538
- // direction: direction?.value,
539
- // currentFocusNode,
540
- // focusableTree,
541
- // nextFocusable,
542
- // });
543
-
544
448
  if (nextFocusable?.component?.isMounted?.()) {
545
449
  const nextRect = nextFocusable.component.getRect();
546
450
 
@@ -563,8 +467,6 @@ export const focusManager = (function () {
563
467
  } else {
564
468
  currentFocusNode.component.failedLostFocus(currentFocusNode, direction);
565
469
  }
566
- } else {
567
- setInitialFocus();
568
470
  }
569
471
  }
570
472
 
@@ -624,7 +526,6 @@ export const focusManager = (function () {
624
526
  on,
625
527
  invokeHandler,
626
528
  removeHandler,
627
- setupInitialFocus,
628
529
  longPress,
629
530
  pressOut,
630
531
  enableFocus,
@@ -633,12 +534,9 @@ export const focusManager = (function () {
633
534
  isFocusDisabled,
634
535
  getCurrentFocusNode,
635
536
  focusableTree,
636
- disableAutomaticFocus,
637
- enableAutomaticFocus,
638
537
  getGroupRootById,
639
538
  isGroupItemFocused,
640
- setFocusOnMenu,
641
- setFocusOnContent,
642
539
  recoverFocus,
540
+ isCurrentFocusOnTheTopScreen,
643
541
  };
644
542
  })();
@@ -1,5 +1,7 @@
1
1
  import { allPass, pathOr, startsWith, isNil } from "ramda";
2
2
  import { isNilOrEmpty } from "@applicaster/zapp-react-native-utils/reactUtils/helpers";
3
+ import { isZero } from "@applicaster/zapp-react-native-utils/numberUtils";
4
+ import { QUICK_BRICK_NAVBAR } from "@applicaster/quick-brick-core/const";
3
5
 
4
6
  import { rejectItemByPath } from "../../../../objectUtils";
5
7
  import {
@@ -145,7 +147,7 @@ const hasComponent = (target) => !!target?.component;
145
147
 
146
148
  const hasComponentAndChildren = allPass([hasComponent, hasChildren]);
147
149
 
148
- const positiveOrZero = (value) => value >= 0;
150
+ const positiveOrZero = (value) => value > 0 || isZero(value);
149
151
 
150
152
  const excludeFromFocusSearching = pathOr(false, [
151
153
  "component",
@@ -153,12 +155,10 @@ const excludeFromFocusSearching = pathOr(false, [
153
155
  "excludeFromFocusSearching",
154
156
  ]);
155
157
 
156
- // const isAllScreens = all(excludeFromFocusSearching);
157
-
158
- const isNavBar = (target) => startsWith("navbar", target?.id);
158
+ const isNavBar = (target) => startsWith(QUICK_BRICK_NAVBAR, target?.id);
159
159
 
160
160
  const ignoreMenuIfMultipleTargets = (nodes) => {
161
- if (nodes.length > 1 && nodes.map((n) => n?.target?.id).includes("navbar")) {
161
+ if (nodes.length > 1) {
162
162
  return nodes.filter((n) => !isNavBar(n?.target));
163
163
  }
164
164
 
@@ -222,24 +222,10 @@ export function getTargetInDirection(
222
222
  }))
223
223
  .filter(({ distance }) => positiveOrZero(distance));
224
224
 
225
- // if (isAllScreens(targets)) {
226
- // return last(targets);
227
- // }
228
-
229
225
  const match = distances
230
226
  .sort((a, b) => a.distance - b.distance) // sorts the distances
231
227
  .filter(ignoreMenuIfMultipleTargets)[0]; // filters out multiple targets if necessary // gets the first element
232
228
 
233
- // console.log("debug_2", "FM getTargetInDirection", {
234
- // direction: direction?.value,
235
- // currentNode,
236
- // targetNodes,
237
- // targets,
238
- // comparisonRect,
239
- // distances,
240
- // match,
241
- // });
242
-
243
229
  return match?.target;
244
230
  }
245
231
 
@@ -337,6 +323,10 @@ export const getNodeBeforeRoot = (node) => {
337
323
  return undefined;
338
324
  }
339
325
 
326
+ if (isNil(node.parent)) {
327
+ return undefined;
328
+ }
329
+
340
330
  if (node.parent.id === "root") {
341
331
  return node;
342
332
  }
@@ -344,9 +334,9 @@ export const getNodeBeforeRoot = (node) => {
344
334
  return getNodeBeforeRoot(node.parent);
345
335
  };
346
336
 
347
- export const isOnTheSameScreen = (currentNode, nextNode) => {
337
+ export const haveSameParentBeforeRoot = (currentNode, nextNode) => {
348
338
  const routeForCurrentNode = getNodeBeforeRoot(currentNode);
349
339
  const routeForNextNode = getNodeBeforeRoot(nextNode);
350
340
 
351
- return routeForCurrentNode.id === routeForNextNode.id;
341
+ return routeForCurrentNode?.id === routeForNextNode?.id;
352
342
  };