@applicaster/zapp-react-native-ui-components 12.0.0-alpha.5432134741 → 12.0.0-alpha.5468407101

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 (100) hide show
  1. package/Components/AudioPlayer/AudioPlayer.tsx +9 -1
  2. package/Components/AudioPlayer/__tests__/__snapshots__/audioPlayer.test.js.snap +5 -0
  3. package/Components/AudioPlayer/helpers.tsx +1 -0
  4. package/Components/Cell/Cell.tsx +2 -2
  5. package/Components/Cell/CellWithFocusable.tsx +21 -14
  6. package/Components/Cell/TvOSCellComponent.tsx +2 -2
  7. package/Components/ErrorScreen/index.tsx +1 -1
  8. package/Components/FocusableCell/index.tsx +7 -7
  9. package/Components/FocusableList/FocusableChild.ts +24 -14
  10. package/Components/FocusableList/FocusableItem.tsx +1 -1
  11. package/Components/FocusableList/FocusableListItemWrapper.tsx +76 -0
  12. package/Components/FocusableList/hooks/useCellState.android.ts +3 -1
  13. package/Components/FocusableList/index.tsx +26 -25
  14. package/Components/GeneralContentScreen/GeneralContentScreen.tsx +11 -8
  15. package/Components/GeneralContentScreen/utils/__tests__/useCurationAPI.test.js +13 -6
  16. package/Components/GeneralContentScreen/utils/useCurationAPI.ts +1 -1
  17. package/Components/HandlePlayable/HandlePlayable.tsx +1 -1
  18. package/Components/HookRenderer/index.tsx +1 -6
  19. package/Components/Image/Image.android.tsx +3 -25
  20. package/Components/Image/Image.tsx +18 -2
  21. package/Components/Image/utils/index.ts +39 -0
  22. package/Components/Layout/TV/__tests__/index.test.tsx +1 -34
  23. package/Components/Layout/TV/index.tsx +20 -36
  24. package/Components/MasterCell/DefaultComponents/BorderContainerView/index.tsx +0 -1
  25. package/Components/MasterCell/DefaultComponents/CellBadge/index.tsx +21 -8
  26. package/Components/MasterCell/DefaultComponents/Image/Image.android.tsx +9 -26
  27. package/Components/MasterCell/DefaultComponents/Image/Image.ios.tsx +5 -3
  28. package/Components/MasterCell/DefaultComponents/Image/hooks/useImageSize.ts +65 -0
  29. package/Components/MasterCell/DefaultComponents/LiveImage/index.tsx +17 -2
  30. package/Components/MasterCell/DefaultComponents/SecondaryImage/Image.tsx +3 -2
  31. package/Components/MasterCell/DefaultComponents/Toggle.tsx +5 -1
  32. package/Components/MasterCell/DefaultComponents/__tests__/image.test.js +1 -1
  33. package/Components/MasterCell/SharedUI/CollapsibleTextContainer/index.ts +6 -10
  34. package/Components/MasterCell/utils/index.ts +16 -5
  35. package/Components/ModalComponent/BottomSheetModalContent.tsx +121 -0
  36. package/Components/ModalComponent/Button/Item.tsx +82 -0
  37. package/Components/ModalComponent/Button/ItemIcon.tsx +60 -0
  38. package/Components/ModalComponent/Button/ItemLabel.tsx +101 -0
  39. package/Components/ModalComponent/Button/assets.ts +4 -0
  40. package/Components/ModalComponent/Button/index.tsx +111 -0
  41. package/Components/ModalComponent/Header/CloseButton.tsx +59 -0
  42. package/Components/ModalComponent/Header/Title.tsx +70 -0
  43. package/Components/ModalComponent/Header/assets.ts +4 -0
  44. package/Components/ModalComponent/Header/index.tsx +71 -0
  45. package/Components/ModalComponent/Header/utils.ts +79 -0
  46. package/Components/ModalComponent/index.tsx +38 -0
  47. package/Components/ModalComponent/utils.ts +126 -0
  48. package/Components/PlayerContainer/PlayerContainer.tsx +61 -30
  49. package/Components/PlayerContainer/ProgramInfo/index.tsx +3 -1
  50. package/Components/PlayerImageBackground/index.tsx +34 -8
  51. package/Components/River/ComponentsMap/ComponentsMap.tsx +91 -2
  52. package/Components/River/RefreshControl.tsx +55 -1
  53. package/Components/River/TV/River.tsx +2 -2
  54. package/Components/River/__tests__/__snapshots__/componentsMap.test.js.snap +1 -1
  55. package/Components/River/__tests__/componentsMap.test.js +7 -0
  56. package/Components/River/useScreenConfiguration.ts +2 -2
  57. package/Components/RouteManager/__tests__/__snapshots__/routeManager.test.js.snap +1 -0
  58. package/Components/RouteManager/__tests__/routeManager.test.js +9 -2
  59. package/Components/RouteManager/index.tsx +5 -3
  60. package/Components/Screen/__tests__/Screen.test.tsx +88 -74
  61. package/Components/Screen/__tests__/__snapshots__/Screen.test.tsx.snap +24 -6
  62. package/Components/Screen/__tests__/navigationHandler.test.ts +1 -178
  63. package/Components/Screen/index.tsx +103 -43
  64. package/Components/Screen/navigationHandler.ts +0 -82
  65. package/Components/ScreenResolver/index.tsx +1 -1
  66. package/Components/Tabs/TV/styles.ts +1 -1
  67. package/Components/TrackedView/index.tsx +6 -3
  68. package/Components/VideoLive/LiveImageManager.ts +37 -10
  69. package/Components/VideoLive/PlayerLiveImageComponent.tsx +81 -72
  70. package/Components/VideoLive/__tests__/PlayerLiveImageComponent.test.tsx +45 -3
  71. package/Components/VideoLive/__tests__/__snapshots__/PlayerLiveImageComponent.test.tsx.snap +18 -28
  72. package/Components/VideoModal/ModalAnimation/AnimatedPlayerModalWrapper.tsx +78 -0
  73. package/Components/VideoModal/ModalAnimation/AnimatedScrollModal.tsx +342 -0
  74. package/Components/VideoModal/ModalAnimation/AnimatedVideoPlayerComponent.tsx +151 -0
  75. package/Components/VideoModal/ModalAnimation/AnimationComponent.tsx +438 -0
  76. package/Components/VideoModal/ModalAnimation/ModalAnimationContext.tsx +154 -0
  77. package/Components/VideoModal/ModalAnimation/index.ts +15 -0
  78. package/Components/VideoModal/ModalAnimation/utils.ts +299 -0
  79. package/Components/VideoModal/PlayerDetails.tsx +3 -0
  80. package/Components/VideoModal/PlayerWrapper.tsx +65 -42
  81. package/Components/VideoModal/VideoModal.tsx +25 -42
  82. package/Components/VideoModal/__tests__/PlayerDetails.test.tsx +0 -2
  83. package/Components/VideoModal/__tests__/PlayerWrapper.test.tsx +5 -1
  84. package/Components/VideoModal/__tests__/__snapshots__/PlayerWrapper.test.tsx.snap +246 -166
  85. package/Components/VideoModal/utils.ts +3 -3
  86. package/Components/Viewport/ViewportAware/__tests__/viewportAware.test.js +26 -21
  87. package/Components/Viewport/ViewportTracker/ViewportTracker.tsx +1 -1
  88. package/Components/Viewport/ViewportTracker/__tests__/viewportTracker.test.js +4 -5
  89. package/Components/Viewport/ViewportTracker/index.tsx +1 -0
  90. package/Components/Viewport/utils.js +1 -1
  91. package/Components/ZappUIComponent/index.tsx +22 -12
  92. package/Components/index.js +2 -0
  93. package/Contexts/MenuToggleContext/{index.js → index.ts} +16 -0
  94. package/Contexts/ScreenContext/__tests__/__snapshots__/index.test.tsx.snap +3 -0
  95. package/Contexts/ScreenContext/__tests__/index.test.tsx +27 -0
  96. package/Contexts/ScreenContext/index.tsx +95 -29
  97. package/Decorators/ComponentsMapWrapper/withComponentsMapProvider.tsx +7 -2
  98. package/package.json +5 -5
  99. package/Components/VideoModal/hooks/usePosition.ts +0 -50
  100. /package/Contexts/{index.js → index.ts} +0 -0
@@ -23,6 +23,7 @@ type Props = {
23
23
  audio_player_summary_color?: string;
24
24
  audio_player_rtl?: boolean;
25
25
  magic_background?: boolean;
26
+ audio_player_background_image_query?: string;
26
27
  start_time?: string;
27
28
  end_time?: string;
28
29
  };
@@ -33,6 +34,7 @@ type Props = {
33
34
  audio_player_summary_color?: string;
34
35
  audio_player_rtl?: string;
35
36
  magic_background?: string;
37
+ audio_player_background_image_query?: string;
36
38
  audio_player_background_image?: string;
37
39
  audio_player_artwork_aspect_ratio?: string;
38
40
  lg_tv_audio_player_title_font_family?: string;
@@ -73,6 +75,11 @@ export function AudioPlayer(props: Props) {
73
75
  const channelIcon = getProp("audio_player_channel_icon");
74
76
  const rtlFlag = getProp("audio_player_rtl");
75
77
  const magicBackground = getProp("magic_background");
78
+
79
+ const audioPlayerBackgroundImageQuery = getProp(
80
+ "audio_player_background_image_query"
81
+ );
82
+
76
83
  const isRTL = rtlFlag === "1" || rtlFlag === "true" || rtlFlag === true;
77
84
 
78
85
  const titleFontFamily = getProp(
@@ -149,7 +156,8 @@ export function AudioPlayer(props: Props) {
149
156
  runTimeFontSize,
150
157
  artworkAspectRatio,
151
158
  channelIcon,
152
- magicBackground
159
+ magicBackground,
160
+ audioPlayerBackgroundImageQuery,
153
161
  };
154
162
  }, [getProp]);
155
163
 
@@ -5,6 +5,7 @@ exports[`<AudioPlayer /> renders correctly 1`] = `
5
5
  config={
6
6
  Object {
7
7
  "artworkAspectRatio": "1:1",
8
+ "audioPlayerBackgroundImageQuery": "",
8
9
  "backgroundColor": "black",
9
10
  "backgroundImage": "https://example.com",
10
11
  "channelIcon": "https://example.com",
@@ -26,6 +27,7 @@ exports[`<AudioPlayer /> renders correctly 1`] = `
26
27
  config={
27
28
  Object {
28
29
  "artworkAspectRatio": "1:1",
30
+ "audioPlayerBackgroundImageQuery": "",
29
31
  "backgroundColor": "black",
30
32
  "backgroundImage": "https://example.com",
31
33
  "channelIcon": "https://example.com",
@@ -47,6 +49,7 @@ exports[`<AudioPlayer /> renders correctly 1`] = `
47
49
  config={
48
50
  Object {
49
51
  "artworkAspectRatio": "1:1",
52
+ "audioPlayerBackgroundImageQuery": "",
50
53
  "backgroundColor": "black",
51
54
  "backgroundImage": "https://example.com",
52
55
  "channelIcon": "https://example.com",
@@ -68,6 +71,7 @@ exports[`<AudioPlayer /> renders correctly 1`] = `
68
71
  config={
69
72
  Object {
70
73
  "artworkAspectRatio": "1:1",
74
+ "audioPlayerBackgroundImageQuery": "",
71
75
  "backgroundColor": "black",
72
76
  "backgroundImage": "https://example.com",
73
77
  "channelIcon": "https://example.com",
@@ -96,6 +100,7 @@ exports[`<AudioPlayer /> renders correctly 1`] = `
96
100
  config={
97
101
  Object {
98
102
  "artworkAspectRatio": "1:1",
103
+ "audioPlayerBackgroundImageQuery": "",
99
104
  "backgroundColor": "black",
100
105
  "backgroundImage": "https://example.com",
101
106
  "channelIcon": "https://example.com",
@@ -5,6 +5,7 @@ const defaults = {
5
5
  audio_player_artwork_aspect_ratio: "1:1",
6
6
  audio_player_rtl: false,
7
7
  magic_background: false,
8
+ audio_player_background_image_query: "",
8
9
  };
9
10
 
10
11
  export function getPropertyFromEntryOrConfig({ entry, plugin_configuration }) {
@@ -202,7 +202,7 @@ export class CellComponent extends React.Component<Props> {
202
202
  groupId,
203
203
  isFocusable = true,
204
204
  skipFocusManagerRegistration,
205
- behavior
205
+ behavior,
206
206
  } = this.props;
207
207
 
208
208
  const { id } = item;
@@ -263,7 +263,7 @@ export class CellComponent extends React.Component<Props> {
263
263
  item,
264
264
  focused: this.isCellFocused(focused),
265
265
  scrollTo: this.scrollToIndex(event),
266
- behavior
266
+ behavior,
267
267
  }}
268
268
  />
269
269
  );
@@ -35,18 +35,18 @@ const useCellFocusedState = (groupId: string, id: string) => {
35
35
  };
36
36
 
37
37
  type Props = {
38
- item: ZappEntry,
39
- CellRenderer: React.ComponentType<{ item: Object, state: string }>,
40
- id: string,
41
- groupId: string,
42
- onFocus: Function,
43
- index: number,
44
- scrollTo: Function,
45
- preferredFocus?: boolean,
46
- skipFocusManagerRegistration?: boolean,
47
- isFocusable?: boolean,
48
- behavior: Behavior,
49
- selected?: boolean,
38
+ item: ZappEntry;
39
+ CellRenderer: React.ComponentType<{ item: Object; state: string }>;
40
+ id: string;
41
+ groupId: string;
42
+ onFocus: Function;
43
+ index: number;
44
+ scrollTo: Function;
45
+ preferredFocus?: boolean;
46
+ skipFocusManagerRegistration?: boolean;
47
+ isFocusable?: boolean;
48
+ behavior: Behavior;
49
+ selected?: boolean;
50
50
  };
51
51
 
52
52
  export function CellWithFocusable(props: Props) {
@@ -62,11 +62,18 @@ export function CellWithFocusable(props: Props) {
62
62
  skipFocusManagerRegistration,
63
63
  isFocusable,
64
64
  behavior,
65
- selected
65
+ selected,
66
66
  } = props;
67
67
 
68
68
  const isFocused = useCellFocusedState(groupId, id);
69
- const state = useCellState({ id: item.id, behavior, focused: isFocused, selected });
69
+
70
+ const state = useCellState({
71
+ id: item.id,
72
+ behavior,
73
+ focused: isFocused,
74
+ selected,
75
+ });
76
+
70
77
  const [focusedButtonId, setFocusedButtonId] = React.useState(undefined);
71
78
 
72
79
  // for horizontal scrolling
@@ -249,7 +249,7 @@ export class TvOSCellComponent extends React.Component<Props, State> {
249
249
  hasReceivedFocus,
250
250
  groupId,
251
251
  isFocusable,
252
- behavior
252
+ behavior,
253
253
  } = this.props;
254
254
 
255
255
  const { id } = item;
@@ -310,7 +310,7 @@ export class TvOSCellComponent extends React.Component<Props, State> {
310
310
  item,
311
311
  focused: this.props.focused || selectedCell || focused,
312
312
  scrollTo: this.scrollTo,
313
- behavior
313
+ behavior,
314
314
  }}
315
315
  />
316
316
  );
@@ -3,7 +3,6 @@ import * as R from "ramda";
3
3
  import {
4
4
  View,
5
5
  StyleSheet,
6
- Image,
7
6
  Text,
8
7
  ViewStyle,
9
8
  TextStyle,
@@ -13,6 +12,7 @@ import {
13
12
  import { defaultAsset } from "./defaultAsset";
14
13
  import { platformSelect } from "@applicaster/zapp-react-native-utils/reactUtils";
15
14
  import { useNavigation } from "@applicaster/zapp-react-native-utils/reactHooks";
15
+ import { QBImage as Image } from "@applicaster/zapp-react-native-ui-components/Components/Image";
16
16
  import { Button } from "./Button";
17
17
 
18
18
  type ButtonProp = {
@@ -3,12 +3,12 @@ import { Platform } from "react-native";
3
3
  import { useCellState } from "../MasterCell/utils";
4
4
 
5
5
  type Props = {
6
- index: number,
7
- item: ZappEntry,
8
- focused: boolean,
9
- scrollTo?: (index: number) => void,
10
- CellRenderer: React.ComponentType<{ item: Object, state: string }>,
11
- behavior: Behavior
6
+ index: number;
7
+ item: ZappEntry;
8
+ focused: boolean;
9
+ scrollTo?: (index: number) => void;
10
+ CellRenderer: React.ComponentType<{ item: Object; state: string }>;
11
+ behavior: Behavior;
12
12
  };
13
13
 
14
14
  const isAndroid = Platform.OS === "android";
@@ -20,7 +20,7 @@ export function FocusableCell(props: Props) {
20
20
  CellRenderer,
21
21
  focused,
22
22
  scrollTo = null,
23
- behavior
23
+ behavior,
24
24
  } = props;
25
25
 
26
26
  const state = useCellState({ id: item.id, behavior, focused });
@@ -1,28 +1,38 @@
1
1
  import * as React from "react";
2
2
  import { isEqual } from "@applicaster/zapp-react-native-utils/equalUtils";
3
- import { FocusableContext } from "../Focusable/index.android";
3
+ import { useFocusable } from "../Focusable/index.android";
4
4
  import { useCellState } from "./hooks/useCellState.android";
5
5
 
6
- function FocusableChildComponent(props) {
7
- const context = React.useContext(FocusableContext);
8
-
9
- const { setIsFocusable } = context || {};
10
-
11
- const nextFocusDown = props.nextFocusDown ?? context.nextFocusDown;
12
- const nextFocusUp = props.nextFocusUp ?? context.nextFocusUp;
13
- const nextFocusRight = props.nextFocusRight ?? context.nextFocusRight;
14
- const nextFocusLeft = props.nextFocusLeft ?? context.nextFocusLeft;
15
-
16
- const parentFocus = React.useMemo(
6
+ /**
7
+ * returns parent focus from prop or from context
8
+ * */
9
+ const useParentFocus = (
10
+ { nextFocusDown, nextFocusUp, nextFocusRight, nextFocusLeft },
11
+ context
12
+ ) =>
13
+ React.useMemo(
17
14
  () => ({
15
+ nextFocusRight: nextFocusRight ?? context.nextFocusRight,
16
+ nextFocusDown: nextFocusDown ?? context.nextFocusDown,
17
+ nextFocusLeft: nextFocusLeft ?? context.nextFocusLeft,
18
+ nextFocusUp: nextFocusUp ?? context.nextFocusUp,
19
+ }),
20
+ [
18
21
  nextFocusRight,
19
22
  nextFocusDown,
20
23
  nextFocusLeft,
21
24
  nextFocusUp,
22
- }),
23
- [nextFocusRight, nextFocusDown, nextFocusLeft, nextFocusUp]
25
+ context.nextFocusLeft,
26
+ context.nextFocusRight,
27
+ context.nextFocusUp,
28
+ context.nextFocusDown,
29
+ ]
24
30
  );
25
31
 
32
+ function FocusableChildComponent(props) {
33
+ const { setIsFocusable, ...focusableContext } = useFocusable();
34
+ const parentFocus = useParentFocus(props, focusableContext);
35
+
26
36
  const onLoadFailed = React.useCallback(() => {
27
37
  setIsFocusable(false);
28
38
  }, []);
@@ -1,5 +1,5 @@
1
1
  import * as React from "react";
2
- import { Focusable } from "../Focusable";
2
+ import { Focusable } from "../Focusable/index.android";
3
3
  import { FocusableChild } from "./FocusableChild";
4
4
  import { noop } from "@applicaster/zapp-react-native-utils/functionUtils";
5
5
  import { IListRenderItem } from "./index";
@@ -0,0 +1,76 @@
1
+ import * as React from "react";
2
+ import { ListRenderItemInfo as IListRenderItemInfo } from "react-native";
3
+ import { FocusableItem } from "./FocusableItem";
4
+
5
+ export type IListRenderItem<ItemT> = (
6
+ info: IListRenderItemInfo<ItemT> & {
7
+ focused: boolean;
8
+ onLoadFinished: () => void;
9
+ onLoadFailed: () => void;
10
+ }
11
+ ) => React.ReactElement | null;
12
+
13
+ type Item = ZappEntry | ZappUIComponent | any;
14
+
15
+ type Props = {
16
+ item: Item;
17
+ onFocus: (
18
+ element: FocusManager.FocusableRef,
19
+ renderArgs: { item: Item; index: number },
20
+ direction: FocusManager.Android.FocusNavigationDirections
21
+ ) => void;
22
+ onListElementBlur?: (any, RenderItemProps, Direction) => void;
23
+ onListElementPress?: (any, RenderItemProps) => void;
24
+ onListElementLongPress?: (any, RenderItemProps) => void;
25
+ onListElementPressOut?: (any, RenderItemProps) => void;
26
+ focusableItemProps: any;
27
+ id: string;
28
+ index: number;
29
+ extraData: any;
30
+ extraChildrenData: any;
31
+ renderItem: IListRenderItem<any> | null | undefined;
32
+ getNextFocus: (index: number) => ParentFocus;
33
+ } & ParentFocus;
34
+
35
+ export const FocusableListItemWrapper = React.memo(
36
+ ({
37
+ onFocus,
38
+ onListElementBlur,
39
+ onListElementPress,
40
+ onListElementLongPress,
41
+ onListElementPressOut,
42
+ focusableItemProps,
43
+ id,
44
+ getNextFocus,
45
+ item,
46
+ index,
47
+ extraData,
48
+ extraChildrenData,
49
+ renderItem,
50
+ }: Props) => {
51
+ const nextFocus = getNextFocus(index);
52
+
53
+ return (
54
+ <FocusableItem
55
+ nextFocusDown={nextFocus.nextFocusDown}
56
+ nextFocusRight={nextFocus.nextFocusRight}
57
+ nextFocusLeft={nextFocus.nextFocusLeft}
58
+ nextFocusUp={nextFocus.nextFocusUp}
59
+ id={id}
60
+ focusableItemProps={focusableItemProps}
61
+ onFocus={onFocus}
62
+ item={item}
63
+ index={index}
64
+ renderItem={renderItem}
65
+ extraChildrenData={extraChildrenData}
66
+ extraData={extraData}
67
+ onListElementBlur={onListElementBlur}
68
+ onListElementPress={onListElementPress}
69
+ onListElementLongPress={onListElementLongPress}
70
+ onListElementPressOut={onListElementPressOut}
71
+ />
72
+ );
73
+ }
74
+ );
75
+
76
+ FocusableListItemWrapper.displayName = "FocusableListItemWrapper";
@@ -5,7 +5,9 @@ import { useFocusManager } from "@applicaster/zapp-react-native-utils/focusManag
5
5
  export const useCellState = (id: string) => {
6
6
  const focusManager = useFocusManager();
7
7
 
8
- const [currentCellFocused, setCurrentCellFocused] = React.useState(false);
8
+ const [currentCellFocused, setCurrentCellFocused] = React.useState(
9
+ focusManager.isFocused(id)
10
+ );
9
11
 
10
12
  React.useEffect(() => {
11
13
  const handler = (focusable) => {
@@ -12,8 +12,9 @@ import { ChildrenFocusDeactivatorView } from "../ChildrenFocusDeactivatorView";
12
12
  import { useInitialFocus } from "@applicaster/zapp-react-native-utils/focusManager";
13
13
 
14
14
  import { noop } from "@applicaster/zapp-react-native-utils/functionUtils";
15
- import { FocusableItem } from "./FocusableItem";
15
+
16
16
  import { useParentFocus, useCheckItemIdsForUnique } from "./hooks";
17
+ import { FocusableListItemWrapper } from "./FocusableListItemWrapper";
17
18
 
18
19
  const mapIndexed = R.addIndex(R.map);
19
20
 
@@ -74,6 +75,8 @@ function FocusableListComponent<ItemT>(props: Props<ItemT>, ref) {
74
75
  nextFocusLeft: parentNextFocusLeft,
75
76
  nextFocusUp: parentNextFocusUp,
76
77
 
78
+ numColumns,
79
+
77
80
  focused: parentFocused,
78
81
 
79
82
  focusableItemProps,
@@ -103,8 +106,8 @@ function FocusableListComponent<ItemT>(props: Props<ItemT>, ref) {
103
106
  });
104
107
 
105
108
  const getFocusableEntryId = React.useCallback(
106
- (_entry: ZappEntry, index?: number) => {
107
- const entry = R.isNil(index) ? _entry : data[index];
109
+ (_entry: ZappEntry | null, index?: number) => {
110
+ const entry = R.isNil(index) ? _entry : data[index as number];
108
111
 
109
112
  return entry ? getFocusableId(props.id, index) : undefined;
110
113
  },
@@ -143,7 +146,6 @@ function FocusableListComponent<ItemT>(props: Props<ItemT>, ref) {
143
146
  const getNextFocus = React.useCallback(
144
147
  (index) => {
145
148
  const itemCount = R.length(data);
146
- const { numColumns } = props;
147
149
 
148
150
  const getFocusableEntryIdForIndex = (entryIndex) =>
149
151
  getFocusableEntryId(null, entryIndex);
@@ -160,22 +162,23 @@ function FocusableListComponent<ItemT>(props: Props<ItemT>, ref) {
160
162
  });
161
163
 
162
164
  const getGridFocus = () => {
163
- const numberOfRows = Math.ceil(itemCount / numColumns);
164
- const currentRowIndex = Math.floor(index / numColumns);
165
+ const _numColumns = toFiniteNumberWithDefault(1, numColumns);
166
+ const numberOfRows = Math.ceil(itemCount / _numColumns);
167
+ const currentRowIndex = Math.floor(index / _numColumns);
165
168
  const isFirstRow = currentRowIndex === 0;
166
169
  const isLastRow = currentRowIndex + 1 === numberOfRows;
167
- const isLeftEdge = index % numColumns === 0;
170
+ const isLeftEdge = index % _numColumns === 0;
168
171
 
169
172
  const isRightEdge =
170
- (index + 1) % numColumns === 0 || itemCount === index + 1;
173
+ (index + 1) % _numColumns === 0 || itemCount === index + 1;
171
174
 
172
175
  return {
173
176
  nextFocusUp: isFirstRow
174
177
  ? nextFocusUp
175
- : getFocusableEntryIdForIndex(index - numColumns),
178
+ : getFocusableEntryIdForIndex(index - _numColumns),
176
179
  nextFocusDown: isLastRow
177
180
  ? nextFocusDown
178
- : getFocusableEntryIdForIndex(index + numColumns),
181
+ : getFocusableEntryIdForIndex(index + _numColumns),
179
182
  nextFocusLeft: isLeftEdge
180
183
  ? nextFocusLeft
181
184
  : getFocusableEntryIdForIndex(index - 1),
@@ -215,26 +218,24 @@ function FocusableListComponent<ItemT>(props: Props<ItemT>, ref) {
215
218
  const renderItem = React.useCallback(
216
219
  ({ item, index }) => {
217
220
  const id = getFocusableId(props.id, index);
218
- const nextFocus = getNextFocus(index);
219
221
 
220
222
  return (
221
- <FocusableItem
222
- nextFocusDown={nextFocus.nextFocusDown}
223
- nextFocusRight={nextFocus.nextFocusRight}
224
- nextFocusLeft={nextFocus.nextFocusLeft}
225
- nextFocusUp={nextFocus.nextFocusUp}
226
- id={id}
223
+ <FocusableListItemWrapper
224
+ {...{
225
+ onFocus,
226
+ onListElementBlur,
227
+ onListElementPress,
228
+ onListElementLongPress,
229
+ onListElementPressOut,
230
+ }}
231
+ renderItem={props.renderItem}
227
232
  focusableItemProps={focusableItemProps}
228
- onFocus={onFocus}
233
+ getNextFocus={getNextFocus}
234
+ id={id}
229
235
  item={item}
230
236
  index={index}
231
- renderItem={props.renderItem}
232
- extraChildrenData={props.extraChildrenData}
233
237
  extraData={props.extraData}
234
- onListElementBlur={onListElementBlur}
235
- onListElementPress={onListElementPress}
236
- onListElementLongPress={onListElementLongPress}
237
- onListElementPressOut={onListElementPressOut}
238
+ extraChildrenData={props.extraChildrenData}
238
239
  />
239
240
  );
240
241
  },
@@ -287,7 +288,7 @@ function FocusableListComponent<ItemT>(props: Props<ItemT>, ref) {
287
288
  );
288
289
 
289
290
  const initialNumToRender = toFiniteNumberWithDefault(
290
- data.length,
291
+ 10,
291
292
  flatListProps.initialNumToRender
292
293
  );
293
294
 
@@ -52,13 +52,13 @@ export const GeneralContentScreen = ({
52
52
  React.useState(actionsInitialStateSetters.length === 0);
53
53
 
54
54
  useEffect(() => {
55
- log_info(
56
- `ScreenContainer: starting to check river action provider ready, current status: ${riverActionProvidersReady}`,
57
- { actionsInitialStateSetters }
58
- );
59
-
60
55
  if (!riverActionProvidersReady) {
61
56
  if (actionsInitialStateSetters.length > 0) {
57
+ log_info(
58
+ "ScreenContainer: starting to check river action providers to initialize",
59
+ { actionsInitialStateSetters }
60
+ );
61
+
62
62
  allSettled(actionsInitialStateSetters).finally(() => {
63
63
  log_info(
64
64
  "ScreenContainer: action provider ready, completed. Starting to present screen"
@@ -98,13 +98,16 @@ export const GeneralContentScreen = ({
98
98
 
99
99
  const isReady = useRiverActionProviderReady();
100
100
 
101
+ const contextValue = React.useMemo(
102
+ () => whenMatchingType(Function, cellTapAction) || onCellTapAction,
103
+ [typeof cellTapAction === "function" ? cellTapAction : onCellTapAction]
104
+ );
105
+
101
106
  if (!isReady || isNilOrEmpty(components || uiComponents)) return null;
102
107
 
103
108
  return (
104
109
  <ScreenTrackedViewPositionsContext.Provider>
105
- <CellTapContext.Provider
106
- value={whenMatchingType(Function, cellTapAction) || onCellTapAction}
107
- >
110
+ <CellTapContext.Provider value={contextValue}>
108
111
  <ComponentsMap
109
112
  feed={feed}
110
113
  riverId={screenId}
@@ -50,7 +50,11 @@ describe("getTransformedPreset should return the passed components if smartCompo
50
50
  );
51
51
 
52
52
  expect(transformed_preset).toBeDefined();
53
- expect(transformed_preset.id).toEqual("comp10"); // id was transformed
53
+
54
+ expect(transformed_preset.id).toEqual(
55
+ `${mockComp.id}-${mockPreset.feed_url}-0`
56
+ ); // id was transformed
57
+
54
58
  expect(transformed_preset.data.source).toEqual(mockPreset.feed_url); // source was replaced with preset feed_url.
55
59
  });
56
60
  });
@@ -117,7 +121,10 @@ describe("getTransformedPreset should return the passed components if smartCompo
117
121
 
118
122
  expect(Array.isArray(result)).toBe(true);
119
123
  expect(result).toHaveLength(2);
120
- expect(result[0].id).toEqual("smart10");
124
+
125
+ expect(result[0].id).toEqual(
126
+ `${mockSmartComp.id}-${mockFeeds.preset_source.data.entry[0].feed_url}-0`
127
+ );
121
128
 
122
129
  expect(result[0].data.source).toEqual(
123
130
  mockFeeds.preset_source.data.entry[0].feed_url
@@ -287,7 +294,7 @@ describe("getTransformedPreset should return the passed components if smartCompo
287
294
  mockComponents[0],
288
295
  {
289
296
  ...mockLayoutPresets.preset_one,
290
- id: mockComponents[1].id + 1,
297
+ id: `${mockComponents[1].id}-${mockPresetEntry[0].feed_url}-1`,
291
298
  data: { source: mockPresetEntry[0].feed_url },
292
299
  },
293
300
  ];
@@ -344,12 +351,12 @@ describe("getTransformedPreset should return the passed components if smartCompo
344
351
  const mockTransformedComponents = [
345
352
  {
346
353
  ...mockLayoutPresets.preset_one,
347
- id: mockComponents[0].id + 0,
354
+ id: `${mockComponents[0].id}-${mockPresetEntry1[0].feed_url}-0`,
348
355
  data: { source: mockPresetEntry1[0].feed_url },
349
356
  },
350
357
  {
351
358
  ...mockLayoutPresets.preset_one,
352
- id: mockComponents[1].id + 1,
359
+ id: `${mockComponents[1].id}-${mockPresetEntry2[0].feed_url}-1`,
353
360
  data: { source: mockPresetEntry2[0].feed_url },
354
361
  },
355
362
  ];
@@ -412,7 +419,7 @@ describe("getTransformedPreset should return the passed components if smartCompo
412
419
  const mockTransformedComponents = mockPresetEntry.map((preset, i) => {
413
420
  return {
414
421
  ...mockLayoutPresets[preset.preset_name],
415
- id: mockComponents[0].id + i,
422
+ id: `${mockComponents[0].id}-${preset.feed_url}-${i}`,
416
423
  data: { source: preset.feed_url },
417
424
  };
418
425
  });
@@ -41,7 +41,7 @@ export const getTransformedPreset = (
41
41
  }
42
42
 
43
43
  const updatedPresetComponent = produce(presetComponent, (draft) => {
44
- draft.id = `${componentId}${index}`;
44
+ draft.id = `${componentId}-${preset?.feed_url}-${index}`;
45
45
  draft.data.source = preset?.feed_url;
46
46
 
47
47
  if (draft.ui_components) {
@@ -104,7 +104,7 @@ export function HandlePlayable({
104
104
  const [Player, playerModuleProperties] = getPlayer(item, state);
105
105
 
106
106
  const { module: CastPlugin } =
107
- findPluginByIdentifier(CHROMECAST_PLUGIN_ID, state.plugins) || {};
107
+ findPluginByIdentifier(CHROMECAST_PLUGIN_ID, state.plugins, true) || {};
108
108
 
109
109
  const [playable, setPlayable] =
110
110
  React.useState<Nullable<PlayableComponent>>(null);
@@ -1,6 +1 @@
1
- import * as R from "ramda";
2
-
3
- import { withNavigator } from "@applicaster/zapp-react-native-ui-components/Decorators/Navigator/";
4
- import { HookRenderer as HookRendererComponent } from "./HookRenderer";
5
-
6
- export const HookRenderer = R.compose(withNavigator)(HookRendererComponent);
1
+ export { HookRenderer } from "./HookRenderer";
@@ -3,32 +3,10 @@ import FastImage, {
3
3
  FastImageProps,
4
4
  } from "@applicaster/react-native-fast-image";
5
5
 
6
- export const QBImage = (props: FastImageProps) => {
7
- const source = React.useMemo(() => {
8
- if (typeof props.source === "number") {
9
- return props.source;
10
- }
6
+ import { useImageSource } from "./utils";
11
7
 
12
- return {
13
- uri: props.source.uri,
14
- headers: props.source.headers,
15
- priority: props.source.priority,
16
- cache: props.source.cache,
17
- maxWidth: props.source.maxWidth,
18
- maxHeight: props.source.maxHeight,
19
- };
20
- }, [
21
- ...(typeof props.source === "object"
22
- ? [
23
- props.source?.uri,
24
- props.source?.priority,
25
- props.source?.cache,
26
- props.source?.headers,
27
- props.source?.maxWidth,
28
- props.source?.maxHeight,
29
- ]
30
- : []),
31
- ]);
8
+ export const QBImage = (props: FastImageProps) => {
9
+ const source = useImageSource(props.source);
32
10
 
33
11
  return <FastImage {...props} source={source} />;
34
12
  };