@applicaster/zapp-react-native-ui-components 15.0.0-alpha.2239032089 → 15.0.0-alpha.2349550201
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/AnimatedInOut/index.tsx +69 -26
- package/Components/Cell/Cell.tsx +8 -3
- package/Components/Cell/FocusableWrapper.tsx +44 -0
- package/Components/Cell/TvOSCellComponent.tsx +80 -14
- package/Components/Focusable/Focusable.tsx +2 -4
- package/Components/Focusable/FocusableTvOS.tsx +1 -5
- package/Components/FocusableGroup/FocusableTvOS.tsx +0 -5
- package/Components/GeneralContentScreen/utils/useCurationAPI.ts +9 -11
- package/Components/HandlePlayable/HandlePlayable.tsx +14 -65
- package/Components/HandlePlayable/const.ts +3 -0
- package/Components/HandlePlayable/utils.ts +74 -0
- package/Components/MasterCell/DefaultComponents/BorderContainerView/__tests__/index.test.tsx +16 -1
- package/Components/MasterCell/DefaultComponents/BorderContainerView/index.tsx +30 -2
- package/Components/MasterCell/DefaultComponents/Text/index.tsx +8 -8
- package/Components/MasterCell/index.tsx +2 -0
- package/Components/PlayerContainer/PlayerContainer.tsx +1 -16
- package/Components/PlayerImageBackground/index.tsx +3 -22
- package/Components/River/TV/River.tsx +3 -9
- package/Components/River/TV/index.tsx +3 -3
- package/Components/River/TV/withTVEventHandler.tsx +27 -0
- package/Components/Screen/TV/hooks/useInitialFocus.ts +14 -4
- package/Components/Screen/__tests__/__snapshots__/Screen.test.tsx.snap +2 -0
- package/Components/Screen/index.tsx +22 -5
- package/Components/ScreenResolver/index.tsx +8 -2
- package/Components/ScreenRevealManager/utils/index.ts +23 -0
- package/Components/ScreenRevealManager/withScreenRevealManager.tsx +54 -24
- package/Components/Tabs/TV/Tabs.tsx +20 -3
- package/Components/VideoLive/__tests__/__snapshots__/PlayerLiveImageComponent.test.tsx.snap +1 -0
- package/Components/VideoModal/ModalAnimation/ModalAnimationContext.tsx +3 -153
- package/Components/VideoModal/ModalAnimation/index.ts +2 -13
- package/Components/VideoModal/ModalAnimation/utils.ts +1 -327
- package/Components/VideoModal/PlayerWrapper.tsx +14 -88
- package/Components/VideoModal/__tests__/PlayerWrapper.test.tsx +1 -0
- package/Components/VideoModal/hooks/useModalSize.ts +10 -5
- package/Components/VideoModal/playerWrapperStyle.ts +70 -0
- package/Components/VideoModal/playerWrapperUtils.ts +91 -0
- package/Components/ZappFrameworkComponents/BarView/BarView.tsx +4 -6
- package/Components/ZappFrameworkComponents/BarView/__tests__/BarView.test.tsx +2 -2
- package/Decorators/RiverFeedLoader/utils/getDatasourceUrl.ts +6 -10
- package/events/index.ts +0 -2
- package/index.d.ts +7 -0
- package/package.json +5 -5
- package/Components/River/TV/withFocusableGroupForContent.tsx +0 -60
- package/Components/VideoModal/ModalAnimation/AnimatedPlayerModalWrapper.tsx +0 -60
- package/Components/VideoModal/ModalAnimation/AnimatedScrollModal.tsx +0 -417
- package/Components/VideoModal/ModalAnimation/AnimatedScrollModal.web.tsx +0 -294
- package/Components/VideoModal/ModalAnimation/AnimatedVideoPlayerComponent.tsx +0 -176
- package/Components/VideoModal/ModalAnimation/AnimatedVideoPlayerComponent.web.tsx +0 -93
- package/Components/VideoModal/ModalAnimation/AnimationComponent.tsx +0 -500
- package/Components/VideoModal/ModalAnimation/__tests__/getMoveUpValue.test.ts +0 -108
|
@@ -6,10 +6,6 @@ import { noop } from "@applicaster/zapp-react-native-utils/functionUtils";
|
|
|
6
6
|
|
|
7
7
|
type AnimatedInterpolatedStyle = any;
|
|
8
8
|
|
|
9
|
-
// type AnimatedInterpolatedStyle =
|
|
10
|
-
// | Animated.AnimatedInterpolation
|
|
11
|
-
// | [{ [Key: string]: Animated.AnimatedInterpolation }];
|
|
12
|
-
|
|
13
9
|
type AnimationConfig = {
|
|
14
10
|
duration: number;
|
|
15
11
|
easing: EasingFunction;
|
|
@@ -45,32 +41,57 @@ export function AnimatedInOut({
|
|
|
45
41
|
children,
|
|
46
42
|
}: Props) {
|
|
47
43
|
const [animatedValue] = React.useState(new Animated.Value(visible ? 1 : 0));
|
|
48
|
-
const
|
|
44
|
+
const animationRef = React.useRef<Animated.CompositeAnimation | null>(null);
|
|
45
|
+
const delayTimerRef = React.useRef<NodeJS.Timeout | null>(null);
|
|
49
46
|
|
|
50
47
|
const previousVisible = usePrevious(toBooleanWithDefaultFalse(visible));
|
|
51
48
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
49
|
+
const startAnimation = React.useCallback(
|
|
50
|
+
(toValue: number, config: AnimationConfig) => {
|
|
51
|
+
if (delayTimerRef.current) {
|
|
52
|
+
clearTimeout(delayTimerRef.current);
|
|
53
|
+
delayTimerRef.current = null;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (animationRef.current) {
|
|
57
|
+
animationRef.current.stop();
|
|
58
|
+
animationRef.current = null;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const { duration, easing, delay = 0, onAnimationEnd = noop } = config;
|
|
62
|
+
|
|
63
|
+
const runAnimation = () => {
|
|
64
|
+
animationRef.current = Animated.timing(animatedValue, {
|
|
65
|
+
duration,
|
|
66
|
+
toValue,
|
|
67
|
+
easing,
|
|
68
|
+
useNativeDriver: true,
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
animationRef.current.start(({ finished }) => {
|
|
72
|
+
if (finished) {
|
|
73
|
+
animationRef.current = null;
|
|
74
|
+
onAnimationEnd();
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
if (delay > 0) {
|
|
80
|
+
delayTimerRef.current = setTimeout(runAnimation, delay);
|
|
81
|
+
} else {
|
|
82
|
+
runAnimation();
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
[animatedValue]
|
|
86
|
+
);
|
|
58
87
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
easing,
|
|
63
|
-
delay,
|
|
64
|
-
useNativeDriver: true,
|
|
65
|
-
}).start(() => {
|
|
66
|
-
setAnimating(undefined);
|
|
67
|
-
onAnimationEnd();
|
|
68
|
-
});
|
|
88
|
+
React.useEffect(() => {
|
|
89
|
+
if (previousVisible === undefined) {
|
|
90
|
+
animatedValue.setValue(visible ? 1 : 0);
|
|
69
91
|
|
|
70
|
-
|
|
71
|
-
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
72
94
|
|
|
73
|
-
React.useEffect(() => {
|
|
74
95
|
if (!previousVisible && visible) {
|
|
75
96
|
startAnimation(1.0, getAnimation(animationConfig, "in"));
|
|
76
97
|
}
|
|
@@ -78,7 +99,29 @@ export function AnimatedInOut({
|
|
|
78
99
|
if (previousVisible && !visible) {
|
|
79
100
|
startAnimation(0.0, getAnimation(animationConfig, "out"));
|
|
80
101
|
}
|
|
81
|
-
}, [
|
|
102
|
+
}, [
|
|
103
|
+
visible,
|
|
104
|
+
previousVisible,
|
|
105
|
+
animatedValue,
|
|
106
|
+
startAnimation,
|
|
107
|
+
animationConfig,
|
|
108
|
+
]);
|
|
109
|
+
|
|
110
|
+
React.useEffect(() => {
|
|
111
|
+
return () => {
|
|
112
|
+
if (delayTimerRef.current) {
|
|
113
|
+
clearTimeout(delayTimerRef.current);
|
|
114
|
+
delayTimerRef.current = null;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (animationRef.current) {
|
|
118
|
+
animationRef.current.stop();
|
|
119
|
+
animationRef.current = null;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
animatedValue.stopAnimation();
|
|
123
|
+
};
|
|
124
|
+
}, [animatedValue]);
|
|
82
125
|
|
|
83
126
|
const styles = visible
|
|
84
127
|
? getAnimation(animationConfig, "in").styles
|
|
@@ -86,7 +129,7 @@ export function AnimatedInOut({
|
|
|
86
129
|
|
|
87
130
|
return (
|
|
88
131
|
<Animated.View
|
|
89
|
-
renderToHardwareTextureAndroid={
|
|
132
|
+
renderToHardwareTextureAndroid={!!animationRef.current}
|
|
90
133
|
style={[styles(animatedValue), staticStyles]}
|
|
91
134
|
>
|
|
92
135
|
{children}
|
package/Components/Cell/Cell.tsx
CHANGED
|
@@ -208,14 +208,14 @@ export class CellComponent extends React.Component<Props, State> {
|
|
|
208
208
|
this.accessibilityManager.readText({
|
|
209
209
|
text: " ",
|
|
210
210
|
});
|
|
211
|
-
} else {
|
|
211
|
+
} else if (this.state.cellFocused) {
|
|
212
212
|
this.accessibilityManager.readText({
|
|
213
213
|
text: `${positionLabel}`,
|
|
214
214
|
});
|
|
215
215
|
}
|
|
216
216
|
}
|
|
217
217
|
|
|
218
|
-
componentDidUpdate(prevProps: Readonly<Props>) {
|
|
218
|
+
componentDidUpdate(prevProps: Readonly<Props>, prevState: Readonly<State>) {
|
|
219
219
|
if (prevProps.item !== this.props.item) {
|
|
220
220
|
this.setState({
|
|
221
221
|
hasFocusableInside: this.props.CellRenderer.hasFocusableInside?.(
|
|
@@ -224,7 +224,12 @@ export class CellComponent extends React.Component<Props, State> {
|
|
|
224
224
|
});
|
|
225
225
|
}
|
|
226
226
|
|
|
227
|
-
|
|
227
|
+
if (
|
|
228
|
+
prevState.cellFocused !== this.state.cellFocused ||
|
|
229
|
+
this.state.hasFocusableInside
|
|
230
|
+
) {
|
|
231
|
+
this.handleAccessibilityFocus(this.props.index, this.props.dataLength);
|
|
232
|
+
}
|
|
228
233
|
}
|
|
229
234
|
|
|
230
235
|
render() {
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { Focusable } from "@applicaster/zapp-react-native-ui-components/Components/Focusable/FocusableTvOS";
|
|
3
|
+
import { noop } from "@applicaster/zapp-react-native-utils/functionUtils";
|
|
4
|
+
|
|
5
|
+
type Props = {
|
|
6
|
+
id: string;
|
|
7
|
+
groupId: string;
|
|
8
|
+
isParallaxDisabled: boolean;
|
|
9
|
+
applyWrapper: boolean;
|
|
10
|
+
children: (focused: boolean) => React.ReactNode;
|
|
11
|
+
onFocus: (arg1: any, index?: number) => void;
|
|
12
|
+
onBlur: Callback;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export const FocusableWrapper = ({
|
|
16
|
+
id,
|
|
17
|
+
groupId,
|
|
18
|
+
isParallaxDisabled,
|
|
19
|
+
children,
|
|
20
|
+
applyWrapper,
|
|
21
|
+
onFocus,
|
|
22
|
+
onBlur,
|
|
23
|
+
}: Props) => {
|
|
24
|
+
if (applyWrapper) {
|
|
25
|
+
return (
|
|
26
|
+
<Focusable
|
|
27
|
+
id={id}
|
|
28
|
+
groupId={groupId}
|
|
29
|
+
isParallaxDisabled={isParallaxDisabled}
|
|
30
|
+
onFocus={onFocus}
|
|
31
|
+
onBlur={onBlur}
|
|
32
|
+
willReceiveFocus={noop}
|
|
33
|
+
hasReceivedFocus={noop}
|
|
34
|
+
// @ts-ignore
|
|
35
|
+
offsetUpdater={noop}
|
|
36
|
+
isFocusable
|
|
37
|
+
>
|
|
38
|
+
{(focused) => children(focused)}
|
|
39
|
+
</Focusable>
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return <>{children(false)}</>;
|
|
44
|
+
};
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import * as R from "ramda";
|
|
3
3
|
import { View, StyleSheet } from "react-native";
|
|
4
|
+
import { first, filter } from "rxjs/operators";
|
|
5
|
+
|
|
6
|
+
import { compose } from "@applicaster/zapp-react-native-utils/utils";
|
|
4
7
|
|
|
5
8
|
import { Focusable } from "@applicaster/zapp-react-native-ui-components/Components/Focusable/FocusableTvOS";
|
|
6
9
|
import { FocusableCell } from "@applicaster/zapp-react-native-ui-components/Components/FocusableCell";
|
|
@@ -9,7 +12,11 @@ import { SCREEN_TYPES } from "@applicaster/zapp-react-native-utils/navigationUti
|
|
|
9
12
|
import { focusManager } from "@applicaster/zapp-react-native-utils/appUtils/focusManager";
|
|
10
13
|
import { sendSelectCellEvent } from "@applicaster/zapp-react-native-utils/analyticsUtils";
|
|
11
14
|
import { noop } from "@applicaster/zapp-react-native-utils/functionUtils";
|
|
15
|
+
import { toBooleanWithDefaultTrue } from "@applicaster/zapp-react-native-utils/booleanUtils";
|
|
12
16
|
import { CellWithFocusable } from "./CellWithFocusable";
|
|
17
|
+
import { FocusableWrapper } from "./FocusableWrapper";
|
|
18
|
+
|
|
19
|
+
import { focusableButtonsRegistration$ } from "@applicaster/zapp-react-native-utils/appUtils/focusManagerAux/utils/utils.ios";
|
|
13
20
|
|
|
14
21
|
type Props = {
|
|
15
22
|
item: ZappEntry;
|
|
@@ -66,6 +73,8 @@ type Props = {
|
|
|
66
73
|
shouldUpdate: boolean;
|
|
67
74
|
behavior: Behavior;
|
|
68
75
|
componentsMapOffset: number;
|
|
76
|
+
applyFocusableWrapper: boolean;
|
|
77
|
+
hasFocusableInside: boolean;
|
|
69
78
|
};
|
|
70
79
|
|
|
71
80
|
type State = {
|
|
@@ -82,7 +91,7 @@ const baseCellStyles = {
|
|
|
82
91
|
flex: 1,
|
|
83
92
|
} as const;
|
|
84
93
|
|
|
85
|
-
|
|
94
|
+
class TvOSCell extends React.Component<Props, State> {
|
|
86
95
|
cell: any;
|
|
87
96
|
target: any;
|
|
88
97
|
layout: any;
|
|
@@ -239,6 +248,8 @@ export class TvOSCellComponent extends React.Component<Props, State> {
|
|
|
239
248
|
groupId,
|
|
240
249
|
isFocusable,
|
|
241
250
|
behavior,
|
|
251
|
+
applyFocusableWrapper,
|
|
252
|
+
hasFocusableInside,
|
|
242
253
|
} = this.props;
|
|
243
254
|
|
|
244
255
|
const { id } = item;
|
|
@@ -254,24 +265,33 @@ export class TvOSCellComponent extends React.Component<Props, State> {
|
|
|
254
265
|
this.onFocus(arg1, index);
|
|
255
266
|
};
|
|
256
267
|
|
|
257
|
-
const hasFocusableInside = CellRenderer.hasFocusableInside?.(item);
|
|
258
|
-
|
|
259
268
|
if (hasFocusableInside) {
|
|
260
269
|
return (
|
|
261
270
|
<View onLayout={this.onLayout}>
|
|
262
|
-
<
|
|
263
|
-
CellRenderer={CellRenderer}
|
|
264
|
-
item={item}
|
|
271
|
+
<FocusableWrapper
|
|
265
272
|
id={focusableId}
|
|
266
|
-
groupId={(groupId || component?.id)
|
|
273
|
+
groupId={String(groupId || component?.id)}
|
|
274
|
+
isParallaxDisabled={this.layout?.width > 1740}
|
|
267
275
|
onFocus={handleFocus}
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
276
|
+
onBlur={onBlur || this.onBlur}
|
|
277
|
+
applyWrapper={applyFocusableWrapper}
|
|
278
|
+
>
|
|
279
|
+
{(focused) => (
|
|
280
|
+
<CellWithFocusable
|
|
281
|
+
CellRenderer={CellRenderer}
|
|
282
|
+
item={item}
|
|
283
|
+
id={focusableId}
|
|
284
|
+
groupId={(groupId || component?.id).toString()}
|
|
285
|
+
onFocus={handleFocus}
|
|
286
|
+
index={index}
|
|
287
|
+
scrollTo={this.scrollTo}
|
|
288
|
+
preferredFocus={preferredFocus}
|
|
289
|
+
focused={focused || this.props.focused}
|
|
290
|
+
behavior={behavior}
|
|
291
|
+
isFocusable={isFocusable}
|
|
292
|
+
/>
|
|
293
|
+
)}
|
|
294
|
+
</FocusableWrapper>
|
|
275
295
|
</View>
|
|
276
296
|
);
|
|
277
297
|
}
|
|
@@ -309,3 +329,49 @@ export class TvOSCellComponent extends React.Component<Props, State> {
|
|
|
309
329
|
);
|
|
310
330
|
}
|
|
311
331
|
}
|
|
332
|
+
|
|
333
|
+
export function withFocusableWrapperHOC(Component) {
|
|
334
|
+
return function WrappedComponent(props) {
|
|
335
|
+
const [focusableViewIsRendered, setFocusableViewIsRendered] =
|
|
336
|
+
React.useState(false);
|
|
337
|
+
|
|
338
|
+
const { CellRenderer, item, groupId, component } = props;
|
|
339
|
+
|
|
340
|
+
const isFocusable = toBooleanWithDefaultTrue(props?.isFocusable);
|
|
341
|
+
|
|
342
|
+
const focusableGroupId = String(groupId || component?.id);
|
|
343
|
+
|
|
344
|
+
const hasFocusableInside = CellRenderer.hasFocusableInside?.(item);
|
|
345
|
+
|
|
346
|
+
React.useEffect(() => {
|
|
347
|
+
// start waiting any first registration of FocusableButton inside this focusableGroup
|
|
348
|
+
// after it we could get rid of applying focusable-wrapper
|
|
349
|
+
const subscription = focusableButtonsRegistration$(focusableGroupId)
|
|
350
|
+
.pipe(
|
|
351
|
+
filter(() => isFocusable),
|
|
352
|
+
first()
|
|
353
|
+
)
|
|
354
|
+
.subscribe(() => {
|
|
355
|
+
setFocusableViewIsRendered(true);
|
|
356
|
+
});
|
|
357
|
+
|
|
358
|
+
return () => {
|
|
359
|
+
subscription.unsubscribe();
|
|
360
|
+
};
|
|
361
|
+
}, [isFocusable, focusableGroupId]);
|
|
362
|
+
|
|
363
|
+
const applyFocusableWrapper = React.useMemo(() => {
|
|
364
|
+
return isFocusable && hasFocusableInside && !focusableViewIsRendered;
|
|
365
|
+
}, [isFocusable, hasFocusableInside, focusableViewIsRendered]);
|
|
366
|
+
|
|
367
|
+
return (
|
|
368
|
+
<Component
|
|
369
|
+
{...props}
|
|
370
|
+
applyFocusableWrapper={applyFocusableWrapper}
|
|
371
|
+
hasFocusableInside={hasFocusableInside}
|
|
372
|
+
/>
|
|
373
|
+
);
|
|
374
|
+
};
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
export const TvOSCellComponent = compose(withFocusableWrapperHOC)(TvOSCell);
|
|
@@ -8,8 +8,6 @@ import { withFocusableContext } from "../../Contexts/FocusableGroupContext/withF
|
|
|
8
8
|
import { StyleSheet, ViewStyle } from "react-native";
|
|
9
9
|
import { AccessibilityManager } from "@applicaster/zapp-react-native-utils/appUtils/accessibilityManager";
|
|
10
10
|
|
|
11
|
-
import { isSearchInputId } from "@applicaster/search-screen/src/tv/utils";
|
|
12
|
-
|
|
13
11
|
type Props = {
|
|
14
12
|
initialFocus?: boolean;
|
|
15
13
|
id: string;
|
|
@@ -108,7 +106,7 @@ class Focusable extends BaseFocusable<Props> {
|
|
|
108
106
|
onMouseEnter() {
|
|
109
107
|
const { id } = this.props;
|
|
110
108
|
|
|
111
|
-
if (
|
|
109
|
+
if (id !== "search_input_group_id") {
|
|
112
110
|
this.mouse = true;
|
|
113
111
|
this.props?.handleFocus?.({ mouse: true });
|
|
114
112
|
|
|
@@ -122,7 +120,7 @@ class Focusable extends BaseFocusable<Props> {
|
|
|
122
120
|
onMouseLeave() {
|
|
123
121
|
const { id } = this.props;
|
|
124
122
|
|
|
125
|
-
if (
|
|
123
|
+
if (id !== "search_input_group_id") {
|
|
126
124
|
this.mouse = false;
|
|
127
125
|
this.blur(null);
|
|
128
126
|
}
|
|
@@ -10,9 +10,8 @@ import {
|
|
|
10
10
|
forceFocusableFocus,
|
|
11
11
|
} from "@applicaster/zapp-react-native-utils/appUtils/focusManager/index.ios";
|
|
12
12
|
import { findNodeHandle, ViewStyle } from "react-native";
|
|
13
|
-
import { noop } from "@applicaster/zapp-react-native-utils/functionUtils";
|
|
14
13
|
|
|
15
|
-
|
|
14
|
+
function noop() {}
|
|
16
15
|
|
|
17
16
|
type Props = {
|
|
18
17
|
id: string;
|
|
@@ -85,9 +84,6 @@ export class Focusable extends BaseFocusable<Props> {
|
|
|
85
84
|
});
|
|
86
85
|
}
|
|
87
86
|
|
|
88
|
-
const id: string = nativeEvent.itemID;
|
|
89
|
-
emitFocused(id);
|
|
90
|
-
|
|
91
87
|
onFocus(nativeEvent);
|
|
92
88
|
}
|
|
93
89
|
|
|
@@ -142,17 +142,15 @@ export const useCurationAPI = (
|
|
|
142
142
|
const url = path(SOURCE_PATH, component);
|
|
143
143
|
const mapping = path(MAPPING_PATH, component);
|
|
144
144
|
|
|
145
|
-
map[component.id] =
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
})
|
|
155
|
-
: url;
|
|
145
|
+
map[component.id] = getInflatedDataSourceUrl({
|
|
146
|
+
source: url,
|
|
147
|
+
contexts: {
|
|
148
|
+
entry: entryContext,
|
|
149
|
+
screen: screenContext,
|
|
150
|
+
search: getSearchContext(searchContext, mapping),
|
|
151
|
+
},
|
|
152
|
+
mapping,
|
|
153
|
+
});
|
|
156
154
|
});
|
|
157
155
|
|
|
158
156
|
return map;
|
|
@@ -1,9 +1,4 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import * as R from "ramda";
|
|
3
|
-
import {
|
|
4
|
-
findPluginByType,
|
|
5
|
-
findPluginByIdentifier,
|
|
6
|
-
} from "@applicaster/zapp-react-native-utils/pluginUtils";
|
|
7
2
|
import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
|
|
8
3
|
import {
|
|
9
4
|
useDimensions,
|
|
@@ -16,6 +11,7 @@ import { PlayerContainer } from "../PlayerContainer";
|
|
|
16
11
|
import { useModalSize } from "../VideoModal/hooks";
|
|
17
12
|
import { ViewStyle } from "react-native";
|
|
18
13
|
import { platformSelect } from "@applicaster/zapp-react-native-utils/reactUtils";
|
|
14
|
+
import { findCastPlugin, getPlayer } from "./utils";
|
|
19
15
|
|
|
20
16
|
type Props = {
|
|
21
17
|
item: ZappEntry;
|
|
@@ -26,62 +22,6 @@ type Props = {
|
|
|
26
22
|
groupId?: string;
|
|
27
23
|
};
|
|
28
24
|
|
|
29
|
-
const YOUTUBE_PLUGIN_ID = "youtube-player-qb";
|
|
30
|
-
const CHROMECAST_PLUGIN_ID = "chromecast_qb";
|
|
31
|
-
|
|
32
|
-
const getPlayerWithModuleProperties = (
|
|
33
|
-
PlayerModule: ZappPlugin
|
|
34
|
-
): [ZappPlugin, PlayerModuleProperties] => {
|
|
35
|
-
const getPlayerModuleProperties = R.ifElse(
|
|
36
|
-
R.is(Object) && R.has("Component"),
|
|
37
|
-
R.omit(["Component"]),
|
|
38
|
-
() => ({})
|
|
39
|
-
);
|
|
40
|
-
|
|
41
|
-
return [
|
|
42
|
-
PlayerModule?.Component || PlayerModule,
|
|
43
|
-
getPlayerModuleProperties(PlayerModule),
|
|
44
|
-
];
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
const getPlayer = (
|
|
48
|
-
item: ZappEntry,
|
|
49
|
-
state
|
|
50
|
-
): [ZappPlugin, PlayerModuleProperties] => {
|
|
51
|
-
const {
|
|
52
|
-
plugins,
|
|
53
|
-
contentTypes,
|
|
54
|
-
rivers,
|
|
55
|
-
appData: { layoutVersion },
|
|
56
|
-
} = state;
|
|
57
|
-
|
|
58
|
-
let PlayerModule;
|
|
59
|
-
|
|
60
|
-
if (layoutVersion === "v2") {
|
|
61
|
-
const { screen_id } = contentTypes?.[item?.type?.value] || {};
|
|
62
|
-
const { type } = rivers?.[screen_id] || {};
|
|
63
|
-
|
|
64
|
-
if (type) {
|
|
65
|
-
PlayerModule = findPluginByIdentifier(type, plugins)?.module;
|
|
66
|
-
|
|
67
|
-
return getPlayerWithModuleProperties(PlayerModule);
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
if (item?.content?.type === "youtube-id") {
|
|
72
|
-
PlayerModule = findPluginByIdentifier(YOUTUBE_PLUGIN_ID, plugins)?.module;
|
|
73
|
-
|
|
74
|
-
return getPlayerWithModuleProperties(PlayerModule);
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
PlayerModule = findPluginByType(
|
|
78
|
-
"playable",
|
|
79
|
-
plugins.filter(({ identifier }) => identifier !== YOUTUBE_PLUGIN_ID)
|
|
80
|
-
);
|
|
81
|
-
|
|
82
|
-
return getPlayerWithModuleProperties(PlayerModule);
|
|
83
|
-
};
|
|
84
|
-
|
|
85
25
|
type PlayableComponent = {
|
|
86
26
|
Component: React.ComponentType<any>;
|
|
87
27
|
};
|
|
@@ -99,14 +39,23 @@ export function HandlePlayable({
|
|
|
99
39
|
mode,
|
|
100
40
|
groupId,
|
|
101
41
|
}: Props): React.ReactElement | null {
|
|
102
|
-
const
|
|
42
|
+
const { plugins, contentTypes, rivers, appData } = usePickFromState([
|
|
43
|
+
"plugins",
|
|
44
|
+
"contentTypes",
|
|
45
|
+
"rivers",
|
|
46
|
+
"appData",
|
|
47
|
+
]);
|
|
103
48
|
|
|
104
49
|
const { closeVideoModal } = useNavigation();
|
|
105
50
|
|
|
106
|
-
const [Player, playerModuleProperties] = getPlayer(item,
|
|
51
|
+
const [Player, playerModuleProperties] = getPlayer(item, {
|
|
52
|
+
plugins,
|
|
53
|
+
contentTypes,
|
|
54
|
+
rivers,
|
|
55
|
+
appData,
|
|
56
|
+
});
|
|
107
57
|
|
|
108
|
-
const { module: CastPlugin } =
|
|
109
|
-
findPluginByIdentifier(CHROMECAST_PLUGIN_ID, state.plugins, true) || {};
|
|
58
|
+
const { module: CastPlugin } = findCastPlugin(plugins);
|
|
110
59
|
|
|
111
60
|
const [playable, setPlayable] =
|
|
112
61
|
React.useState<Nullable<PlayableComponent>>(null);
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import {
|
|
2
|
+
findPluginByIdentifier,
|
|
3
|
+
findPluginByType,
|
|
4
|
+
} from "@applicaster/zapp-react-native-utils/pluginUtils";
|
|
5
|
+
|
|
6
|
+
import { CHROMECAST_PLUGIN_ID, YOUTUBE_PLUGIN_ID } from "./const";
|
|
7
|
+
import { omit } from "@applicaster/zapp-react-native-utils/utils";
|
|
8
|
+
|
|
9
|
+
const getPlayerModuleProperties = (PlayerModule: ZappPlugin) => {
|
|
10
|
+
if (PlayerModule?.Component && typeof PlayerModule.Component === "object") {
|
|
11
|
+
return omit(["Component"], PlayerModule);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
return {};
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export const getPlayerWithModuleProperties = (
|
|
18
|
+
PlayerModule: ZappPlugin
|
|
19
|
+
): [ZappPlugin, PlayerModuleProperties] => {
|
|
20
|
+
return [
|
|
21
|
+
PlayerModule?.Component || PlayerModule,
|
|
22
|
+
getPlayerModuleProperties(PlayerModule),
|
|
23
|
+
];
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export const findCastPlugin = (plugins: ZappPlugin[]) =>
|
|
27
|
+
findPluginByIdentifier(CHROMECAST_PLUGIN_ID, plugins, true) || {};
|
|
28
|
+
|
|
29
|
+
export const findYoutubePlugin = (plugins: ZappPlugin[]) =>
|
|
30
|
+
findPluginByIdentifier(YOUTUBE_PLUGIN_ID, plugins, true) || {};
|
|
31
|
+
|
|
32
|
+
export const getPlayer = (
|
|
33
|
+
item: ZappEntry,
|
|
34
|
+
{
|
|
35
|
+
plugins,
|
|
36
|
+
contentTypes,
|
|
37
|
+
rivers,
|
|
38
|
+
appData: { layoutVersion },
|
|
39
|
+
}: {
|
|
40
|
+
plugins: ZappPlugin[];
|
|
41
|
+
contentTypes: Record<string, any>;
|
|
42
|
+
rivers: Record<string, any>;
|
|
43
|
+
appData: { layoutVersion: string };
|
|
44
|
+
}
|
|
45
|
+
): [ZappPlugin, PlayerModuleProperties] => {
|
|
46
|
+
let PlayerModule;
|
|
47
|
+
|
|
48
|
+
if (layoutVersion === "v2") {
|
|
49
|
+
const screen_id = contentTypes?.[item?.type?.value]?.screen_id;
|
|
50
|
+
const type = rivers?.[screen_id]?.type;
|
|
51
|
+
|
|
52
|
+
if (type) {
|
|
53
|
+
PlayerModule = findPluginByIdentifier(type, plugins)?.module;
|
|
54
|
+
|
|
55
|
+
return getPlayerWithModuleProperties(PlayerModule);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (item?.content?.type === "youtube-id") {
|
|
60
|
+
PlayerModule = findYoutubePlugin(plugins)?.module;
|
|
61
|
+
|
|
62
|
+
return getPlayerWithModuleProperties(PlayerModule);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
PlayerModule = findPluginByType(
|
|
66
|
+
"playable",
|
|
67
|
+
(plugins as any[]).filter(
|
|
68
|
+
({ identifier }: { identifier: string }) =>
|
|
69
|
+
identifier !== YOUTUBE_PLUGIN_ID
|
|
70
|
+
)
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
return getPlayerWithModuleProperties(PlayerModule);
|
|
74
|
+
};
|
package/Components/MasterCell/DefaultComponents/BorderContainerView/__tests__/index.test.tsx
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
+
import * as React from "react";
|
|
1
2
|
import {
|
|
2
3
|
BorderContainerView,
|
|
3
4
|
getBorderPadding, // Export for testing (using a double underscore prefix is a common convention)
|
|
4
5
|
} from "../index";
|
|
5
|
-
import * as React from "react";
|
|
6
6
|
import { render } from "@testing-library/react-native";
|
|
7
7
|
import { toNumberWithDefaultZero } from "@applicaster/zapp-react-native-utils/numberUtils";
|
|
8
8
|
import { View } from "react-native";
|
|
@@ -11,6 +11,15 @@ jest.mock("@applicaster/zapp-react-native-utils/numberUtils", () => ({
|
|
|
11
11
|
toNumberWithDefaultZero: jest.fn((value) => Number(value) || 0),
|
|
12
12
|
}));
|
|
13
13
|
|
|
14
|
+
jest.mock(
|
|
15
|
+
"@applicaster/zapp-react-native-utils/appUtils/accessibilityManager/hooks",
|
|
16
|
+
() => ({
|
|
17
|
+
useAccessibilityManager: jest.fn(() => ({
|
|
18
|
+
addHeading: jest.fn(),
|
|
19
|
+
})),
|
|
20
|
+
})
|
|
21
|
+
);
|
|
22
|
+
|
|
14
23
|
describe("BorderContainerView", () => {
|
|
15
24
|
describe("getBorderPadding", () => {
|
|
16
25
|
it("returns 0 for inside", () => {
|
|
@@ -42,6 +51,8 @@ describe("BorderContainerView", () => {
|
|
|
42
51
|
};
|
|
43
52
|
|
|
44
53
|
const borderPosition = null;
|
|
54
|
+
const mockEntry = { id: "test-entry" } as ZappEntry;
|
|
55
|
+
const mockHasFocusableInside = jest.fn(() => false);
|
|
45
56
|
|
|
46
57
|
const { queryByTestId } = render(
|
|
47
58
|
<BorderContainerView
|
|
@@ -52,6 +63,10 @@ describe("BorderContainerView", () => {
|
|
|
52
63
|
borderPaddingRight={toNumberWithDefaultZero(padding.paddingRight)}
|
|
53
64
|
borderPaddingBottom={toNumberWithDefaultZero(padding.paddingBottom)}
|
|
54
65
|
borderPaddingLeft={toNumberWithDefaultZero(padding.paddingLeft)}
|
|
66
|
+
hasFocusableInside={mockHasFocusableInside}
|
|
67
|
+
entry={mockEntry}
|
|
68
|
+
state="focused"
|
|
69
|
+
hasTextLabels={false}
|
|
55
70
|
>
|
|
56
71
|
<View testID="child" />
|
|
57
72
|
</BorderContainerView>
|