@applicaster/zapp-react-native-utils 12.0.0-alpha.4337072244 → 12.0.0-alpha.4354608902

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 (65) hide show
  1. package/analyticsUtils/AnalyticsEvents/index.ts +7 -0
  2. package/analyticsUtils/AnalyticsEvents/sendShareEvent.ts +21 -0
  3. package/analyticsUtils/analyticsPlugins.ts +25 -0
  4. package/analyticsUtils/events.ts +6 -0
  5. package/analyticsUtils/index.tsx +6 -0
  6. package/appUtils/HooksManager/{Hook.js → Hook.ts} +35 -23
  7. package/appUtils/HooksManager/{constants.js → constants.ts} +1 -1
  8. package/appUtils/HooksManager/{index.js → index.ts} +118 -111
  9. package/appUtils/HooksManager/types.ts +116 -0
  10. package/appUtils/RiverFocusManager/index.js +17 -12
  11. package/appUtils/accessibilityManager/const.ts +50 -0
  12. package/appUtils/accessibilityManager/hooks.ts +31 -0
  13. package/appUtils/accessibilityManager/index.ts +150 -0
  14. package/appUtils/accessibilityManager/logger.ts +5 -0
  15. package/appUtils/focusManager/__tests__/__snapshots__/focusManager.test.js.snap +1 -2
  16. package/appUtils/focusManager/__tests__/index.test.ts +1 -2
  17. package/appUtils/focusManager/index.ts +7 -73
  18. package/appUtils/focusManager/treeDataStructure/Tree/index.js +2 -3
  19. package/appUtils/focusManager/treeDataStructure/Utils/index.js +7 -8
  20. package/appUtils/focusManager/utils/index.ts +8 -2
  21. package/appUtils/focusManagerAux/index.ts +76 -0
  22. package/appUtils/focusManagerAux/utils/index.ts +100 -0
  23. package/appUtils/{index.js → index.ts} +2 -0
  24. package/appUtils/keyCodes/{index.js → index.ts} +2 -0
  25. package/appUtils/keyCodes/keys/index.ts +3 -0
  26. package/appUtils/keyCodes/{keys.android.js → keys/keyEventMapper.ts} +0 -19
  27. package/appUtils/keyCodes/keys/keys.android.ts +18 -0
  28. package/appUtils/keyCodes/keys/keys.ios.ts +25 -0
  29. package/appUtils/keyCodes/keys/keys.ts +15 -0
  30. package/appUtils/keyCodes/{keys.web.js → keys/keys.web.ts} +8 -0
  31. package/appUtils/keyCodes/{keysByPlatform.js → keys/keysByPlatform.ts} +11 -1
  32. package/appUtils/platform/const.ts +25 -0
  33. package/appUtils/platform/index.ts +3 -0
  34. package/appUtils/platform/platformUtils.ts +171 -0
  35. package/appUtils/playerManager/conts.ts +1 -0
  36. package/appUtils/playerManager/index.ts +11 -5
  37. package/appUtils/playerManager/nativePlayerManager.ts +12 -0
  38. package/appUtils/playerManager/player.ts +9 -3
  39. package/appUtils/playerManager/playerNative.ts +5 -14
  40. package/appUtils/playerManager/usePlayerControllerSetup.tsx +7 -1
  41. package/booleanUtils/index.ts +4 -4
  42. package/domUtils/{cookieManager.js → cookieManager.ts} +1 -2
  43. package/functionUtils/index.ts +15 -11
  44. package/keyboardState/index.ts +0 -0
  45. package/modalState/index.ts +1 -5
  46. package/navigationUtils/index.ts +62 -5
  47. package/package.json +2 -2
  48. package/pluginUtils/index.ts +9 -0
  49. package/reactHooks/cell-click/__tests__/index.test.js +2 -1
  50. package/reactHooks/cell-click/index.ts +1 -1
  51. package/reactHooks/feed/__tests__/useFeedRefresh.test.tsx +6 -2
  52. package/reactHooks/feed/useFeedRefresh.tsx +9 -7
  53. package/reactHooks/navigation/__tests__/index.test.tsx +11 -8
  54. package/reactHooks/navigation/index.ts +53 -72
  55. package/reactHooks/screen/useScreenContext.ts +1 -2
  56. package/reactUtils/index.ts +91 -0
  57. package/appUtils/focusManager/FocusableEvents.ts +0 -8
  58. package/appUtils/focusManager/treeDataStructure/Utils/__tests__/Utils_android.test.js +0 -1094
  59. package/appUtils/focusManager/treeDataStructure/Utils/index.android.js +0 -261
  60. package/appUtils/keyCodes/keys.ios.js +0 -46
  61. /package/appUtils/HooksManager/{logger.js → logger.ts} +0 -0
  62. /package/appUtils/{directionHelper.js → directionHelper.ts} +0 -0
  63. /package/appUtils/keyCodes/{androidTVKeys.js → androidTVKeys.ts} +0 -0
  64. /package/appUtils/{localizationsHelper.js → localizationsHelper.ts} +0 -0
  65. /package/domUtils/{logger.js → logger.ts} +0 -0
@@ -0,0 +1,116 @@
1
+ import { SubscriberObj } from "../../functionUtils";
2
+ import { HOOKS_EVENTS } from "./constants";
3
+
4
+ export interface HookConfiguration {}
5
+
6
+ /* existing Hook Plugn props: sample */
7
+ interface _HookModulePlugin {
8
+ Component:
9
+ | React.FC<HookPluginProps>
10
+ | React.Component<HookPluginProps, any>
11
+ | React.ReactNode;
12
+ ModalContainer?: React.FC<ModalProps> | React.Component<ModalProps, any>;
13
+ skipHook?: (payload: ZappRiver | ZappEntry) => boolean;
14
+ presentFullScreen: boolean;
15
+ showNavBar?: boolean;
16
+ isFlowBlocker: (() => boolean) | boolean; // narrow this
17
+ hasPlayerHook?: boolean;
18
+ name: string;
19
+ runInBackground?: (
20
+ item: HookPluginProps["payload"],
21
+ callback: hookCallback,
22
+ hookPlugin: HookScreenData,
23
+ presentUI: (payload?: HookPluginProps["payload"]) => void
24
+ ) => any;
25
+ }
26
+
27
+ //* Derived from usage */
28
+ export interface HookModule {
29
+ ModalContainer?: React.ComponentType<any>;
30
+ Component: React.ComponentType<any>;
31
+ presentFullScreen: boolean;
32
+ run?: (
33
+ arg0: unknown,
34
+ callback: () => void,
35
+ configuration: HookConfiguration
36
+ ) => void; // not sure about optional parameter
37
+ hasPlayerHook?: boolean;
38
+ configuration?: HookConfiguration;
39
+ isFlowBlocker: () => boolean;
40
+ skipHook?: (payload?: ZappRiver | ZappEntry) => boolean;
41
+ runInBackground?: (
42
+ arg0: unknown,
43
+ callback: () => void,
44
+ hookPlugin: Hook,
45
+ presentUI: (payload?: HookPluginProps["payload"]) => void
46
+ ) => void;
47
+ name: string;
48
+ showNavBar?: boolean; // unsure
49
+ }
50
+
51
+ export type HookManagerArgs = {
52
+ rivers: Record<string, ZappRiver>;
53
+ plugins: ZappPlugin[];
54
+ targetScreen: ZappRiver;
55
+ startUpHooksData?: {
56
+ startUpHooks?: unknown[] | "in_process";
57
+ setStartUpHooks?: (arg0: string) => void;
58
+ };
59
+ };
60
+
61
+ export interface HookManager {
62
+ subscriber: SubscriberObj;
63
+ presentScreenHook: (
64
+ hook: Hook,
65
+ payload: unknown,
66
+ callback: (...any) => void
67
+ ) => void;
68
+ executeHook: (
69
+ hook: Hook,
70
+ payload: unknown,
71
+ callback: (...any) => void
72
+ ) => void;
73
+ handleHooks: (payload: unknown) => void;
74
+ runInBackground: (
75
+ hook: Hook,
76
+ payload: unknown,
77
+ callback: (...any) => void,
78
+ presentUI: (payload?: HookPluginProps["payload"]) => void
79
+ ) => void;
80
+ }
81
+
82
+ export type HookIniObj = {
83
+ hook: HookModule & {
84
+ module: HookModule;
85
+ general: unknown;
86
+ screen_id?: string;
87
+ identifier?: string;
88
+ weight?: number | string;
89
+ };
90
+ hooks: Hook<any>[];
91
+ manager: HookManager;
92
+ };
93
+
94
+ export interface Hook<T extends HookModule = HookModule> {
95
+ manager: HookManager;
96
+ lastHook: boolean;
97
+ state: number;
98
+ module: T;
99
+ screen_id: string;
100
+ identifier: string;
101
+ configuration: T["configuration"];
102
+ setStateAndNotify(
103
+ event: typeof HOOKS_EVENTS[keyof typeof HOOKS_EVENTS],
104
+ opts: {
105
+ error?: typeof Error;
106
+ route?: string;
107
+ hookPlugin: Hook<T>;
108
+ payload: unknown;
109
+ }
110
+ );
111
+ general?: {
112
+ transition_type: typeof HOOKS_EVENTS[keyof typeof HOOKS_EVENTS];
113
+ allow_screen_plugin_presentation: boolean;
114
+ is_flow_blocker: boolean;
115
+ };
116
+ }
@@ -26,7 +26,7 @@ export const riverFocusManager = (function () {
26
26
  /**
27
27
  * Retrieve screen focus data by id
28
28
  *
29
- * @param {String} screenFocusableGroupId Id that was used to save screen data.
29
+ * @param {{screenFocusableGroupId: string}} screenFocusableGroupId Unique Id of the screen from layout.json
30
30
  *
31
31
  */
32
32
  function screenFocusableData({ screenFocusableGroupId }) {
@@ -36,8 +36,9 @@ export const riverFocusManager = (function () {
36
36
  /**
37
37
  * Clear screen data for specific screen
38
38
  *
39
- * @param {String} screenId Unique Id of the screen from layout.json
40
- * @param {boolean} isInsideContainer If this screen a screen picker child
39
+ * @param {{ screenId: string, isInsideContainer: boolean }}
40
+ * screenId Unique Id of the screen from layout.json
41
+ * isInsideContainer If this screen a screen picker child
41
42
  *
42
43
  */
43
44
  function clearScreenData({ screenId, isInsideContainer }) {
@@ -60,9 +61,13 @@ export const riverFocusManager = (function () {
60
61
  /**
61
62
  * Focus on selected items
62
63
  *
63
- * @param {String} screenFocusableGroupId Top group id that was saved as screenn
64
- * @param {String} screenFocusedOnItem focusable item to focus
65
- * @param {object} history navigator history object
64
+ * @param {{
65
+ * screenFocusableGroupId: string,
66
+ * screenFocusedOnItem: () => void,
67
+ * previousAction: QuickBrickNavigationActionType,
68
+ * isDeepLink: boolean }} object contains data for focus
69
+ * - `screenFocusedOnItem` focusable item to focus
70
+ * - `previousActionhistory` navigator history object
66
71
  *
67
72
  */
68
73
  function focusOnSelectedItem({
@@ -115,15 +120,15 @@ export const riverFocusManager = (function () {
115
120
 
116
121
  /**
117
122
  * Create unique key that will be used for save focused group data inside specific screen
118
- *
119
- * @param {String} screenId Unique Id of the screen from layout.json
120
- * @param {boolean} isInsideContainer If this screen a screen picker child
123
+ * @param {{ screenId: string, isInsideContainer: boolean }}
124
+ * screenId Unique Id of the screen from layout.json
125
+ * isInsideContainer If this screen a screen picker child
121
126
  *
122
127
  */
123
128
  function screenFocusableGroupId({ screenId, isInsideContainer }) {
124
- return R.isNil(isInsideContainer)
125
- ? `RiverFocusableGroup-${screenId}`
126
- : `RiverFocusableGroup-${screenId}-isInsideContainer`;
129
+ return `RiverFocusableGroup-${screenId}${
130
+ R.isNil(isInsideContainer) ? "" : "-isInsideContainer"
131
+ }`;
127
132
  }
128
133
 
129
134
  return {
@@ -0,0 +1,50 @@
1
+ export const BUTTON_ACCESSIBILITY_KEYS = {
2
+ play: {
3
+ label: "accessibility_play_label",
4
+ hint: "accessibility_play_hint",
5
+ mini: {
6
+ label: "accessibility_play_mini_label",
7
+ hint: "accessibility_play_mini_hint",
8
+ },
9
+ },
10
+ pause: {
11
+ label: "accessibility_pause_label",
12
+ hint: "accessibility_pause_hint",
13
+ mini: {
14
+ label: "accessibility_pause_mini_label",
15
+ hint: "accessibility_pause_mini_hint",
16
+ },
17
+ },
18
+ rewind: {
19
+ label: "accessibility_rewind_label",
20
+ hint: "accessibility_rewind_hint",
21
+ },
22
+ forward: {
23
+ label: "accessibility_forward_label",
24
+ hint: "accessibility_forward_hint",
25
+ },
26
+ close: {
27
+ label: "accessibility_close_label",
28
+ hint: "accessibility_close_hint",
29
+ mini: {
30
+ label: "accessibility_close_mini_label",
31
+ hint: "accessibility_close_mini_hint",
32
+ },
33
+ },
34
+ maximize: {
35
+ label: "accessibility_maximize_label",
36
+ hint: "accessibility_maximize_hint",
37
+ },
38
+ subtitles: {
39
+ label: "accessibility_subtitle_label",
40
+ hint: "accessibility_subtitle_hint",
41
+ },
42
+ back: {
43
+ label: "accessibility_back_label",
44
+ hint: "accessibility_back_hint",
45
+ },
46
+ fullscreen: {
47
+ label: "accessibility_fullscreen_label",
48
+ hint: "accessibility_fullscreen_hint",
49
+ },
50
+ } as const;
@@ -0,0 +1,31 @@
1
+ import { useEffect, useMemo } from "react";
2
+ import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
3
+ import { AccessibilityManager } from "./index";
4
+
5
+ export const useAccessibilityManager = () => {
6
+ const { remoteConfigurations } = usePickFromState(["remoteConfigurations"]);
7
+ const { localizations } = remoteConfigurations;
8
+
9
+ const accessibilityManager = useMemo(() => {
10
+ return AccessibilityManager.getInstance();
11
+ }, []);
12
+
13
+ useEffect(() => {
14
+ accessibilityManager.updateLocalizations(localizations);
15
+ }, [localizations]);
16
+
17
+ useEffect(() => {
18
+ const subscription = accessibilityManager.getStateAsObservable().subscribe({
19
+ next: () => {
20
+ // TODO: handle accessibility states
21
+ // screenReaderEnabled: false
22
+ // reduceMotionEnabled: false
23
+ // boldTextEnabled: false
24
+ },
25
+ });
26
+
27
+ return () => subscription.unsubscribe();
28
+ }, [accessibilityManager]);
29
+
30
+ return accessibilityManager;
31
+ };
@@ -0,0 +1,150 @@
1
+ import { BehaviorSubject } from "rxjs";
2
+ import { accessibilityManagerLogger as logger } from "./logger";
3
+ import { TTSManager } from "../platform/platformUtils";
4
+ import { getLocalizations } from "../../localizationUtils";
5
+ import { BUTTON_ACCESSIBILITY_KEYS } from "./const";
6
+
7
+ export interface AccessibilityState {
8
+ screenReaderEnabled: boolean;
9
+ reduceMotionEnabled: boolean;
10
+ boldTextEnabled: boolean;
11
+ }
12
+
13
+ export interface AccessibilityProps {
14
+ accessibilityLabel?: string;
15
+ accessibilityHint?: string;
16
+ "aria-label"?: string;
17
+ "aria-description"?: string;
18
+ }
19
+
20
+ export class AccessibilityManager {
21
+ private static _instance: AccessibilityManager | null = null;
22
+ private state$ = new BehaviorSubject<AccessibilityState>({
23
+ screenReaderEnabled: false,
24
+ reduceMotionEnabled: false,
25
+ boldTextEnabled: false,
26
+ });
27
+
28
+ private announcements$ = new BehaviorSubject<{
29
+ message: string;
30
+ localizedMessage?: string | undefined;
31
+ timestamp: number;
32
+ } | null>(null);
33
+
34
+ private ttsManager = TTSManager.getInstance();
35
+ private localizations: { [key: string]: string };
36
+
37
+ private constructor(localizations?: { [key: string]: string }) {
38
+ if (localizations) {
39
+ this.localizations = getLocalizations({ localizations });
40
+ }
41
+ }
42
+
43
+ public static getInstance(): AccessibilityManager {
44
+ if (!AccessibilityManager._instance) {
45
+ AccessibilityManager._instance = new AccessibilityManager();
46
+ }
47
+
48
+ return AccessibilityManager._instance;
49
+ }
50
+
51
+ public updateLocalizations(localizations: { [key: string]: string }) {
52
+ this.localizations = getLocalizations({ localizations });
53
+ }
54
+
55
+ public getState(): AccessibilityState {
56
+ return this.state$.getValue();
57
+ }
58
+
59
+ public getStateAsObservable() {
60
+ return this.state$.asObservable();
61
+ }
62
+
63
+ /**
64
+ * text you want to be read, if you want to use localized text pass keyOfLocalizedText instead
65
+ * keyOfLocalizedText is the key to the localized text
66
+ */
67
+ public readText({
68
+ text,
69
+ keyOfLocalizedText,
70
+ }: {
71
+ text: string;
72
+ keyOfLocalizedText?: string;
73
+ }) {
74
+ logger.debug("Reading text", { text, keyOfLocalizedText });
75
+
76
+ if (keyOfLocalizedText) {
77
+ if (!this.localizations) {
78
+ logger.error(
79
+ "Attempting to use localized key without initialized localizations"
80
+ );
81
+
82
+ return;
83
+ }
84
+
85
+ const localizedMessage = this.getLocalizedMessage(keyOfLocalizedText);
86
+
87
+ if (!localizedMessage) {
88
+ logger.warn(`No localization found for key: ${keyOfLocalizedText}`);
89
+
90
+ return;
91
+ }
92
+
93
+ text = localizedMessage;
94
+ }
95
+
96
+ if (this.ttsManager) {
97
+ this.ttsManager.readText(text);
98
+ }
99
+
100
+ this.announcements$.next({
101
+ message: text,
102
+ localizedMessage: keyOfLocalizedText ? text : undefined,
103
+ timestamp: Date.now(),
104
+ });
105
+ }
106
+
107
+ public getButtonAccessibilityProps(buttonName: string): AccessibilityProps {
108
+ const buttonConfig = BUTTON_ACCESSIBILITY_KEYS[buttonName];
109
+
110
+ if (!buttonConfig) {
111
+ return {
112
+ accessibilityLabel: buttonName,
113
+ accessibilityHint: `Press button to perform action on ${buttonName}`,
114
+ "aria-label": buttonName,
115
+ "aria-description": `Press button to perform action on ${buttonName}`,
116
+ };
117
+ }
118
+
119
+ const labelKey = buttonConfig.label;
120
+ const hintKey = buttonConfig.hint;
121
+
122
+ const label = this.getLocalizedMessage(labelKey) || buttonName;
123
+
124
+ const hint =
125
+ this.getLocalizedMessage(hintKey) ||
126
+ `Press button to perform action on ${buttonName}`;
127
+
128
+ return {
129
+ accessibilityLabel: label,
130
+ accessibilityHint: hint,
131
+ "aria-label": label,
132
+ "aria-description": hint,
133
+ };
134
+ }
135
+
136
+ public getLocalizedMessage(key: string): string | void {
137
+ if (!key) return;
138
+
139
+ if (!this.localizations) {
140
+ logger.error(
141
+ "Attempting to use localized key without initialized localizations",
142
+ { key }
143
+ );
144
+
145
+ return;
146
+ }
147
+
148
+ return this.localizations[key];
149
+ }
150
+ }
@@ -0,0 +1,5 @@
1
+ import { utilsLogger } from "../../logger";
2
+
3
+ export const accessibilityManagerLogger = utilsLogger.addSubsystem(
4
+ "accessibilityManager"
5
+ );
@@ -21,6 +21,7 @@ Object {
21
21
  "getGroupById": [Function],
22
22
  "getGroupRootById": [Function],
23
23
  "invokeHandler": [Function],
24
+ "isCurrentFocusOnTheTopScreen": [Function],
24
25
  "isFocusDisabled": [Function],
25
26
  "isGroupItemFocused": [Function],
26
27
  "longPress": [Function],
@@ -32,8 +33,6 @@ Object {
32
33
  "register": [Function],
33
34
  "removeHandler": [Function],
34
35
  "setFocus": [Function],
35
- "setFocusOnContent": [Function],
36
- "setFocusOnMenu": [Function],
37
36
  "setInitialFocus": [Function],
38
37
  "unregister": [Function],
39
38
  }
@@ -28,9 +28,8 @@ describe("focusManager", () => {
28
28
  "focusableTree",
29
29
  "getGroupRootById",
30
30
  "isGroupItemFocused",
31
- "setFocusOnMenu",
32
- "setFocusOnContent",
33
31
  "recoverFocus",
32
+ "isCurrentFocusOnTheTopScreen",
34
33
  ];
35
34
 
36
35
  expectedMethods.forEach((method) => {
@@ -8,18 +8,11 @@ import { Tree } from "./treeDataStructure/Tree";
8
8
  import {
9
9
  findFocusableNode,
10
10
  findPriorityItem,
11
- isTransitionHappening,
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
- getNavbarNode,
21
- } from "./utils";
22
-
23
16
  const logger = coreLogger.addSubsystem("focusManager");
24
17
 
25
18
  const isFocusEnabled = (focusableItem): boolean => {
@@ -416,77 +409,19 @@ export const focusManager = (function () {
416
409
  group ? unregisterGroup(id) : unregisterItem(id);
417
410
  }
418
411
 
419
- async function setFocusOnMenu(currentRoute: string) {
420
- try {
421
- await waitForActiveScreen(currentRoute, focusableTree);
422
-
423
- const navbar = getNavbarNode(focusableTree);
424
-
425
- const selectedMenuItemId = R.find(
426
- (child) => child.component.props.selected,
427
- navbar.children
428
- )?.id;
429
-
430
- if (selectedMenuItemId) {
431
- // set focus on selected menu item
432
- setFocus(selectedMenuItemId);
433
-
434
- return;
435
- }
436
-
437
- const firstMenuItemId = R.path(["children", 0, "id"], navbar);
438
-
439
- if (firstMenuItemId) {
440
- // set focus on first menu item
441
- setFocus(firstMenuItemId);
442
- }
443
- } catch (error) {
444
- logger.log({
445
- message: "setFocusOnMenu – failed to put focus on top-menu",
446
- data: {
447
- currentRoute,
448
- error,
449
- },
450
- });
451
- }
452
- }
453
-
454
- async function setFocusOnContent(currentRoute: string) {
455
- // we need to put focus on content here
456
- // For doing it we have to wait registration of first focusable node into focusableTree
457
- // we wait until content node starts having children
458
- try {
459
- await waitForActiveScreen(currentRoute, focusableTree);
460
- await waitForContent(focusableTree);
461
-
462
- const content = getContentNode(focusableTree);
463
-
464
- const { success } = setInitialFocus(content);
465
-
466
- if (!success) {
467
- // we've failed to put initial focus on content, re-run "setFocusOnContent" again as a fallback
468
- throw Error(
469
- "we've failed to put initial focus on content, re-run 'setFocusOnContent' again as a fallback"
470
- );
471
- }
472
- } catch (error) {
473
- setFocusOnContent(currentRoute);
474
- }
475
- }
476
-
477
- function isTransitionInProgress() {
412
+ function isCurrentFocusOnTheTopScreen() {
478
413
  const routes = R.pathOr([], ["root", "children"], focusableTree);
479
414
 
480
415
  if (routes.length <= 1) {
481
416
  // there is only one or zero routes
482
- return false;
417
+ return true;
483
418
  }
484
419
 
485
- return isTransitionHappening(currentFocusNode, R.last(routes));
420
+ return haveSameParentBeforeRoot(currentFocusNode, R.last(routes));
486
421
  }
487
422
 
488
423
  function recoverFocus() {
489
- if (isTransitionInProgress()) {
424
+ if (!isCurrentFocusOnTheTopScreen()) {
490
425
  // We've failed to set focused node on the new screen => run focus recovery
491
426
  setInitialFocus();
492
427
  }
@@ -498,7 +433,7 @@ export const focusManager = (function () {
498
433
  * @param {Object} direction of the scroll
499
434
  */
500
435
  function moveFocus(direction) {
501
- if (isTransitionInProgress()) {
436
+ if (!isCurrentFocusOnTheTopScreen()) {
502
437
  // We are opening new screen. We need to ignore movement of focus.
503
438
  return false;
504
439
  }
@@ -600,8 +535,7 @@ export const focusManager = (function () {
600
535
  focusableTree,
601
536
  getGroupRootById,
602
537
  isGroupItemFocused,
603
- setFocusOnMenu,
604
- setFocusOnContent,
605
538
  recoverFocus,
539
+ isCurrentFocusOnTheTopScreen,
606
540
  };
607
541
  })();
@@ -59,7 +59,7 @@ export class Tree {
59
59
  /**
60
60
  * Update node with provided data from newNode
61
61
  * @private
62
- * @param {Object} node to update
62
+ * @param {Object} currentNode to update
63
63
  * @param {Object} newNode node to take data from
64
64
  */
65
65
  updateNode(currentNode, newNode) {
@@ -175,7 +175,6 @@ export class Tree {
175
175
  * @private
176
176
  * @param {Object} node to check
177
177
  * @returns True if node has defined groupID
178
- * @returns False if node has NOT defined groupID
179
178
  */
180
179
  hasGroupID(node) {
181
180
  return node.component && node.component.props.groupId;
@@ -191,7 +190,7 @@ export class Tree {
191
190
  const findChildNode = this.findInTree(node.component.props.groupId);
192
191
 
193
192
  if (findChildNode) {
194
- this.root.children.pop(findChildNode);
193
+ this.root.children.pop();
195
194
  node.children.push(findChildNode);
196
195
  }
197
196
  }
@@ -1,6 +1,7 @@
1
1
  import { allPass, pathOr, startsWith, isNil } from "ramda";
2
2
  import { isNilOrEmpty } from "@applicaster/zapp-react-native-utils/reactUtils/helpers";
3
3
  import { isZero } from "@applicaster/zapp-react-native-utils/numberUtils";
4
+ import { QUICK_BRICK_NAVBAR } from "@applicaster/quick-brick-core/const";
4
5
 
5
6
  import { rejectItemByPath } from "../../../../objectUtils";
6
7
  import {
@@ -154,10 +155,10 @@ const excludeFromFocusSearching = pathOr(false, [
154
155
  "excludeFromFocusSearching",
155
156
  ]);
156
157
 
157
- const isNavBar = (target) => startsWith("navbar", target?.id);
158
+ const isNavBar = (target) => startsWith(QUICK_BRICK_NAVBAR, target?.id);
158
159
 
159
160
  const ignoreMenuIfMultipleTargets = (nodes) => {
160
- if (nodes.length > 1 && nodes.map((n) => n?.target?.id).includes("navbar")) {
161
+ if (nodes.length > 1) {
161
162
  return nodes.filter((n) => !isNavBar(n?.target));
162
163
  }
163
164
 
@@ -190,7 +191,6 @@ const toDistance = ({ target, direction, comparisonRect }) => {
190
191
  * Get target in shortest distance in specified direction
191
192
  * @private
192
193
  * @param {Object} direction of the navigation, which led to this focus change
193
- * @param {Object} excludedNode node which should be excluded from target group
194
194
  * @param {Array} targetNodes array of input target nodes
195
195
  * @param {Object} comparisonRect rectangle to compare sides in direction.
196
196
  * @returns {Object} target in direction.
@@ -205,7 +205,7 @@ export function getTargetInDirection(
205
205
  const overrideTarget = currentNode?.component?.props[overridePropName];
206
206
 
207
207
  if (overrideTarget) {
208
- const target = targetNodes.find((n) => n.id === overrideTarget);
208
+ const target = targetNodes.find((n) => n?.id === overrideTarget);
209
209
 
210
210
  if (target) return target;
211
211
  }
@@ -299,8 +299,7 @@ export function findFocusableNode(direction, currentFocusNode) {
299
299
  * @public
300
300
  * @param {Object} direction of the navigation, which led to this focus change
301
301
  * @param {Object} component - object to check props.prioritiseFocusOn
302
- * @returns {Boolean} TRUE if object has priority in direction.
303
- * @returns {Boolean} FALSE if object has NO priority in direction.
302
+ * @returns {Boolean} TRUE if object has priority in direction. FALSE if object has NO priority in direction.
304
303
  */
305
304
  export function hasPriorityInDirection(direction, component) {
306
305
  const { prioritiseFocusOn = 0 } = component.props;
@@ -333,9 +332,9 @@ export const getNodeBeforeRoot = (node) => {
333
332
  return getNodeBeforeRoot(node.parent);
334
333
  };
335
334
 
336
- export const isTransitionHappening = (currentNode, nextNode) => {
335
+ export const haveSameParentBeforeRoot = (currentNode, nextNode) => {
337
336
  const routeForCurrentNode = getNodeBeforeRoot(currentNode);
338
337
  const routeForNextNode = getNodeBeforeRoot(nextNode);
339
338
 
340
- return routeForCurrentNode?.id !== routeForNextNode?.id;
339
+ return routeForCurrentNode?.id === routeForNextNode?.id;
341
340
  };
@@ -1,5 +1,9 @@
1
1
  import { isNotNil } from "@applicaster/zapp-react-native-utils/reactUtils/helpers";
2
2
  import { find, last, startsWith, pathOr } from "ramda";
3
+ import {
4
+ QUICK_BRICK_NAVBAR,
5
+ QUICK_BRICK_CONTENT,
6
+ } from "@applicaster/quick-brick-core/const";
3
7
 
4
8
  // run check each 300 ms
5
9
  // run this check too often could lead to performance penalty on low-end devices
@@ -60,7 +64,9 @@ const getActiveScreenChildren = (focusableTree) => {
60
64
 
61
65
  export const getContentNode = (focusableTree) => {
62
66
  const content = find(
63
- (child) => startsWith("content", child.id),
67
+ (child) =>
68
+ startsWith(QUICK_BRICK_CONTENT, child.id) ||
69
+ startsWith("player", child.id),
64
70
  getActiveScreenChildren(focusableTree)
65
71
  );
66
72
 
@@ -69,7 +75,7 @@ export const getContentNode = (focusableTree) => {
69
75
 
70
76
  export const getNavbarNode = (focusableTree) => {
71
77
  const navbar = find(
72
- (child) => startsWith("navbar", child.id),
78
+ (child) => startsWith(QUICK_BRICK_NAVBAR, child.id),
73
79
  getActiveScreenChildren(focusableTree)
74
80
  );
75
81