@applicaster/zapp-react-native-ui-components 12.0.0-rc.88 → 12.0.0-rc.89

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.
@@ -11,6 +11,7 @@ import { noop } from "@applicaster/zapp-react-native-utils/functionUtils";
11
11
 
12
12
  import { CellWithFocusable } from "./CellWithFocusable";
13
13
  import { BaseFocusable } from "../BaseFocusable";
14
+ import { AccessibilityManager } from "@applicaster/zapp-react-native-utils/appUtils/accessibilityManager";
14
15
 
15
16
  type Props = {
16
17
  item: {
@@ -139,6 +140,10 @@ export class CellComponent extends React.Component<Props> {
139
140
  shouldScrollVertically?.(mouse, focusable, id, title)
140
141
  ) {
141
142
  this.scrollVertically(focusable);
143
+
144
+ const accessibilityManager = AccessibilityManager.getInstance();
145
+ // Text from DSP should be localized already
146
+ accessibilityManager.readText({ text: title });
142
147
  }
143
148
  }
144
149
  }
@@ -5,13 +5,30 @@ import * as R from "ramda";
5
5
  import { ScreenLayoutContext } from "@applicaster/zapp-react-native-ui-components/Contexts/ScreenLayoutContext";
6
6
  import { useNavigation } from "@applicaster/zapp-react-native-utils/reactHooks/navigation";
7
7
  import { ifEmptyUseFallback } from "@applicaster/zapp-react-native-utils/cellUtils";
8
- import { useCurrentScreenData } from "@applicaster/zapp-react-native-utils/reactHooks/screen";
8
+ import {
9
+ useCurrentScreenData,
10
+ useNavbarState,
11
+ } from "@applicaster/zapp-react-native-utils/reactHooks/screen";
9
12
  import { useTheme } from "@applicaster/zapp-react-native-utils/theme";
10
13
 
11
14
  import { useScreenConfiguration } from "../../River/useScreenConfiguration";
12
- import { routeIsPlayerScreen } from "@applicaster/zapp-react-native-utils/navigationUtils";
15
+ import {
16
+ getNavigationProps,
17
+ resolveNavigationPlugin,
18
+ routeIsPlayerScreen,
19
+ } from "@applicaster/zapp-react-native-utils/navigationUtils";
20
+ import { isApplePlatform } from "@applicaster/zapp-react-native-utils/reactUtils";
21
+ import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
22
+ import { NavBarContainer } from "./NavBarContainer";
23
+
24
+ type ComponentsExtraProps = {
25
+ Background?: Record<string, any>;
26
+ NavBar?: Record<string, any>;
27
+ };
13
28
 
14
29
  type Props = {
30
+ ComponentsExtraProps?: ComponentsExtraProps;
31
+ NavBar: React.ComponentType<any>;
15
32
  children: React.ReactNode;
16
33
  };
17
34
 
@@ -30,9 +47,13 @@ const styles = StyleSheet.create({
30
47
  container: { flex: 1, height: "100%", width: "100%" },
31
48
  });
32
49
 
50
+ const isTVOS = isApplePlatform();
51
+
33
52
  // eslint-disable-next-line react/display-name
34
53
  export const ScreenContainer = React.memo(function ScreenContainer({
35
54
  children,
55
+ ComponentsExtraProps,
56
+ NavBar,
36
57
  }: Props) {
37
58
  const { screenMarginBottom } = React.useContext(ScreenLayoutContext);
38
59
  const { currentRoute, screenData } = useNavigation();
@@ -80,9 +101,67 @@ export const ScreenContainer = React.memo(function ScreenContainer({
80
101
  [themeStyles]
81
102
  );
82
103
 
104
+ const navigator = useNavigation();
105
+ const { activeRiver } = navigator;
106
+ const { title, visible } = useNavbarState();
107
+
108
+ const { plugins = [] } = usePickFromState([
109
+ "appState",
110
+ "remoteConfigurations",
111
+ "plugins",
112
+ ]);
113
+
114
+ const navigationProps = getNavigationProps({
115
+ navigator,
116
+ title,
117
+ category: "menu",
118
+ });
119
+
120
+ const menuPlugin = React.useMemo(
121
+ () =>
122
+ resolveNavigationPlugin({
123
+ category: "menu",
124
+ navigations: activeRiver?.navigations,
125
+ plugins,
126
+ }) as QuickBrickPlugin,
127
+ []
128
+ );
129
+
130
+ const NavBarComponent = React.useMemo(
131
+ () => NavBar || (menuPlugin.module as React.ComponentType<any>),
132
+ []
133
+ );
134
+
135
+ const [navBarReady, setNavBarReady] = React.useState(false);
136
+
137
+ const navBarContainer = (
138
+ <NavBarContainer isVisible={visible} onReady={setNavBarReady}>
139
+ <NavBarComponent
140
+ ref={ComponentsExtraProps?.NavBar?.ref}
141
+ isVisible={visible}
142
+ menuPlugin={menuPlugin}
143
+ navigationProps={navigationProps}
144
+ {...R.omit(["ref"])(ComponentsExtraProps?.NavBar)}
145
+ />
146
+ </NavBarContainer>
147
+ );
148
+
83
149
  return (
84
- <View testID="screen-container" style={viewStyles}>
85
- {children}
86
- </View>
150
+ <>
151
+ {!isTVOS ? navBarContainer : null}
152
+ {navBarReady ? (
153
+ /**
154
+ Need to re-mount this component on each navigation event
155
+ It's a hack to work around the fact that we don't support
156
+ correct screen rendering in our navigator (shared currentRoute state)
157
+ **/
158
+ <View testID="screen-container" style={viewStyles}>
159
+ {children}
160
+ </View>
161
+ ) : null}
162
+ {/** Render NavBarContainer over ScreenContainer to let tvOS native
163
+ focus manager works correctly to focus nav bar items first **/}
164
+ {isTVOS ? navBarContainer : null}
165
+ </>
87
166
  );
88
167
  });
@@ -1,14 +1,27 @@
1
1
  import * as React from "react";
2
2
  import { View } from "react-native";
3
- import { render } from "@testing-library/react-native";
3
+ import { render, waitFor } from "@testing-library/react-native";
4
+ import { WrappedWithProviders } from "@applicaster/zapp-react-native-utils/testUtils";
4
5
 
5
6
  import { ScreenLayoutContext } from "@applicaster/zapp-react-native-ui-components/Contexts/ScreenLayoutContext";
6
7
 
7
8
  const navigator_mock = {
8
9
  currentRoute: "/river/A1234",
9
10
  screenData: {},
11
+ activeRiver: {
12
+ navigations: {},
13
+ id: "A1234",
14
+ home: false,
15
+ },
10
16
  };
11
17
 
18
+ jest.mock("@applicaster/zapp-react-native-utils/navigationUtils", () => ({
19
+ ...jest.requireActual<any>(
20
+ "@applicaster/zapp-react-native-utils/navigationUtils"
21
+ ),
22
+ resolveNavigationPlugin: () => ({}),
23
+ }));
24
+
12
25
  jest.mock("@applicaster/quick-brick-core/App/ActionSetters", () => ({
13
26
  useRiverInitialState: () => ({}),
14
27
  }));
@@ -17,13 +30,13 @@ jest.mock("@applicaster/zapp-react-native-utils/reactHooks/navigation", () => ({
17
30
  useNavigation: () => navigator_mock,
18
31
  }));
19
32
 
20
- jest.mock("../../../River/useScreenConfiguration.ts", () => ({
33
+ jest.mock("../../../River/useScreenConfiguration", () => ({
21
34
  useScreenConfiguration: () => ({}),
22
35
  }));
23
36
 
24
- jest.mock("@applicaster/zapp-react-native-utils/reactHooks/screen", () => ({
25
- useCurrentScreenData: jest.fn(() => ({})),
26
- }));
37
+ jest.mock(
38
+ "@applicaster/zapp-react-native-utils/reactHooks/screen/useCurrentScreenData"
39
+ );
27
40
 
28
41
  jest.mock("@applicaster/zapp-react-native-utils/theme", () => ({
29
42
  useTheme: () => ({}),
@@ -44,42 +57,39 @@ describe("ScreenContainer", () => {
44
57
  const setScreenLayout = () => {};
45
58
 
46
59
  const wrapper = ({ children }) => (
47
- <ScreenLayoutContext.Provider value={{ ...screenLayout, setScreenLayout }}>
48
- {children}
49
- </ScreenLayoutContext.Provider>
60
+ <WrappedWithProviders>
61
+ <ScreenLayoutContext.Provider
62
+ value={{ ...screenLayout, setScreenLayout }}
63
+ >
64
+ <ScreenContainer NavBar={View}>{children}</ScreenContainer>
65
+ </ScreenLayoutContext.Provider>
66
+ </WrappedWithProviders>
50
67
  );
51
68
 
52
69
  const TestComp = () => <View testID="test-component" />;
53
70
 
54
71
  it("renders", () => {
55
- const { toJSON } = render(
56
- <ScreenContainer>
57
- <TestComp />
58
- </ScreenContainer>,
59
- { wrapper }
60
- );
72
+ const { toJSON } = render(<TestComp />, { wrapper });
61
73
 
62
74
  expect(toJSON()).toMatchSnapshot();
63
75
  });
64
76
 
65
- it("renders passed component", () => {
66
- const { getByTestId } = render(
67
- <ScreenContainer>
68
- <TestComp />
69
- </ScreenContainer>,
70
- { wrapper }
71
- );
77
+ it("renders passed component", async () => {
78
+ const { getByTestId } = render(<TestComp />, { wrapper });
79
+
80
+ await waitFor(() => {
81
+ return expect(getByTestId("screen-container")).toBeDefined();
82
+ });
72
83
 
73
84
  expect(getByTestId("test-component")).toBeDefined();
74
85
  });
75
86
 
76
- it("sets margins provided by the theme", () => {
77
- const { getByTestId } = render(
78
- <ScreenContainer>
79
- <TestComp />
80
- </ScreenContainer>,
81
- { wrapper }
82
- );
87
+ it("sets margins provided by the theme", async () => {
88
+ const { getByTestId } = render(<TestComp />, { wrapper });
89
+
90
+ await waitFor(() => {
91
+ return expect(getByTestId("screen-container")).toBeDefined();
92
+ });
83
93
 
84
94
  const screen = getByTestId("screen-container");
85
95
  expect(screen.props.style).toMatchSnapshot();
@@ -1,28 +1,40 @@
1
1
  // Jest Snapshot v1, https://goo.gl/fbAQLP
2
2
 
3
3
  exports[`ScreenContainer renders 1`] = `
4
- <View
4
+ <RNCSafeAreaProvider
5
+ onInsetsChange={[Function]}
5
6
  style={
6
7
  Array [
7
8
  Object {
8
9
  "flex": 1,
9
- "height": "100%",
10
- "width": "100%",
11
- },
12
- Object {
13
- "backgroundColor": "transparent",
14
- "marginBottom": 10,
15
- "paddingBottom": 0,
16
- "paddingTop": 0,
17
10
  },
11
+ undefined,
18
12
  ]
19
13
  }
20
- testID="screen-container"
21
14
  >
22
15
  <View
23
- testID="test-component"
24
- />
25
- </View>
16
+ style={
17
+ Array [
18
+ Object {
19
+ "position": "absolute",
20
+ "top": 0,
21
+ "width": 1920,
22
+ "zIndex": 10,
23
+ },
24
+ Object {
25
+ "maxHeight": 10,
26
+ },
27
+ ]
28
+ }
29
+ testID="nav-bar-container"
30
+ >
31
+ <View
32
+ isVisible={true}
33
+ menuPlugin={Object {}}
34
+ navigationProps={null}
35
+ />
36
+ </View>
37
+ </RNCSafeAreaProvider>
26
38
  `;
27
39
 
28
40
  exports[`ScreenContainer sets margins provided by the theme 1`] = `
@@ -21,10 +21,11 @@ const mockStore = configureStore()({
21
21
  describe("Layout TV", () => {
22
22
  const navigator = {
23
23
  currentRoute: "/river/A1234",
24
+ canGoBack: jest.fn(),
24
25
  mainStack: [
25
26
  {
26
27
  route: "/river/A1234",
27
- state: "state",
28
+ state: { screen: {} },
28
29
  },
29
30
  ],
30
31
  };
@@ -4,22 +4,14 @@ import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
4
4
  import { useNavigation } from "@applicaster/zapp-react-native-utils/reactHooks/navigation";
5
5
  import { useTheme } from "@applicaster/zapp-react-native-utils/theme";
6
6
 
7
- import {
8
- getNavigationProps,
9
- resolveNavigationPlugin,
10
- routeIsPlayerScreen,
11
- } from "@applicaster/zapp-react-native-utils/navigationUtils";
12
-
13
7
  import { getBackgroundImageUrl } from "../utils";
14
8
  import { LayoutContainer } from "./LayoutContainer";
15
- import { NavBarContainer } from "./NavBarContainer";
16
9
  import { ScreenContainer } from "./ScreenContainer";
17
10
 
18
11
  import { ScreenLayoutContextProvider } from "./ScreenLayoutContextProvider";
19
- import { isApplePlatform } from "@applicaster/zapp-react-native-utils/reactUtils";
20
12
  import { PathnameContext } from "../../../Contexts/PathnameContext";
21
- import { useNavbarState } from "@applicaster/zapp-react-native-utils/reactHooks/screen/useScreenContext";
22
13
  import { ScreenDataContext } from "../../../Contexts/ScreenDataContext";
14
+ import { ScreenContextProvider } from "../../../Contexts/ScreenContext";
23
15
 
24
16
  type Components = {
25
17
  NavBar: React.ComponentType<any>;
@@ -40,20 +32,9 @@ type Props = {
40
32
  const Layout = ({ Components, ComponentsExtraProps, children }: Props) => {
41
33
  const navigator = useNavigation();
42
34
  const theme = useTheme();
43
- const { title, visible } = useNavbarState();
44
- const { activeRiver, currentRoute } = navigator;
45
-
46
- const {
47
- appState: { appReady = false } = {},
48
- remoteConfigurations,
49
- plugins = [],
50
- } = usePickFromState(["appState", "remoteConfigurations", "plugins"]);
51
35
 
52
- const navigationProps = getNavigationProps({
53
- navigator,
54
- title,
55
- category: "menu",
56
- });
36
+ const { appState: { appReady = false } = {}, remoteConfigurations } =
37
+ usePickFromState(["appState", "remoteConfigurations", "plugins"]);
57
38
 
58
39
  const backgroundColor = React.useMemo(() => theme.app_background_color, []);
59
40
 
@@ -62,37 +43,6 @@ const Layout = ({ Components, ComponentsExtraProps, children }: Props) => {
62
43
  [remoteConfigurations]
63
44
  );
64
45
 
65
- const menuPlugin = React.useMemo(
66
- () =>
67
- resolveNavigationPlugin({
68
- category: "menu",
69
- navigations: activeRiver?.navigations,
70
- plugins,
71
- }) as QuickBrickPlugin,
72
- []
73
- );
74
-
75
- const NavBar = React.useMemo(
76
- () => Components.NavBar || (menuPlugin.module as React.ComponentType<any>),
77
- []
78
- );
79
-
80
- const [navBarReady, setNavBarReady] = React.useState(false);
81
-
82
- const navBarContainer = (
83
- <NavBarContainer isVisible={visible} onReady={setNavBarReady}>
84
- <NavBar
85
- ref={ComponentsExtraProps?.NavBar?.ref}
86
- isVisible={visible && !routeIsPlayerScreen(currentRoute)}
87
- menuPlugin={menuPlugin}
88
- navigationProps={navigationProps}
89
- {...R.omit(["ref"])(ComponentsExtraProps?.NavBar)}
90
- />
91
- </NavBarContainer>
92
- );
93
-
94
- const isTVOS = isApplePlatform();
95
-
96
46
  if (!appReady) {
97
47
  return null;
98
48
  }
@@ -107,18 +57,14 @@ const Layout = ({ Components, ComponentsExtraProps, children }: Props) => {
107
57
  >
108
58
  <ScreenDataContext.Provider value={navigator.data}>
109
59
  <PathnameContext.Provider value={navigator.currentRoute}>
110
- {!isTVOS ? navBarContainer : null}
111
- {navBarReady ? (
112
- /**
113
- Need to re-mount this component on each navigation event
114
- It's a hack to work around the fact that we don't support
115
- correct screen rendering in our navigator (shared currentRoute state)
116
- **/
117
- <ScreenContainer>{children}</ScreenContainer>
118
- ) : null}
119
- {/** Render NavBarContainer over ScreenContainer to let tvOS native
120
- focus manager works correctly to focus nav bar items first **/}
121
- {isTVOS ? navBarContainer : null}
60
+ <ScreenContextProvider pathname={navigator.currentRoute}>
61
+ <ScreenContainer
62
+ ComponentsExtraProps={ComponentsExtraProps}
63
+ NavBar={Components.NavBar}
64
+ >
65
+ {children}
66
+ </ScreenContainer>
67
+ </ScreenContextProvider>
122
68
  </PathnameContext.Provider>
123
69
  </ScreenDataContext.Provider>
124
70
  </Components.Background>
@@ -9,6 +9,7 @@ import { PathnameContext } from "@applicaster/zapp-react-native-ui-components/Co
9
9
 
10
10
  import { Screen } from "../Screen/TV/index.web";
11
11
  import { isLast } from "@applicaster/zapp-react-native-utils/arrayUtils";
12
+ import { ScreenContextProvider } from "../../Contexts/ScreenContext";
12
13
 
13
14
  type Components = {
14
15
  NavBar: React.ComponentType<any>;
@@ -43,7 +44,9 @@ export const StackNavigator = ({ Components }: Props) => {
43
44
  >
44
45
  <ScreenDataContext.Provider value={state}>
45
46
  <PathnameContext.Provider value={route}>
46
- <Screen route={route} Components={Components} />
47
+ <ScreenContextProvider pathname={route}>
48
+ <Screen route={route} Components={Components} />
49
+ </ScreenContextProvider>
47
50
  </PathnameContext.Provider>
48
51
  </ScreenDataContext.Provider>
49
52
  </FocusableGroup>
@@ -1,5 +1,5 @@
1
1
  import * as React from "react";
2
- import { last, pathOr } from "ramda";
2
+ import { last } from "ramda";
3
3
  import { View, StyleSheet } from "react-native";
4
4
  import {
5
5
  getNavigationProps,
@@ -9,12 +9,16 @@ import {
9
9
  import { useNavigation } from "@applicaster/zapp-react-native-utils/reactHooks";
10
10
  import { noop } from "@applicaster/zapp-react-native-utils/functionUtils";
11
11
  import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
12
- import { useScreenBackgroundColor } from "@applicaster/zapp-react-native-utils/reactHooks/screen";
12
+ import {
13
+ useNavbarState,
14
+ useScreenBackgroundColor,
15
+ } from "@applicaster/zapp-react-native-utils/reactHooks/screen";
13
16
  import { isNilOrEmpty } from "@applicaster/zapp-react-native-utils/reactUtils/helpers";
14
17
 
15
18
  import { NavBarContainer } from "../../Layout/TV/NavBarContainer";
16
19
  import { ScreenResolver } from "../../ScreenResolver";
17
20
  import { useInitialFocus, useRestoreFocus } from "./hooks";
21
+ import { isPlayerPlugin } from "@applicaster/zapp-react-native-utils/pluginUtils";
18
22
 
19
23
  const styles = StyleSheet.create({
20
24
  container: {
@@ -36,25 +40,6 @@ type Props = {
36
40
  Components: Components;
37
41
  };
38
42
 
39
- const getPluginType = pathOr("unknown_plugin_type", [
40
- "state",
41
- "screen",
42
- "plugin_type",
43
- ]);
44
-
45
- export const isPresentFullScreen = pathOr(false, [
46
- "state",
47
- "screen",
48
- "module",
49
- "presentFullScreen",
50
- ]);
51
-
52
- const isPlayerPlugin = (routeState): boolean =>
53
- getPluginType(routeState) === "player";
54
-
55
- const isLoginPlugin = (routeState): boolean =>
56
- getPluginType(routeState) === "login";
57
-
58
43
  const getActiveRiver = ({
59
44
  screenId,
60
45
  screenType,
@@ -156,10 +141,8 @@ export const Screen = ({ route, Components }: Props) => {
156
141
  menuPlugin.module) as React.ComponentType<any>;
157
142
 
158
143
  const isPlayer = isPlayerPlugin(routeState);
159
- const isLogin = isLoginPlugin(routeState);
160
- const isFullScreen = isPresentFullScreen(routeState);
161
144
 
162
- const isNavBarVisible = !isPlayer && !isLogin && !isFullScreen;
145
+ const { visible: isNavBarVisible } = useNavbarState();
163
146
 
164
147
  const screenData =
165
148
  screenType === "hooks" || isPlayer
@@ -168,7 +168,7 @@ export function Screen(_props: Props) {
168
168
  layoutData,
169
169
  })
170
170
  ) {
171
- return null;
171
+ return <View style={style} />;
172
172
  }
173
173
 
174
174
  return (
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@applicaster/zapp-react-native-ui-components",
3
- "version": "12.0.0-rc.88",
3
+ "version": "12.0.0-rc.89",
4
4
  "description": "Applicaster Zapp React Native ui components for the Quick Brick App",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -34,10 +34,10 @@
34
34
  "redux-mock-store": "^1.5.3"
35
35
  },
36
36
  "dependencies": {
37
- "@applicaster/applicaster-types": "12.0.0-rc.88",
38
- "@applicaster/zapp-react-native-bridge": "12.0.0-rc.88",
39
- "@applicaster/zapp-react-native-redux": "12.0.0-rc.88",
40
- "@applicaster/zapp-react-native-utils": "12.0.0-rc.88",
37
+ "@applicaster/applicaster-types": "12.0.0-rc.89",
38
+ "@applicaster/zapp-react-native-bridge": "12.0.0-rc.89",
39
+ "@applicaster/zapp-react-native-redux": "12.0.0-rc.89",
40
+ "@applicaster/zapp-react-native-utils": "12.0.0-rc.89",
41
41
  "promise": "^8.3.0",
42
42
  "react-router-native": "^5.1.2",
43
43
  "url": "^0.11.0",