@applicaster/zapp-react-native-ui-components 12.0.0-alpha.4201443043 → 12.0.0-alpha.4271512420
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 +26 -5
- package/Components/Cell/CellWithFocusable.tsx +6 -4
- package/Components/Cell/TvOSCellComponent.tsx +3 -7
- 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 +52 -9
- 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/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/dataAdapter.ts +21 -7
- package/Components/MasterCell/index.tsx +3 -1
- package/Components/MasterCell/utils/__tests__/insertBetween.test.js +9 -0
- package/Components/MasterCell/utils/index.ts +17 -30
- package/Components/Navigator/StackNavigator.tsx +14 -5
- package/Components/PlayerContainer/PlayerContainer.tsx +2 -0
- package/Components/Screen/TV/index.web.tsx +9 -23
- 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 +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 +10 -0
- 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 +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/package.json +5 -5
- 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
|
@@ -7,50 +7,28 @@ type BorderPosition = "inside" | "outside" | "center";
|
|
|
7
7
|
interface Props {
|
|
8
8
|
style: ImageStyle | ViewStyle;
|
|
9
9
|
borderPosition: BorderPosition;
|
|
10
|
+
borderPaddingTop: number;
|
|
11
|
+
borderPaddingRight: number;
|
|
12
|
+
borderPaddingBottom: number;
|
|
13
|
+
borderPaddingLeft: number;
|
|
10
14
|
children: React.ReactNode;
|
|
11
15
|
}
|
|
12
16
|
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
const
|
|
28
|
-
if (typeof value === "string" && value.endsWith("%")) {
|
|
29
|
-
return true;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
return false;
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
const calculateContainerSpacing = ({
|
|
36
|
-
spacingKey,
|
|
37
|
-
style,
|
|
38
|
-
additionalSpacing,
|
|
39
|
-
}: {
|
|
40
|
-
spacingKey: typeof MARGINS[number] | typeof PADDINGS[number];
|
|
41
|
-
style: ImageStyle | ViewStyle;
|
|
42
|
-
additionalSpacing: number;
|
|
43
|
-
}) => {
|
|
44
|
-
return {
|
|
45
|
-
[spacingKey]:
|
|
46
|
-
toNumberWithDefaultZero(style[spacingKey]) + additionalSpacing,
|
|
47
|
-
};
|
|
48
|
-
};
|
|
49
|
-
|
|
50
|
-
const getContainerBorderWidth = (
|
|
51
|
-
borderPosition: BorderPosition,
|
|
52
|
-
borderWidth
|
|
53
|
-
) => {
|
|
17
|
+
const COLOR_TRANSPARENT = "transparent";
|
|
18
|
+
|
|
19
|
+
const styles = StyleSheet.create({
|
|
20
|
+
container: {
|
|
21
|
+
overflow: "visible",
|
|
22
|
+
borderWidth: 0,
|
|
23
|
+
borderColor: COLOR_TRANSPARENT,
|
|
24
|
+
},
|
|
25
|
+
border: {
|
|
26
|
+
...StyleSheet.absoluteFillObject,
|
|
27
|
+
zIndex: 1,
|
|
28
|
+
},
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
const getBorderPadding = (borderPosition: BorderPosition, borderWidth) => {
|
|
54
32
|
switch (borderPosition) {
|
|
55
33
|
case "inside":
|
|
56
34
|
return 0;
|
|
@@ -63,104 +41,102 @@ const getContainerBorderWidth = (
|
|
|
63
41
|
}
|
|
64
42
|
};
|
|
65
43
|
|
|
66
|
-
const
|
|
67
|
-
switch (borderPosition) {
|
|
68
|
-
case "inside":
|
|
69
|
-
return borderWidth;
|
|
70
|
-
case "center":
|
|
71
|
-
return borderWidth / 2;
|
|
72
|
-
case "outside":
|
|
73
|
-
return 0;
|
|
74
|
-
default:
|
|
75
|
-
return 0;
|
|
76
|
-
}
|
|
77
|
-
};
|
|
78
|
-
|
|
79
|
-
const InsideBorder = ({
|
|
44
|
+
const Border = ({
|
|
80
45
|
style,
|
|
46
|
+
padding,
|
|
81
47
|
borderPosition,
|
|
82
48
|
}: {
|
|
83
49
|
style: ViewStyle;
|
|
50
|
+
padding: ViewStyle;
|
|
84
51
|
borderPosition: BorderPosition;
|
|
85
52
|
}) => {
|
|
86
|
-
if (borderPosition
|
|
53
|
+
if (!borderPosition) {
|
|
87
54
|
return null;
|
|
88
55
|
}
|
|
89
56
|
|
|
90
|
-
const
|
|
91
|
-
|
|
57
|
+
const borderWidth = toNumberWithDefaultZero(style.borderWidth);
|
|
58
|
+
const containerPadding = getBorderPadding(borderPosition, borderWidth);
|
|
59
|
+
|
|
60
|
+
const initialBorderRadius = toNumberWithDefaultZero(style.borderRadius);
|
|
61
|
+
const paddingTop = toNumberWithDefaultZero(padding.paddingTop);
|
|
62
|
+
const paddingRight = toNumberWithDefaultZero(padding.paddingRight);
|
|
63
|
+
const paddingBottom = toNumberWithDefaultZero(padding.paddingBottom);
|
|
64
|
+
const paddingLeft = toNumberWithDefaultZero(padding.paddingLeft);
|
|
65
|
+
|
|
66
|
+
const borderRadiusStyle = initialBorderRadius
|
|
67
|
+
? {
|
|
68
|
+
borderTopLeftRadius:
|
|
69
|
+
initialBorderRadius +
|
|
70
|
+
containerPadding +
|
|
71
|
+
Math.min(paddingTop, paddingLeft),
|
|
72
|
+
borderTopRightRadius:
|
|
73
|
+
initialBorderRadius +
|
|
74
|
+
containerPadding +
|
|
75
|
+
Math.min(paddingTop, paddingRight),
|
|
76
|
+
borderBottomLeftRadius:
|
|
77
|
+
initialBorderRadius +
|
|
78
|
+
containerPadding +
|
|
79
|
+
Math.min(paddingBottom, paddingLeft),
|
|
80
|
+
borderBottomRightRadius:
|
|
81
|
+
initialBorderRadius +
|
|
82
|
+
containerPadding +
|
|
83
|
+
Math.min(paddingBottom, paddingRight),
|
|
84
|
+
}
|
|
85
|
+
: {
|
|
86
|
+
borderTopLeftRadius: 0,
|
|
87
|
+
borderTopRightRadius: 0,
|
|
88
|
+
borderBottomLeftRadius: 0,
|
|
89
|
+
borderBottomRightRadius: 0,
|
|
90
|
+
};
|
|
92
91
|
|
|
93
92
|
return (
|
|
94
93
|
<View
|
|
94
|
+
pointerEvents="none"
|
|
95
95
|
style={{
|
|
96
|
-
...
|
|
97
|
-
|
|
96
|
+
...styles.border,
|
|
97
|
+
right: -containerPadding - paddingRight,
|
|
98
|
+
bottom: -containerPadding - paddingBottom,
|
|
99
|
+
left: -containerPadding - paddingLeft,
|
|
100
|
+
top: -containerPadding - paddingTop,
|
|
101
|
+
borderWidth,
|
|
98
102
|
borderColor: style.borderColor,
|
|
99
|
-
|
|
103
|
+
...borderRadiusStyle,
|
|
100
104
|
}}
|
|
101
105
|
/>
|
|
102
106
|
);
|
|
103
107
|
};
|
|
104
108
|
|
|
105
109
|
export const BorderContainerView = (props: Props) => {
|
|
106
|
-
const {
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
110
|
+
const {
|
|
111
|
+
borderPosition,
|
|
112
|
+
borderPaddingTop,
|
|
113
|
+
borderPaddingRight,
|
|
114
|
+
borderPaddingBottom,
|
|
115
|
+
borderPaddingLeft,
|
|
116
|
+
style,
|
|
117
|
+
children,
|
|
118
|
+
} = props;
|
|
112
119
|
|
|
113
120
|
const borderStyleForMissingBorder =
|
|
114
121
|
style?.borderWidth === 0 || !style?.borderColor ? { borderRadius: 0 } : {};
|
|
115
122
|
|
|
116
|
-
const
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
const updatedPaddings = PADDINGS.reduce((acc, padding) => {
|
|
127
|
-
const paddingValue = calculateContainerSpacing({
|
|
128
|
-
spacingKey: padding,
|
|
129
|
-
style,
|
|
130
|
-
additionalSpacing: spacing,
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
return { ...acc, ...paddingValue };
|
|
134
|
-
}, {});
|
|
135
|
-
|
|
136
|
-
const updatedWidth = style.width
|
|
137
|
-
? isPercentageValue(style.width)
|
|
138
|
-
? style.width
|
|
139
|
-
: toNumberWithDefaultZero(style.width) - spacing * 2
|
|
140
|
-
: undefined;
|
|
141
|
-
|
|
142
|
-
const updatedHeight = style.height
|
|
143
|
-
? isPercentageValue(style.height)
|
|
144
|
-
? style.height
|
|
145
|
-
: toNumberWithDefaultZero(style.height) - spacing * 2
|
|
146
|
-
: undefined;
|
|
147
|
-
|
|
148
|
-
const containerStyle = {
|
|
149
|
-
borderWidth: getContainerBorderWidth(borderPosition, borderWidth),
|
|
150
|
-
padding: spacing,
|
|
151
|
-
...updatedMargins,
|
|
152
|
-
...updatedPaddings,
|
|
153
|
-
width: updatedWidth,
|
|
154
|
-
height: updatedHeight,
|
|
155
|
-
};
|
|
123
|
+
const padding =
|
|
124
|
+
borderPosition === "outside"
|
|
125
|
+
? {
|
|
126
|
+
paddingTop: borderPaddingTop,
|
|
127
|
+
paddingRight: borderPaddingRight,
|
|
128
|
+
paddingBottom: borderPaddingBottom,
|
|
129
|
+
paddingLeft: borderPaddingLeft,
|
|
130
|
+
}
|
|
131
|
+
: {};
|
|
156
132
|
|
|
157
133
|
return (
|
|
158
|
-
<View
|
|
134
|
+
<View
|
|
135
|
+
{...props}
|
|
136
|
+
style={[style, styles.container, borderStyleForMissingBorder]}
|
|
137
|
+
>
|
|
138
|
+
<Border style={style} padding={padding} borderPosition={borderPosition} />
|
|
159
139
|
{children}
|
|
160
|
-
<InsideBorder
|
|
161
|
-
style={{ ...style, ...borderStyleForMissingBorder }}
|
|
162
|
-
borderPosition={borderPosition}
|
|
163
|
-
/>
|
|
164
140
|
</View>
|
|
165
141
|
);
|
|
166
142
|
};
|
|
@@ -4,6 +4,7 @@ import { Focusable } from "@applicaster/zapp-react-native-ui-components/Componen
|
|
|
4
4
|
import { useActions } from "@applicaster/zapp-react-native-utils/reactHooks/actions";
|
|
5
5
|
import * as R from "ramda";
|
|
6
6
|
import { getXray } from "@applicaster/zapp-react-native-utils/logger";
|
|
7
|
+
import { toBooleanWithDefaultFalse } from "@applicaster/zapp-react-native-utils/booleanUtils";
|
|
7
8
|
|
|
8
9
|
const { Logger } = getXray();
|
|
9
10
|
|
|
@@ -35,7 +36,9 @@ export function FocusableView({ style, children, item, ...otherProps }: Props) {
|
|
|
35
36
|
|
|
36
37
|
const focusableId = getFocusableId(prefixId, suffixId);
|
|
37
38
|
|
|
38
|
-
const focused =
|
|
39
|
+
const focused =
|
|
40
|
+
focusableId === focusedButtonId ||
|
|
41
|
+
toBooleanWithDefaultFalse(otherProps.focused);
|
|
39
42
|
|
|
40
43
|
const additionalStyles = focused ? focusedStyles : normalStyles;
|
|
41
44
|
|
|
@@ -108,6 +108,26 @@ const prepareEntry = (entry) => {
|
|
|
108
108
|
};
|
|
109
109
|
}
|
|
110
110
|
|
|
111
|
+
const previewPlayback =
|
|
112
|
+
entry.extensions?.["brightcove"]?.["preview_playback"];
|
|
113
|
+
|
|
114
|
+
if (previewPlayback) {
|
|
115
|
+
return {
|
|
116
|
+
...entry,
|
|
117
|
+
extensions: {
|
|
118
|
+
...entry.extensions,
|
|
119
|
+
brightcove: {
|
|
120
|
+
...entry?.extensions?.["brightcove"],
|
|
121
|
+
video_id: previewPlayback,
|
|
122
|
+
},
|
|
123
|
+
},
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (entry.extensions?.["brightcove"]?.["video_id"]) {
|
|
128
|
+
return entry;
|
|
129
|
+
}
|
|
130
|
+
|
|
111
131
|
const src = entry.content?.src;
|
|
112
132
|
|
|
113
133
|
if (!src) {
|
|
@@ -7,6 +7,10 @@ import type {
|
|
|
7
7
|
ContainerProps,
|
|
8
8
|
ContainerChildren,
|
|
9
9
|
} from "./types";
|
|
10
|
+
import {
|
|
11
|
+
useIsRTL,
|
|
12
|
+
applyRTLStylesIfNeeded,
|
|
13
|
+
} from "@applicaster/zapp-react-native-utils/localizationUtils";
|
|
10
14
|
|
|
11
15
|
const HorizontalSeparator = ({ width }: HorizontalSeparatorProps) => (
|
|
12
16
|
<View style={{ width }} />
|
|
@@ -17,6 +21,7 @@ export function ButtonContainerView({
|
|
|
17
21
|
children,
|
|
18
22
|
...otherProps
|
|
19
23
|
}: ContainerProps) {
|
|
24
|
+
const isRTL = useIsRTL();
|
|
20
25
|
const horizontalGutter = R.pathOr(0, ["horizontalGutter"], otherProps);
|
|
21
26
|
|
|
22
27
|
const filteredChildren = useFilterChildren<ContainerChildren>(children);
|
|
@@ -26,7 +31,7 @@ export function ButtonContainerView({
|
|
|
26
31
|
}
|
|
27
32
|
|
|
28
33
|
return (
|
|
29
|
-
<View style={style}>
|
|
34
|
+
<View style={applyRTLStylesIfNeeded(style, isRTL)}>
|
|
30
35
|
{insertBetween(
|
|
31
36
|
(index) => (
|
|
32
37
|
<HorizontalSeparator
|
|
@@ -37,14 +37,28 @@ function retrieveData(entry, func, args) {
|
|
|
37
37
|
*/
|
|
38
38
|
|
|
39
39
|
export function configInflater(
|
|
40
|
-
entry,
|
|
41
|
-
{
|
|
40
|
+
entry: any,
|
|
41
|
+
{
|
|
42
|
+
type,
|
|
43
|
+
style,
|
|
44
|
+
additionalProps = {},
|
|
45
|
+
data = [],
|
|
46
|
+
elements,
|
|
47
|
+
}: {
|
|
48
|
+
type: any;
|
|
49
|
+
style: any;
|
|
50
|
+
additionalProps?: Record<string, any>;
|
|
51
|
+
data?: Array<{ propName: string; func: Function; args: any[] }>;
|
|
52
|
+
elements?: any[];
|
|
53
|
+
}
|
|
42
54
|
) {
|
|
43
|
-
const props =
|
|
44
|
-
(acc, curr) =>
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
55
|
+
const props = data.reduce(
|
|
56
|
+
(acc, curr) => {
|
|
57
|
+
acc[curr.propName] = retrieveData(entry, curr.func, curr.args);
|
|
58
|
+
|
|
59
|
+
return acc;
|
|
60
|
+
},
|
|
61
|
+
{ ...additionalProps }
|
|
48
62
|
);
|
|
49
63
|
|
|
50
64
|
let adjustedElements;
|
|
@@ -52,6 +52,8 @@ export function masterCellBuilder({
|
|
|
52
52
|
const { View } = componentsMap;
|
|
53
53
|
const elementsBuilder = dataAdapter(cellConfiguration);
|
|
54
54
|
|
|
55
|
+
// This is very expensive operation
|
|
56
|
+
// Keep calls to minimum
|
|
55
57
|
const hasFocusableInside = hasFocusableInsideBuilder(elementsBuilder);
|
|
56
58
|
|
|
57
59
|
/**
|
|
@@ -84,7 +86,7 @@ export function masterCellBuilder({
|
|
|
84
86
|
entry: item,
|
|
85
87
|
state: getEntryState(state, entryIsSelected),
|
|
86
88
|
}),
|
|
87
|
-
[state, item, entryIsSelected]
|
|
89
|
+
[state, item?.id, entryIsSelected] // Assuming that item won't mutate
|
|
88
90
|
);
|
|
89
91
|
|
|
90
92
|
const wrapperRef = React.useRef(null);
|
|
@@ -9,4 +9,13 @@ describe("insertBetween", () => {
|
|
|
9
9
|
|
|
10
10
|
expect(result).toEqual([1, "|", 2, "|", 3]);
|
|
11
11
|
});
|
|
12
|
+
|
|
13
|
+
it("insertBetween", () => {
|
|
14
|
+
const separator = (index) => `separator:${index}`;
|
|
15
|
+
const items = [1, 2, 3];
|
|
16
|
+
|
|
17
|
+
const result = insertBetween(separator, items);
|
|
18
|
+
|
|
19
|
+
expect(result).toEqual([1, "separator:0", 2, "separator:1", 3]);
|
|
20
|
+
});
|
|
12
21
|
});
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import React, { useEffect, useMemo } from "react";
|
|
2
2
|
import * as R from "ramda";
|
|
3
|
+
import validateColor from "validate-color";
|
|
3
4
|
import { platformSelect } from "@applicaster/zapp-react-native-utils/reactUtils";
|
|
4
5
|
import { useActions } from "@applicaster/zapp-react-native-utils/reactHooks/actions";
|
|
5
6
|
|
|
@@ -9,6 +10,7 @@ import { usePlayer } from "@applicaster/zapp-react-native-utils/appUtils/playerM
|
|
|
9
10
|
import { PushTopicManager } from "@applicaster/zapp-react-native-bridge/PushNotifications/PushTopicManager";
|
|
10
11
|
import { StorageMultiSelectProvider } from "@applicaster/zapp-react-native-bridge/ZappStorage/StorageMultiSelectProvider";
|
|
11
12
|
import { getCellState } from "../../Cell/utils";
|
|
13
|
+
import { getColorFromData } from "@applicaster/zapp-react-native-utils/cellUtils";
|
|
12
14
|
|
|
13
15
|
const hasElementSpecificViewType = (viewType) => (element) => {
|
|
14
16
|
if (R.isNil(element)) {
|
|
@@ -47,44 +49,29 @@ export const hasElementsSpecificViewType = (viewType) => (elements) => {
|
|
|
47
49
|
return R.any(hasElementSpecificViewType(viewType))(elements);
|
|
48
50
|
};
|
|
49
51
|
|
|
50
|
-
const isColorOrEmpty = (value) =>
|
|
51
|
-
value === null ||
|
|
52
|
-
value === undefined ||
|
|
53
|
-
value === "" ||
|
|
54
|
-
value.startsWith("#") ||
|
|
55
|
-
value.startsWith("rgba") ||
|
|
56
|
-
value === "transparent";
|
|
57
|
-
|
|
58
52
|
function resolveColorForProp(entry, style, colorProp) {
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
53
|
+
const colorFromProp = style[colorProp];
|
|
54
|
+
const nestedEntryValue = R.path(colorFromProp.split("."), entry);
|
|
55
|
+
|
|
56
|
+
if (
|
|
57
|
+
nestedEntryValue === undefined &&
|
|
58
|
+
!validateColor(colorFromProp.replace(".00", "")) // https://github.com/dreamyguy/validate-color/issues/44
|
|
59
|
+
) {
|
|
60
|
+
logWarning(colorFromProp, style, entry, nestedEntryValue);
|
|
63
61
|
}
|
|
64
62
|
|
|
65
|
-
const
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
if (nestedEntryValue === null || typeof nestedEntryValue !== "object") {
|
|
70
|
-
logWarning(colorValue, style, entry, nestedEntryValue);
|
|
71
|
-
|
|
72
|
-
return style;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
nestedEntryValue = nestedEntryValue[part];
|
|
76
|
-
}
|
|
63
|
+
const colorValue = getColorFromData({
|
|
64
|
+
data: entry,
|
|
65
|
+
valueFromLayout: colorFromProp,
|
|
66
|
+
});
|
|
77
67
|
|
|
78
|
-
if (
|
|
79
|
-
logWarning(
|
|
68
|
+
if (!colorValue) {
|
|
69
|
+
logWarning(colorProp, style, entry, colorValue);
|
|
80
70
|
|
|
81
71
|
return style;
|
|
82
72
|
}
|
|
83
73
|
|
|
84
|
-
|
|
85
|
-
style[colorProp] = nestedEntryValue;
|
|
86
|
-
|
|
87
|
-
return style;
|
|
74
|
+
return { ...style, [colorProp]: colorValue };
|
|
88
75
|
}
|
|
89
76
|
|
|
90
77
|
export function resolveColor(entry, style) {
|
|
@@ -8,6 +8,8 @@ import { ScreenDataContext } from "@applicaster/zapp-react-native-ui-components/
|
|
|
8
8
|
import { PathnameContext } from "@applicaster/zapp-react-native-ui-components/Contexts/PathnameContext";
|
|
9
9
|
|
|
10
10
|
import { Screen } from "../Screen/TV/index.web";
|
|
11
|
+
import { isLast } from "@applicaster/zapp-react-native-utils/arrayUtils";
|
|
12
|
+
import { ScreenContextProvider } from "../../Contexts/ScreenContext";
|
|
11
13
|
|
|
12
14
|
type Components = {
|
|
13
15
|
NavBar: React.ComponentType<any>;
|
|
@@ -19,25 +21,32 @@ type Props = {
|
|
|
19
21
|
};
|
|
20
22
|
|
|
21
23
|
export const StackNavigator = ({ Components }: Props) => {
|
|
22
|
-
const { mainStack
|
|
24
|
+
const { mainStack } = useNavigation();
|
|
23
25
|
|
|
24
|
-
const renderScreen = ({ route, state }) => {
|
|
26
|
+
const renderScreen = ({ route, state }, index) => {
|
|
25
27
|
const pathAttributes = getPathAttributes({ pathname: route });
|
|
26
28
|
|
|
27
29
|
if (isEmpty(pathAttributes)) {
|
|
28
30
|
return null;
|
|
29
31
|
}
|
|
30
32
|
|
|
33
|
+
// HACK: Adding index to route to avoid conflicts in the navigator.
|
|
34
|
+
// Startup hooks are all using PUSH navigation action to navigate, but their routes are always like root routes.
|
|
35
|
+
// This means some hooks can have the same routes, e.g., ["hooks/context-setter", "/hooks/login-plug", "hooks/context-setter"].
|
|
36
|
+
const routeId = `${route}--${index}`;
|
|
37
|
+
|
|
31
38
|
return (
|
|
32
39
|
<FocusableGroup
|
|
33
40
|
id={route}
|
|
34
|
-
preferredFocus={
|
|
41
|
+
preferredFocus={isLast(index, mainStack.length)}
|
|
35
42
|
excludeFromFocusSearching
|
|
36
|
-
key={
|
|
43
|
+
key={routeId}
|
|
37
44
|
>
|
|
38
45
|
<ScreenDataContext.Provider value={state}>
|
|
39
46
|
<PathnameContext.Provider value={route}>
|
|
40
|
-
<
|
|
47
|
+
<ScreenContextProvider pathname={route}>
|
|
48
|
+
<Screen route={route} Components={Components} />
|
|
49
|
+
</ScreenContextProvider>
|
|
41
50
|
</PathnameContext.Provider>
|
|
42
51
|
</ScreenDataContext.Provider>
|
|
43
52
|
</FocusableGroup>
|
|
@@ -124,6 +124,7 @@ const nativeStyles = {
|
|
|
124
124
|
playerScreen: {
|
|
125
125
|
flex: 1,
|
|
126
126
|
backgroundColor: "black",
|
|
127
|
+
overflow: "hidden",
|
|
127
128
|
},
|
|
128
129
|
playerWrapper: {
|
|
129
130
|
flex: 1,
|
|
@@ -252,6 +253,7 @@ const PlayerContainerComponent = (props: Props) => {
|
|
|
252
253
|
}
|
|
253
254
|
|
|
254
255
|
showNavBar(true);
|
|
256
|
+
navigator.goBack();
|
|
255
257
|
}, [isModal, navigator.goBack, showNavBar]);
|
|
256
258
|
|
|
257
259
|
const playEntry = (entry) => navigator.replaceTop(entry, { mode });
|
|
@@ -1,20 +1,24 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import { last
|
|
2
|
+
import { last } from "ramda";
|
|
3
3
|
import { View, StyleSheet } from "react-native";
|
|
4
4
|
import {
|
|
5
|
+
findMenuPlugin,
|
|
5
6
|
getNavigationProps,
|
|
6
7
|
getPathAttributes,
|
|
7
|
-
resolveNavigationPlugin,
|
|
8
8
|
} from "@applicaster/zapp-react-native-utils/navigationUtils";
|
|
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 {
|
|
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,18 +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
|
-
const isPlayerPlugin = (routeState): boolean =>
|
|
46
|
-
getPluginType(routeState) === "player";
|
|
47
|
-
|
|
48
|
-
const isLoginPlugin = (routeState): boolean =>
|
|
49
|
-
getPluginType(routeState) === "login";
|
|
50
|
-
|
|
51
43
|
const getActiveRiver = ({
|
|
52
44
|
screenId,
|
|
53
45
|
screenType,
|
|
@@ -139,19 +131,14 @@ export const Screen = ({ route, Components }: Props) => {
|
|
|
139
131
|
fallbackNavigations: navigator.activeRiver.navigations,
|
|
140
132
|
});
|
|
141
133
|
|
|
142
|
-
const menuPlugin =
|
|
143
|
-
category: "menu",
|
|
144
|
-
navigations,
|
|
145
|
-
plugins,
|
|
146
|
-
}) as QuickBrickPlugin;
|
|
134
|
+
const menuPlugin = findMenuPlugin(navigations, plugins);
|
|
147
135
|
|
|
148
136
|
const NavBar = (Components.NavBar ||
|
|
149
137
|
menuPlugin.module) as React.ComponentType<any>;
|
|
150
138
|
|
|
151
139
|
const isPlayer = isPlayerPlugin(routeState);
|
|
152
|
-
const isLogin = isLoginPlugin(routeState);
|
|
153
140
|
|
|
154
|
-
const isNavBarVisible =
|
|
141
|
+
const { visible: isNavBarVisible } = useNavbarState();
|
|
155
142
|
|
|
156
143
|
const screenData =
|
|
157
144
|
screenType === "hooks" || isPlayer
|
|
@@ -162,7 +149,6 @@ export const Screen = ({ route, Components }: Props) => {
|
|
|
162
149
|
<View style={[styles.container, { backgroundColor }]}>
|
|
163
150
|
<NavBarContainer isVisible={isNavBarVisible} onReady={noop}>
|
|
164
151
|
<NavBar
|
|
165
|
-
groupId={route}
|
|
166
152
|
isVisible={isNavBarVisible}
|
|
167
153
|
menuPlugin={menuPlugin}
|
|
168
154
|
navigationProps={navigationProps}
|
|
@@ -10,6 +10,8 @@ const mock_navBarVisibleFlag = true;
|
|
|
10
10
|
|
|
11
11
|
const mockIsNavBarVisible = jest.fn(() => mock_navBarVisibleFlag);
|
|
12
12
|
|
|
13
|
+
const mockIsOrientationCompatible = jest.fn(() => true);
|
|
14
|
+
|
|
13
15
|
jest.mock("react-native-safe-area-context", () => ({
|
|
14
16
|
useSafeAreaInsets: () => ({ top: 44 }),
|
|
15
17
|
}));
|
|
@@ -21,6 +23,7 @@ jest.mock("../../RouteManager", () => ({
|
|
|
21
23
|
jest.mock(
|
|
22
24
|
"@applicaster/zapp-react-native-utils/appUtils/orientationHelper",
|
|
23
25
|
() => ({
|
|
26
|
+
isOrientationCompatible: mockIsOrientationCompatible,
|
|
24
27
|
allowedOrientationsForScreen: jest.fn(),
|
|
25
28
|
getOrientation: jest.fn(),
|
|
26
29
|
getScreenOrientation: jest.fn(),
|