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

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 (67) 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/ErrorScreen/index.tsx +1 -1
  5. package/Components/FocusableList/FocusableChild.ts +24 -14
  6. package/Components/FocusableList/FocusableItem.tsx +1 -1
  7. package/Components/FocusableList/FocusableListItemWrapper.tsx +76 -0
  8. package/Components/FocusableList/hooks/useCellState.android.ts +3 -1
  9. package/Components/FocusableList/index.tsx +26 -25
  10. package/Components/GeneralContentScreen/GeneralContentScreen.tsx +11 -8
  11. package/Components/HandlePlayable/HandlePlayable.tsx +1 -1
  12. package/Components/HookRenderer/index.tsx +1 -4
  13. package/Components/Image/Image.android.tsx +3 -25
  14. package/Components/Image/Image.tsx +18 -2
  15. package/Components/Image/utils/index.ts +29 -0
  16. package/Components/Layout/TV/__tests__/index.test.tsx +0 -21
  17. package/Components/Layout/TV/index.tsx +20 -36
  18. package/Components/MasterCell/DefaultComponents/BorderContainerView/index.tsx +0 -1
  19. package/Components/MasterCell/DefaultComponents/CellBadge/index.tsx +21 -8
  20. package/Components/MasterCell/DefaultComponents/Image/Image.android.tsx +9 -26
  21. package/Components/MasterCell/DefaultComponents/Image/hooks/useImageSize.ts +65 -0
  22. package/Components/MasterCell/DefaultComponents/LiveImage/index.tsx +3 -1
  23. package/Components/MasterCell/DefaultComponents/SecondaryImage/Image.tsx +3 -2
  24. package/Components/MasterCell/SharedUI/CollapsibleTextContainer/index.ts +8 -10
  25. package/Components/MasterCell/utils/index.ts +2 -2
  26. package/Components/ModalComponent/BottomSheetModalContent.tsx +121 -0
  27. package/Components/ModalComponent/Button/Item.tsx +82 -0
  28. package/Components/ModalComponent/Button/ItemIcon.tsx +60 -0
  29. package/Components/ModalComponent/Button/ItemLabel.tsx +101 -0
  30. package/Components/ModalComponent/Button/assets.ts +4 -0
  31. package/Components/ModalComponent/Button/index.tsx +111 -0
  32. package/Components/ModalComponent/Header/CloseButton.tsx +59 -0
  33. package/Components/ModalComponent/Header/Title.tsx +70 -0
  34. package/Components/ModalComponent/Header/assets.ts +4 -0
  35. package/Components/ModalComponent/Header/index.tsx +71 -0
  36. package/Components/ModalComponent/Header/utils.ts +79 -0
  37. package/Components/ModalComponent/index.tsx +38 -0
  38. package/Components/ModalComponent/utils.ts +126 -0
  39. package/Components/PlayerContainer/ProgramInfo/index.tsx +3 -1
  40. package/Components/River/ComponentsMap/ComponentsMap.tsx +25 -0
  41. package/Components/River/TV/River.tsx +2 -2
  42. package/Components/River/__tests__/__snapshots__/componentsMap.test.js.snap +1 -1
  43. package/Components/River/useScreenConfiguration.ts +2 -2
  44. package/Components/RouteManager/__tests__/__snapshots__/routeManager.test.js.snap +1 -0
  45. package/Components/RouteManager/__tests__/routeManager.test.js +9 -2
  46. package/Components/RouteManager/index.tsx +5 -3
  47. package/Components/Screen/__tests__/Screen.test.tsx +83 -73
  48. package/Components/Screen/__tests__/__snapshots__/Screen.test.tsx.snap +10 -4
  49. package/Components/Screen/__tests__/navigationHandler.test.ts +1 -178
  50. package/Components/Screen/index.tsx +92 -45
  51. package/Components/Screen/navigationHandler.ts +0 -82
  52. package/Components/ScreenResolver/index.tsx +1 -1
  53. package/Components/TrackedView/index.tsx +6 -3
  54. package/Components/VideoLive/LiveImageManager.ts +37 -10
  55. package/Components/VideoLive/PlayerLiveImageComponent.tsx +81 -72
  56. package/Components/VideoLive/__tests__/PlayerLiveImageComponent.test.tsx +25 -3
  57. package/Components/VideoLive/__tests__/__snapshots__/PlayerLiveImageComponent.test.tsx.snap +22 -27
  58. package/Components/VideoModal/PlayerDetails.tsx +3 -0
  59. package/Components/VideoModal/PlayerWrapper.tsx +1 -1
  60. package/Components/VideoModal/__tests__/PlayerDetails.test.tsx +0 -2
  61. package/Components/VideoModal/__tests__/PlayerWrapper.test.tsx +1 -2
  62. package/Components/Viewport/ViewportAware/__tests__/viewportAware.test.js +26 -21
  63. package/Components/Viewport/ViewportTracker/__tests__/viewportTracker.test.js +4 -5
  64. package/Components/ZappUIComponent/index.tsx +22 -12
  65. package/Components/index.js +2 -0
  66. package/Contexts/ScreenContext/index.tsx +1 -4
  67. package/package.json +5 -5
@@ -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 }) {
@@ -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 = {
@@ -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}
@@ -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,3 @@
1
- import * as R from "ramda";
2
-
3
- import { withNavigator } from "@applicaster/zapp-react-native-ui-components/Decorators/Navigator/";
4
1
  import { HookRenderer as HookRendererComponent } from "./HookRenderer";
5
2
 
6
- export const HookRenderer = R.compose(withNavigator)(HookRendererComponent);
3
+ export const HookRenderer = HookRendererComponent;
@@ -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
  };
@@ -1,8 +1,24 @@
1
- import { Image, ImageProps, ImageStyle, StyleProp } from "react-native";
1
+ import React from "react";
2
+ import {
3
+ Image,
4
+ ImageBackground,
5
+ ImageProps,
6
+ ImageStyle,
7
+ StyleProp,
8
+ } from "react-native";
2
9
 
3
10
  export interface Props extends ImageProps {
4
11
  style?: StyleProp<ImageStyle> | undefined;
5
12
  }
6
13
 
7
14
  // TODO - React.FC<Props> QBImage should process incoming url and apply any transformations if needed
8
- export const QBImage = Image;
15
+ export const QBImage = ({
16
+ children,
17
+ ...props
18
+ }: Props & { children?: React.ReactNode }) => {
19
+ if (children) {
20
+ return <ImageBackground {...props}>{children}</ImageBackground>;
21
+ }
22
+
23
+ return <Image {...props} />;
24
+ };
@@ -0,0 +1,29 @@
1
+ import { useMemo } from "react";
2
+
3
+ export const useImageSource = (source) => {
4
+ return useMemo(() => {
5
+ if (typeof source === "number") {
6
+ return source;
7
+ }
8
+
9
+ return {
10
+ uri: source.uri,
11
+ headers: source.headers,
12
+ priority: source.priority,
13
+ cache: source.cache,
14
+ maxWidth: source.maxWidth,
15
+ maxHeight: source.maxHeight,
16
+ };
17
+ }, [
18
+ ...(typeof source === "object"
19
+ ? [
20
+ source?.uri,
21
+ source?.priority,
22
+ source?.cache,
23
+ source?.headers,
24
+ source?.maxWidth,
25
+ source?.maxHeight,
26
+ ]
27
+ : []),
28
+ ]);
29
+ };
@@ -125,25 +125,4 @@ describe("Layout TV", () => {
125
125
  expect(bgComponent.props.testProp).toBe(true);
126
126
  });
127
127
  });
128
-
129
- describe("props passed to navbar component", () => {
130
- it("passes correct props", () => {
131
- const { getByTestId } = render(
132
- <Layout
133
- Components={Components}
134
- ComponentsExtraProps={{
135
- NavBar: { testProp: true },
136
- }}
137
- >
138
- <Screen />
139
- </Layout>,
140
- { wrapper }
141
- );
142
-
143
- const navbarComponent = getByTestId("nav-bar-component");
144
- expect(navbarComponent.props.isVisible).toBe(isNavBarVisible);
145
- expect(navbarComponent.props.menuPlugin).toBe(plugins[0]);
146
- expect(navbarComponent.props.testProp).toBe(true);
147
- });
148
- });
149
128
  });
@@ -1,10 +1,7 @@
1
1
  import * as React from "react";
2
2
  import * as R from "ramda";
3
3
  import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
4
- import {
5
- useIsNavBarVisible,
6
- useNavigation,
7
- } from "@applicaster/zapp-react-native-utils/reactHooks/navigation";
4
+ import { useNavigation } from "@applicaster/zapp-react-native-utils/reactHooks/navigation";
8
5
  import { useTheme } from "@applicaster/zapp-react-native-utils/theme";
9
6
 
10
7
  import {
@@ -43,7 +40,7 @@ type Props = {
43
40
  const Layout = ({ Components, ComponentsExtraProps, children }: Props) => {
44
41
  const navigator = useNavigation();
45
42
  const theme = useTheme();
46
- const { title } = useNavbarState();
43
+ const { title, visible } = useNavbarState();
47
44
  const { activeRiver, currentRoute } = navigator;
48
45
 
49
46
  const {
@@ -80,10 +77,22 @@ const Layout = ({ Components, ComponentsExtraProps, children }: Props) => {
80
77
  []
81
78
  );
82
79
 
83
- const navBarVisible = useIsNavBarVisible();
84
-
85
80
  const [navBarReady, setNavBarReady] = React.useState(false);
86
81
 
82
+ const navBarContainer = (
83
+ <NavBarContainer isVisible={visible} onReady={setNavBarReady}>
84
+ <NavBar
85
+ ref={ComponentsExtraProps?.NavBar?.ref}
86
+ isVisible={visible && !routeIsPlayerScreen(currentRoute)}
87
+ menuPlugin={menuPlugin}
88
+ navigationProps={navigationProps}
89
+ {...R.omit(["ref"])(ComponentsExtraProps?.NavBar)}
90
+ />
91
+ </NavBarContainer>
92
+ );
93
+
94
+ const isTVOS = isApplePlatform();
95
+
87
96
  if (!appReady) {
88
97
  return null;
89
98
  }
@@ -96,18 +105,7 @@ const Layout = ({ Components, ComponentsExtraProps, children }: Props) => {
96
105
  backgroundImageUrl={backgroundImageUrl}
97
106
  {...R.omit(["ref"])(ComponentsExtraProps?.Background)}
98
107
  >
99
- {!isApplePlatform() ? (
100
- <NavBarContainer isVisible={navBarVisible} onReady={setNavBarReady}>
101
- <NavBar
102
- ref={ComponentsExtraProps?.NavBar?.ref}
103
- isVisible={navBarVisible && !routeIsPlayerScreen(currentRoute)}
104
- menuPlugin={menuPlugin}
105
- navigationProps={navigationProps}
106
- {...R.omit(["ref"])(ComponentsExtraProps?.NavBar)}
107
- />
108
- </NavBarContainer>
109
- ) : null}
110
-
108
+ {!isTVOS ? navBarContainer : null}
111
109
  {navBarReady ? (
112
110
  /**
113
111
  Need to re-mount this component on each navigation event
@@ -118,23 +116,9 @@ const Layout = ({ Components, ComponentsExtraProps, children }: Props) => {
118
116
  <ScreenContainer>{children}</ScreenContainer>
119
117
  </PathnameContext.Provider>
120
118
  ) : null}
121
-
122
- {isApplePlatform() ? (
123
- /**
124
- Render NavBarContainer over ScreenContainer to let tvOS native
125
- focus manager works correctly to focus nav bar items first
126
- **/
127
- <NavBarContainer isVisible={navBarVisible} onReady={setNavBarReady}>
128
- <NavBar
129
- ref={ComponentsExtraProps?.NavBar?.ref}
130
- isVisible={navBarVisible && !routeIsPlayerScreen(currentRoute)}
131
- menuPlugin={menuPlugin}
132
- navigationProps={navigationProps}
133
- {...R.omit(["ref"])(ComponentsExtraProps?.NavBar)}
134
- />
135
- </NavBarContainer>
136
- ) : null}
137
-
119
+ {/** Render NavBarContainer over ScreenContainer to let tvOS native
120
+ focus manager works correctly to focus nav bar items first **/}
121
+ {isTVOS ? navBarContainer : null}
138
122
  <TransitionOverlay />
139
123
  </Components.Background>
140
124
  </ScreenLayoutContextProvider>
@@ -152,7 +152,6 @@ export const BorderContainerView = (props: Props) => {
152
152
  ...updatedPaddings,
153
153
  width: updatedWidth,
154
154
  height: updatedHeight,
155
- ...borderStyleForMissingBorder,
156
155
  };
157
156
 
158
157
  return (