@applicaster/zapp-react-native-ui-components 12.0.0-alpha.4195481103 → 12.0.0-alpha.4220424021

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 (45) hide show
  1. package/Components/Cell/Cell.tsx +21 -5
  2. package/Components/FreezeWithCallback/Freeze.tsx +31 -0
  3. package/Components/FreezeWithCallback/LICENSE +21 -0
  4. package/Components/FreezeWithCallback/Suspender.tsx +17 -0
  5. package/Components/FreezeWithCallback/__tests__/index.test.tsx +170 -0
  6. package/Components/FreezeWithCallback/index.tsx +3 -0
  7. package/Components/Layout/TV/ScreenContainer.tsx +3 -8
  8. package/Components/Layout/TV/__tests__/ScreenContainer.test.tsx +1 -1
  9. package/Components/MasterCell/DefaultComponents/ActionButton.tsx +2 -1
  10. package/Components/MasterCell/DefaultComponents/BorderContainerView/index.tsx +1 -7
  11. package/Components/MasterCell/DefaultComponents/ImageBorderContainer/index.ts +71 -0
  12. package/Components/MasterCell/DefaultComponents/LiveImage/index.tsx +20 -0
  13. package/Components/MasterCell/DefaultComponents/index.ts +2 -0
  14. package/Components/MasterCell/SharedUI/ProgressBar/hooks/useFillInPercent.ts +7 -1
  15. package/Components/MasterCell/dataAdapter.ts +21 -7
  16. package/Components/MasterCell/index.tsx +5 -3
  17. package/Components/PlayerContainer/PlayerContainer.tsx +2 -5
  18. package/Components/Screen/TV/hooks/index.ts +0 -2
  19. package/Components/Screen/TV/index.web.tsx +34 -25
  20. package/Components/Screen/__tests__/Screen.test.tsx +0 -49
  21. package/Components/Screen/index.tsx +27 -76
  22. package/Components/Screen/navigationHandler.ts +6 -3
  23. package/Components/Screen/orientationHandler.ts +18 -7
  24. package/Components/Screen/utils.ts +16 -0
  25. package/Components/ScreenResolver/index.tsx +6 -11
  26. package/Components/Transitioner/Scene.tsx +20 -12
  27. package/Components/Transitioner/Transitioner.tsx +26 -21
  28. package/Components/Transitioner/__tests__/Scene.test.js +7 -0
  29. package/Components/Transitioner/__tests__/__snapshots__/Scene.test.js.snap +8 -4
  30. package/Components/Transitioner/__tests__/__snapshots__/transitioner.test.js.snap +1 -0
  31. package/Components/VideoLive/PlayerLiveImageComponent.tsx +52 -24
  32. package/Components/VideoLive/__tests__/__snapshots__/PlayerLiveImageComponent.test.tsx.snap +26 -24
  33. package/Components/VideoModal/ModalAnimation/AnimatedPlayerModalWrapper.tsx +2 -14
  34. package/Components/VideoModal/ModalAnimation/AnimatedScrollModal.tsx +31 -7
  35. package/Components/VideoModal/ModalAnimation/AnimatedVideoPlayerComponent.tsx +9 -2
  36. package/Components/VideoModal/ModalAnimation/AnimationComponent.tsx +23 -5
  37. package/Components/VideoModal/ModalAnimation/ModalAnimationContext.tsx +28 -8
  38. package/Components/VideoModal/ModalAnimation/utils.ts +1 -0
  39. package/Components/VideoModal/PlayerWrapper.tsx +1 -1
  40. package/Components/VideoModal/__tests__/__snapshots__/PlayerWrapper.test.tsx.snap +48 -2
  41. package/Components/VideoModal/hooks/useModalSize.ts +10 -12
  42. package/Components/ZappFrameworkComponents/BarView/BarView.tsx +4 -3
  43. package/Components/default-cell-renderer/__tests__/__snapshots__/defaultCellRenderer.test.tsx.snap +4 -4
  44. package/package.json +5 -5
  45. package/Components/Screen/TV/hooks/useRestoreFocus.ts +0 -22
@@ -1,5 +1,5 @@
1
1
  import * as React from "react";
2
- import { join, path, merge } from "ramda";
2
+ import { join, merge, path } from "ramda";
3
3
  import { View } from "react-native";
4
4
 
5
5
  import { Focusable } from "@applicaster/zapp-react-native-ui-components/Components/Focusable";
@@ -67,6 +67,10 @@ type Props = {
67
67
  behavior: Behavior;
68
68
  };
69
69
 
70
+ type State = {
71
+ hasFocusableInside: boolean;
72
+ };
73
+
70
74
  const baseCellStyles = {
71
75
  height: "100%",
72
76
  display: "flex",
@@ -78,7 +82,7 @@ const touchableStyles = {
78
82
  height: "100%",
79
83
  } as const;
80
84
 
81
- export class CellComponent extends React.Component<Props> {
85
+ export class CellComponent extends React.Component<Props, State> {
82
86
  constructor(props) {
83
87
  super(props);
84
88
  this.onPress = this.onPress.bind(this);
@@ -88,6 +92,10 @@ export class CellComponent extends React.Component<Props> {
88
92
  this.hasReceivedFocus = this.hasReceivedFocus.bind(this);
89
93
  this.scrollVertically = this.scrollVertically.bind(this);
90
94
  this.scrollToIndex = this.scrollToIndex.bind(this);
95
+
96
+ this.state = {
97
+ hasFocusableInside: props.CellRenderer.hasFocusableInside?.(props.item),
98
+ };
91
99
  }
92
100
 
93
101
  setScreenLayout(componentAnchorPointY, screenLayout) {
@@ -192,6 +200,16 @@ export class CellComponent extends React.Component<Props> {
192
200
  return !isFocusable ? false : focused || focusableFocused;
193
201
  }
194
202
 
203
+ componentDidUpdate(prevProps: Readonly<Props>) {
204
+ if (prevProps.item !== this.props.item) {
205
+ this.setState({
206
+ hasFocusableInside: this.props.CellRenderer.hasFocusableInside?.(
207
+ this.props.item
208
+ ),
209
+ });
210
+ }
211
+ }
212
+
195
213
  render() {
196
214
  const {
197
215
  item,
@@ -220,9 +238,7 @@ export class CellComponent extends React.Component<Props> {
220
238
  this.onFocus(focusable, mouse);
221
239
  };
222
240
 
223
- const hasFocusableInside = CellRenderer.hasFocusableInside?.(item);
224
-
225
- if (hasFocusableInside) {
241
+ if (this.state.hasFocusableInside) {
226
242
  return (
227
243
  <CellWithFocusable
228
244
  CellRenderer={CellRenderer}
@@ -0,0 +1,31 @@
1
+ import { usePrevious } from "@applicaster/zapp-react-native-utils/reactHooks/utils";
2
+ import React, { Suspense, useEffect } from "react";
3
+ import { Suspender } from "./Suspender";
4
+
5
+ interface Props {
6
+ freeze: boolean;
7
+ children: React.ReactNode;
8
+ placeholder?: React.ReactNode;
9
+ onRelease?: () => void;
10
+ }
11
+
12
+ export function Freeze({
13
+ freeze,
14
+ children,
15
+ placeholder = null,
16
+ onRelease,
17
+ }: Props) {
18
+ const prevFreeze = usePrevious(freeze);
19
+
20
+ useEffect(() => {
21
+ if (prevFreeze && !freeze && onRelease) {
22
+ onRelease();
23
+ }
24
+ }, [freeze, onRelease, prevFreeze]);
25
+
26
+ return (
27
+ <Suspense fallback={placeholder}>
28
+ <Suspender freeze={freeze}>{children}</Suspender>
29
+ </Suspense>
30
+ );
31
+ }
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2021 Software Mansion
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,17 @@
1
+ import React, { Fragment } from "react";
2
+
3
+ const infiniteThenable = { then() {} };
4
+
5
+ export const Suspender = ({
6
+ freeze,
7
+ children,
8
+ }: {
9
+ freeze: boolean;
10
+ children: React.ReactNode;
11
+ }) => {
12
+ if (freeze) {
13
+ throw infiniteThenable;
14
+ }
15
+
16
+ return <Fragment>{children}</Fragment>;
17
+ };
@@ -0,0 +1,170 @@
1
+ import React, { Dispatch, useEffect, useState } from "react";
2
+ import {
3
+ act,
4
+ create,
5
+ ReactTestRenderer,
6
+ ReactTestRendererJSON,
7
+ } from "react-test-renderer";
8
+ import { FreezeWithCallback } from "../index";
9
+
10
+ const SimpleContent = () => <div />;
11
+
12
+ interface InnerProps {
13
+ value: number;
14
+ }
15
+ // eslint-disable-next-line unused-imports/no-unused-vars
16
+ const Inner = ({ value }: InnerProps) => <div />;
17
+
18
+ interface TestSubscriber {
19
+ renderCount: number;
20
+ subscription: Dispatch<number>;
21
+ }
22
+
23
+ function createSubscriberComponent(): [React.FC, TestSubscriber] {
24
+ const testState: TestSubscriber = {
25
+ renderCount: 0,
26
+ subscription: () => {},
27
+ };
28
+
29
+ const Subscriber: React.FC = () => {
30
+ const [value, setValue] = useState(0);
31
+
32
+ useEffect(() => {
33
+ testState.subscription = setValue;
34
+ }, []);
35
+
36
+ testState.renderCount += 1;
37
+
38
+ return <Inner value={value} />;
39
+ };
40
+
41
+ return [Subscriber, testState];
42
+ }
43
+
44
+ interface ContainerProps {
45
+ freeze: boolean;
46
+ children: React.ReactNode;
47
+ }
48
+
49
+ const Container = ({ freeze, children }: ContainerProps) => (
50
+ <FreezeWithCallback freeze={freeze}>{children}</FreezeWithCallback>
51
+ );
52
+
53
+ function setupTest(initialFreeze: boolean = false) {
54
+ let testRenderer: ReactTestRenderer | undefined;
55
+ const [Subscriber, subscriberState] = createSubscriberComponent();
56
+
57
+ act(() => {
58
+ testRenderer = create(
59
+ <Container freeze={initialFreeze}>
60
+ <Subscriber />
61
+ </Container>
62
+ );
63
+ });
64
+
65
+ return {
66
+ testRenderer,
67
+ testInstance: testRenderer?.root,
68
+ subscriberState,
69
+ updateFreeze: (freeze: boolean) => {
70
+ act(() =>
71
+ testRenderer?.update(
72
+ <Container freeze={freeze}>
73
+ <Subscriber />
74
+ </Container>
75
+ )
76
+ );
77
+ },
78
+ };
79
+ }
80
+
81
+ describe("FreezeWithCallback", () => {
82
+ test("Renders stuff not frozen", () => {
83
+ const testRenderer = create(
84
+ <Container freeze={false}>
85
+ <SimpleContent />
86
+ </Container>
87
+ );
88
+
89
+ expect(testRenderer.root.findByType(SimpleContent)).toBeTruthy();
90
+ });
91
+
92
+ test("Does not render stuff when frozen", () => {
93
+ const testRenderer = create(
94
+ <Container freeze>
95
+ <SimpleContent />
96
+ </Container>
97
+ );
98
+
99
+ expect(testRenderer.root.findAllByType(SimpleContent)).toHaveLength(0);
100
+ });
101
+
102
+ test("Stuff is gone after freeze", () => {
103
+ const testRenderer = create(
104
+ <Container freeze={false}>
105
+ <SimpleContent />
106
+ </Container>
107
+ );
108
+
109
+ expect(testRenderer.root.findByType(SimpleContent)).toBeTruthy();
110
+
111
+ act(() =>
112
+ testRenderer.update(
113
+ <Container freeze>
114
+ <SimpleContent />
115
+ </Container>
116
+ )
117
+ );
118
+
119
+ expect(testRenderer.toJSON()).toBe(null);
120
+ });
121
+
122
+ test("Updates work when not frozen", () => {
123
+ const { testInstance, subscriberState } = setupTest();
124
+
125
+ expect(testInstance?.findByType(Inner).props.value).toEqual(0);
126
+ act(() => subscriberState.subscription(1));
127
+ expect(testInstance?.findByType(Inner).props.value).toEqual(1);
128
+ expect(subscriberState.renderCount).toBe(2);
129
+ });
130
+
131
+ test("Updates does not propagate when frozen", () => {
132
+ const { testInstance, subscriberState, updateFreeze } = setupTest();
133
+
134
+ expect(testInstance?.findByType(Inner).props.value).toEqual(0);
135
+ updateFreeze(true);
136
+ act(() => subscriberState.subscription(1));
137
+ expect(testInstance?.findByType(Inner).props.value).toEqual(0);
138
+ expect(subscriberState.renderCount).toBe(1);
139
+ });
140
+
141
+ test("State persists after defrost", () => {
142
+ const { testInstance, subscriberState, updateFreeze, testRenderer } =
143
+ setupTest();
144
+
145
+ expect(testInstance?.findByType(Inner).props.value).toEqual(0);
146
+ act(() => subscriberState.subscription(1));
147
+ expect(testInstance?.findByType(Inner).props.value).toEqual(1);
148
+
149
+ updateFreeze(true);
150
+ expect(testRenderer?.toJSON()).toBe(null);
151
+
152
+ updateFreeze(false);
153
+ expect((testRenderer?.toJSON() as ReactTestRendererJSON).type).toBe("div");
154
+ expect(testInstance?.findByType(Inner).props.value).toEqual(1);
155
+ });
156
+
157
+ test("Update propagate after defrost", () => {
158
+ const { testInstance, subscriberState, updateFreeze } = setupTest();
159
+
160
+ updateFreeze(true);
161
+ act(() => subscriberState.subscription(1));
162
+ act(() => subscriberState.subscription(2));
163
+ act(() => subscriberState.subscription(3));
164
+ expect(testInstance?.findByType(Inner).props.value).toEqual(0);
165
+
166
+ updateFreeze(false);
167
+ expect(testInstance?.findByType(Inner).props.value).toEqual(3);
168
+ expect(subscriberState.renderCount).toBe(2);
169
+ });
170
+ });
@@ -0,0 +1,3 @@
1
+ import { Freeze } from "./Freeze";
2
+
3
+ export const FreezeWithCallback = Freeze;
@@ -13,8 +13,8 @@ import { useTheme } from "@applicaster/zapp-react-native-utils/theme";
13
13
 
14
14
  import { useScreenConfiguration } from "../../River/useScreenConfiguration";
15
15
  import {
16
+ findMenuPlugin,
16
17
  getNavigationProps,
17
- resolveNavigationPlugin,
18
18
  routeIsPlayerScreen,
19
19
  } from "@applicaster/zapp-react-native-utils/navigationUtils";
20
20
  import { isApplePlatform } from "@applicaster/zapp-react-native-utils/reactUtils";
@@ -118,13 +118,8 @@ export const ScreenContainer = React.memo(function ScreenContainer({
118
118
  });
119
119
 
120
120
  const menuPlugin = React.useMemo(
121
- () =>
122
- resolveNavigationPlugin({
123
- category: "menu",
124
- navigations: activeRiver?.navigations,
125
- plugins,
126
- }) as QuickBrickPlugin,
127
- []
121
+ () => findMenuPlugin(activeRiver?.navigations, plugins),
122
+ [activeRiver?.navigations]
128
123
  );
129
124
 
130
125
  const NavBarComponent = React.useMemo(
@@ -19,7 +19,7 @@ jest.mock("@applicaster/zapp-react-native-utils/navigationUtils", () => ({
19
19
  ...jest.requireActual<any>(
20
20
  "@applicaster/zapp-react-native-utils/navigationUtils"
21
21
  ),
22
- resolveNavigationPlugin: () => ({}),
22
+ findMenuPlugin: () => ({}),
23
23
  }));
24
24
 
25
25
  jest.mock("@applicaster/quick-brick-core/App/ActionSetters", () => ({
@@ -53,6 +53,7 @@ export function ActionButton(props: Props) {
53
53
  const { item, action, asset, flavour = "flavour_1", cellUUID } = props;
54
54
  const actionContext = useActions(action?.identifier);
55
55
 
56
+ // TODO: add subscription API for action availability
56
57
  const actionDisabled =
57
58
  typeof actionContext?.isActionAvailable === "function" &&
58
59
  !actionContext.isActionAvailable(item);
@@ -68,7 +69,7 @@ export function ActionButton(props: Props) {
68
69
  if (actionDisabled || !actionContext) return;
69
70
 
70
71
  setActionState(actionContext.initialEntryState(item));
71
- }, [actionDisabled, item?.id]);
72
+ }, [actionDisabled, item?.id, actionContext]);
72
73
 
73
74
  const onPress = useCallback(() => {
74
75
  actionContext.invokeAction(item, {
@@ -117,9 +117,6 @@ export const BorderContainerView = (props: Props) => {
117
117
  children,
118
118
  } = props;
119
119
 
120
- const borderStyleForMissingBorder =
121
- style?.borderWidth === 0 || !style?.borderColor ? { borderRadius: 0 } : {};
122
-
123
120
  const padding =
124
121
  borderPosition === "outside"
125
122
  ? {
@@ -131,10 +128,7 @@ export const BorderContainerView = (props: Props) => {
131
128
  : {};
132
129
 
133
130
  return (
134
- <View
135
- {...props}
136
- style={[style, styles.container, borderStyleForMissingBorder]}
137
- >
131
+ <View pointerEvents="box-none" {...props} style={[style, styles.container]}>
138
132
  <Border style={style} padding={padding} borderPosition={borderPosition} />
139
133
  {children}
140
134
  </View>
@@ -0,0 +1,71 @@
1
+ import { ImageStyle } from "react-native";
2
+
3
+ import {
4
+ getImageContainerMarginStyles,
5
+ ifElseFocusedSelected,
6
+ } from "@applicaster/zapp-react-native-utils/cellUtils";
7
+ import { toNumberWithDefaultZero } from "@applicaster/zapp-react-native-utils/numberUtils";
8
+
9
+ export const ImageBorderContainer = ({
10
+ value,
11
+ state,
12
+ imageStyles,
13
+ }: {
14
+ value: (key: string) => string;
15
+ state: CellState;
16
+ imageStyles: ImageStyle;
17
+ }) => {
18
+ const imageMargins = getImageContainerMarginStyles({ value });
19
+
20
+ return {
21
+ type: "BorderContainerView",
22
+ style: {
23
+ position: "absolute",
24
+ // Image border now separated from the image, so cell padding affects the border position
25
+ marginTop:
26
+ toNumberWithDefaultZero(imageMargins.marginTop) +
27
+ toNumberWithDefaultZero(value("cell_padding_top")),
28
+ marginLeft:
29
+ toNumberWithDefaultZero(imageMargins.marginLeft) +
30
+ toNumberWithDefaultZero(value("cell_padding_left")),
31
+ marginRight:
32
+ toNumberWithDefaultZero(imageMargins.marginRight) +
33
+ toNumberWithDefaultZero(value("cell_padding_right")),
34
+ marginBottom:
35
+ toNumberWithDefaultZero(imageMargins.marginBottom) +
36
+ toNumberWithDefaultZero(value("cell_padding_bottom")),
37
+ zIndex: 1,
38
+ borderWidth: value("image_border_size"),
39
+ borderColor: ifElseFocusedSelected(
40
+ state,
41
+ value("image_focused_border_color"),
42
+ value("image_selected_border_color"),
43
+ value("image_focused_selected_border_color"),
44
+ value("image_border_color")
45
+ ),
46
+ borderRadius: toNumberWithDefaultZero(value("image_corner_radius")),
47
+ },
48
+ additionalProps: {
49
+ pointerEvents: "none",
50
+ borderPosition: value("image_border_position"),
51
+ borderPaddingTop: toNumberWithDefaultZero(
52
+ value("image_border_padding_top")
53
+ ),
54
+ borderPaddingRight: toNumberWithDefaultZero(
55
+ value("image_border_padding_right")
56
+ ),
57
+ borderPaddingBottom: toNumberWithDefaultZero(
58
+ value("image_border_padding_bottom")
59
+ ),
60
+ borderPaddingLeft: toNumberWithDefaultZero(
61
+ value("image_border_padding_left")
62
+ ),
63
+ },
64
+ elements: [
65
+ {
66
+ type: "View",
67
+ style: imageStyles,
68
+ },
69
+ ],
70
+ };
71
+ };
@@ -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) {
@@ -15,6 +15,7 @@ import { BorderContainerView } from "./BorderContainerView";
15
15
  import { CellBadge } from "./CellBadge";
16
16
  import { TvActionButtons } from "./tv/TvActionButtons";
17
17
  import { ButtonContainerView } from "./tv/ButtonContainerView";
18
+ import { ImageBorderContainer } from "./ImageBorderContainer";
18
19
 
19
20
  export const defaultComponents = {
20
21
  View,
@@ -28,6 +29,7 @@ export const defaultComponents = {
28
29
  ProgressBar,
29
30
  Toggle,
30
31
  LiveImage,
32
+ ImageBorderContainer,
31
33
  BorderContainerView,
32
34
  DynamicBadge,
33
35
  SecondaryImage,
@@ -5,6 +5,7 @@ import * as R from "ramda";
5
5
 
6
6
  import { useActions } from "@applicaster/zapp-react-native-utils/reactHooks/actions";
7
7
  import { normalizeProgressValue } from "./utils";
8
+ import { useIsScreenActive } from "@applicaster/zapp-react-native-utils/reactHooks";
8
9
 
9
10
  const ACTION_NAME = "continue-watching";
10
11
  const DEFAULT_FILL = 0;
@@ -27,6 +28,7 @@ const getProgressValue = (
27
28
 
28
29
  export const useFillInPercent = (entry: ZappEntry): number => {
29
30
  const action = useActions(ACTION_NAME);
31
+ const isActive = useIsScreenActive();
30
32
 
31
33
  const [fillInPercent, setFillInPercent] =
32
34
  React.useState<number>(DEFAULT_FILL);
@@ -39,6 +41,10 @@ export const useFillInPercent = (entry: ZappEntry): number => {
39
41
  }, []);
40
42
 
41
43
  React.useEffect(() => {
44
+ if (!isActive) {
45
+ return;
46
+ }
47
+
42
48
  // refresh progress in UI when it was changed in CW
43
49
  const unsubscribe = action?.addDataSourceListener?.(() => {
44
50
  getProgressValue(action, entry, (progress) => {
@@ -49,7 +55,7 @@ export const useFillInPercent = (entry: ZappEntry): number => {
49
55
  return () => {
50
56
  unsubscribe?.();
51
57
  };
52
- }, []);
58
+ }, [isActive]);
53
59
 
54
60
  return fillInPercent;
55
61
  };
@@ -37,14 +37,28 @@ function retrieveData(entry, func, args) {
37
37
  */
38
38
 
39
39
  export function configInflater(
40
- entry,
41
- { type, style, additionalProps = {}, data = [], elements }
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 = R.reduce(
44
- (acc, curr) =>
45
- R.assoc(curr.propName, retrieveData(entry, curr.func, curr.args), acc),
46
- additionalProps,
47
- data
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
  /**
@@ -74,8 +76,8 @@ export function masterCellBuilder({
74
76
  const selectedState = screen?.selectedEntry;
75
77
 
76
78
  const entryIsSelected = React.useMemo(
77
- () => selectedState?.id === item?.id,
78
- [selectedState?.id]
79
+ () => !!(selectedState?.id && selectedState?.id === item?.id),
80
+ [selectedState?.id, item?.id]
79
81
  );
80
82
 
81
83
  const elements = React.useMemo(
@@ -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);
@@ -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,11 +253,7 @@ const PlayerContainerComponent = (props: Props) => {
252
253
  }
253
254
 
254
255
  showNavBar(true);
255
-
256
- // Hack to close player screen on mobile only (tv handles that in InteractionManager)
257
- if (!isTV()) {
258
- navigator.goBack();
259
- }
256
+ navigator.goBack();
260
257
  }, [isModal, navigator.goBack, showNavBar]);
261
258
 
262
259
  const playEntry = (entry) => navigator.replaceTop(entry, { mode });
@@ -1,3 +1 @@
1
1
  export { useInitialFocus } from "./useInitialFocus";
2
-
3
- export { useRestoreFocus } from "./useRestoreFocus";