@applicaster/zapp-react-native-ui-components 15.0.0-alpha.1692821627 → 15.0.0-alpha.2004137882

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.
Files changed (74) hide show
  1. package/Components/AnimatedInOut/index.tsx +69 -26
  2. package/Components/BaseFocusable/index.ios.ts +12 -2
  3. package/Components/Cell/Cell.tsx +8 -3
  4. package/Components/Cell/FocusableWrapper.tsx +47 -0
  5. package/Components/Cell/TvOSCellComponent.tsx +106 -19
  6. package/Components/Focusable/FocusableTvOS.tsx +11 -2
  7. package/Components/Focusable/__tests__/__snapshots__/FocusableTvOS.test.tsx.snap +1 -0
  8. package/Components/FocusableGroup/FocusableTvOS.tsx +11 -0
  9. package/Components/HandlePlayable/HandlePlayable.tsx +17 -65
  10. package/Components/HandlePlayable/const.ts +3 -0
  11. package/Components/HandlePlayable/utils.ts +74 -0
  12. package/Components/Layout/TV/LayoutBackground.tsx +5 -2
  13. package/Components/Layout/TV/ScreenContainer.tsx +2 -6
  14. package/Components/Layout/TV/index.tsx +3 -4
  15. package/Components/Layout/TV/index.web.tsx +3 -4
  16. package/Components/LinkHandler/LinkHandler.tsx +2 -2
  17. package/Components/MasterCell/DefaultComponents/BorderContainerView/__tests__/index.test.tsx +16 -1
  18. package/Components/MasterCell/DefaultComponents/BorderContainerView/index.tsx +30 -2
  19. package/Components/MasterCell/DefaultComponents/Image/Image.android.tsx +5 -1
  20. package/Components/MasterCell/DefaultComponents/Image/Image.ios.tsx +11 -3
  21. package/Components/MasterCell/DefaultComponents/Image/Image.web.tsx +9 -1
  22. package/Components/MasterCell/DefaultComponents/Image/hooks/useImage.ts +15 -14
  23. package/Components/MasterCell/DefaultComponents/LiveImage/index.tsx +10 -6
  24. package/Components/MasterCell/DefaultComponents/Text/index.tsx +8 -8
  25. package/Components/MasterCell/index.tsx +2 -0
  26. package/Components/MasterCell/utils/__tests__/resolveColor.test.js +82 -3
  27. package/Components/MasterCell/utils/index.ts +61 -31
  28. package/Components/MeasurmentsPortal/MeasurementsPortal.tsx +102 -87
  29. package/Components/MeasurmentsPortal/__tests__/MeasurementsPortal.test.tsx +355 -0
  30. package/Components/OfflineHandler/NotificationView/NotificationView.tsx +2 -2
  31. package/Components/OfflineHandler/NotificationView/__tests__/index.test.tsx +17 -18
  32. package/Components/OfflineHandler/__tests__/index.test.tsx +27 -18
  33. package/Components/PlayerContainer/PlayerContainer.tsx +5 -19
  34. package/Components/PlayerImageBackground/index.tsx +3 -22
  35. package/Components/Screen/TV/index.web.tsx +4 -2
  36. package/Components/Screen/__tests__/Screen.test.tsx +65 -42
  37. package/Components/Screen/__tests__/__snapshots__/Screen.test.tsx.snap +68 -44
  38. package/Components/Screen/hooks.ts +2 -3
  39. package/Components/Screen/index.tsx +2 -3
  40. package/Components/Screen/navigationHandler.ts +49 -24
  41. package/Components/Screen/orientationHandler.ts +3 -3
  42. package/Components/ScreenResolver/index.tsx +13 -7
  43. package/Components/ScreenRevealManager/ScreenRevealManager.ts +40 -8
  44. package/Components/ScreenRevealManager/__tests__/ScreenRevealManager.test.ts +86 -69
  45. package/Components/ScreenRevealManager/withScreenRevealManager.tsx +44 -26
  46. package/Components/Tabs/TV/Tabs.tsx +20 -3
  47. package/Components/Transitioner/Scene.tsx +15 -2
  48. package/Components/Transitioner/index.js +3 -3
  49. package/Components/VideoLive/__tests__/__snapshots__/PlayerLiveImageComponent.test.tsx.snap +1 -0
  50. package/Components/VideoModal/ModalAnimation/ModalAnimationContext.tsx +118 -171
  51. package/Components/VideoModal/ModalAnimation/index.ts +2 -13
  52. package/Components/VideoModal/ModalAnimation/utils.ts +1 -327
  53. package/Components/VideoModal/PlayerWrapper.tsx +14 -88
  54. package/Components/VideoModal/VideoModal.tsx +1 -5
  55. package/Components/VideoModal/__tests__/PlayerWrapper.test.tsx +1 -0
  56. package/Components/VideoModal/hooks/useModalSize.ts +10 -5
  57. package/Components/VideoModal/playerWrapperStyle.ts +70 -0
  58. package/Components/VideoModal/playerWrapperUtils.ts +91 -0
  59. package/Components/VideoModal/utils.ts +19 -9
  60. package/Decorators/Analytics/index.tsx +6 -5
  61. package/Decorators/ZappPipesDataConnector/index.tsx +2 -2
  62. package/Decorators/ZappPipesDataConnector/resolvers/StaticFeedResolver.tsx +1 -1
  63. package/Helpers/DataSourceHelper/__tests__/itemLimitForData.test.ts +80 -0
  64. package/Helpers/DataSourceHelper/index.ts +19 -0
  65. package/index.d.ts +7 -0
  66. package/package.json +6 -5
  67. package/Components/VideoModal/ModalAnimation/AnimatedPlayerModalWrapper.tsx +0 -60
  68. package/Components/VideoModal/ModalAnimation/AnimatedScrollModal.tsx +0 -417
  69. package/Components/VideoModal/ModalAnimation/AnimatedScrollModal.web.tsx +0 -294
  70. package/Components/VideoModal/ModalAnimation/AnimatedVideoPlayerComponent.tsx +0 -176
  71. package/Components/VideoModal/ModalAnimation/AnimatedVideoPlayerComponent.web.tsx +0 -93
  72. package/Components/VideoModal/ModalAnimation/AnimationComponent.tsx +0 -500
  73. package/Components/VideoModal/ModalAnimation/__tests__/getMoveUpValue.test.ts +0 -108
  74. package/Helpers/DataSourceHelper/index.js +0 -19
@@ -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 [animating, setAnimating] = React.useState(undefined);
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
- function startAnimation(toValue, config) {
53
- if (animating) {
54
- animating.reset();
55
- }
56
-
57
- const { duration, easing, delay = 0, onAnimationEnd = noop } = config;
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
- const compositeAnimation = Animated.timing(animatedValue, {
60
- duration,
61
- toValue,
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
- setAnimating(compositeAnimation);
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
- }, [visible, previousVisible]);
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={animating}
132
+ renderToHardwareTextureAndroid={!!animationRef.current}
90
133
  style={[styles(animatedValue), staticStyles]}
91
134
  >
92
135
  {children}
@@ -22,6 +22,7 @@ type Props = {
22
22
  onFocus?: FocusManager.FocusEventCB;
23
23
  onBlur?: FocusManager.FocusEventCB;
24
24
  selected?: boolean;
25
+ skipFocusManagerRegistration?: boolean;
25
26
  };
26
27
 
27
28
  export class BaseFocusable<
@@ -61,10 +62,14 @@ export class BaseFocusable<
61
62
  }
62
63
 
63
64
  componentDidMount() {
64
- const { id } = this.props;
65
+ const { id, skipFocusManagerRegistration } = this.props;
65
66
  const component = this;
66
67
  this.node = this.ref.current;
67
68
 
69
+ if (skipFocusManagerRegistration) {
70
+ return;
71
+ }
72
+
68
73
  focusManager.register({
69
74
  id,
70
75
  component: component,
@@ -118,7 +123,12 @@ export class BaseFocusable<
118
123
 
119
124
  componentWillUnmount() {
120
125
  this._isMounted = false;
121
- const { id } = this.props;
126
+ const { id, skipFocusManagerRegistration } = this.props;
127
+
128
+ if (skipFocusManagerRegistration) {
129
+ return;
130
+ }
131
+
122
132
  focusManager.unregister(id, { group: this.isGroup || false });
123
133
  }
124
134
 
@@ -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
- this.handleAccessibilityFocus(this.props.index, this.props.dataLength);
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,47 @@
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
+ skipFocusManagerRegistration?: boolean;
14
+ };
15
+
16
+ export const FocusableWrapper = ({
17
+ id,
18
+ groupId,
19
+ isParallaxDisabled,
20
+ children,
21
+ applyWrapper,
22
+ onFocus,
23
+ onBlur,
24
+ skipFocusManagerRegistration,
25
+ }: Props) => {
26
+ if (applyWrapper) {
27
+ return (
28
+ <Focusable
29
+ id={id}
30
+ groupId={groupId}
31
+ isParallaxDisabled={isParallaxDisabled}
32
+ onFocus={onFocus}
33
+ onBlur={onBlur}
34
+ willReceiveFocus={noop}
35
+ hasReceivedFocus={noop}
36
+ // @ts-ignore
37
+ offsetUpdater={noop}
38
+ isFocusable
39
+ skipFocusManagerRegistration={skipFocusManagerRegistration}
40
+ >
41
+ {(focused) => children(focused)}
42
+ </Focusable>
43
+ );
44
+ }
45
+
46
+ return <>{children(false)}</>;
47
+ };
@@ -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,12 @@ 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";
20
+ import { toNumberWithDefaultZero } from "@applicaster/zapp-react-native-utils/numberUtils";
13
21
 
14
22
  type Props = {
15
23
  item: ZappEntry;
@@ -30,6 +38,10 @@ type Props = {
30
38
  component: {
31
39
  id: number | string;
32
40
  component_type: string;
41
+ styles?: {
42
+ component_margin_top?: number;
43
+ component_padding_top?: number;
44
+ };
33
45
  };
34
46
  selected: boolean;
35
47
  CellRenderer: React.FunctionComponent<any> & {
@@ -66,6 +78,9 @@ type Props = {
66
78
  shouldUpdate: boolean;
67
79
  behavior: Behavior;
68
80
  componentsMapOffset: number;
81
+ applyFocusableWrapper: boolean;
82
+ hasFocusableInside: boolean;
83
+ skipFocusManagerRegistration?: boolean;
69
84
  };
70
85
 
71
86
  type State = {
@@ -82,7 +97,7 @@ const baseCellStyles = {
82
97
  flex: 1,
83
98
  } as const;
84
99
 
85
- export class TvOSCellComponent extends React.Component<Props, State> {
100
+ class TvOSCell extends React.Component<Props, State> {
86
101
  cell: any;
87
102
  target: any;
88
103
  layout: any;
@@ -192,14 +207,25 @@ export class TvOSCellComponent extends React.Component<Props, State> {
192
207
  ) {
193
208
  const { headerOffset } = getHeaderOffset();
194
209
 
195
- const extraAnchorPointYOffset =
196
- screenLayout?.extraAnchorPointYOffset || 0;
210
+ const extraAnchorPointYOffset = toNumberWithDefaultZero(
211
+ screenLayout?.extraAnchorPointYOffset
212
+ );
213
+
214
+ const componentMarginTop = toNumberWithDefaultZero(
215
+ component?.styles?.component_margin_top
216
+ );
217
+
218
+ const componentPaddingTop = toNumberWithDefaultZero(
219
+ component?.styles?.component_padding_top
220
+ );
197
221
 
198
222
  const totalOffset =
199
223
  headerOffset +
200
- (componentAnchorPointY || 0) +
201
- extraAnchorPointYOffset -
202
- componentsMapOffset || 0;
224
+ toNumberWithDefaultZero(componentAnchorPointY) +
225
+ extraAnchorPointYOffset -
226
+ toNumberWithDefaultZero(componentsMapOffset) +
227
+ componentMarginTop +
228
+ componentPaddingTop;
203
229
 
204
230
  mainOffsetUpdater?.(
205
231
  { tag: this.target },
@@ -239,6 +265,9 @@ export class TvOSCellComponent extends React.Component<Props, State> {
239
265
  groupId,
240
266
  isFocusable,
241
267
  behavior,
268
+ applyFocusableWrapper,
269
+ hasFocusableInside,
270
+ skipFocusManagerRegistration,
242
271
  } = this.props;
243
272
 
244
273
  const { id } = item;
@@ -254,24 +283,35 @@ export class TvOSCellComponent extends React.Component<Props, State> {
254
283
  this.onFocus(arg1, index);
255
284
  };
256
285
 
257
- const hasFocusableInside = CellRenderer.hasFocusableInside?.(item);
258
-
259
286
  if (hasFocusableInside) {
260
287
  return (
261
288
  <View onLayout={this.onLayout}>
262
- <CellWithFocusable
263
- CellRenderer={CellRenderer}
264
- item={item}
289
+ <FocusableWrapper
265
290
  id={focusableId}
266
- groupId={(groupId || component?.id).toString()}
291
+ groupId={String(groupId || component?.id)}
292
+ isParallaxDisabled={this.layout?.width > 1740}
267
293
  onFocus={handleFocus}
268
- index={index}
269
- scrollTo={this.scrollTo}
270
- preferredFocus={preferredFocus}
271
- focused={this.props.focused}
272
- behavior={behavior}
273
- isFocusable={isFocusable}
274
- />
294
+ onBlur={onBlur || this.onBlur}
295
+ applyWrapper={applyFocusableWrapper}
296
+ skipFocusManagerRegistration={skipFocusManagerRegistration}
297
+ >
298
+ {(focused) => (
299
+ <CellWithFocusable
300
+ CellRenderer={CellRenderer}
301
+ item={item}
302
+ id={focusableId}
303
+ groupId={(groupId || component?.id).toString()}
304
+ onFocus={handleFocus}
305
+ index={index}
306
+ scrollTo={this.scrollTo}
307
+ preferredFocus={preferredFocus}
308
+ focused={focused || this.props.focused}
309
+ behavior={behavior}
310
+ isFocusable={isFocusable}
311
+ skipFocusManagerRegistration={skipFocusManagerRegistration}
312
+ />
313
+ )}
314
+ </FocusableWrapper>
275
315
  </View>
276
316
  );
277
317
  }
@@ -291,6 +331,7 @@ export class TvOSCellComponent extends React.Component<Props, State> {
291
331
  offsetUpdater={offsetUpdater}
292
332
  style={baseCellStyles}
293
333
  isFocusable={isFocusable}
334
+ skipFocusManagerRegistration={skipFocusManagerRegistration}
294
335
  >
295
336
  {(focused) => (
296
337
  <FocusableCell
@@ -309,3 +350,49 @@ export class TvOSCellComponent extends React.Component<Props, State> {
309
350
  );
310
351
  }
311
352
  }
353
+
354
+ export function withFocusableWrapperHOC(Component) {
355
+ return function WrappedComponent(props) {
356
+ const [focusableViewIsRendered, setFocusableViewIsRendered] =
357
+ React.useState(false);
358
+
359
+ const { CellRenderer, item, groupId, component } = props;
360
+
361
+ const isFocusable = toBooleanWithDefaultTrue(props?.isFocusable);
362
+
363
+ const focusableGroupId = String(groupId || component?.id);
364
+
365
+ const hasFocusableInside = CellRenderer.hasFocusableInside?.(item);
366
+
367
+ React.useEffect(() => {
368
+ // start waiting any first registration of FocusableButton inside this focusableGroup
369
+ // after it we could get rid of applying focusable-wrapper
370
+ const subscription = focusableButtonsRegistration$(focusableGroupId)
371
+ .pipe(
372
+ filter(() => isFocusable),
373
+ first()
374
+ )
375
+ .subscribe(() => {
376
+ setFocusableViewIsRendered(true);
377
+ });
378
+
379
+ return () => {
380
+ subscription.unsubscribe();
381
+ };
382
+ }, [isFocusable, focusableGroupId]);
383
+
384
+ const applyFocusableWrapper = React.useMemo(() => {
385
+ return isFocusable && hasFocusableInside && !focusableViewIsRendered;
386
+ }, [isFocusable, hasFocusableInside, focusableViewIsRendered]);
387
+
388
+ return (
389
+ <Component
390
+ {...props}
391
+ applyFocusableWrapper={applyFocusableWrapper}
392
+ hasFocusableInside={hasFocusableInside}
393
+ />
394
+ );
395
+ };
396
+ }
397
+
398
+ export const TvOSCellComponent = compose(withFocusableWrapperHOC)(TvOSCell);
@@ -10,8 +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
-
14
- function noop() {}
13
+ import { emitNativeRegistered } from "@applicaster/zapp-react-native-utils/appUtils/focusManagerAux/utils/utils.ios";
14
+ import { noop } from "@applicaster/zapp-react-native-utils/functionUtils";
15
15
 
16
16
  type Props = {
17
17
  id: string;
@@ -39,6 +39,7 @@ type Props = {
39
39
  hasReceivedFocus: () => void;
40
40
  offsetUpdater: (arg1: string, arg2: number) => number;
41
41
  style: ViewStyle;
42
+ skipFocusManagerRegistration?: boolean;
42
43
  };
43
44
 
44
45
  export class Focusable extends BaseFocusable<Props> {
@@ -169,6 +170,13 @@ export class Focusable extends BaseFocusable<Props> {
169
170
  });
170
171
  }
171
172
 
173
+ onRegistered({ nativeEvent }) {
174
+ const groupId = nativeEvent?.groupId;
175
+ const id = nativeEvent?.itemId;
176
+
177
+ emitNativeRegistered({ id, groupId, isGroup: false });
178
+ }
179
+
172
180
  render() {
173
181
  const {
174
182
  children,
@@ -203,6 +211,7 @@ export class Focusable extends BaseFocusable<Props> {
203
211
  focusable={isFocusable}
204
212
  {...this.nextFocusableReactTags}
205
213
  {...otherProps}
214
+ onRegistered={this.onRegistered}
206
215
  >
207
216
  {typeof children === "function" ? children(focused) : children}
208
217
  </FocusableItemNative>
@@ -5,6 +5,7 @@ exports[`FocusableTvOS should render correctly 1`] = `
5
5
  groupId={null}
6
6
  itemId={null}
7
7
  onLayout={[Function]}
8
+ onRegistered={[Function]}
8
9
  onViewBlur={[Function]}
9
10
  onViewFocus={[Function]}
10
11
  onViewPress={[Function]}
@@ -2,6 +2,7 @@ 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
4
  import { createLogger } from "@applicaster/zapp-react-native-utils/logger";
5
+ import { emitNativeRegistered } from "@applicaster/zapp-react-native-utils/appUtils/focusManagerAux/utils/utils.ios";
5
6
 
6
7
  const { log_verbose } = createLogger({
7
8
  subsystem: "General",
@@ -34,6 +35,15 @@ type Props = {
34
35
  };
35
36
 
36
37
  export class FocusableGroup extends BaseFocusable<Props> {
38
+ public readonly isGroup: boolean = true;
39
+
40
+ onRegistered({ nativeEvent }) {
41
+ const groupId = nativeEvent?.groupId;
42
+ const id = nativeEvent?.itemId;
43
+
44
+ emitNativeRegistered({ id, groupId, isGroup: true });
45
+ }
46
+
37
47
  render() {
38
48
  const {
39
49
  children,
@@ -66,6 +76,7 @@ export class FocusableGroup extends BaseFocusable<Props> {
66
76
  onGroupBlur={onGroupBlur}
67
77
  style={style}
68
78
  {...otherProps}
79
+ onRegistered={this.onRegistered}
69
80
  >
70
81
  {children}
71
82
  </FocusableGroupNative>
@@ -1,14 +1,14 @@
1
1
  import * as React from "react";
2
- import * as R from "ramda";
3
2
  import {
4
- findPluginByType,
5
- findPluginByIdentifier,
6
- } from "@applicaster/zapp-react-native-utils/pluginUtils";
7
- import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
3
+ useAppData,
4
+ useContentTypes,
5
+ usePlugins,
6
+ } from "@applicaster/zapp-react-native-redux/hooks";
8
7
  import {
9
8
  useDimensions,
10
9
  useIsTablet as isTablet,
11
10
  useNavigation,
11
+ useRivers,
12
12
  } from "@applicaster/zapp-react-native-utils/reactHooks";
13
13
 
14
14
  import { BufferAnimation } from "../PlayerContainer/BufferAnimation";
@@ -16,6 +16,7 @@ import { PlayerContainer } from "../PlayerContainer";
16
16
  import { useModalSize } from "../VideoModal/hooks";
17
17
  import { ViewStyle } from "react-native";
18
18
  import { platformSelect } from "@applicaster/zapp-react-native-utils/reactUtils";
19
+ import { findCastPlugin, getPlayer } from "./utils";
19
20
 
20
21
  type Props = {
21
22
  item: ZappEntry;
@@ -26,62 +27,6 @@ type Props = {
26
27
  groupId?: string;
27
28
  };
28
29
 
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
30
  type PlayableComponent = {
86
31
  Component: React.ComponentType<any>;
87
32
  };
@@ -99,14 +44,21 @@ export function HandlePlayable({
99
44
  mode,
100
45
  groupId,
101
46
  }: Props): React.ReactElement | null {
102
- const state = usePickFromState();
47
+ const plugins = usePlugins();
48
+ const contentTypes = useContentTypes();
49
+ const rivers = useRivers();
50
+ const appData = useAppData();
103
51
 
104
52
  const { closeVideoModal } = useNavigation();
105
53
 
106
- const [Player, playerModuleProperties] = getPlayer(item, state);
54
+ const [Player, playerModuleProperties] = getPlayer(item, {
55
+ plugins,
56
+ contentTypes,
57
+ rivers,
58
+ appData,
59
+ });
107
60
 
108
- const { module: CastPlugin } =
109
- findPluginByIdentifier(CHROMECAST_PLUGIN_ID, state.plugins, true) || {};
61
+ const { module: CastPlugin } = findCastPlugin(plugins);
110
62
 
111
63
  const [playable, setPlayable] =
112
64
  React.useState<Nullable<PlayableComponent>>(null);
@@ -0,0 +1,3 @@
1
+ export const YOUTUBE_PLUGIN_ID = "youtube-player-qb";
2
+
3
+ export const CHROMECAST_PLUGIN_ID = "chromecast_qb";