@applicaster/zapp-react-native-ui-components 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.
- package/Components/BaseFocusable/index.tsx +2 -2
- package/Components/Cell/Cell.tsx +9 -8
- package/Components/Cell/CellWithFocusable.tsx +7 -5
- package/Components/Cell/TvOSCellComponent.tsx +6 -11
- package/Components/Focusable/Focusable.tsx +6 -1
- package/Components/FocusableGroup/index.tsx +10 -2
- package/Components/Layout/TV/ScreenContainer.tsx +79 -5
- package/Components/Layout/TV/__tests__/ScreenContainer.test.tsx +38 -28
- package/Components/Layout/TV/__tests__/__snapshots__/ScreenContainer.test.tsx.snap +25 -13
- package/Components/Layout/TV/__tests__/index.test.tsx +3 -2
- package/Components/Layout/TV/index.tsx +47 -41
- package/Components/Layout/TV/index.web.tsx +33 -0
- package/Components/Layout/index.tsx +15 -11
- package/Components/MasterCell/DefaultComponents/BorderContainerView/index.tsx +88 -112
- package/Components/MasterCell/DefaultComponents/DynamicBadge.tsx +4 -2
- package/Components/MasterCell/DefaultComponents/FocusableView/index.tsx +4 -1
- package/Components/MasterCell/DefaultComponents/LiveImage/index.tsx +20 -0
- package/Components/MasterCell/DefaultComponents/tv/ButtonContainerView/index.tsx +6 -1
- package/Components/MasterCell/utils/__tests__/insertBetween.test.js +9 -0
- package/Components/MasterCell/utils/index.ts +17 -30
- package/Components/NativeFocusables/{index.js → index.ts} +4 -2
- package/Components/Navigator/StackNavigator.tsx +57 -0
- package/Components/Navigator/index.ts +1 -0
- package/Components/PlayerContainer/PlayerContainer.tsx +2 -0
- package/Components/River/ComponentsMap/ComponentsMap.tsx +6 -0
- package/Components/River/RefreshControl.tsx +2 -2
- package/Components/RouteManager/index.tsx +2 -2
- package/Components/Screen/TV/hooks/useInitialFocus.ts +6 -3
- package/Components/Screen/TV/index.web.tsx +12 -21
- package/Components/Screen/__tests__/Screen.test.tsx +3 -0
- package/Components/Screen/index.tsx +55 -58
- package/Components/Screen/navigationHandler.ts +5 -0
- package/Components/Transitioner/Scene.tsx +32 -26
- package/Components/Transitioner/Transitioner.tsx +21 -28
- package/Components/Transitioner/__tests__/__snapshots__/Scene.test.js.snap +12 -4
- package/Components/Transitioner/__tests__/__snapshots__/transitioner.test.js.snap +1 -0
- package/Components/VideoLive/LiveImageManager.ts +28 -1
- package/Components/VideoModal/ModalAnimation/AnimatedPlayerModalWrapper.tsx +2 -14
- package/Components/VideoModal/ModalAnimation/AnimatedScrollModal.tsx +56 -43
- package/Components/VideoModal/ModalAnimation/AnimatedVideoPlayerComponent.tsx +42 -32
- package/Components/VideoModal/ModalAnimation/AnimationComponent.tsx +104 -86
- package/Components/VideoModal/ModalAnimation/ModalAnimationContext.tsx +32 -4
- package/Components/VideoModal/ModalAnimation/utils.ts +7 -4
- package/Components/VideoModal/PlayerDetails.tsx +3 -3
- package/Components/VideoModal/PlayerWrapper.tsx +69 -62
- package/Components/VideoModal/VideoModal.tsx +4 -4
- package/Components/VideoModal/__tests__/PlayerWrapper.test.tsx +7 -0
- package/Components/VideoModal/__tests__/__snapshots__/PlayerWrapper.test.tsx.snap +32 -12
- package/Components/VideoModal/hooks/useModalSize.ts +10 -12
- package/Components/VideoModal/utils.ts +5 -2
- package/Components/Viewport/ViewportTracker/ViewportTracker.tsx +31 -40
- package/Contexts/FocusableGroupContext/FocusableGroupContext.ts +3 -0
- package/Contexts/FocusableGroupContext/FocusableGroupContextProvider.tsx +16 -0
- package/Contexts/FocusableGroupContext/__tests__/FocusableGroupContextProvider.test.tsx +22 -0
- package/Contexts/FocusableGroupContext/__tests__/withFocusableContext.test.tsx +26 -0
- package/Contexts/FocusableGroupContext/index.ts +7 -0
- package/Contexts/FocusableGroupContext/withFocusableContext.tsx +17 -0
- package/Contexts/ScreenDataContext/index.tsx +20 -0
- package/Decorators/Analytics/{index.js → index.tsx} +11 -11
- package/README.md +1 -13
- package/package.json +5 -5
- /package/Components/FocusableGroup/{index.android.js → index.android.ts} +0 -0
- /package/Components/FocusableGroup/{index.ios.js → index.ios.ts} +0 -0
|
@@ -71,9 +71,9 @@ export class BaseFocusable<
|
|
|
71
71
|
}
|
|
72
72
|
|
|
73
73
|
getId(props?: { id: string; groupId: string }) {
|
|
74
|
-
const { id
|
|
74
|
+
const { id } = props || this.props;
|
|
75
75
|
|
|
76
|
-
return
|
|
76
|
+
return id;
|
|
77
77
|
}
|
|
78
78
|
|
|
79
79
|
getRect() {
|
package/Components/Cell/Cell.tsx
CHANGED
|
@@ -11,12 +11,10 @@ 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
|
-
item:
|
|
17
|
-
id: string;
|
|
18
|
-
title: string;
|
|
19
|
-
};
|
|
17
|
+
item: ZappEntry;
|
|
20
18
|
index: number;
|
|
21
19
|
shouldScrollHorizontally: (arg1: [any]) => boolean | null | undefined;
|
|
22
20
|
shouldScrollVertically: (...args: any) => boolean | null | undefined;
|
|
@@ -32,10 +30,9 @@ type Props = {
|
|
|
32
30
|
id: string;
|
|
33
31
|
};
|
|
34
32
|
selected?: boolean;
|
|
35
|
-
CellRenderer: React.
|
|
36
|
-
item:
|
|
37
|
-
|
|
38
|
-
}> & { hasFocusableInside: (item: Record<string, string>) => boolean };
|
|
33
|
+
CellRenderer: React.FunctionComponent<any> & {
|
|
34
|
+
hasFocusableInside: (item: ZappEntry) => boolean;
|
|
35
|
+
};
|
|
39
36
|
preferredFocus: boolean;
|
|
40
37
|
navigator: {
|
|
41
38
|
push: (arg1: Record<any, any>) => void;
|
|
@@ -139,6 +136,10 @@ export class CellComponent extends React.Component<Props> {
|
|
|
139
136
|
shouldScrollVertically?.(mouse, focusable, id, title)
|
|
140
137
|
) {
|
|
141
138
|
this.scrollVertically(focusable);
|
|
139
|
+
|
|
140
|
+
const accessibilityManager = AccessibilityManager.getInstance();
|
|
141
|
+
// Text from DSP should be localized already
|
|
142
|
+
accessibilityManager.readText({ text: title.toString() });
|
|
142
143
|
}
|
|
143
144
|
}
|
|
144
145
|
}
|
|
@@ -3,6 +3,8 @@ import * as React from "react";
|
|
|
3
3
|
import { focusManager } from "@applicaster/zapp-react-native-utils/appUtils/focusManager";
|
|
4
4
|
import * as FOCUS_EVENTS from "@applicaster/zapp-react-native-utils/appUtils/focusManager/events";
|
|
5
5
|
import { noop } from "@applicaster/zapp-react-native-utils/functionUtils";
|
|
6
|
+
import { toBooleanWithDefaultFalse } from "@applicaster/zapp-react-native-utils/booleanUtils";
|
|
7
|
+
|
|
6
8
|
import { isAppleTV } from "../../Helpers/Platform";
|
|
7
9
|
import { useCellState } from "../MasterCell/utils";
|
|
8
10
|
|
|
@@ -44,7 +46,7 @@ const useCellFocusedState = (
|
|
|
44
46
|
|
|
45
47
|
type Props = {
|
|
46
48
|
item: ZappEntry;
|
|
47
|
-
CellRenderer: React.
|
|
49
|
+
CellRenderer: React.FunctionComponent<any>;
|
|
48
50
|
id: string;
|
|
49
51
|
groupId: string;
|
|
50
52
|
onFocus: Function;
|
|
@@ -54,7 +56,7 @@ type Props = {
|
|
|
54
56
|
skipFocusManagerRegistration?: boolean;
|
|
55
57
|
isFocusable?: boolean;
|
|
56
58
|
behavior: Behavior;
|
|
57
|
-
|
|
59
|
+
focused?: boolean;
|
|
58
60
|
};
|
|
59
61
|
|
|
60
62
|
export function CellWithFocusable(props: Props) {
|
|
@@ -70,7 +72,7 @@ export function CellWithFocusable(props: Props) {
|
|
|
70
72
|
skipFocusManagerRegistration,
|
|
71
73
|
isFocusable,
|
|
72
74
|
behavior,
|
|
73
|
-
|
|
75
|
+
focused,
|
|
74
76
|
} = props;
|
|
75
77
|
|
|
76
78
|
const isFocused = useCellFocusedState(
|
|
@@ -82,8 +84,7 @@ export function CellWithFocusable(props: Props) {
|
|
|
82
84
|
const state = useCellState({
|
|
83
85
|
id: item.id,
|
|
84
86
|
behavior,
|
|
85
|
-
focused: isFocused,
|
|
86
|
-
selected,
|
|
87
|
+
focused: isFocused || toBooleanWithDefaultFalse(focused),
|
|
87
88
|
});
|
|
88
89
|
|
|
89
90
|
const [focusedButtonId, setFocusedButtonId] = React.useState(undefined);
|
|
@@ -114,6 +115,7 @@ export function CellWithFocusable(props: Props) {
|
|
|
114
115
|
preferredFocus={preferredFocus}
|
|
115
116
|
skipFocusManagerRegistration={skipFocusManagerRegistration}
|
|
116
117
|
isFocusable={isFocusable}
|
|
118
|
+
focused={focused}
|
|
117
119
|
/>
|
|
118
120
|
);
|
|
119
121
|
}
|
|
@@ -36,10 +36,9 @@ type Props = {
|
|
|
36
36
|
component_type: string;
|
|
37
37
|
};
|
|
38
38
|
selected: boolean;
|
|
39
|
-
CellRenderer: React.
|
|
40
|
-
item: any;
|
|
41
|
-
|
|
42
|
-
}> & { hasFocusableInside: (item: any) => boolean };
|
|
39
|
+
CellRenderer: React.FunctionComponent<any> & {
|
|
40
|
+
hasFocusableInside: (item: any) => boolean;
|
|
41
|
+
};
|
|
43
42
|
preferredFocus: boolean;
|
|
44
43
|
navigator: {
|
|
45
44
|
push: (arg1: Record<any, any>) => void;
|
|
@@ -226,13 +225,7 @@ export class TvOSCellComponent extends React.Component<Props, State> {
|
|
|
226
225
|
|
|
227
226
|
hasReceivedFocus() {}
|
|
228
227
|
|
|
229
|
-
scrollTo(
|
|
230
|
-
// Workaround for HL autoscroll/autoloop feature, we scroll manually on tvOS.
|
|
231
|
-
// Should be removed after refactoring autoscroll/autoloop feature
|
|
232
|
-
if (this.props.component?.component_type !== "horizontal_list_qb") {
|
|
233
|
-
this.props?.scrollToIndex?.(index);
|
|
234
|
-
}
|
|
235
|
-
}
|
|
228
|
+
scrollTo() {}
|
|
236
229
|
|
|
237
230
|
render() {
|
|
238
231
|
const {
|
|
@@ -279,7 +272,9 @@ export class TvOSCellComponent extends React.Component<Props, State> {
|
|
|
279
272
|
index={index}
|
|
280
273
|
scrollTo={this.scrollTo}
|
|
281
274
|
preferredFocus={preferredFocus}
|
|
275
|
+
focused={this.props.focused}
|
|
282
276
|
behavior={behavior}
|
|
277
|
+
isFocusable={isFocusable}
|
|
283
278
|
/>
|
|
284
279
|
</View>
|
|
285
280
|
);
|
|
@@ -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
|
-
|
|
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;
|
|
@@ -29,7 +31,7 @@ type Props = {
|
|
|
29
31
|
excludeFromFocusSearching?: boolean;
|
|
30
32
|
};
|
|
31
33
|
|
|
32
|
-
|
|
34
|
+
class FocusableGroup extends BaseFocusable<Props> {
|
|
33
35
|
constructor(props) {
|
|
34
36
|
super(props);
|
|
35
37
|
this.isGroup = true;
|
|
@@ -82,8 +84,14 @@ export class FocusableGroup extends BaseFocusable<Props> {
|
|
|
82
84
|
style={style}
|
|
83
85
|
ref={this.ref}
|
|
84
86
|
>
|
|
85
|
-
{
|
|
87
|
+
<FocusableGroupContextProvider id={id}>
|
|
88
|
+
{children}
|
|
89
|
+
</FocusableGroupContextProvider>
|
|
86
90
|
</div>
|
|
87
91
|
);
|
|
88
92
|
}
|
|
89
93
|
}
|
|
94
|
+
|
|
95
|
+
const FocusableGroupWithFocusableContext = withFocusableContext(FocusableGroup);
|
|
96
|
+
|
|
97
|
+
export { FocusableGroupWithFocusableContext as FocusableGroup };
|
|
@@ -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 {
|
|
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 {
|
|
15
|
+
import {
|
|
16
|
+
findMenuPlugin,
|
|
17
|
+
getNavigationProps,
|
|
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,62 @@ 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
|
+
() => findMenuPlugin(activeRiver?.navigations, plugins),
|
|
122
|
+
[activeRiver?.navigations]
|
|
123
|
+
);
|
|
124
|
+
|
|
125
|
+
const NavBarComponent = React.useMemo(
|
|
126
|
+
() => NavBar || (menuPlugin.module as React.ComponentType<any>),
|
|
127
|
+
[]
|
|
128
|
+
);
|
|
129
|
+
|
|
130
|
+
const [navBarReady, setNavBarReady] = React.useState(false);
|
|
131
|
+
|
|
132
|
+
const navBarContainer = (
|
|
133
|
+
<NavBarContainer isVisible={visible} onReady={setNavBarReady}>
|
|
134
|
+
<NavBarComponent
|
|
135
|
+
ref={ComponentsExtraProps?.NavBar?.ref}
|
|
136
|
+
isVisible={visible}
|
|
137
|
+
menuPlugin={menuPlugin}
|
|
138
|
+
navigationProps={navigationProps}
|
|
139
|
+
{...R.omit(["ref"])(ComponentsExtraProps?.NavBar)}
|
|
140
|
+
/>
|
|
141
|
+
</NavBarContainer>
|
|
142
|
+
);
|
|
143
|
+
|
|
83
144
|
return (
|
|
84
|
-
|
|
85
|
-
{
|
|
86
|
-
|
|
145
|
+
<>
|
|
146
|
+
{!isTVOS ? navBarContainer : null}
|
|
147
|
+
{navBarReady ? (
|
|
148
|
+
/**
|
|
149
|
+
Need to re-mount this component on each navigation event
|
|
150
|
+
It's a hack to work around the fact that we don't support
|
|
151
|
+
correct screen rendering in our navigator (shared currentRoute state)
|
|
152
|
+
**/
|
|
153
|
+
<View testID="screen-container" style={viewStyles}>
|
|
154
|
+
{children}
|
|
155
|
+
</View>
|
|
156
|
+
) : null}
|
|
157
|
+
{/** Render NavBarContainer over ScreenContainer to let tvOS native
|
|
158
|
+
focus manager works correctly to focus nav bar items first **/}
|
|
159
|
+
{isTVOS ? navBarContainer : null}
|
|
160
|
+
</>
|
|
87
161
|
);
|
|
88
162
|
});
|
|
@@ -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
|
+
findMenuPlugin: () => ({}),
|
|
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
|
|
33
|
+
jest.mock("../../../River/useScreenConfiguration", () => ({
|
|
21
34
|
useScreenConfiguration: () => ({}),
|
|
22
35
|
}));
|
|
23
36
|
|
|
24
|
-
jest.mock(
|
|
25
|
-
useCurrentScreenData
|
|
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
|
-
<
|
|
48
|
-
|
|
49
|
-
|
|
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
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
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
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
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
|
-
<
|
|
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
|
-
|
|
24
|
-
|
|
25
|
-
|
|
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`] = `
|
|
@@ -12,7 +12,7 @@ jest.mock("../../../Screen/TV/index.web", () => ({
|
|
|
12
12
|
Screen: View,
|
|
13
13
|
}));
|
|
14
14
|
|
|
15
|
-
const Layout = require("
|
|
15
|
+
const Layout = require("../index.web").default;
|
|
16
16
|
|
|
17
17
|
const mockStore = configureStore()({
|
|
18
18
|
appState: { appReady: true },
|
|
@@ -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:
|
|
28
|
+
state: { screen: {} },
|
|
28
29
|
},
|
|
29
30
|
],
|
|
30
31
|
};
|
|
@@ -1,69 +1,75 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import
|
|
2
|
+
import * as R from "ramda";
|
|
3
3
|
import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
|
|
4
4
|
import { useNavigation } from "@applicaster/zapp-react-native-utils/reactHooks/navigation";
|
|
5
|
-
import {
|
|
5
|
+
import { useTheme } from "@applicaster/zapp-react-native-utils/theme";
|
|
6
|
+
|
|
7
|
+
import { getBackgroundImageUrl } from "../utils";
|
|
8
|
+
import { LayoutContainer } from "./LayoutContainer";
|
|
9
|
+
import { ScreenContainer } from "./ScreenContainer";
|
|
6
10
|
|
|
7
11
|
import { ScreenLayoutContextProvider } from "./ScreenLayoutContextProvider";
|
|
8
12
|
import { PathnameContext } from "../../../Contexts/PathnameContext";
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
|
|
12
|
-
export const ScreenDataContext = React.createContext(null);
|
|
13
|
+
import { ScreenDataContext } from "../../../Contexts/ScreenDataContext";
|
|
14
|
+
import { ScreenContextProvider } from "../../../Contexts/ScreenContext";
|
|
13
15
|
|
|
14
16
|
type Components = {
|
|
15
17
|
NavBar: React.ComponentType<any>;
|
|
16
18
|
Background: React.ComponentType<any>;
|
|
17
19
|
};
|
|
18
20
|
|
|
21
|
+
type ComponentsExtraProps = {
|
|
22
|
+
Background?: Record<string, any>;
|
|
23
|
+
NavBar?: Record<string, any>;
|
|
24
|
+
};
|
|
25
|
+
|
|
19
26
|
type Props = {
|
|
20
27
|
Components: Components;
|
|
28
|
+
ComponentsExtraProps?: ComponentsExtraProps;
|
|
29
|
+
children: React.ReactNode;
|
|
21
30
|
};
|
|
22
31
|
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
const renderScreen = ({ route, state }) => {
|
|
28
|
-
const pathAttributes = getPathAttributes({ pathname: route });
|
|
32
|
+
const Layout = ({ Components, ComponentsExtraProps, children }: Props) => {
|
|
33
|
+
const navigator = useNavigation();
|
|
34
|
+
const theme = useTheme();
|
|
29
35
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
}
|
|
36
|
+
const { appState: { appReady = false } = {}, remoteConfigurations } =
|
|
37
|
+
usePickFromState(["appState", "remoteConfigurations", "plugins"]);
|
|
33
38
|
|
|
34
|
-
|
|
39
|
+
const backgroundColor = React.useMemo(() => theme.app_background_color, []);
|
|
35
40
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
excludeFromFocusSearching
|
|
41
|
-
key={id}
|
|
42
|
-
>
|
|
43
|
-
<ScreenDataContext.Provider value={state}>
|
|
44
|
-
<PathnameContext.Provider value={route}>
|
|
45
|
-
<Screen route={route} Components={Components} />
|
|
46
|
-
</PathnameContext.Provider>
|
|
47
|
-
</ScreenDataContext.Provider>
|
|
48
|
-
</FocusableGroup>
|
|
49
|
-
);
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
return mainStack.map(renderScreen);
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
const Layout = ({ Components }: Props) => {
|
|
56
|
-
const { appState } = usePickFromState(["appState"]);
|
|
57
|
-
const appReady = pathOr(false, ["appReady"], appState);
|
|
41
|
+
const backgroundImageUrl = React.useMemo(
|
|
42
|
+
() => getBackgroundImageUrl(remoteConfigurations),
|
|
43
|
+
[remoteConfigurations]
|
|
44
|
+
);
|
|
58
45
|
|
|
59
46
|
if (!appReady) {
|
|
60
47
|
return null;
|
|
61
48
|
}
|
|
62
49
|
|
|
63
50
|
return (
|
|
64
|
-
<
|
|
65
|
-
<
|
|
66
|
-
|
|
51
|
+
<LayoutContainer>
|
|
52
|
+
<ScreenLayoutContextProvider>
|
|
53
|
+
<Components.Background
|
|
54
|
+
backgroundColor={backgroundColor}
|
|
55
|
+
backgroundImageUrl={backgroundImageUrl}
|
|
56
|
+
{...R.omit(["ref"])(ComponentsExtraProps?.Background)}
|
|
57
|
+
>
|
|
58
|
+
<ScreenDataContext.Provider value={navigator.data}>
|
|
59
|
+
<PathnameContext.Provider value={navigator.currentRoute}>
|
|
60
|
+
<ScreenContextProvider pathname={navigator.currentRoute}>
|
|
61
|
+
<ScreenContainer
|
|
62
|
+
ComponentsExtraProps={ComponentsExtraProps}
|
|
63
|
+
NavBar={Components.NavBar}
|
|
64
|
+
>
|
|
65
|
+
{children}
|
|
66
|
+
</ScreenContainer>
|
|
67
|
+
</ScreenContextProvider>
|
|
68
|
+
</PathnameContext.Provider>
|
|
69
|
+
</ScreenDataContext.Provider>
|
|
70
|
+
</Components.Background>
|
|
71
|
+
</ScreenLayoutContextProvider>
|
|
72
|
+
</LayoutContainer>
|
|
67
73
|
);
|
|
68
74
|
};
|
|
69
75
|
|
|
@@ -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;
|