@applicaster/zapp-react-native-ui-components 13.0.0-alpha.6523249552 → 13.0.0-alpha.6651373134
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/AppContainer/__tests__/AppContainer.test.js +4 -6
- package/Components/AudioPlayer/AudioPlayer.tsx +7 -0
- package/Components/AudioPlayer/__tests__/Runtime.test.js +5 -8
- package/Components/AudioPlayer/__tests__/__snapshots__/audioPlayer.test.js.snap +54 -111
- package/Components/AudioPlayer/__tests__/__snapshots__/audioPlayerLayout.test.js.snap +36 -20
- package/Components/AudioPlayer/__tests__/artWork.test.js +3 -5
- package/Components/AudioPlayer/__tests__/audioPlayer.test.js +3 -5
- package/Components/AudioPlayer/__tests__/audioPlayerLayout.test.js +7 -8
- package/Components/AudioPlayer/__tests__/channel.test.js +3 -5
- package/Components/AudioPlayer/__tests__/summary.test.js +3 -5
- package/Components/AudioPlayer/__tests__/title.test.js +3 -5
- package/Components/AudioPlayer/helpers.tsx +1 -0
- package/Components/BaseFocusable/index.tsx +1 -2
- package/Components/Cell/Cell.tsx +4 -13
- package/Components/Cell/CellWithFocusable.tsx +48 -59
- package/Components/Cell/CellWrapper.ts +5 -0
- package/Components/Cell/TvOSCellComponent.tsx +20 -22
- package/Components/Cell/__tests__/CellWIthFocusable.test.js +13 -6
- package/Components/Cell/index.js +3 -1
- package/Components/Cell/styles.ts +17 -0
- package/Components/CellRendererResolver/__tests__/cellRendererResolver.test.js +46 -48
- package/Components/ComponentResolver/__tests__/__snapshots__/componentResolver.test.js.snap +1 -42
- package/Components/ComponentResolver/__tests__/componentResolver.test.js +16 -22
- package/Components/ContentScreen/__tests__/contentScreen.test.js +3 -3
- package/Components/ErrorScreen/index.tsx +14 -6
- package/Components/Focusable/Focusable.tsx +1 -0
- package/Components/Focusable/FocusableTvOS.tsx +5 -1
- package/Components/Focusable/index.android.tsx +10 -3
- package/Components/FocusableCell/index.tsx +1 -1
- package/Components/FocusableGroup/FocusableTvOS.tsx +34 -86
- package/Components/FocusableGroup/index.tsx +0 -3
- package/Components/FocusableList/index.tsx +26 -9
- package/Components/FocusableScrollView/index.tsx +43 -13
- package/Components/HandlePlayable/HandlePlayable.tsx +14 -27
- package/Components/Layout/TV/NavBarContainer.tsx +19 -23
- package/Components/Layout/TV/ScreenContainer.tsx +8 -1
- package/Components/Layout/TV/ScreenLayoutContextProvider.tsx +5 -0
- package/Components/Layout/TV/__tests__/ScreenContainer.test.tsx +2 -1
- package/Components/Layout/TV/__tests__/__snapshots__/NavBarContainer.test.tsx.snap +3 -2
- package/Components/Layout/TV/__tests__/__snapshots__/ScreenContainer.test.tsx.snap +3 -2
- package/Components/MasterCell/DefaultComponents/ActionButton.tsx +2 -3
- package/Components/MasterCell/DefaultComponents/Image/Image.ios.tsx +4 -3
- package/Components/MasterCell/DefaultComponents/Image/hooks/useImage.ts +11 -7
- package/Components/MasterCell/DefaultComponents/LiveImage/index.tsx +2 -2
- package/Components/MasterCell/SharedUI/ProgressBar/hooks/useFillInPercent.ts +2 -8
- package/Components/MasterCell/__tests__/__snapshots__/elementMapper.test.js.snap +4 -12
- package/Components/MasterCell/__tests__/__snapshots__/masterCell.test.js.snap +0 -229
- package/Components/MasterCell/__tests__/elementMapper.test.js +18 -5
- package/Components/MasterCell/__tests__/masterCell.test.js +26 -26
- package/Components/MasterCell/hooks/useAsyncRendering/MasterCellAsyncRenderManager.ts +2 -2
- package/Components/MasterCell/utils/behaviorProvider.ts +136 -0
- package/Components/MasterCell/utils/index.ts +8 -134
- package/Components/ModalComponent/Button/assets.ts +1 -1
- package/Components/ModalComponent/Button/index.tsx +6 -6
- package/Components/OfflineHandler/NotificationView/NotificationView.lg.tsx +2 -2
- package/Components/OfflineHandler/NotificationView/NotificationView.samsung.tsx +2 -2
- package/Components/OfflineHandler/NotificationView/__tests__/index.test.tsx +0 -5
- package/Components/OfflineHandler/utils/index.ts +1 -1
- package/Components/PlayerContainer/PlayerContainer.tsx +17 -13
- package/Components/PlayerContainer/ProgramInfo/index.tsx +2 -2
- package/Components/PlayerImageBackground/index.tsx +1 -1
- package/Components/River/ComponentsMap/ComponentsMap.tsx +42 -65
- package/Components/River/ComponentsMap/hooks/useLoadingState.ts +78 -51
- package/Components/River/RiverFooter.tsx +39 -9
- package/Components/River/RiverItem.tsx +37 -2
- package/Components/River/TV/index.tsx +6 -1
- package/Components/River/__tests__/__snapshots__/componentsMap.test.js.snap +100 -31
- package/Components/River/__tests__/__snapshots__/river.test.js.snap +20 -82
- package/Components/River/__tests__/componentsMap.test.js +3 -4
- package/Components/River/__tests__/river.test.js +75 -40
- package/Components/RouteManager/__tests__/__snapshots__/routeManager.test.js.snap +11 -4
- package/Components/RouteManager/__tests__/routeManager.test.js +29 -14
- package/Components/RouteManager/__tests__/testId.test.js +8 -6
- package/Components/Screen/TV/index.web.tsx +5 -6
- package/Components/Screen/hooks.ts +53 -0
- package/Components/Screen/index.tsx +16 -43
- package/Components/ScreenResolver/__tests__/screenResolver.test.js +91 -70
- package/Components/Tabs/Tab.tsx +5 -3
- package/Components/TextInputTv/index.tsx +2 -1
- package/Components/TrackedView/index.tsx +1 -0
- package/Components/Transitioner/AnimationManager.js +15 -15
- package/Components/Transitioner/Scene.tsx +1 -1
- package/Components/Transitioner/Transitioner.tsx +3 -3
- package/Components/Transitioner/__tests__/Scene.test.js +25 -14
- package/Components/Transitioner/__tests__/__snapshots__/Scene.test.js.snap +12 -68
- package/Components/Transitioner/__tests__/__snapshots__/transitioner.test.js.snap +2 -2
- package/Components/Transitioner/__tests__/transitioner.test.js +13 -4
- package/Components/VideoLive/PlayerLiveImageComponent.tsx +7 -3
- package/Components/VideoLive/__tests__/__snapshots__/PlayerLiveImageComponent.test.tsx.snap +1 -0
- package/Components/VideoModal/ModalAnimation/AnimatedPlayerModalWrapper.tsx +1 -1
- package/Components/VideoModal/ModalAnimation/AnimatedScrollModal.tsx +44 -30
- package/Components/VideoModal/ModalAnimation/AnimatedVideoPlayerComponent.tsx +3 -3
- package/Components/VideoModal/ModalAnimation/AnimationComponent.tsx +24 -11
- package/Components/VideoModal/ModalAnimation/ModalAnimationContext.tsx +4 -5
- package/Components/VideoModal/PlayerDetails.tsx +9 -6
- package/Components/VideoModal/PlayerWrapper.tsx +28 -5
- package/Components/VideoModal/VideoModal.tsx +2 -2
- package/Components/Viewport/ViewportAware/__tests__/__snapshots__/viewportAware.test.js.snap +24 -36
- package/Components/Viewport/ViewportAware/__tests__/viewportAware.test.js +12 -18
- package/Components/Viewport/__tests__/utils.test.js +5 -4
- package/Components/ZappUIComponent/Placeholder.tsx +3 -1
- package/Components/ZappUIComponent/__tests__/{ZappUIComponent.test.js → ZappUIComponent.test.tsx} +26 -10
- package/Components/ZappUIComponent/index.tsx +3 -16
- package/Components/default-cell-renderer/__tests__/defaultCellRenderer.test.tsx +20 -17
- package/Components/default-cell-renderer/viewTrees/tv/DefaultCell/__tests__/DefaultCell.test.tsx +15 -11
- package/Contexts/ComponentsMapOffsetContext/index.tsx +49 -0
- package/Contexts/FocusableGroupContext/withFocusableContext.tsx +4 -10
- package/Contexts/HeaderOffsetContext/index.tsx +4 -6
- package/Contexts/ScreenContext/index.tsx +3 -10
- package/Contexts/ScreenLayoutContext/index.tsx +5 -3
- package/Decorators/Navigator/__tests__/navigator.test.js +16 -16
- package/Decorators/Navigator/index.tsx +1 -1
- package/Decorators/RiverResolver/__tests__/riverResolver.test.tsx +18 -24
- package/Decorators/RiverResolver/index.tsx +6 -8
- package/Decorators/ZappPipesDataConnector/__tests__/zappPipesDataConnector.test.js +29 -22
- package/Decorators/ZappPipesDataConnector/index.tsx +4 -30
- package/package.json +7 -11
- package/tsconfig.json +2 -3
- package/.babelrc +0 -8
- package/Components/Cell/CellStyles/FallbackCellStyle/index.js +0 -157
- package/Components/Cell/CellStyles/Hero/index.js +0 -111
- package/Components/Cell/CellStyles/ScreenSelector/index.js +0 -68
- package/Components/Cell/CellStyles/cellStylesResolver.ts +0 -19
- package/Components/Cell/CellStyles/colors.js +0 -40
- package/Components/Cell/CellStyles/index.js +0 -15
- package/Components/CellRendererResolver/__tests__/__snapshots__/cellRendererResolver.test.js.snap +0 -53
- package/Components/RouteManager/__tests__/__snapshots__/testId.test.js.snap +0 -17
- package/Components/ScreenResolver/__tests__/__snapshots__/screenResolver.test.js.snap +0 -17
- package/Components/ZappUIComponent/__tests__/__snapshots__/ZappUIComponent.test.js.snap +0 -91
- package/Components/default-cell-renderer/__tests__/__snapshots__/defaultCellRenderer.test.tsx.snap +0 -338
- package/Decorators/Navigator/__tests__/__snapshots__/navigator.test.js.snap +0 -18
- package/Decorators/RiverResolver/__tests__/__snapshots__/riverResolver.test.tsx.snap +0 -28
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
focusManager,
|
|
10
10
|
forceFocusableFocus,
|
|
11
11
|
} from "@applicaster/zapp-react-native-utils/appUtils/focusManager/index.ios";
|
|
12
|
-
import { findNodeHandle } from "react-native";
|
|
12
|
+
import { findNodeHandle, ViewStyle } from "react-native";
|
|
13
13
|
|
|
14
14
|
function noop() {}
|
|
15
15
|
|
|
@@ -35,6 +35,10 @@ type Props = {
|
|
|
35
35
|
forceFocus?: boolean;
|
|
36
36
|
initialFocus?: boolean;
|
|
37
37
|
onLayout?: (e: any) => void;
|
|
38
|
+
willReceiveFocus: () => void;
|
|
39
|
+
hasReceivedFocus: () => void;
|
|
40
|
+
offsetUpdater: (arg1: string, arg2: number) => number;
|
|
41
|
+
style: ViewStyle;
|
|
38
42
|
};
|
|
39
43
|
|
|
40
44
|
export class Focusable extends BaseFocusable<Props> {
|
|
@@ -33,6 +33,8 @@ type Props = {
|
|
|
33
33
|
onLongPress?: (ref: FocusManager.FocusableRef) => void;
|
|
34
34
|
onRegister?: () => void;
|
|
35
35
|
isFocusableCell?: boolean;
|
|
36
|
+
/** only for FocusableScrollView */
|
|
37
|
+
onSetIsFocusable?: (isFocusable: boolean) => void;
|
|
36
38
|
} & ParentFocus;
|
|
37
39
|
|
|
38
40
|
export const FocusableContext = React.createContext<
|
|
@@ -67,6 +69,7 @@ function FocusableComponent(props: Props, forwardedRef) {
|
|
|
67
69
|
onLongPress,
|
|
68
70
|
onRegister = noop,
|
|
69
71
|
isFocusableCell = true,
|
|
72
|
+
onSetIsFocusable,
|
|
70
73
|
} = props;
|
|
71
74
|
|
|
72
75
|
const isRTL = useIsRTL();
|
|
@@ -137,9 +140,13 @@ function FocusableComponent(props: Props, forwardedRef) {
|
|
|
137
140
|
[onBlur]
|
|
138
141
|
);
|
|
139
142
|
|
|
140
|
-
const setIsFocusable = React.useCallback(
|
|
141
|
-
|
|
142
|
-
|
|
143
|
+
const setIsFocusable = React.useCallback(
|
|
144
|
+
(blockFocus) => {
|
|
145
|
+
onSetIsFocusable?.(blockFocus);
|
|
146
|
+
setDisableFocus(!blockFocus);
|
|
147
|
+
},
|
|
148
|
+
[onSetIsFocusable]
|
|
149
|
+
);
|
|
143
150
|
|
|
144
151
|
const parentFocus = React.useMemo(
|
|
145
152
|
() => ({
|
|
@@ -23,7 +23,7 @@ export function FocusableCell(props: Props) {
|
|
|
23
23
|
behavior,
|
|
24
24
|
} = props;
|
|
25
25
|
|
|
26
|
-
const state = useCellState({
|
|
26
|
+
const state = useCellState({ item, behavior, focused });
|
|
27
27
|
|
|
28
28
|
React.useEffect(() => {
|
|
29
29
|
if (focused && scrollTo && !isAndroid) {
|
|
@@ -1,17 +1,30 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import { FocusableGroupNative } from "@applicaster/zapp-react-native-ui-components/Components/NativeFocusables";
|
|
3
3
|
import { BaseFocusable } from "@applicaster/zapp-react-native-ui-components/Components/BaseFocusable";
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
import { createLogger } from "@applicaster/zapp-react-native-utils/logger";
|
|
5
|
+
|
|
6
|
+
const { log_verbose } = createLogger({
|
|
7
|
+
subsystem: "General",
|
|
8
|
+
category: "FocusableGroup",
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
type FocusableGroupNativeEvent = {
|
|
12
|
+
nativeEvent: {
|
|
13
|
+
focusHeading: FocusManager.Direction;
|
|
14
|
+
groupId: string;
|
|
15
|
+
isActive: boolean;
|
|
16
|
+
isFocusDisabled: boolean;
|
|
17
|
+
isFocusingByUser: boolean;
|
|
18
|
+
itemId: string;
|
|
19
|
+
target: number;
|
|
20
|
+
};
|
|
21
|
+
};
|
|
6
22
|
|
|
7
23
|
type Props = {
|
|
8
24
|
id: string;
|
|
9
25
|
children: (arg1: boolean) => React.ComponentType<any>;
|
|
10
|
-
onWillUpdateFocus: (nativeEvent: any) => void;
|
|
11
|
-
onDidUpdateFocus: (nativeEvent: any) => void;
|
|
12
26
|
isFocusDisabled: boolean;
|
|
13
|
-
|
|
14
|
-
resetFocusToInitialValue: boolean;
|
|
27
|
+
isWithMemory: boolean;
|
|
15
28
|
focusGroupRef: React.Component;
|
|
16
29
|
shouldUsePreferredFocus: boolean;
|
|
17
30
|
groupId: string;
|
|
@@ -21,86 +34,26 @@ type Props = {
|
|
|
21
34
|
};
|
|
22
35
|
|
|
23
36
|
export class FocusableGroup extends BaseFocusable<Props> {
|
|
24
|
-
focusableGroupNativeRef: React.Component | null;
|
|
25
|
-
constructor(props) {
|
|
26
|
-
super(props);
|
|
27
|
-
this.focusableGroupNativeRef = null;
|
|
28
|
-
|
|
29
|
-
this.state = {
|
|
30
|
-
isActive: false,
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
this.onWillUpdateFocus = this.onWillUpdateFocus.bind(this);
|
|
34
|
-
this.onDidUpdateFocus = this.onDidUpdateFocus.bind(this);
|
|
35
|
-
this.isGroup = true;
|
|
36
|
-
|
|
37
|
-
this.shouldUsePreferredFocus = this.shouldUsePreferredFocus.bind(this);
|
|
38
|
-
this.measureView = this.measureView.bind(this);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
connectedScreenId() {
|
|
42
|
-
const {
|
|
43
|
-
screenData: { screenId, parentScreenId },
|
|
44
|
-
} = this.props;
|
|
45
|
-
|
|
46
|
-
if (screenId) {
|
|
47
|
-
return null;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
return parentScreenId ? `${parentScreenId}-${screenId}` : screenId;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* tells whether the group should give focus to a preferred item when it gains focus from another
|
|
55
|
-
* group
|
|
56
|
-
* @returns {boolean}
|
|
57
|
-
*/
|
|
58
|
-
shouldUsePreferredFocus() {
|
|
59
|
-
return this.props.shouldUsePreferredFocus || false;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* indicates whether the underlying component should claim preferred focus
|
|
64
|
-
* when navigating into the group of this item
|
|
65
|
-
* @returns {boolean}
|
|
66
|
-
*/
|
|
67
|
-
isPreferredFocus() {
|
|
68
|
-
return this.props.preferredFocus || false;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
onWillUpdateFocus({ nativeEvent }) {
|
|
72
|
-
const { isActive } = nativeEvent;
|
|
73
|
-
this.setState({ isActive });
|
|
74
|
-
const { onWillUpdateFocus = noop } = this.props;
|
|
75
|
-
onWillUpdateFocus(nativeEvent);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
onDidUpdateFocus({ nativeEvent }) {
|
|
79
|
-
const { onDidUpdateFocus = noop } = this.props;
|
|
80
|
-
onDidUpdateFocus(nativeEvent);
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
setFocusDisabled(isFocusDisabled) {
|
|
84
|
-
if (this.ref) {
|
|
85
|
-
this.ref.current.setNativeProps({
|
|
86
|
-
isFocusDisabled,
|
|
87
|
-
});
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
|
|
91
37
|
render() {
|
|
92
38
|
const {
|
|
93
39
|
children,
|
|
94
40
|
id,
|
|
95
41
|
isFocusDisabled,
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
style,
|
|
42
|
+
isWithMemory,
|
|
43
|
+
style = {},
|
|
99
44
|
groupId,
|
|
100
45
|
...otherProps
|
|
101
46
|
} = this.props;
|
|
102
47
|
|
|
103
|
-
const
|
|
48
|
+
const onGroupFocus = ({ nativeEvent }: FocusableGroupNativeEvent) => {
|
|
49
|
+
log_verbose("FOCUSABLE_GROUP: onGroupFocus", { nativeEvent });
|
|
50
|
+
this.onFocus(this.ref, nativeEvent.focusHeading);
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
const onGroupBlur = ({ nativeEvent }: FocusableGroupNativeEvent) => {
|
|
54
|
+
log_verbose("FOCUSABLE_GROUP: onGroupBlur", { nativeEvent });
|
|
55
|
+
this.onBlur(this.ref, nativeEvent.focusHeading);
|
|
56
|
+
};
|
|
104
57
|
|
|
105
58
|
return (
|
|
106
59
|
<FocusableGroupNative
|
|
@@ -108,16 +61,11 @@ export class FocusableGroup extends BaseFocusable<Props> {
|
|
|
108
61
|
itemId={id}
|
|
109
62
|
ref={this.ref}
|
|
110
63
|
isFocusDisabled={isFocusDisabled}
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
onViewPress={this.onPress}
|
|
116
|
-
onViewBlur={this.onBlur}
|
|
117
|
-
style={focusableStyles}
|
|
64
|
+
isWithMemory={isWithMemory}
|
|
65
|
+
onGroupFocus={onGroupFocus}
|
|
66
|
+
onGroupBlur={onGroupBlur}
|
|
67
|
+
style={style}
|
|
118
68
|
{...otherProps}
|
|
119
|
-
onWillUpdateFocus={this.onWillUpdateFocus}
|
|
120
|
-
onDidUpdateFocus={this.onDidUpdateFocus}
|
|
121
69
|
>
|
|
122
70
|
{children}
|
|
123
71
|
</FocusableGroupNative>
|
|
@@ -16,12 +16,9 @@ type Props = {
|
|
|
16
16
|
prioritiseFocusOn?: number;
|
|
17
17
|
groupId?: string;
|
|
18
18
|
hasTVPreferredFocus?: boolean;
|
|
19
|
-
resetFocusToInitialValue?: boolean;
|
|
20
19
|
onFocus?: () => void;
|
|
21
20
|
onBlur?: () => void;
|
|
22
|
-
onWillUpdateFocus?: (event?: any) => void;
|
|
23
21
|
willReceiveFocus?: (event?: any) => void;
|
|
24
|
-
onDidUpdateFocus?: (event?: any) => void;
|
|
25
22
|
hasLostFocus?: any;
|
|
26
23
|
nextFocusUp?: any;
|
|
27
24
|
nextFocusDown?: any;
|
|
@@ -15,6 +15,7 @@ import { noop } from "@applicaster/zapp-react-native-utils/functionUtils";
|
|
|
15
15
|
|
|
16
16
|
import { useParentFocus, useCheckItemIdsForUnique } from "./hooks";
|
|
17
17
|
import { FocusableListItemWrapper } from "./FocusableListItemWrapper";
|
|
18
|
+
import { FocusableScrollView } from "../FocusableScrollView";
|
|
18
19
|
|
|
19
20
|
const mapIndexed = R.addIndex(R.map);
|
|
20
21
|
|
|
@@ -54,6 +55,7 @@ export type Props<ItemT> = FlatListProps<ItemT> & {
|
|
|
54
55
|
disableNextFocusUp?: boolean;
|
|
55
56
|
disableNextFocusLeft?: boolean;
|
|
56
57
|
disableNextFocusRight?: boolean;
|
|
58
|
+
useScrollView?: boolean;
|
|
57
59
|
} & ParentFocus;
|
|
58
60
|
|
|
59
61
|
function FocusableListComponent<ItemT>(props: Props<ItemT>, ref) {
|
|
@@ -88,6 +90,7 @@ function FocusableListComponent<ItemT>(props: Props<ItemT>, ref) {
|
|
|
88
90
|
data = [],
|
|
89
91
|
// eslint-disable-next-line unused-imports/no-unused-vars
|
|
90
92
|
omitPropsPropagation = [],
|
|
93
|
+
useScrollView = false,
|
|
91
94
|
} = props;
|
|
92
95
|
|
|
93
96
|
useCheckItemIdsForUnique({ componentId: props.id, items: data });
|
|
@@ -273,6 +276,7 @@ function FocusableListComponent<ItemT>(props: Props<ItemT>, ref) {
|
|
|
273
276
|
"initialFocusDirection",
|
|
274
277
|
"withStateMemory",
|
|
275
278
|
"useSequentialLoading",
|
|
279
|
+
"useScrollView",
|
|
276
280
|
...omitPropsPropagation,
|
|
277
281
|
],
|
|
278
282
|
R.__
|
|
@@ -295,15 +299,28 @@ function FocusableListComponent<ItemT>(props: Props<ItemT>, ref) {
|
|
|
295
299
|
return (
|
|
296
300
|
// @ts-ignore
|
|
297
301
|
<ChildrenFocusDeactivatorView flex={1}>
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
302
|
+
{useScrollView ? (
|
|
303
|
+
<FocusableScrollView
|
|
304
|
+
ref={ref}
|
|
305
|
+
{...getFlatListProps(props)}
|
|
306
|
+
onEndReached={onEndReached}
|
|
307
|
+
initialNumToRender={initialNumToRender}
|
|
308
|
+
renderItem={renderItem}
|
|
309
|
+
focused={focused}
|
|
310
|
+
data={data}
|
|
311
|
+
/>
|
|
312
|
+
) : (
|
|
313
|
+
<FlatList
|
|
314
|
+
testID="focusable-list-flat-list"
|
|
315
|
+
focusable={false}
|
|
316
|
+
scrollEnabled={false}
|
|
317
|
+
ref={ref}
|
|
318
|
+
{...getFlatListProps(props)}
|
|
319
|
+
renderItem={renderItem}
|
|
320
|
+
onEndReached={onEndReached}
|
|
321
|
+
initialNumToRender={initialNumToRender}
|
|
322
|
+
/>
|
|
323
|
+
)}
|
|
307
324
|
</ChildrenFocusDeactivatorView>
|
|
308
325
|
);
|
|
309
326
|
}
|
|
@@ -11,6 +11,13 @@ import {
|
|
|
11
11
|
useInitialFocus,
|
|
12
12
|
} from "@applicaster/zapp-react-native-utils/focusManager";
|
|
13
13
|
|
|
14
|
+
export type FocusableScrollViewRenderItem = (info: {
|
|
15
|
+
item: ZappUIComponent;
|
|
16
|
+
index: number;
|
|
17
|
+
focused: boolean;
|
|
18
|
+
parentFocus: ParentFocus;
|
|
19
|
+
}) => React.ReactElement;
|
|
20
|
+
|
|
14
21
|
export type Props = ScrollViewProps & {
|
|
15
22
|
id?: number | string;
|
|
16
23
|
horizontal?: boolean;
|
|
@@ -32,17 +39,27 @@ export type Props = ScrollViewProps & {
|
|
|
32
39
|
initialFocusDirection?: FocusManager.Android.FocusNavigationDirections;
|
|
33
40
|
onAllComponentsLoaded?: () => void;
|
|
34
41
|
omitPropsPropagation?: Array<keyof FlatListProps<any>>;
|
|
35
|
-
renderItem:
|
|
36
|
-
item: ZappUIComponent;
|
|
37
|
-
index: number;
|
|
38
|
-
focused: boolean;
|
|
39
|
-
parentFocus: ParentFocus;
|
|
40
|
-
}) => React.ReactElement;
|
|
42
|
+
renderItem: FocusableScrollViewRenderItem;
|
|
41
43
|
} & ParentFocus;
|
|
42
44
|
|
|
43
45
|
type State = boolean[];
|
|
44
46
|
type Action = { index?: number; isFocusable: boolean; type?: string };
|
|
45
47
|
|
|
48
|
+
const unwrapArray = (maybeArray) =>
|
|
49
|
+
Array.isArray(maybeArray) ? maybeArray[0] : maybeArray;
|
|
50
|
+
|
|
51
|
+
const getEntry = <T extends unknown>(data: T | T[], index: unknown): T => {
|
|
52
|
+
let entry;
|
|
53
|
+
|
|
54
|
+
if (R.isNil(index)) {
|
|
55
|
+
entry = unwrapArray(data);
|
|
56
|
+
} else if (typeof index === "number") {
|
|
57
|
+
entry = unwrapArray(data[index]);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return entry;
|
|
61
|
+
};
|
|
62
|
+
|
|
46
63
|
const focusableStateReducer = (
|
|
47
64
|
state: State,
|
|
48
65
|
{ index = null, isFocusable, type = null }: Action
|
|
@@ -73,7 +90,7 @@ const extendScrollViewRef = (_ref, childCompsMeasurementsMap) => {
|
|
|
73
90
|
};
|
|
74
91
|
|
|
75
92
|
_ref.scrollToIndex = (params) => {
|
|
76
|
-
const { index, viewOffset } = params;
|
|
93
|
+
const { index, viewOffset = 0 } = params;
|
|
77
94
|
|
|
78
95
|
const itemByIndex = R.find(R.propEq("index", index))(
|
|
79
96
|
R.values(childCompsMeasurementsMap)
|
|
@@ -129,8 +146,11 @@ function FocusableScrollViewComponent(props: Props, ref) {
|
|
|
129
146
|
);
|
|
130
147
|
|
|
131
148
|
const getFocusableEntryId = React.useCallback(
|
|
132
|
-
(_entry: ZappEntry, index?: number) => {
|
|
133
|
-
const entry
|
|
149
|
+
(_entry: ZappEntry | null, index?: number) => {
|
|
150
|
+
const entry: { id?: string } = getEntry(
|
|
151
|
+
R.isNil(index) ? _entry : data,
|
|
152
|
+
index
|
|
153
|
+
);
|
|
134
154
|
|
|
135
155
|
return entry ? `${props.id}--${entry?.id}` : undefined;
|
|
136
156
|
},
|
|
@@ -273,16 +293,25 @@ function FocusableScrollViewComponent(props: Props, ref) {
|
|
|
273
293
|
const renderItem = React.useCallback(
|
|
274
294
|
(item, index) => {
|
|
275
295
|
const renderArgs = { item, index };
|
|
276
|
-
|
|
277
|
-
const
|
|
296
|
+
|
|
297
|
+
const id = getFocusableEntryId(
|
|
298
|
+
Array.isArray(item) ? item[0] : item,
|
|
299
|
+
index
|
|
300
|
+
);
|
|
301
|
+
|
|
302
|
+
const nextFocus = getNextFocus(index);
|
|
278
303
|
|
|
279
304
|
const onItemLayout = (event) => {
|
|
280
|
-
childCompsMeasurementsMap.current[
|
|
305
|
+
childCompsMeasurementsMap.current[
|
|
306
|
+
Array.isArray(item) ? index : item.id
|
|
307
|
+
] = {
|
|
281
308
|
index,
|
|
282
309
|
layout: event.nativeEvent.layout,
|
|
283
310
|
};
|
|
284
311
|
};
|
|
285
312
|
|
|
313
|
+
const onSetIsFocusable = setIsFocusable(renderArgs.index);
|
|
314
|
+
|
|
286
315
|
return (
|
|
287
316
|
<View key={id} onLayout={onItemLayout}>
|
|
288
317
|
<Focusable
|
|
@@ -305,6 +334,7 @@ function FocusableScrollViewComponent(props: Props, ref) {
|
|
|
305
334
|
id={id}
|
|
306
335
|
disableFocus={shouldDisableFocus(renderArgs?.index)}
|
|
307
336
|
blockFocus={!isRendered(renderArgs?.index)}
|
|
337
|
+
onSetIsFocusable={onSetIsFocusable}
|
|
308
338
|
{...focusableItemProps}
|
|
309
339
|
>
|
|
310
340
|
{(focused, parentFocus, parentRef) => (
|
|
@@ -319,7 +349,7 @@ function FocusableScrollViewComponent(props: Props, ref) {
|
|
|
319
349
|
isReadyToRender={isReadyToRender}
|
|
320
350
|
onLoadFinished={onLoadFinished(renderArgs.index)}
|
|
321
351
|
onLoadFailed={onLoadFailed(renderArgs.index)}
|
|
322
|
-
setIsFocusable={
|
|
352
|
+
setIsFocusable={onSetIsFocusable}
|
|
323
353
|
/>
|
|
324
354
|
)}
|
|
325
355
|
</Focusable>
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import * as R from "ramda";
|
|
3
|
-
import { ViewStyle } from "react-native";
|
|
4
3
|
import {
|
|
5
4
|
findPluginByType,
|
|
6
5
|
findPluginByIdentifier,
|
|
7
6
|
} from "@applicaster/zapp-react-native-utils/pluginUtils";
|
|
8
|
-
import { useDimensions } from "@applicaster/zapp-react-native-utils/reactHooks/layout";
|
|
9
7
|
import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
|
|
10
|
-
import {
|
|
11
|
-
|
|
8
|
+
import {
|
|
9
|
+
useDimensions,
|
|
10
|
+
useNavigation,
|
|
11
|
+
} from "@applicaster/zapp-react-native-utils/reactHooks";
|
|
12
12
|
|
|
13
13
|
import { BufferAnimation } from "../PlayerContainer/BufferAnimation";
|
|
14
14
|
import { PlayerContainer } from "../PlayerContainer";
|
|
@@ -78,12 +78,6 @@ const getPlayer = (
|
|
|
78
78
|
return getPlayerWithModuleProperties(PlayerModule);
|
|
79
79
|
};
|
|
80
80
|
|
|
81
|
-
const dimensionsContext: "window" | "screen" = platformSelect({
|
|
82
|
-
android_tv: "window",
|
|
83
|
-
amazon: "window",
|
|
84
|
-
default: "screen",
|
|
85
|
-
});
|
|
86
|
-
|
|
87
81
|
type PlayableComponent = {
|
|
88
82
|
Component: React.ComponentType<any>;
|
|
89
83
|
};
|
|
@@ -91,16 +85,11 @@ type PlayableComponent = {
|
|
|
91
85
|
export function HandlePlayable({
|
|
92
86
|
item,
|
|
93
87
|
isModal,
|
|
94
|
-
modalHeight,
|
|
95
|
-
modalWidth,
|
|
96
88
|
mode,
|
|
97
89
|
groupId,
|
|
98
90
|
}: Props): React.ReactElement | null {
|
|
99
91
|
const state = usePickFromState();
|
|
100
92
|
|
|
101
|
-
const { width: screenWidth, height: screenHeight } =
|
|
102
|
-
useDimensions(dimensionsContext);
|
|
103
|
-
|
|
104
93
|
const { closeVideoModal } = useNavigation();
|
|
105
94
|
|
|
106
95
|
const [Player, playerModuleProperties] = getPlayer(item, state);
|
|
@@ -118,9 +107,7 @@ export function HandlePlayable({
|
|
|
118
107
|
if (!isModal) {
|
|
119
108
|
closeVideoModal();
|
|
120
109
|
}
|
|
121
|
-
}, []);
|
|
122
110
|
|
|
123
|
-
React.useEffect(() => {
|
|
124
111
|
const castStateHandler = async () => {
|
|
125
112
|
const castState = await CastPlugin?.getCastState();
|
|
126
113
|
setCasting(castState === "Connected");
|
|
@@ -142,23 +129,23 @@ export function HandlePlayable({
|
|
|
142
129
|
}, []);
|
|
143
130
|
|
|
144
131
|
React.useEffect(() => {
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
}
|
|
148
|
-
setPlayable({ Component: PlayerContainer });
|
|
149
|
-
}
|
|
132
|
+
setPlayable({
|
|
133
|
+
Component: casting ? CastPlugin?.CastHandler : PlayerContainer,
|
|
134
|
+
});
|
|
150
135
|
}, [casting]);
|
|
151
136
|
|
|
152
|
-
const
|
|
137
|
+
const { width: screenWidth, height: screenHeight } = useDimensions("window");
|
|
153
138
|
|
|
154
139
|
const style = React.useMemo(
|
|
155
140
|
() => ({
|
|
156
|
-
width: isModal ?
|
|
157
|
-
height: isModal ?
|
|
141
|
+
width: isModal ? "100%" : mode === "PIP" ? "100%" : screenWidth,
|
|
142
|
+
height: isModal ? "100%" : mode === "PIP" ? "100%" : screenHeight,
|
|
158
143
|
}),
|
|
159
|
-
[screenWidth, screenHeight,
|
|
144
|
+
[screenWidth, screenHeight, isModal, mode]
|
|
160
145
|
);
|
|
161
146
|
|
|
147
|
+
const Component = playable?.Component;
|
|
148
|
+
|
|
162
149
|
if (Component) {
|
|
163
150
|
return (
|
|
164
151
|
<Component
|
|
@@ -174,5 +161,5 @@ export function HandlePlayable({
|
|
|
174
161
|
);
|
|
175
162
|
}
|
|
176
163
|
|
|
177
|
-
return !isModal ? <BufferAnimation videoStyle={style
|
|
164
|
+
return !isModal ? <BufferAnimation videoStyle={style} /> : null;
|
|
178
165
|
}
|
|
@@ -1,9 +1,5 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import {
|
|
3
|
-
import { ScreenLayoutContext } from "@applicaster/zapp-react-native-ui-components/Contexts/ScreenLayoutContext";
|
|
4
|
-
import { ifEmptyUseFallback } from "@applicaster/zapp-react-native-utils/cellUtils";
|
|
5
|
-
import { useCurrentScreenData } from "@applicaster/zapp-react-native-utils/reactHooks/screen";
|
|
6
|
-
import { useScreenConfiguration } from "../../River/useScreenConfiguration";
|
|
2
|
+
import { StyleSheet, View } from "react-native";
|
|
7
3
|
|
|
8
4
|
type Props = {
|
|
9
5
|
children: React.ReactNode;
|
|
@@ -12,33 +8,33 @@ type Props = {
|
|
|
12
8
|
};
|
|
13
9
|
|
|
14
10
|
const styles = StyleSheet.create({
|
|
15
|
-
container: {
|
|
11
|
+
container: {
|
|
12
|
+
position: "absolute",
|
|
13
|
+
top: 0,
|
|
14
|
+
zIndex: 10,
|
|
15
|
+
flex: 1,
|
|
16
|
+
width: "100%",
|
|
17
|
+
},
|
|
18
|
+
themeStyles: {
|
|
19
|
+
// limits the height of the focusable container of the TopMenuBarTV component
|
|
20
|
+
// to prevent it from being overlapped by the screen content,
|
|
21
|
+
// as it makes TopMenuBarTV unfocusable on tvOS
|
|
22
|
+
maxHeight: 1,
|
|
23
|
+
},
|
|
16
24
|
});
|
|
17
25
|
|
|
18
26
|
export const NavBarContainer = ({ children, isVisible, onReady }: Props) => {
|
|
19
|
-
const screenLayout = React.useContext(ScreenLayoutContext);
|
|
20
|
-
const screenMarginTop = screenLayout?.screenMarginTop || 0;
|
|
21
|
-
const screen = useCurrentScreenData();
|
|
22
|
-
const screenConfig = useScreenConfiguration(screen?.id);
|
|
23
|
-
|
|
24
|
-
const themeStyles = React.useMemo(
|
|
25
|
-
() => ({
|
|
26
|
-
// limits the height of the focusable container of the TopMenuBarTV component
|
|
27
|
-
// to prevent it from being overlapped by the screen content,
|
|
28
|
-
// as it makes TopMenuBarTV unfocusable on tvOS
|
|
29
|
-
maxHeight: ifEmptyUseFallback(screenConfig?.marginTop, screenMarginTop),
|
|
30
|
-
}),
|
|
31
|
-
[screenLayout, screenConfig]
|
|
32
|
-
);
|
|
33
|
-
|
|
34
27
|
React.useEffect(() => {
|
|
35
28
|
setTimeout(() => {
|
|
36
29
|
onReady?.(true);
|
|
37
30
|
}, 0);
|
|
38
|
-
}, []);
|
|
31
|
+
}, [onReady]);
|
|
39
32
|
|
|
40
33
|
return isVisible ? (
|
|
41
|
-
<View
|
|
34
|
+
<View
|
|
35
|
+
testID="nav-bar-container"
|
|
36
|
+
style={[styles.container, styles.themeStyles]}
|
|
37
|
+
>
|
|
42
38
|
{children}
|
|
43
39
|
</View>
|
|
44
40
|
) : null;
|
|
@@ -55,8 +55,11 @@ export const ScreenContainer = React.memo(function ScreenContainer({
|
|
|
55
55
|
ComponentsExtraProps,
|
|
56
56
|
NavBar,
|
|
57
57
|
}: Props) {
|
|
58
|
-
const { screenMarginBottom } =
|
|
58
|
+
const { screenMarginBottom, resetScreenLayout } =
|
|
59
|
+
React.useContext(ScreenLayoutContext);
|
|
60
|
+
|
|
59
61
|
const { currentRoute, screenData } = useNavigation();
|
|
62
|
+
|
|
60
63
|
const screen = useCurrentScreenData();
|
|
61
64
|
|
|
62
65
|
const { marginBottom, backgroundColor, paddingTop, paddingBottom } =
|
|
@@ -65,6 +68,10 @@ export const ScreenContainer = React.memo(function ScreenContainer({
|
|
|
65
68
|
const theme = useTheme();
|
|
66
69
|
const getThemeValue = React.useCallback(R.propOr(0, R.__, theme), [theme]);
|
|
67
70
|
|
|
71
|
+
React.useEffect(() => {
|
|
72
|
+
resetScreenLayout();
|
|
73
|
+
}, [currentRoute]);
|
|
74
|
+
|
|
68
75
|
const fullscreen = React.useCallback(
|
|
69
76
|
displayFullScreen({ currentRoute, screenData }),
|
|
70
77
|
[currentRoute, screenData]
|
|
@@ -60,10 +60,15 @@ export function ScreenLayoutContextProvider(props: {
|
|
|
60
60
|
initialState
|
|
61
61
|
);
|
|
62
62
|
|
|
63
|
+
const resetScreenLayout = React.useCallback(() => {
|
|
64
|
+
setScreenLayout(initialState);
|
|
65
|
+
}, [initialState]);
|
|
66
|
+
|
|
63
67
|
const screenLayoutValue = React.useMemo(
|
|
64
68
|
() => ({
|
|
65
69
|
...screenLayout,
|
|
66
70
|
setScreenLayout,
|
|
71
|
+
resetScreenLayout,
|
|
67
72
|
}),
|
|
68
73
|
[screenLayout]
|
|
69
74
|
);
|
|
@@ -56,11 +56,12 @@ describe("ScreenContainer", () => {
|
|
|
56
56
|
};
|
|
57
57
|
|
|
58
58
|
const setScreenLayout = () => {};
|
|
59
|
+
const resetScreenLayout = () => {};
|
|
59
60
|
|
|
60
61
|
const wrapper = ({ children }) => (
|
|
61
62
|
<WrappedWithProviders>
|
|
62
63
|
<ScreenLayoutContext.Provider
|
|
63
|
-
value={{ ...screenLayout, setScreenLayout }}
|
|
64
|
+
value={{ ...screenLayout, setScreenLayout, resetScreenLayout }}
|
|
64
65
|
>
|
|
65
66
|
<ScreenContainer NavBar={View}>{children}</ScreenContainer>
|
|
66
67
|
</ScreenLayoutContext.Provider>
|