@applicaster/zapp-react-native-ui-components 12.0.0-alpha.3893335783 → 12.0.0-alpha.3964644693

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 (52) hide show
  1. package/Components/BaseFocusable/index.tsx +1 -1
  2. package/Components/Cell/Cell.tsx +5 -5
  3. package/Components/Cell/CellWithFocusable.tsx +17 -5
  4. package/Components/Focusable/Focusable.tsx +6 -1
  5. package/Components/FocusableGroup/index.tsx +11 -2
  6. package/Components/HandlePlayable/HandlePlayable.tsx +3 -0
  7. package/Components/Layout/TV/ScreenLayoutContextProvider.tsx +2 -2
  8. package/Components/Layout/TV/__tests__/__snapshots__/index.test.tsx.snap +10 -50
  9. package/Components/Layout/TV/__tests__/index.test.tsx +19 -75
  10. package/Components/Layout/TV/index.tsx +0 -2
  11. package/Components/Layout/TV/index.web.tsx +33 -0
  12. package/Components/Layout/index.tsx +15 -11
  13. package/Components/MasterCell/DefaultComponents/BorderContainerView/index.tsx +88 -112
  14. package/Components/MasterCell/DefaultComponents/tv/ButtonContainerView/index.android.tsx +4 -1
  15. package/Components/MasterCell/DefaultComponents/tv/ButtonContainerView/index.tsx +4 -1
  16. package/Components/MasterCell/utils/index.ts +17 -30
  17. package/Components/Navigator/StackNavigator.tsx +48 -0
  18. package/Components/Navigator/index.ts +1 -0
  19. package/Components/PlayerContainer/PlayerContainer.tsx +8 -1
  20. package/Components/River/TV/River.tsx +0 -23
  21. package/Components/Screen/TV/hooks/index.ts +3 -0
  22. package/Components/Screen/TV/hooks/useInitialFocus.ts +70 -0
  23. package/Components/Screen/TV/hooks/useRestoreFocus.ts +22 -0
  24. package/Components/Screen/TV/index.web.tsx +178 -0
  25. package/Components/Screen/__tests__/Screen.test.tsx +3 -0
  26. package/Components/Screen/index.tsx +29 -1
  27. package/Components/ScreenResolver/index.tsx +3 -1
  28. package/Components/Transitioner/Transitioner.tsx +15 -29
  29. package/Components/VideoLive/LiveImageManager.ts +15 -1
  30. package/Components/VideoModal/ModalAnimation/AnimatedScrollModal.tsx +48 -38
  31. package/Components/VideoModal/ModalAnimation/AnimatedVideoPlayerComponent.tsx +40 -33
  32. package/Components/VideoModal/ModalAnimation/AnimationComponent.tsx +98 -81
  33. package/Components/VideoModal/ModalAnimation/ModalAnimationContext.tsx +13 -5
  34. package/Components/VideoModal/ModalAnimation/utils.ts +6 -4
  35. package/Components/VideoModal/PlayerDetails.tsx +3 -3
  36. package/Components/VideoModal/PlayerWrapper.tsx +9 -21
  37. package/Components/VideoModal/VideoModal.tsx +4 -4
  38. package/Components/VideoModal/__tests__/__snapshots__/PlayerWrapper.test.tsx.snap +32 -19
  39. package/Components/VideoModal/utils.ts +5 -2
  40. package/Contexts/FocusableGroupContext/FocusableGroupContext.ts +3 -0
  41. package/Contexts/FocusableGroupContext/FocusableGroupContextProvider.tsx +16 -0
  42. package/Contexts/FocusableGroupContext/__tests__/FocusableGroupContextProvider.test.tsx +22 -0
  43. package/Contexts/FocusableGroupContext/__tests__/withFocusableContext.test.tsx +26 -0
  44. package/Contexts/FocusableGroupContext/index.ts +7 -0
  45. package/Contexts/FocusableGroupContext/withFocusableContext.tsx +17 -0
  46. package/Contexts/ScreenDataContext/index.tsx +20 -0
  47. package/Contexts/ZappPipesContext/ZappPipesEntryContext.ts +1 -1
  48. package/package.json +5 -5
  49. package/Components/Layout/TV/TransitionOverlay.tsx +0 -64
  50. package/Contexts/ScreenDataContext/index.ts +0 -3
  51. /package/Components/FocusableGroup/{index.android.js → index.android.ts} +0 -0
  52. /package/Components/FocusableGroup/{index.ios.js → index.ios.ts} +0 -0
@@ -66,7 +66,7 @@ export class BaseFocusable<
66
66
  const { initialFocus } = this.props;
67
67
 
68
68
  if (initialFocus) {
69
- focusManager.setupInitialFocus(this.getId());
69
+ focusManager.setFocus(this.getId());
70
70
  }
71
71
  }
72
72
 
@@ -1,5 +1,5 @@
1
1
  import * as React from "react";
2
- import * as R from "ramda";
2
+ import { join, path, merge } from "ramda";
3
3
  import { View } from "react-native";
4
4
 
5
5
  import { Focusable } from "@applicaster/zapp-react-native-ui-components/Components/Focusable";
@@ -105,8 +105,8 @@ export class CellComponent extends React.Component<Props> {
105
105
  onPress(item, index);
106
106
  } else {
107
107
  const { item, navigator, component, appData } = this.props;
108
- const itemTargetScreen = R.path(["screen_type"], item);
109
- const componentTargetScreen = R.path(["data", "target"], component);
108
+ const itemTargetScreen = path(["screen_type"], item);
109
+ const componentTargetScreen = path(["data", "target"], component);
110
110
  const itemType = getItemType(item, appData?.layoutVersion);
111
111
 
112
112
  sendSelectCellEvent(item, component, item.title, index);
@@ -116,7 +116,7 @@ export class CellComponent extends React.Component<Props> {
116
116
  componentTargetScreen &&
117
117
  !itemTargetScreen
118
118
  ) {
119
- navigator.push(R.merge(item, { screen_type: componentTargetScreen }));
119
+ navigator.push(merge(item, { screen_type: componentTargetScreen }));
120
120
 
121
121
  return;
122
122
  }
@@ -207,7 +207,7 @@ export class CellComponent extends React.Component<Props> {
207
207
 
208
208
  const { id } = item;
209
209
 
210
- const focusableId = R.join("-", [component?.id, id, index]);
210
+ const focusableId = join("-", [component?.id, id, index]);
211
211
 
212
212
  const handleFocus = (focusable, mouse) => {
213
213
  const focusFn = onFocus || noop;
@@ -6,12 +6,20 @@ import { noop } from "@applicaster/zapp-react-native-utils/functionUtils";
6
6
  import { isAppleTV } from "../../Helpers/Platform";
7
7
  import { useCellState } from "../MasterCell/utils";
8
8
 
9
- const useCellFocusedState = (groupId: string, id: string) => {
9
+ const useCellFocusedState = (
10
+ skipFocusManagerRegistration: boolean,
11
+ groupId: string,
12
+ id: string
13
+ ) => {
10
14
  const [currentCellFocused, setCurrentCellFocused] = React.useState(false);
11
15
 
12
16
  React.useEffect(() => {
13
- const isGroupItemFocused = () =>
14
- setCurrentCellFocused(focusManager.isGroupItemFocused(groupId, id));
17
+ const isGroupItemFocused = () => {
18
+ if (!skipFocusManagerRegistration) {
19
+ const isFocused = focusManager.isGroupItemFocused(groupId, id);
20
+ setCurrentCellFocused(isFocused);
21
+ }
22
+ };
15
23
 
16
24
  const handler = () => {
17
25
  // tvOS hack for properly checking focus
@@ -29,7 +37,7 @@ const useCellFocusedState = (groupId: string, id: string) => {
29
37
  return () => {
30
38
  focusManager.removeHandler(FOCUS_EVENTS.FOCUS, handler);
31
39
  };
32
- }, [groupId]);
40
+ }, [groupId, skipFocusManagerRegistration]);
33
41
 
34
42
  return currentCellFocused;
35
43
  };
@@ -65,7 +73,11 @@ export function CellWithFocusable(props: Props) {
65
73
  selected,
66
74
  } = props;
67
75
 
68
- const isFocused = useCellFocusedState(groupId, id);
76
+ const isFocused = useCellFocusedState(
77
+ skipFocusManagerRegistration,
78
+ groupId,
79
+ id
80
+ );
69
81
 
70
82
  const state = useCellState({
71
83
  id: item.id,
@@ -4,6 +4,7 @@ import * as R from "ramda";
4
4
  import { BaseFocusable } from "../BaseFocusable";
5
5
  import { focusManager } from "@applicaster/zapp-react-native-utils/appUtils/focusManager";
6
6
  import { LONG_KEY_PRESS_TIMEOUT } from "@applicaster/quick-brick-core/const";
7
+ import { withFocusableContext } from "../../Contexts/FocusableGroupContext/withFocusableContext";
7
8
 
8
9
  type Props = {
9
10
  initialFocus?: boolean;
@@ -23,7 +24,7 @@ type Props = {
23
24
  style?: React.CSSProperties;
24
25
  };
25
26
 
26
- export class Focusable extends BaseFocusable<Props> {
27
+ class Focusable extends BaseFocusable<Props> {
27
28
  isGroup: boolean;
28
29
  mouse: boolean;
29
30
  longPressTimeout = null;
@@ -198,3 +199,7 @@ export class Focusable extends BaseFocusable<Props> {
198
199
  );
199
200
  }
200
201
  }
202
+
203
+ const FocusableWithFocusableContext = withFocusableContext(Focusable);
204
+
205
+ export { FocusableWithFocusableContext as Focusable };
@@ -1,6 +1,8 @@
1
1
  import * as React from "react";
2
2
 
3
3
  import { BaseFocusable } from "../BaseFocusable";
4
+ import { FocusableGroupContextProvider } from "../../Contexts/FocusableGroupContext";
5
+ import { withFocusableContext } from "../../Contexts/FocusableGroupContext/withFocusableContext";
4
6
 
5
7
  type Props = {
6
8
  testID?: string;
@@ -26,9 +28,10 @@ type Props = {
26
28
  nextFocusLeft?: any;
27
29
  nextFocusRight?: any;
28
30
  onLayout?: any;
31
+ excludeFromFocusSearching?: boolean;
29
32
  };
30
33
 
31
- export class FocusableGroup extends BaseFocusable<Props> {
34
+ class FocusableGroup extends BaseFocusable<Props> {
32
35
  constructor(props) {
33
36
  super(props);
34
37
  this.isGroup = true;
@@ -81,8 +84,14 @@ export class FocusableGroup extends BaseFocusable<Props> {
81
84
  style={style}
82
85
  ref={this.ref}
83
86
  >
84
- {children}
87
+ <FocusableGroupContextProvider id={id}>
88
+ {children}
89
+ </FocusableGroupContextProvider>
85
90
  </div>
86
91
  );
87
92
  }
88
93
  }
94
+
95
+ const FocusableGroupWithFocusableContext = withFocusableContext(FocusableGroup);
96
+
97
+ export { FocusableGroupWithFocusableContext as FocusableGroup };
@@ -19,6 +19,7 @@ type Props = {
19
19
  modalHeight?: number;
20
20
  modalWidth?: number;
21
21
  mode: VideoModalMode;
22
+ groupId?: string;
22
23
  };
23
24
 
24
25
  const YOUTUBE_PLUGIN_ID = "youtube-player-qb";
@@ -93,6 +94,7 @@ export function HandlePlayable({
93
94
  modalHeight,
94
95
  modalWidth,
95
96
  mode,
97
+ groupId,
96
98
  }: Props): React.ReactElement | null {
97
99
  const state = usePickFromState();
98
100
 
@@ -167,6 +169,7 @@ export function HandlePlayable({
167
169
  isModal={isModal}
168
170
  mode={mode}
169
171
  disableCastAction={playerModuleProperties?.disableCastAction}
172
+ groupId={groupId}
170
173
  />
171
174
  );
172
175
  }
@@ -60,7 +60,7 @@ export function ScreenLayoutContextProvider(props: {
60
60
  initialState
61
61
  );
62
62
 
63
- const screeenLayoutValue = React.useMemo(
63
+ const screenLayoutValue = React.useMemo(
64
64
  () => ({
65
65
  ...screenLayout,
66
66
  setScreenLayout,
@@ -69,7 +69,7 @@ export function ScreenLayoutContextProvider(props: {
69
69
  );
70
70
 
71
71
  return (
72
- <ScreenLayoutContext.Provider value={screeenLayoutValue}>
72
+ <ScreenLayoutContext.Provider value={screenLayoutValue}>
73
73
  {props.children}
74
74
  </ScreenLayoutContext.Provider>
75
75
  );
@@ -2,58 +2,18 @@
2
2
 
3
3
  exports[`Layout TV renders 1`] = `
4
4
  <View
5
- style={
6
- Object {
7
- "flex": 1,
8
- "height": 1080,
9
- "width": 1920,
10
- }
11
- }
12
- testID="layout-container"
5
+ excludeFromFocusSearching={true}
6
+ id="/river/A1234"
7
+ preferredFocus={true}
13
8
  >
14
9
  <View
15
- backgroundImageUrl="http://applicaster.com"
16
- testID="background-component"
17
- >
18
- <View
19
- style={
20
- Array [
21
- Object {
22
- "position": "absolute",
23
- "top": 0,
24
- "width": 1920,
25
- "zIndex": 10,
26
- },
27
- Object {
28
- "maxHeight": 10,
29
- },
30
- ]
10
+ Components={
11
+ Object {
12
+ "Background": [Function],
13
+ "NavBar": [Function],
31
14
  }
32
- testID="nav-bar-container"
33
- >
34
- <View
35
- isVisible={true}
36
- menuPlugin={
37
- Object {
38
- "module": [Function],
39
- "name": "resolved-menu-plug",
40
- "type": "menu",
41
- }
42
- }
43
- navigationProps={
44
- Object {
45
- "assets": undefined,
46
- "home": undefined,
47
- "nav_items": undefined,
48
- "rules": undefined,
49
- "selected": undefined,
50
- "styles": undefined,
51
- "title": "",
52
- }
53
- }
54
- testID="nav-bar-component"
55
- />
56
- </View>
57
- </View>
15
+ }
16
+ route="/river/A1234"
17
+ />
58
18
  </View>
59
19
  `;
@@ -1,79 +1,48 @@
1
1
  import * as React from "react";
2
- import * as R from "ramda";
2
+ import { omit } from "ramda";
3
3
  import { View } from "react-native";
4
4
  import { render } from "@testing-library/react-native";
5
5
  import { Provider } from "react-redux";
6
- import { createStore } from "redux";
7
6
  import { NavigationContext } from "@applicaster/zapp-react-native-ui-components/Contexts/NavigationContext";
7
+ import configureStore from "redux-mock-store";
8
8
 
9
- import { ThemeContext } from "@applicaster/zapp-react-native-utils/theme";
9
+ const withoutChildren = omit(["children"]);
10
10
 
11
- jest.mock("@applicaster/quick-brick-core/App/ActionSetters", () => ({
12
- useRiverInitialState: () => ({}),
11
+ jest.mock("../../../Screen/TV/index.web", () => ({
12
+ Screen: View,
13
13
  }));
14
14
 
15
- jest.mock("@applicaster/zapp-react-native-utils/reactHooks/screen");
15
+ const Layout = require("../index.web").default;
16
16
 
17
- const Layout = require("..").default;
18
-
19
- const ResolvedMenuPlug = () => <View testID="resolved-menu-plug" />;
20
-
21
- const plugins = [
22
- {
23
- module: ResolvedMenuPlug,
24
- type: "menu",
25
- name: "resolved-menu-plug",
26
- },
27
- ];
28
-
29
- const bgImage = "http://applicaster.com";
30
- const isNavBarVisible = true;
31
-
32
- const store = createStore(() => ({
17
+ const mockStore = configureStore()({
33
18
  appState: { appReady: true },
34
- remoteConfigurations: { sdkAssets: { bgImage } },
35
- plugins,
36
- }));
19
+ });
37
20
 
38
21
  describe("Layout TV", () => {
39
- const themes = {
40
- myTheme: { screen_margin_top: 10, screen_margin_bottom: 10 },
41
- };
42
-
43
- const selectedThemeId = "myTheme";
44
-
45
22
  const navigator = {
46
- activeRiver: {
47
- navigations: [{ category: "menu", navigation_type: "menu" }],
48
- },
49
- canGoBack: () => false,
50
23
  currentRoute: "/river/A1234",
51
- screenData: {
52
- navigations: [{ category: "menu", navigation_type: "menu" }],
53
- },
54
- isNavBarVisible: isNavBarVisible,
24
+ mainStack: [
25
+ {
26
+ route: "/river/A1234",
27
+ state: "state",
28
+ },
29
+ ],
55
30
  };
56
31
 
57
32
  const wrapper = ({ children }) => (
58
- <Provider store={store}>
33
+ <Provider store={mockStore}>
59
34
  <NavigationContext.Provider value={navigator}>
60
- <ThemeContext.Provider value={{ themes, selectedThemeId }}>
61
- {children}
62
- </ThemeContext.Provider>
35
+ {children}
63
36
  </NavigationContext.Provider>
64
37
  </Provider>
65
38
  );
66
39
 
67
- const Screen = (props) => (
68
- <View testID="screen-component" {...R.omit(["children"])(props)} />
69
- );
70
-
71
40
  const NavBar = (props) => (
72
- <View testID="nav-bar-component" {...R.omit(["children"])(props)} />
41
+ <View testID="nav-bar-component" {...withoutChildren(props)} />
73
42
  );
74
43
 
75
44
  const Background = (props: Record<any, any>) => (
76
- <View testID="background-component" {...R.omit(["children"])(props)}>
45
+ <View testID="background-component" {...withoutChildren(props)}>
77
46
  {props.children}
78
47
  </View>
79
48
  );
@@ -84,33 +53,8 @@ describe("Layout TV", () => {
84
53
  };
85
54
 
86
55
  it("renders", () => {
87
- const { toJSON } = render(
88
- <Layout Components={Components}>
89
- <Screen />
90
- </Layout>,
91
- { wrapper }
92
- );
56
+ const { toJSON } = render(<Layout Components={Components} />, { wrapper });
93
57
 
94
58
  expect(toJSON()).toMatchSnapshot();
95
59
  });
96
-
97
- describe("props passed to background component", () => {
98
- it("passes correct props", () => {
99
- const { getByTestId } = render(
100
- <Layout
101
- Components={Components}
102
- ComponentsExtraProps={{
103
- Background: { testProp: true },
104
- }}
105
- >
106
- <Screen />
107
- </Layout>,
108
- { wrapper }
109
- );
110
-
111
- const bgComponent = getByTestId("background-component");
112
- expect(bgComponent.props.backgroundImageUrl).toBe(bgImage);
113
- expect(bgComponent.props.testProp).toBe(true);
114
- });
115
- });
116
60
  });
@@ -14,7 +14,6 @@ import { getBackgroundImageUrl } from "../utils";
14
14
  import { LayoutContainer } from "./LayoutContainer";
15
15
  import { NavBarContainer } from "./NavBarContainer";
16
16
  import { ScreenContainer } from "./ScreenContainer";
17
- import { TransitionOverlay } from "./TransitionOverlay";
18
17
 
19
18
  import { ScreenLayoutContextProvider } from "./ScreenLayoutContextProvider";
20
19
  import { isApplePlatform } from "@applicaster/zapp-react-native-utils/reactUtils";
@@ -122,7 +121,6 @@ const Layout = ({ Components, ComponentsExtraProps, children }: Props) => {
122
121
  {isTVOS ? navBarContainer : null}
123
122
  </PathnameContext.Provider>
124
123
  </ScreenDataContext.Provider>
125
- <TransitionOverlay />
126
124
  </Components.Background>
127
125
  </ScreenLayoutContextProvider>
128
126
  </LayoutContainer>
@@ -0,0 +1,33 @@
1
+ import * as React from "react";
2
+ import { pathOr } from "ramda";
3
+
4
+ import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
5
+
6
+ import { ScreenLayoutContextProvider } from "./ScreenLayoutContextProvider";
7
+ import { StackNavigator } from "../../Navigator";
8
+
9
+ type Components = {
10
+ NavBar: React.ComponentType<any>;
11
+ Background: React.ComponentType<any>;
12
+ };
13
+
14
+ type Props = {
15
+ Components: Components;
16
+ };
17
+
18
+ const Layout = ({ Components }: Props) => {
19
+ const { appState } = usePickFromState(["appState"]);
20
+ const appReady = pathOr(false, ["appReady"], appState);
21
+
22
+ if (!appReady) {
23
+ return null;
24
+ }
25
+
26
+ return (
27
+ <ScreenLayoutContextProvider>
28
+ <StackNavigator Components={Components} />
29
+ </ScreenLayoutContextProvider>
30
+ );
31
+ };
32
+
33
+ export default Layout;
@@ -1,20 +1,24 @@
1
1
  import * as React from "react";
2
- import { isTV } from "@applicaster/zapp-react-native-utils/reactUtils";
3
- import { useNavigation } from "@applicaster/zapp-react-native-utils/reactHooks/navigation";
4
- import { ScreenContextProvider } from "../../Contexts/ScreenContext";
2
+ import {
3
+ isTV,
4
+ platformSelect,
5
+ } from "@applicaster/zapp-react-native-utils/reactUtils";
5
6
 
6
7
  import Mobile from "./Mobile";
7
- import TV from "./TV";
8
8
 
9
- export default function Layout(props) {
10
- const { currentRoute: pathname } = useNavigation();
9
+ import TVWeb from "./TV/index.web";
10
+ import TVDefault from "./TV/index";
11
+
12
+ const TV = platformSelect({
13
+ samsung_tv: TVWeb,
14
+ lg_tv: TVWeb,
15
+ web: TVWeb,
16
+ default: TVDefault,
17
+ });
11
18
 
19
+ export default function Layout(props) {
12
20
  if (isTV()) {
13
- return (
14
- <ScreenContextProvider pathname={pathname}>
15
- <TV {...props} />
16
- </ScreenContextProvider>
17
- );
21
+ return <TV {...props} />;
18
22
  } else {
19
23
  return <Mobile {...props} />;
20
24
  }