@applicaster/zapp-react-native-ui-components 12.0.0-alpha.4342066143 → 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 +3 -3
- package/Components/Cell/Cell.tsx +14 -13
- package/Components/Cell/CellWithFocusable.tsx +24 -10
- package/Components/Cell/TvOSCellComponent.tsx +6 -11
- package/Components/Focusable/Focusable.tsx +6 -1
- package/Components/FocusableGroup/index.tsx +11 -2
- package/Components/HandlePlayable/HandlePlayable.tsx +3 -0
- package/Components/Layout/TV/ScreenContainer.tsx +79 -5
- package/Components/Layout/TV/ScreenLayoutContextProvider.tsx +2 -2
- 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__/__snapshots__/index.test.tsx.snap +10 -50
- package/Components/Layout/TV/__tests__/index.test.tsx +20 -75
- package/Components/Layout/TV/index.tsx +11 -67
- package/Components/Layout/TV/index.web.tsx +33 -0
- package/Components/Layout/index.tsx +15 -11
- package/Components/MasterCell/DefaultComponents/BorderContainerView/index.tsx +7 -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.android.tsx +4 -1
- package/Components/MasterCell/DefaultComponents/tv/ButtonContainerView/index.tsx +10 -2
- 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 +5 -1
- package/Components/River/TV/River.tsx +0 -23
- package/Components/Screen/TV/hooks/index.ts +3 -0
- package/Components/Screen/TV/hooks/useInitialFocus.ts +70 -0
- package/Components/Screen/TV/hooks/useRestoreFocus.ts +22 -0
- package/Components/Screen/TV/index.web.tsx +165 -0
- 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/ScreenResolver/index.tsx +3 -1
- package/Components/Transitioner/Scene.tsx +12 -11
- package/Components/Transitioner/Transitioner.tsx +15 -29
- package/Components/Transitioner/__tests__/__snapshots__/Scene.test.js.snap +8 -4
- package/Components/VideoLive/LiveImageManager.ts +25 -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/PlayerWrapper.tsx +10 -10
- package/Components/VideoModal/VideoModal.tsx +4 -4
- 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/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/Contexts/ZappPipesContext/ZappPipesEntryContext.ts +1 -1
- package/Decorators/Analytics/{index.js → index.tsx} +11 -11
- package/README.md +1 -13
- package/package.json +5 -5
- package/Components/Layout/TV/TransitionOverlay.tsx +0 -64
- package/Contexts/ScreenDataContext/index.ts +0 -3
- /package/Components/FocusableGroup/{index.android.js → index.android.ts} +0 -0
- /package/Components/FocusableGroup/{index.ios.js → index.ios.ts} +0 -0
|
@@ -66,14 +66,14 @@ export class BaseFocusable<
|
|
|
66
66
|
const { initialFocus } = this.props;
|
|
67
67
|
|
|
68
68
|
if (initialFocus) {
|
|
69
|
-
focusManager.
|
|
69
|
+
focusManager.setFocus(this.getId());
|
|
70
70
|
}
|
|
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
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import
|
|
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";
|
|
@@ -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;
|
|
@@ -105,8 +102,8 @@ export class CellComponent extends React.Component<Props> {
|
|
|
105
102
|
onPress(item, index);
|
|
106
103
|
} else {
|
|
107
104
|
const { item, navigator, component, appData } = this.props;
|
|
108
|
-
const itemTargetScreen =
|
|
109
|
-
const componentTargetScreen =
|
|
105
|
+
const itemTargetScreen = path(["screen_type"], item);
|
|
106
|
+
const componentTargetScreen = path(["data", "target"], component);
|
|
110
107
|
const itemType = getItemType(item, appData?.layoutVersion);
|
|
111
108
|
|
|
112
109
|
sendSelectCellEvent(item, component, item.title, index);
|
|
@@ -116,7 +113,7 @@ export class CellComponent extends React.Component<Props> {
|
|
|
116
113
|
componentTargetScreen &&
|
|
117
114
|
!itemTargetScreen
|
|
118
115
|
) {
|
|
119
|
-
navigator.push(
|
|
116
|
+
navigator.push(merge(item, { screen_type: componentTargetScreen }));
|
|
120
117
|
|
|
121
118
|
return;
|
|
122
119
|
}
|
|
@@ -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
|
}
|
|
@@ -207,7 +208,7 @@ export class CellComponent extends React.Component<Props> {
|
|
|
207
208
|
|
|
208
209
|
const { id } = item;
|
|
209
210
|
|
|
210
|
-
const focusableId =
|
|
211
|
+
const focusableId = join("-", [component?.id, id, index]);
|
|
211
212
|
|
|
212
213
|
const handleFocus = (focusable, mouse) => {
|
|
213
214
|
const focusFn = onFocus || noop;
|
|
@@ -3,15 +3,25 @@ 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
|
|
|
9
|
-
const useCellFocusedState = (
|
|
11
|
+
const useCellFocusedState = (
|
|
12
|
+
skipFocusManagerRegistration: boolean,
|
|
13
|
+
groupId: string,
|
|
14
|
+
id: string
|
|
15
|
+
) => {
|
|
10
16
|
const [currentCellFocused, setCurrentCellFocused] = React.useState(false);
|
|
11
17
|
|
|
12
18
|
React.useEffect(() => {
|
|
13
|
-
const isGroupItemFocused = () =>
|
|
14
|
-
|
|
19
|
+
const isGroupItemFocused = () => {
|
|
20
|
+
if (!skipFocusManagerRegistration) {
|
|
21
|
+
const isFocused = focusManager.isGroupItemFocused(groupId, id);
|
|
22
|
+
setCurrentCellFocused(isFocused);
|
|
23
|
+
}
|
|
24
|
+
};
|
|
15
25
|
|
|
16
26
|
const handler = () => {
|
|
17
27
|
// tvOS hack for properly checking focus
|
|
@@ -29,14 +39,14 @@ const useCellFocusedState = (groupId: string, id: string) => {
|
|
|
29
39
|
return () => {
|
|
30
40
|
focusManager.removeHandler(FOCUS_EVENTS.FOCUS, handler);
|
|
31
41
|
};
|
|
32
|
-
}, [groupId]);
|
|
42
|
+
}, [groupId, skipFocusManagerRegistration]);
|
|
33
43
|
|
|
34
44
|
return currentCellFocused;
|
|
35
45
|
};
|
|
36
46
|
|
|
37
47
|
type Props = {
|
|
38
48
|
item: ZappEntry;
|
|
39
|
-
CellRenderer: React.
|
|
49
|
+
CellRenderer: React.FunctionComponent<any>;
|
|
40
50
|
id: string;
|
|
41
51
|
groupId: string;
|
|
42
52
|
onFocus: Function;
|
|
@@ -46,7 +56,7 @@ type Props = {
|
|
|
46
56
|
skipFocusManagerRegistration?: boolean;
|
|
47
57
|
isFocusable?: boolean;
|
|
48
58
|
behavior: Behavior;
|
|
49
|
-
|
|
59
|
+
focused?: boolean;
|
|
50
60
|
};
|
|
51
61
|
|
|
52
62
|
export function CellWithFocusable(props: Props) {
|
|
@@ -62,16 +72,19 @@ export function CellWithFocusable(props: Props) {
|
|
|
62
72
|
skipFocusManagerRegistration,
|
|
63
73
|
isFocusable,
|
|
64
74
|
behavior,
|
|
65
|
-
|
|
75
|
+
focused,
|
|
66
76
|
} = props;
|
|
67
77
|
|
|
68
|
-
const isFocused = useCellFocusedState(
|
|
78
|
+
const isFocused = useCellFocusedState(
|
|
79
|
+
skipFocusManagerRegistration,
|
|
80
|
+
groupId,
|
|
81
|
+
id
|
|
82
|
+
);
|
|
69
83
|
|
|
70
84
|
const state = useCellState({
|
|
71
85
|
id: item.id,
|
|
72
86
|
behavior,
|
|
73
|
-
focused: isFocused,
|
|
74
|
-
selected,
|
|
87
|
+
focused: isFocused || toBooleanWithDefaultFalse(focused),
|
|
75
88
|
});
|
|
76
89
|
|
|
77
90
|
const [focusedButtonId, setFocusedButtonId] = React.useState(undefined);
|
|
@@ -102,6 +115,7 @@ export function CellWithFocusable(props: Props) {
|
|
|
102
115
|
preferredFocus={preferredFocus}
|
|
103
116
|
skipFocusManagerRegistration={skipFocusManagerRegistration}
|
|
104
117
|
isFocusable={isFocusable}
|
|
118
|
+
focused={focused}
|
|
105
119
|
/>
|
|
106
120
|
);
|
|
107
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;
|
|
@@ -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
|
-
|
|
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
|
-
{
|
|
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
|
}
|
|
@@ -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
|
});
|
|
@@ -60,7 +60,7 @@ export function ScreenLayoutContextProvider(props: {
|
|
|
60
60
|
initialState
|
|
61
61
|
);
|
|
62
62
|
|
|
63
|
-
const
|
|
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={
|
|
72
|
+
<ScreenLayoutContext.Provider value={screenLayoutValue}>
|
|
73
73
|
{props.children}
|
|
74
74
|
</ScreenLayoutContext.Provider>
|
|
75
75
|
);
|
|
@@ -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`] = `
|
|
@@ -2,58 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
exports[`Layout TV renders 1`] = `
|
|
4
4
|
<View
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
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
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
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
|
-
|
|
33
|
-
|
|
34
|
-
|
|
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
|
`;
|