@applicaster/zapp-react-dom-app 14.0.0-alpha.5351122050 → 14.0.0-alpha.5365702091

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.
@@ -7,6 +7,7 @@ jest.mock("@applicaster/zapp-react-native-utils/appUtils", () => ({
7
7
  focusManager: {
8
8
  isFocusOnMenu: jest.fn(),
9
9
  isFocusOnContent: jest.fn(),
10
+ isTabsScreenContentFocused: jest.fn(),
10
11
  },
11
12
  }));
12
13
 
@@ -44,6 +45,20 @@ describe("withBackToTopActionHOC", () => {
44
45
  jest.clearAllMocks();
45
46
  });
46
47
 
48
+ it("returns PLATFORM_BACK when on root screen, and startup hooks", () => {
49
+ expect.assertions(1);
50
+
51
+ (useCurrentScreenIsRoot as jest.Mock).mockReturnValue(true);
52
+
53
+ (useNavigation as jest.Mock).mockReturnValue({
54
+ startUpHooks: ["some_startup_hook"],
55
+ });
56
+
57
+ render(<Wrapped />);
58
+
59
+ expect(receivedProps.backToTopAction()).toBe("PLATFORM_BACK");
60
+ });
61
+
47
62
  it("returns PLATFORM_BACK when on root screen, focus on menu, and is home", () => {
48
63
  expect.assertions(1);
49
64
 
@@ -52,7 +67,7 @@ describe("withBackToTopActionHOC", () => {
52
67
  (useCurrentScreenIsTabs as jest.Mock).mockReturnValue(false);
53
68
 
54
69
  (useNavigation as jest.Mock).mockReturnValue({
55
- getNestedEntry: () => undefined,
70
+ startUpHooks: [],
56
71
  });
57
72
 
58
73
  (focusManager.isFocusOnMenu as jest.Mock).mockReturnValue(true);
@@ -60,9 +75,7 @@ describe("withBackToTopActionHOC", () => {
60
75
 
61
76
  render(<Wrapped />);
62
77
 
63
- expect(receivedProps.backToTopAction()).toEqual({
64
- action: "PLATFORM_BACK",
65
- });
78
+ expect(receivedProps.backToTopAction()).toBe("PLATFORM_BACK");
66
79
  });
67
80
 
68
81
  it("returns GO_HOME when on root screen, focus on menu, and not home", () => {
@@ -73,23 +86,23 @@ describe("withBackToTopActionHOC", () => {
73
86
  (useCurrentScreenIsTabs as jest.Mock).mockReturnValue(false);
74
87
 
75
88
  (useNavigation as jest.Mock).mockReturnValue({
76
- getNestedEntry: () => undefined,
89
+ startUpHooks: [],
77
90
  });
78
91
 
79
92
  (focusManager.isFocusOnMenu as jest.Mock).mockReturnValue(true);
80
93
  (focusManager.isFocusOnContent as jest.Mock).mockReturnValue(false);
81
94
 
82
95
  render(<Wrapped />);
83
- expect(receivedProps.backToTopAction()).toEqual({ action: "GO_HOME" });
96
+ expect(receivedProps.backToTopAction()).toBe("GO_HOME");
84
97
  });
85
98
 
86
- it("returns FOCUS_TOP_NAVIGATION when on root screen and focus on content without tabs_screen", () => {
99
+ it("returns FOCUS_ON_SELECTED_TOP_MENU_ITEM when on root screen and focus on content without tabs_screen", () => {
87
100
  (useCurrentScreenIsRoot as jest.Mock).mockReturnValue(true);
88
101
  (useCurrentScreenIsHome as jest.Mock).mockReturnValue(false);
89
102
  (useCurrentScreenIsTabs as jest.Mock).mockReturnValue(false);
90
103
 
91
104
  (useNavigation as jest.Mock).mockReturnValue({
92
- getNestedEntry: () => "selectedEntry",
105
+ startUpHooks: [],
93
106
  });
94
107
 
95
108
  (focusManager.isFocusOnMenu as jest.Mock).mockReturnValue(false);
@@ -97,36 +110,30 @@ describe("withBackToTopActionHOC", () => {
97
110
 
98
111
  render(<Wrapped />);
99
112
 
100
- expect(receivedProps.backToTopAction()).toEqual({
101
- action: "FOCUS_TOP_NAVIGATION",
102
- payload: {
103
- isTabsScreen: false,
104
- selectedEntry: "selectedEntry",
105
- },
106
- });
113
+ expect(receivedProps.backToTopAction()).toBe(
114
+ "FOCUS_ON_SELECTED_TOP_MENU_ITEM"
115
+ );
107
116
  });
108
117
 
109
- it("returns FOCUS_TOP_NAVIGATION when on root screen and focus on content with tabs_screen", () => {
118
+ it("returns FOCUS_ON_SELECTED_TAB_ITEM when on root screen and focus on content with tabs_screen", () => {
110
119
  (useCurrentScreenIsRoot as jest.Mock).mockReturnValue(true);
111
120
  (useCurrentScreenIsHome as jest.Mock).mockReturnValue(false);
112
121
  (useCurrentScreenIsTabs as jest.Mock).mockReturnValue(true);
113
122
 
114
123
  (useNavigation as jest.Mock).mockReturnValue({
115
- getNestedEntry: () => "selectedEntry",
124
+ startUpHooks: [],
116
125
  });
117
126
 
118
127
  (focusManager.isFocusOnMenu as jest.Mock).mockReturnValue(false);
119
128
  (focusManager.isFocusOnContent as jest.Mock).mockReturnValue(true);
120
129
 
130
+ (focusManager.isTabsScreenContentFocused as jest.Mock).mockReturnValue(
131
+ true
132
+ );
133
+
121
134
  render(<Wrapped />);
122
135
 
123
- expect(receivedProps.backToTopAction()).toEqual({
124
- action: "FOCUS_TOP_NAVIGATION",
125
- payload: {
126
- isTabsScreen: true,
127
- selectedEntry: "selectedEntry",
128
- },
129
- });
136
+ expect(receivedProps.backToTopAction()).toBe("FOCUS_ON_SELECTED_TAB_ITEM");
130
137
  });
131
138
 
132
139
  it("returns GO_BACK in default case", () => {
@@ -137,13 +144,17 @@ describe("withBackToTopActionHOC", () => {
137
144
  (useCurrentScreenIsTabs as jest.Mock).mockReturnValue(false);
138
145
 
139
146
  (useNavigation as jest.Mock).mockReturnValue({
140
- getNestedEntry: () => undefined,
147
+ startUpHooks: [],
141
148
  });
142
149
 
143
150
  (focusManager.isFocusOnMenu as jest.Mock).mockReturnValue(false);
144
151
  (focusManager.isFocusOnContent as jest.Mock).mockReturnValue(false);
145
152
 
153
+ (focusManager.isTabsScreenContentFocused as jest.Mock).mockReturnValue(
154
+ false
155
+ );
156
+
146
157
  render(<Wrapped />);
147
- expect(receivedProps.backToTopAction()).toEqual({ action: "GO_BACK" });
158
+ expect(receivedProps.backToTopAction()).toBe("GO_BACK");
148
159
  });
149
160
  });
@@ -1,5 +1,10 @@
1
1
  import * as React from "react";
2
+ import { isFilledArray } from "@applicaster/zapp-react-native-utils/arrayUtils";
2
3
  import { focusManager } from "@applicaster/zapp-react-native-utils/appUtils";
4
+
5
+ import { useSubscriberFor } from "@applicaster/zapp-react-native-utils/reactHooks/useSubscriberFor";
6
+ import { QBUIComponentEvents } from "@applicaster/zapp-react-native-ui-components/events";
7
+
3
8
  import {
4
9
  useCurrentScreenIsHome,
5
10
  useCurrentScreenIsRoot,
@@ -7,10 +12,12 @@ import {
7
12
  } from "./hooks";
8
13
  import { useNavigation } from "@applicaster/zapp-react-native-utils/reactHooks";
9
14
 
10
- export type BACK_TO_TOP_ACTION = {
11
- action: "PLATFORM_BACK" | "GO_HOME" | "FOCUS_TOP_NAVIGATION" | "GO_BACK";
12
- payload?: { isTabsScreen: boolean; selectedEntry: ZappEntry };
13
- };
15
+ export type BACK_TO_TOP_ACTION =
16
+ | "PLATFORM_BACK"
17
+ | "GO_HOME"
18
+ | "GO_BACK"
19
+ | "FOCUS_ON_SELECTED_TOP_MENU_ITEM"
20
+ | "FOCUS_ON_SELECTED_TAB_ITEM";
14
21
 
15
22
  export type BackToTopAction = () => BACK_TO_TOP_ACTION;
16
23
 
@@ -21,28 +28,49 @@ export function withBackToTopActionHOC(Component) {
21
28
  const isTabsScreen = useCurrentScreenIsTabs();
22
29
 
23
30
  const navigator = useNavigation();
24
- const selectedEntry = navigator.getNestedEntry();
31
+
32
+ const isStartUpHook = isFilledArray(navigator.startUpHooks);
33
+
34
+ const emitFocusOnSelectedTab = useSubscriberFor(
35
+ QBUIComponentEvents.focusOnSelectedTab
36
+ );
37
+
38
+ const emitFocusOnSelectedTopMenuItem = useSubscriberFor(
39
+ QBUIComponentEvents.focusOnSelectedTopMenuItem
40
+ );
25
41
 
26
42
  const backToTopAction = React.useCallback((): BACK_TO_TOP_ACTION => {
43
+ if (isRoot && isStartUpHook) {
44
+ return "PLATFORM_BACK";
45
+ }
46
+
27
47
  if (isRoot && focusManager.isFocusOnMenu() && isHome) {
28
- return { action: "PLATFORM_BACK" };
48
+ return "PLATFORM_BACK";
29
49
  }
30
50
 
31
51
  if (isRoot && focusManager.isFocusOnMenu() && !isHome) {
32
- return { action: "GO_HOME" };
52
+ return "GO_HOME";
53
+ }
54
+
55
+ if (isRoot && isTabsScreen && focusManager.isTabsScreenContentFocused()) {
56
+ return "FOCUS_ON_SELECTED_TAB_ITEM";
33
57
  }
34
58
 
35
59
  if (isRoot && focusManager.isFocusOnContent()) {
36
- return {
37
- action: "FOCUS_TOP_NAVIGATION",
38
- payload: { isTabsScreen, selectedEntry },
39
- };
60
+ return "FOCUS_ON_SELECTED_TOP_MENU_ITEM";
40
61
  }
41
62
 
42
63
  // default
43
- return { action: "GO_BACK" };
44
- }, [isHome, isRoot, isTabsScreen, selectedEntry]);
64
+ return "GO_BACK";
65
+ }, [isHome, isRoot, isTabsScreen, isStartUpHook]);
45
66
 
46
- return <Component {...props} backToTopAction={backToTopAction} />;
67
+ return (
68
+ <Component
69
+ {...props}
70
+ backToTopAction={backToTopAction}
71
+ emitFocusOnSelectedTab={emitFocusOnSelectedTab}
72
+ emitFocusOnSelectedTopMenuItem={emitFocusOnSelectedTopMenuItem}
73
+ />
74
+ );
47
75
  };
48
76
  }
@@ -16,6 +16,7 @@ import {
16
16
  } from "@applicaster/zapp-react-native-utils/functionUtils";
17
17
 
18
18
  import {
19
+ AccessibilityManager,
19
20
  ARROW_KEYS,
20
21
  focusManager,
21
22
  keyCode,
@@ -58,7 +59,7 @@ import { withBackToTopActionHOC, BackToTopAction } from "./hoc";
58
59
  const { withXray } = getXray();
59
60
  const globalAny: any = global;
60
61
 
61
- const { log_debug, log_warning } = createLogger({
62
+ const { log_debug, log_warning, log_info } = createLogger({
62
63
  category: "InteractionManager",
63
64
  subsystem: "zapp-react-dom-app",
64
65
  });
@@ -76,6 +77,8 @@ type Props = {
76
77
  xray: XRayContext;
77
78
  confirmDialog: typeof confirmationDialogStore;
78
79
  backToTopAction: BackToTopAction;
80
+ emitFocusOnSelectedTopMenuItem: Callback;
81
+ emitFocusOnSelectedTab: Callback;
79
82
  };
80
83
 
81
84
  interface State {
@@ -86,8 +89,8 @@ interface State {
86
89
 
87
90
  type KeyCode = { code: string; keyCode: number | string };
88
91
 
89
- export const alertConfirmationMesage =
90
- "Are you sure you want to exit application?";
92
+ const VIDEO_PLAYER_CONTROLS_NAVIGATION_MESSAGE =
93
+ "Video player controls - use left/right to navigate";
91
94
 
92
95
  class InteractionManagerClass extends React.Component<Props, State> {
93
96
  onKeyDownListener: (keyCode: KeyCode) => void;
@@ -104,6 +107,8 @@ class InteractionManagerClass extends React.Component<Props, State> {
104
107
  private confirmDialog: ConfirmationDialogState =
105
108
  confirmationDialogStore.getState();
106
109
 
110
+ accessibilityManager: AccessibilityManager;
111
+
107
112
  state: State = {
108
113
  isKeyboardVisible: false,
109
114
  keyboardInput: "",
@@ -155,6 +160,7 @@ class InteractionManagerClass extends React.Component<Props, State> {
155
160
  this.confirmDialog.setConfirmAction(this.performExit);
156
161
  this.confirmDialog.setCancelAction(this.onConfirmDialogClose);
157
162
  this.longPressDetector = new KeyboardLongPressManager();
163
+ this.accessibilityManager = AccessibilityManager.getInstance();
158
164
  }
159
165
 
160
166
  componentDidMount() {
@@ -260,7 +266,6 @@ class InteractionManagerClass extends React.Component<Props, State> {
260
266
  */
261
267
  showConfirmationDialog({
262
268
  title: "",
263
- message: alertConfirmationMesage,
264
269
  confirmCompletion: this.performExit,
265
270
  });
266
271
  }
@@ -283,7 +288,6 @@ class InteractionManagerClass extends React.Component<Props, State> {
283
288
  } else {
284
289
  showConfirmationDialog({
285
290
  title: "",
286
- message: alertConfirmationMesage,
287
291
  confirmCompletion: this.performExit,
288
292
  cancelCompletion: this.onConfirmDialogClose,
289
293
  });
@@ -390,8 +394,14 @@ class InteractionManagerClass extends React.Component<Props, State> {
390
394
  note: backspace affects the keyboard input, so it behaves differently
391
395
  */
392
396
  onBackPress(event) {
393
- const { displayState, setDisplayState, navigator, backToTopAction } =
394
- this.props;
397
+ const {
398
+ displayState,
399
+ setDisplayState,
400
+ navigator,
401
+ backToTopAction,
402
+ emitFocusOnSelectedTopMenuItem,
403
+ emitFocusOnSelectedTab,
404
+ } = this.props;
395
405
 
396
406
  const { isDialogVisible } = confirmationDialogStore.getState();
397
407
  const { isKeyboardVisible } = this.state;
@@ -411,26 +421,41 @@ class InteractionManagerClass extends React.Component<Props, State> {
411
421
  return;
412
422
  }
413
423
 
414
- const { action, payload } = backToTopAction();
424
+ const action = backToTopAction();
415
425
 
416
426
  switch (displayState) {
417
427
  case DISPLAY_STATES.DEFAULT:
418
428
  if (action === "PLATFORM_BACK") {
429
+ log_info(action);
430
+
419
431
  this.platformBack();
420
432
  }
421
433
 
422
434
  if (action === "GO_HOME") {
435
+ log_info(action);
436
+
423
437
  this.goToHome();
424
438
  }
425
439
 
426
- if (action === "FOCUS_TOP_NAVIGATION") {
427
- focusManager.focusTopNavigation(
428
- payload.isTabsScreen,
429
- payload.selectedEntry
430
- );
440
+ if (action === "FOCUS_ON_SELECTED_TOP_MENU_ITEM") {
441
+ log_info(action);
442
+
443
+ // we don't have enough context at this point to set focus properly on selected top-menu-item, just emit event about it.
444
+ // TopMenu component is supposed to handle this event.
445
+ emitFocusOnSelectedTopMenuItem();
446
+ }
447
+
448
+ if (action === "FOCUS_ON_SELECTED_TAB_ITEM") {
449
+ log_info(action);
450
+
451
+ // we don't have enough context at this point to set focus properly on selected tab-menu-item, just emit event about it
452
+ // Tabs component is supposed to handle this event.
453
+ emitFocusOnSelectedTab();
431
454
  }
432
455
 
433
456
  if (action === "GO_BACK") {
457
+ log_info(action);
458
+
434
459
  if (navigator.canGoBack()) {
435
460
  navigator.goBack();
436
461
  }
@@ -576,6 +601,13 @@ class InteractionManagerClass extends React.Component<Props, State> {
576
601
  ) {
577
602
  if (displayState === DISPLAY_STATES.PLAYER) {
578
603
  setDisplayState(DISPLAY_STATES.HUD);
604
+
605
+ this.accessibilityManager.addHeading(
606
+ VIDEO_PLAYER_CONTROLS_NAVIGATION_MESSAGE
607
+ );
608
+
609
+ focusManager.recoverFocus();
610
+ this.resetHudTimeout();
579
611
  } else {
580
612
  focusManager.pressIn();
581
613
  focusManager.press();
@@ -620,6 +652,12 @@ class InteractionManagerClass extends React.Component<Props, State> {
620
652
  this.resetHudTimeout();
621
653
  }
622
654
 
655
+ if (displayState === DISPLAY_STATES.PLAYER) {
656
+ this.accessibilityManager.addHeading(
657
+ VIDEO_PLAYER_CONTROLS_NAVIGATION_MESSAGE
658
+ );
659
+ }
660
+
623
661
  return true;
624
662
  }
625
663
  }
@@ -1,4 +1,5 @@
1
1
  import * as React from "react";
2
+ import { createPortal } from "react-dom";
2
3
 
3
4
  import { Background } from "@applicaster/zapp-react-dom-ui-components/Components/Background";
4
5
  import { ConfirmDialog } from "@applicaster/zapp-react-dom-ui-components/Components/ConfirmDialog";
@@ -29,7 +30,7 @@ export function Layout({ children }: Props) {
29
30
  >
30
31
  {children}
31
32
  </LayoutComponent>
32
- <ConfirmDialog />
33
+ {createPortal(<ConfirmDialog />, document.body)}
33
34
  </>
34
35
  );
35
36
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@applicaster/zapp-react-dom-app",
3
- "version": "14.0.0-alpha.5351122050",
3
+ "version": "14.0.0-alpha.5365702091",
4
4
  "description": "Zapp App Component for Applicaster's Quick Brick React Native App",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -22,11 +22,11 @@
22
22
  },
23
23
  "homepage": "https://github.com/applicaster/zapp-react-dom-app#readme",
24
24
  "dependencies": {
25
- "@applicaster/zapp-react-dom-ui-components": "14.0.0-alpha.5351122050",
26
- "@applicaster/zapp-react-native-bridge": "14.0.0-alpha.5351122050",
27
- "@applicaster/zapp-react-native-redux": "14.0.0-alpha.5351122050",
28
- "@applicaster/zapp-react-native-ui-components": "14.0.0-alpha.5351122050",
29
- "@applicaster/zapp-react-native-utils": "14.0.0-alpha.5351122050",
25
+ "@applicaster/zapp-react-dom-ui-components": "14.0.0-alpha.5365702091",
26
+ "@applicaster/zapp-react-native-bridge": "14.0.0-alpha.5365702091",
27
+ "@applicaster/zapp-react-native-redux": "14.0.0-alpha.5365702091",
28
+ "@applicaster/zapp-react-native-ui-components": "14.0.0-alpha.5365702091",
29
+ "@applicaster/zapp-react-native-utils": "14.0.0-alpha.5365702091",
30
30
  "abortcontroller-polyfill": "^1.7.5",
31
31
  "typeface-montserrat": "^0.0.54",
32
32
  "video.js": "7.14.3",