@applicaster/zapp-react-native-ui-components 13.0.0-rc.99 → 14.0.0-alpha.1216545755

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/index.tsx +15 -0
  2. package/Components/AudioPlayer/mobile/Layout.tsx +66 -0
  3. package/Components/AudioPlayer/{__tests__/__snapshots__/audioPlayer.test.js.snap → mobile/__tests__/__snapshots__/audioPlayerMobileLayout.test.js.snap} +2 -2
  4. package/Components/AudioPlayer/mobile/__tests__/audioPlayerMobileLayout.test.js +18 -0
  5. package/Components/AudioPlayer/mobile/index.tsx +18 -0
  6. package/Components/AudioPlayer/tv/Artwork.tsx +40 -0
  7. package/Components/AudioPlayer/{AudioPlayerLayout.tsx → tv/Layout.tsx} +37 -79
  8. package/Components/AudioPlayer/{Runtime.tsx → tv/Runtime.tsx} +2 -1
  9. package/Components/AudioPlayer/{Summary.tsx → tv/Summary.tsx} +12 -9
  10. package/Components/AudioPlayer/{Title.tsx → tv/Title.tsx} +12 -9
  11. package/Components/AudioPlayer/{__tests__ → tv/__tests__}/__snapshots__/artWork.test.js.snap +9 -4
  12. package/Components/AudioPlayer/tv/__tests__/__snapshots__/audioPlayer.test.js.snap +170 -0
  13. package/Components/AudioPlayer/{__tests__ → tv/__tests__}/__snapshots__/summary.test.js.snap +1 -1
  14. package/Components/AudioPlayer/{__tests__ → tv/__tests__}/__snapshots__/title.test.js.snap +1 -1
  15. package/Components/AudioPlayer/{__tests__ → tv/__tests__}/audioPlayer.test.js +7 -3
  16. package/Components/AudioPlayer/{helpers.tsx → tv/helpers.tsx} +3 -6
  17. package/Components/AudioPlayer/{AudioPlayer.tsx → tv/index.tsx} +14 -70
  18. package/Components/AudioPlayer/types.ts +40 -0
  19. package/Components/GeneralContentScreen/GeneralContentScreen.tsx +3 -2
  20. package/Components/GeneralContentScreen/utils/useCurationAPI.ts +4 -2
  21. package/Components/GeneralContentScreen/utils/useEventAlerts.ts +30 -0
  22. package/Components/MasterCell/DefaultComponents/Text/index.tsx +1 -0
  23. package/Components/MasterCell/utils/behaviorProvider.ts +82 -14
  24. package/Components/MasterCell/utils/index.ts +23 -3
  25. package/Components/ModalComponent/BottomSheetModalContent.tsx +32 -46
  26. package/Components/ModalComponent/Button/index.tsx +25 -29
  27. package/Components/ModalComponent/Header/index.tsx +9 -8
  28. package/Components/PlayerContainer/PlayerContainer.tsx +25 -42
  29. package/Components/PlayerImageBackground/index.tsx +1 -1
  30. package/Components/River/ComponentsMap/ComponentsMap.tsx +7 -3
  31. package/Components/River/RiverItem.tsx +8 -4
  32. package/Components/River/TV/River.tsx +0 -3
  33. package/Components/River/__tests__/__snapshots__/componentsMap.test.js.snap +1 -1
  34. package/Components/RouteManager/TestId.tsx +1 -5
  35. package/Components/RouteManager/__tests__/__snapshots__/routeManager.test.js.snap +0 -1
  36. package/Components/RouteManager/__tests__/testId.test.js +0 -4
  37. package/Components/Screen/TV/__tests__/index.web.test.tsx +26 -0
  38. package/Components/Screen/__tests__/Screen.test.tsx +22 -14
  39. package/Components/Screen/__tests__/__snapshots__/Screen.test.tsx.snap +2 -2
  40. package/Components/TopMarginApplicator/TopMarginApplicator.tsx +16 -15
  41. package/Components/Transitioner/Scene.tsx +1 -0
  42. package/Components/VideoModal/ModalAnimation/AnimationComponent.tsx +1 -2
  43. package/Components/VideoModal/ModalAnimation/ModalAnimationContext.tsx +1 -0
  44. package/Components/VideoModal/ModalAnimation/utils.ts +3 -9
  45. package/Components/VideoModal/PlayerWrapper.tsx +9 -19
  46. package/Components/VideoModal/__tests__/__snapshots__/PlayerWrapper.test.tsx.snap +60 -0
  47. package/Components/VideoModal/hooks/__tests__/useDelayedPlayerDetails.test.ts +17 -55
  48. package/Components/VideoModal/hooks/useDelayedPlayerDetails.ts +15 -26
  49. package/Contexts/ScreenDataContext/index.tsx +2 -0
  50. package/Decorators/RiverFeedLoader/index.tsx +8 -2
  51. package/Decorators/RiverFeedLoader/utils/index.ts +7 -2
  52. package/Decorators/ZappPipesDataConnector/index.tsx +20 -2
  53. package/index.d.ts +0 -1
  54. package/package.json +5 -6
  55. package/Components/AudioPlayer/Artwork.tsx +0 -35
  56. package/Components/AudioPlayer/__tests__/__snapshots__/audioPlayerLayout.test.js.snap +0 -66
  57. package/Components/AudioPlayer/__tests__/audioPlayerLayout.test.js +0 -26
  58. package/Components/AudioPlayer/index.ts +0 -1
  59. package/Decorators/Navigator/__tests__/react-router-native-mock.js +0 -11
  60. package/Components/AudioPlayer/{Channel.tsx → tv/Channel.tsx} +0 -0
  61. package/Components/AudioPlayer/{__tests__ → tv/__tests__}/Runtime.test.js +0 -0
  62. package/Components/AudioPlayer/{__tests__ → tv/__tests__}/__snapshots__/Runtime.test.js.snap +2 -2
  63. /package/Components/AudioPlayer/{__tests__ → tv/__tests__}/__snapshots__/channel.test.js.snap +0 -0
  64. /package/Components/AudioPlayer/{__tests__ → tv/__tests__}/artWork.test.js +0 -0
  65. /package/Components/AudioPlayer/{__tests__ → tv/__tests__}/channel.test.js +0 -0
  66. /package/Components/AudioPlayer/{__tests__ → tv/__tests__}/summary.test.js +0 -0
  67. /package/Components/AudioPlayer/{__tests__ → tv/__tests__}/title.test.js +0 -0
@@ -7,7 +7,6 @@ import { defaultSelectedAsset } from "./assets";
7
7
 
8
8
  type ButtonProps = {
9
9
  configuration: any;
10
- width: number;
11
10
  selectedItem?: any;
12
11
  item: any; // Adjust type as needed
13
12
  onPress: (item: any) => void; // Adjust type as needed
@@ -33,7 +32,6 @@ export function Button({
33
32
  item,
34
33
  onPress,
35
34
  configuration,
36
- width,
37
35
  iconBaseProps,
38
36
  itemBaseProps: itemProps,
39
37
  labelBaseProps,
@@ -65,34 +63,32 @@ export function Button({
65
63
  if (disabled) return null;
66
64
 
67
65
  return (
68
- <View style={{ maxWidth: width }}>
69
- <TouchableOpacity
70
- activeOpacity={1}
71
- onPress={() => onPress(item)}
72
- onPressIn={() => setFocused(true)}
73
- onPressOut={() => setFocused(false)}
74
- >
75
- <Item {...itemProps} focused={focused} selected={selected}>
76
- <View style={styles.label_icon_container}>
77
- {iconPlacement === "left" && renderItemIcon}
66
+ <TouchableOpacity
67
+ activeOpacity={1}
68
+ onPress={() => onPress(item)}
69
+ onPressIn={() => setFocused(true)}
70
+ onPressOut={() => setFocused(false)}
71
+ >
72
+ <Item {...itemProps} focused={focused} selected={selected}>
73
+ <View style={styles.label_icon_container}>
74
+ {iconPlacement === "left" && renderItemIcon}
78
75
 
79
- {label ? (
80
- <ItemLabel
81
- {...labelBaseProps}
82
- label={label ?? null}
83
- focused={focused}
84
- selected={selected}
85
- />
86
- ) : null}
87
- </View>
76
+ {label ? (
77
+ <ItemLabel
78
+ {...labelBaseProps}
79
+ label={label ?? null}
80
+ focused={focused}
81
+ selected={selected}
82
+ />
83
+ ) : null}
84
+ </View>
88
85
 
89
- {selected ? (
90
- <ItemIcon {...iconBaseProps} asset={selectedItemIconPropsAssets} />
91
- ) : (
92
- iconPlacement === "right" && renderItemIcon
93
- )}
94
- </Item>
95
- </TouchableOpacity>
96
- </View>
86
+ {selected ? (
87
+ <ItemIcon {...iconBaseProps} asset={selectedItemIconPropsAssets} />
88
+ ) : (
89
+ iconPlacement === "right" && renderItemIcon
90
+ )}
91
+ </Item>
92
+ </TouchableOpacity>
97
93
  );
98
94
  }
@@ -8,13 +8,18 @@ import { PluginConfiguration } from "../index";
8
8
  type Props = {
9
9
  dismiss: () => void;
10
10
  configuration: PluginConfiguration;
11
- width: number;
12
11
  onLayout?: (event: LayoutChangeEvent) => void;
13
12
  summary?: string;
14
13
  title?: string;
15
14
  };
16
15
 
17
16
  const styles = StyleSheet.create({
17
+ noFlex: {
18
+ flex: 0,
19
+ },
20
+ flex: {
21
+ flex: 1,
22
+ },
18
23
  container: {
19
24
  flexDirection: "row",
20
25
  alignItems: "center",
@@ -22,7 +27,7 @@ const styles = StyleSheet.create({
22
27
  });
23
28
 
24
29
  export function ModalHeader(props: Props) {
25
- const { configuration, dismiss, width, onLayout, summary, title } = props;
30
+ const { configuration, dismiss, onLayout, summary, title } = props;
26
31
 
27
32
  const closeButtonProps = useMemo<CloseButtonProps>(
28
33
  () => ({
@@ -55,15 +60,11 @@ export function ModalHeader(props: Props) {
55
60
 
56
61
  return (
57
62
  <View onLayout={onLayout} style={styles.container}>
58
- <View
59
- style={{
60
- width: width - buttonsContainerWidth,
61
- }}
62
- >
63
+ <View style={styles.flex}>
63
64
  {title ? <Title {...titleProps} /> : null}
64
65
  {summary ? <Title {...summaryProps} /> : null}
65
66
  </View>
66
- <View style={{ width: buttonsContainerWidth }}>
67
+ <View style={[styles.noFlex, { width: buttonsContainerWidth }]}>
67
68
  <CloseButton {...closeButtonProps} />
68
69
  </View>
69
70
  </View>
@@ -6,11 +6,15 @@ import * as R from "ramda";
6
6
  import uuid from "uuid/v4";
7
7
  import { playerManager } from "@applicaster/zapp-react-native-utils/appUtils/playerManager";
8
8
  import {
9
- isApplePlatform,
10
9
  isTV,
11
10
  platformSelect,
12
11
  isAndroidTVPlatform,
12
+ isTvOSPlatform,
13
13
  } from "@applicaster/zapp-react-native-utils/reactUtils";
14
+ import {
15
+ isAudioItem,
16
+ isInlineTV as isInlineTVUtil,
17
+ } from "@applicaster/zapp-react-native-utils/playerUtils";
14
18
 
15
19
  import { TVEventHandlerComponent } from "@applicaster/zapp-react-native-tvos-ui-components/Components/TVEventHandlerComponent";
16
20
  import { usePrevious } from "@applicaster/zapp-react-native-utils/reactHooks/utils";
@@ -21,7 +25,7 @@ import {
21
25
  } from "@applicaster/zapp-react-native-utils/reactHooks";
22
26
 
23
27
  import { PlayerStateContext } from "../../Contexts/PlayerStateContext";
24
- import { isAppleTV } from "../../Helpers/Platform";
28
+
25
29
  import {
26
30
  QUICK_BRICK_EVENTS,
27
31
  QuickBrickEvent,
@@ -96,6 +100,11 @@ const focusableBottomContainerId = "player-container-bottom";
96
100
 
97
101
  const isAndroidTV = isAndroidTVPlatform();
98
102
 
103
+ const isTvOS = isTvOSPlatform();
104
+
105
+ // height for container with additional content below player
106
+ const INLINE_CONTAINER_CONTENT_HEIGHT = 400;
107
+
99
108
  const withBorderHack = () => {
100
109
  if (isAndroidTV) {
101
110
  /* @HACK: see GH#7269 */
@@ -125,7 +134,7 @@ const webStyles = {
125
134
  flex: "initial",
126
135
  },
127
136
  inlineRiver: {
128
- height: 400,
137
+ height: INLINE_CONTAINER_CONTENT_HEIGHT,
129
138
  },
130
139
  };
131
140
 
@@ -143,7 +152,7 @@ const nativeStyles = {
143
152
  flex: 1,
144
153
  },
145
154
  inlineRiver: {
146
- height: 400,
155
+ height: INLINE_CONTAINER_CONTENT_HEIGHT,
147
156
  },
148
157
  };
149
158
 
@@ -163,12 +172,11 @@ const renderApplePlayer = ({
163
172
  videoStyle,
164
173
  playNextData,
165
174
  }) => {
166
- const { title, summary } = item || {};
167
-
168
- if (!isAppleTV() || !player) {
175
+ if (!isTvOS || !player) {
169
176
  return null;
170
177
  }
171
178
 
179
+ // render audio_player for tvos
172
180
  if (isAudioContent) {
173
181
  return (
174
182
  <AudioPlayer
@@ -182,6 +190,8 @@ const renderApplePlayer = ({
182
190
  return null;
183
191
  }
184
192
 
193
+ const { title, summary } = item || {};
194
+
185
195
  return (
186
196
  <ProgramInfo
187
197
  title={title}
@@ -192,21 +202,6 @@ const renderApplePlayer = ({
192
202
  );
193
203
  };
194
204
 
195
- const renderRestPlayers = ({ item, showAudioPlayer, pluginConfiguration }) => {
196
- if (isApplePlatform()) {
197
- return null;
198
- }
199
-
200
- return (
201
- showAudioPlayer && (
202
- <AudioPlayer
203
- audio_item={item}
204
- plugin_configuration={pluginConfiguration}
205
- />
206
- )
207
- );
208
- };
209
-
210
205
  const PlayerContainerComponent = (props: Props) => {
211
206
  const {
212
207
  Player,
@@ -336,7 +331,7 @@ const PlayerContainerComponent = (props: Props) => {
336
331
 
337
332
  setState({ error: errorObj });
338
333
 
339
- if (!isAppleTV()) {
334
+ if (!isTvOS) {
340
335
  setTimeout(() => {
341
336
  close();
342
337
  }, 800);
@@ -493,9 +488,7 @@ const PlayerContainerComponent = (props: Props) => {
493
488
  // TODO: Skip hook call on TV platform
494
489
  useBackHandler(backHandler);
495
490
 
496
- const isAudioContent =
497
- typeof item?.content?.type === "string" &&
498
- item?.content?.type.includes("audio");
491
+ const isAudioContent = isAudioItem(item);
499
492
 
500
493
  useEffect(() => {
501
494
  if (!isAudioContent) {
@@ -569,10 +562,7 @@ const PlayerContainerComponent = (props: Props) => {
569
562
 
570
563
  const uri = item?.content ? item.content?.src : null;
571
564
 
572
- const isInlineTV =
573
- screenData?.ui_components &&
574
- screenData?.ui_components?.length > 0 &&
575
- isTV();
565
+ const isInlineTV = isInlineTVUtil(screenData);
576
566
 
577
567
  const inline =
578
568
  [VideoModalMode.MAXIMIZED, VideoModalMode.MINIMIZED].includes(mode) ||
@@ -597,7 +587,7 @@ const PlayerContainerComponent = (props: Props) => {
597
587
  );
598
588
  }
599
589
 
600
- if (screen_background_color) {
590
+ if (screen_background_color && mode !== VideoModalMode.FULLSCREEN) {
601
591
  updatedStyles.playerScreen.backgroundColor = screen_background_color;
602
592
  }
603
593
 
@@ -615,6 +605,7 @@ const PlayerContainerComponent = (props: Props) => {
615
605
  tv_component_container_height,
616
606
  screen_background_color,
617
607
  isInlineTV,
608
+ mode,
618
609
  ]);
619
610
 
620
611
  const applePlayerProps = {
@@ -626,12 +617,6 @@ const PlayerContainerComponent = (props: Props) => {
626
617
  playNextData,
627
618
  };
628
619
 
629
- const restPlayerProps = {
630
- item,
631
- showAudioPlayer: isAudioContent,
632
- pluginConfiguration,
633
- };
634
-
635
620
  return (
636
621
  <PlayerStateContext.Provider value={value}>
637
622
  <PlayerContainerContextProvider
@@ -707,8 +692,6 @@ const PlayerContainerComponent = (props: Props) => {
707
692
  </Player>
708
693
  </PlayerFocusableWrapperView>
709
694
 
710
- {renderRestPlayers(restPlayerProps)}
711
-
712
695
  {state.error ? <ErrorDisplay error={state.error} /> : null}
713
696
  </View>
714
697
  {/* Components container */}
@@ -732,12 +715,12 @@ const PlayerContainerComponent = (props: Props) => {
732
715
  screenId={screenData.id}
733
716
  key={item.id}
734
717
  groupId={FocusableGroupMainContainerId}
735
- cellTapAction={(event) => onCellTap(event)}
736
- extraAnchorPointYOffset={-600}
718
+ cellTapAction={onCellTap}
719
+ extraAnchorPointYOffset={0}
737
720
  isScreenWrappedInContainer={true}
738
721
  containerHeight={styles.inlineRiver.height}
739
722
  componentsMapExtraProps={{
740
- isNestedComponentsMap: R.T,
723
+ isNestedComponentsMap: true,
741
724
  }}
742
725
  />
743
726
  )}
@@ -28,7 +28,7 @@ const PlayerImageBackgroundComponent = ({
28
28
  defaultImageDimensions,
29
29
  }: Props) => {
30
30
  const source = React.useMemo(
31
- () => ({ uri: imageSrcFromMediaItem(entry, imageKey) }),
31
+ () => ({ uri: imageSrcFromMediaItem(entry, [imageKey]) }),
32
32
  [imageKey, entry]
33
33
  );
34
34
 
@@ -1,6 +1,6 @@
1
1
  import * as React from "react";
2
2
  import * as R from "ramda";
3
- import { View, StyleSheet, Platform, FlatList } from "react-native";
3
+ import { View, StyleSheet, FlatList } from "react-native";
4
4
  import { useTheme } from "@applicaster/zapp-react-native-utils/theme";
5
5
  import { RiverItem } from "../RiverItem";
6
6
  import { RiverFooter } from "../RiverFooter";
@@ -24,6 +24,10 @@ import { withComponentsMapProvider } from "@applicaster/zapp-react-native-ui-com
24
24
  import { useScreenContextV2 } from "@applicaster/zapp-react-native-utils/reactHooks/screen/useScreenContext";
25
25
  import { useShallow } from "zustand/react/shallow";
26
26
 
27
+ import { isAndroidPlatform } from "@applicaster/zapp-react-native-utils/reactUtils";
28
+
29
+ const isAndroid = isAndroidPlatform();
30
+
27
31
  type Props = {
28
32
  feed: ZappFeed;
29
33
  groupId?: string;
@@ -273,12 +277,12 @@ function ComponentsMapComponent(props: Props) {
273
277
  }}
274
278
  // Fix for WebView rerender crashes on Android API 28+
275
279
  // https://github.com/react-native-webview/react-native-webview/issues/1915#issuecomment-964035468
276
- overScrollMode={Platform.OS === "android" ? "never" : "auto"}
280
+ overScrollMode={isAndroid ? "never" : "auto"}
277
281
  scrollIndicatorInsets={scrollIndicatorInsets}
278
282
  extraData={feed}
279
283
  stickyHeaderIndices={stickyHeaderIndices}
284
+ removeClippedSubviews={isAndroid}
280
285
  onLayout={handleOnLayout}
281
- removeClippedSubviews
282
286
  initialNumToRender={3}
283
287
  maxToRenderPerBatch={10}
284
288
  windowSize={12}
@@ -39,6 +39,10 @@ function getFeedUrl(feed: ZappFeed, index: number) {
39
39
  }
40
40
  }
41
41
 
42
+ const isNextIndex = (index, readyIndex) => {
43
+ return readyIndex + 1 >= index;
44
+ };
45
+
42
46
  /**
43
47
  * useLoadingState for RiverItemComponent
44
48
  * takes currentIndex and loadingState as arguments
@@ -48,12 +52,12 @@ const useLoadingState = (
48
52
  loadingState: RiverItemType["loadingState"]
49
53
  ) => {
50
54
  const [readyToBeDisplayed, setReadyToBeDisplayed] = React.useState(
51
- loadingState.getValue().index + 1 === currentIndex
55
+ isNextIndex(currentIndex, loadingState.getValue().index)
52
56
  );
53
57
 
54
58
  useEffect(() => {
55
59
  const subscription = loadingState.subscribe(({ index }) => {
56
- if (index + 1 === currentIndex) {
60
+ if (isNextIndex(currentIndex, index)) {
57
61
  setReadyToBeDisplayed(true);
58
62
  }
59
63
  });
@@ -61,7 +65,7 @@ const useLoadingState = (
61
65
  return () => {
62
66
  subscription.unsubscribe();
63
67
  };
64
- }, [loadingState, currentIndex]);
68
+ }, [currentIndex]);
65
69
 
66
70
  return readyToBeDisplayed;
67
71
  };
@@ -147,7 +151,7 @@ function RiverItemComponent(props: RiverItemType) {
147
151
  component={item}
148
152
  componentIndex={index}
149
153
  onLoadFailed={onLoadFailed}
150
- onLoadFinished={() => onLoadFinished(index)} // Keeping it here to don't break the plugins.
154
+ onLoadFinished={() => onLoadFinished(index)}
151
155
  groupId={groupId}
152
156
  feedUrl={feedUrl}
153
157
  isLast={isLast}
@@ -26,7 +26,6 @@ type Props = {
26
26
  componentsMapExtraProps?: any;
27
27
  isInsideContainer?: boolean;
28
28
  extraAnchorPointYOffset: number;
29
- extraOffset: number;
30
29
  river?: ZappRiver | ZappEntry;
31
30
  };
32
31
 
@@ -39,7 +38,6 @@ export const River = (props: Props) => {
39
38
  componentsMapExtraProps,
40
39
  isInsideContainer,
41
40
  extraAnchorPointYOffset,
42
- extraOffset,
43
41
  } = props;
44
42
 
45
43
  const { title: screenTitle, summary: screenSummary } = useNavbarState();
@@ -120,7 +118,6 @@ export const River = (props: Props) => {
120
118
  <GeneralContentScreen
121
119
  feed={feedData}
122
120
  screenId={screenId}
123
- extraOffset={extraOffset}
124
121
  isScreenWrappedInContainer={isInsideContainer}
125
122
  extraAnchorPointYOffset={extraAnchorPointYOffset}
126
123
  componentsMapExtraProps={componentsMapExtraProps}
@@ -145,7 +145,7 @@ exports[`componentsMap renders renders components map correctly 1`] = `
145
145
  onScrollEndDrag={[Function]}
146
146
  overScrollMode="auto"
147
147
  refreshControl={null}
148
- removeClippedSubviews={true}
148
+ removeClippedSubviews={false}
149
149
  renderItem={[Function]}
150
150
  scrollEventThrottle={16}
151
151
  scrollIndicatorInsets={
@@ -12,11 +12,7 @@ const styles = StyleSheet.create({
12
12
 
13
13
  export function TestId({ screenId, children }: Props) {
14
14
  return (
15
- <View
16
- testID={screenId}
17
- accessibilityLabel={screenId}
18
- style={styles.container}
19
- >
15
+ <View testID={screenId} style={styles.container}>
20
16
  {children}
21
17
  </View>
22
18
  );
@@ -2,7 +2,6 @@
2
2
 
3
3
  exports[`<RouteManager /> renders correctly 1`] = `
4
4
  <View
5
- accessibilityLabel="A1234"
6
5
  style={
7
6
  {
8
7
  "flex": 1,
@@ -24,9 +24,5 @@ describe("TestId", () => {
24
24
  );
25
25
 
26
26
  expect(wrapper.getByTestId(screenId)).toBeTruthy();
27
-
28
- expect(wrapper.getByTestId(screenId).props.accessibilityLabel).toEqual(
29
- screenId
30
- );
31
27
  });
32
28
  });
@@ -0,0 +1,26 @@
1
+ const {
2
+ useScreenBackgroundColor,
3
+ } = require("@applicaster/zapp-react-native-utils/reactHooks/screen");
4
+
5
+ jest.mock("@applicaster/zapp-react-native-utils/reactHooks/screen", () => ({
6
+ useScreenBackgroundColor: jest.fn(),
7
+ useNavbarState: jest.fn().mockReturnValue({ visible: true }),
8
+ }));
9
+
10
+ describe("TV Screen Component", () => {
11
+ it("uses the useScreenBackgroundColor hook with the correct screen ID", () => {
12
+ useScreenBackgroundColor.mockReturnValue("#FF0000");
13
+
14
+ expect(useScreenBackgroundColor("test-screen-id")).toBe("#FF0000");
15
+
16
+ // Verify the hook was called with the correct screen ID
17
+ expect(useScreenBackgroundColor).toHaveBeenCalledWith("test-screen-id");
18
+ });
19
+
20
+ it("returns 'transparent' when the screen background color is not defined", () => {
21
+ useScreenBackgroundColor.mockReturnValue("transparent");
22
+
23
+ // Verify the hook returns 'transparent'
24
+ expect(useScreenBackgroundColor("test-screen-id")).toBe("transparent");
25
+ });
26
+ });
@@ -68,21 +68,21 @@ jest.mock(
68
68
  })
69
69
  );
70
70
 
71
- jest.mock(
72
- "@applicaster/zapp-react-native-utils/reactHooks/screen/useScreenData",
73
- () => ({
74
- useScreenData: jest.fn(() => ({
75
- id: "testId",
76
- navigations: [{ id: "testId", category: "nav_bar" }],
77
- })),
78
- })
79
- );
80
-
81
71
  jest.mock("@applicaster/zapp-react-native-utils/reactHooks/navigation", () => ({
82
72
  isNavBarVisible: mockIsNavBarVisible,
83
- useRoute: jest.fn(() => ({
84
- pathname: "/river/testId",
85
- screenData: { id: "testId" },
73
+ useIsScreenActive: jest.fn().mockReturnValue(true),
74
+ }));
75
+
76
+ jest.mock("@applicaster/zapp-react-native-utils/reactHooks", () => ({
77
+ useCurrentScreenData: jest.fn(() => ({
78
+ id: "testId",
79
+ })),
80
+ useNavbarState: jest.fn(() => ({
81
+ title: "Test Title",
82
+ })),
83
+ useScreenData: jest.fn(() => ({
84
+ id: "testId",
85
+ navigations: [{ id: "testId", category: "nav_bar" }],
86
86
  })),
87
87
  useNavigation: jest.fn(() => ({
88
88
  canGoBack: () => false,
@@ -91,7 +91,15 @@ jest.mock("@applicaster/zapp-react-native-utils/reactHooks/navigation", () => ({
91
91
  screenData: { id: "testId" },
92
92
  data: { screen: { id: "testId" } },
93
93
  })),
94
- useIsScreenActive: jest.fn().mockReturnValue(true),
94
+ useRoute: jest.fn(() => ({
95
+ pathname: "/river/testId",
96
+ screenData: { id: "testId" },
97
+ })),
98
+ useDimensions: jest.fn(() => ({
99
+ width: 1920,
100
+ height: 1080,
101
+ })),
102
+ useIsTablet: jest.fn(() => false),
95
103
  }));
96
104
 
97
105
  jest.mock("@applicaster/zapp-react-native-redux/hooks/usePickFromState", () => {
@@ -16,7 +16,7 @@ exports[`<Screen Component /> when the navbar should be hidden renders correctly
16
16
  pathname="/river/testId"
17
17
  selected="testId"
18
18
  testID="navBar"
19
- title=""
19
+ title="Test Title"
20
20
  />
21
21
  <View>
22
22
  <View
@@ -48,7 +48,7 @@ exports[`<Screen Component /> when the navbar should show renders correctly 1`]
48
48
  pathname="/river/testId"
49
49
  selected="testId"
50
50
  testID="navBar"
51
- title=""
51
+ title="Test Title"
52
52
  />
53
53
  <View>
54
54
  <View
@@ -1,17 +1,17 @@
1
1
  import React from "react";
2
- import { View, ViewProps, ViewStyle } from "react-native";
2
+ import { View, ViewStyle } from "react-native";
3
3
  import { useTheme } from "@applicaster/zapp-react-native-utils/theme";
4
4
  import { useCurrentScreenData } from "@applicaster/zapp-react-native-utils/reactHooks";
5
5
  import { isFirstComponentScreenPicker } from "@applicaster/zapp-react-native-utils/componentsUtils";
6
+ import { toNumberWithDefault } from "@applicaster/zapp-react-native-utils/numberUtils";
6
7
 
7
8
  interface IProps {
8
9
  targetScreenId?: string;
9
10
  children?: React.ReactNode;
10
11
  style?: ViewStyle;
11
- extraOffset?: number;
12
+ extraVerticalOffset: Option<number>;
12
13
  }
13
14
 
14
- type CombinedProps = IProps & ViewProps;
15
15
  /**
16
16
  * The MarginTop is essentially a feature used for managing the visibility of components on your screen.
17
17
  * A more accurate term for this might be something like a 'component visibility threshold' or 'cut-off point'.
@@ -47,7 +47,7 @@ export const useMarginTop = (targetScreenId: string): number => {
47
47
 
48
48
  // Empty string means that value is blank in the CMS. Fallback to theme
49
49
  if (String(screenData?.styles?.screen_margin_top) === "") {
50
- return Number(theme.screen_margin_top);
50
+ return toNumberWithDefault(0, theme.screen_margin_top);
51
51
  }
52
52
 
53
53
  /**
@@ -58,28 +58,29 @@ export const useMarginTop = (targetScreenId: string): number => {
58
58
  */
59
59
  if (screenData?.styles?.screen_margin_top === undefined) {
60
60
  if (isGeneralContentScreen || supportsUiComponents) {
61
- return Number(theme.screen_margin_top);
61
+ return toNumberWithDefault(0, theme.screen_margin_top);
62
62
  }
63
63
 
64
64
  return 0;
65
65
  }
66
66
 
67
- return Number(screenData?.styles?.screen_margin_top);
67
+ return toNumberWithDefault(0, screenData?.styles?.screen_margin_top);
68
68
  };
69
69
 
70
- export const TopMarginApplicator: React.FC<CombinedProps> = (
71
- props: CombinedProps
72
- ) => {
73
- const extraOffset = props?.extraOffset ?? 0;
70
+ export const TopMarginApplicator: React.FC<IProps> = ({
71
+ targetScreenId,
72
+ style,
73
+ children,
74
+ extraVerticalOffset,
75
+ }: IProps) => {
76
+ const extraOffset = toNumberWithDefault(0, extraVerticalOffset);
74
77
 
75
78
  // HACK: Remove extraOffset when focusIssue with absolute elements is fixed on tvos
76
- const marginTop = useMarginTop(props.targetScreenId) + extraOffset;
77
- const style = { ...((props.style as {}) || {}), marginTop };
79
+ const marginTop = useMarginTop(targetScreenId);
78
80
 
79
- // Then, spread the rest of the props on your returned JSX.
80
81
  return (
81
- <View {...props} style={style}>
82
- {props.children}
82
+ <View style={[style, { marginTop: marginTop + extraOffset }]}>
83
+ {children}
83
84
  </View>
84
85
  );
85
86
  };
@@ -36,6 +36,7 @@ export function CurrentScreenContextProvider({
36
36
  screenData: NavigationScreenData;
37
37
  }) {
38
38
  const { pathname, isActive = false, screenData } = props;
39
+ console.log("CurrentScreenContextProvider", { screenData });
39
40
 
40
41
  const [initialScreenData, setInitialScreenData] = React.useState(screenData);
41
42
 
@@ -94,7 +94,7 @@ export const AnimationView = ({
94
94
  const isAudioItem = React.useMemo(
95
95
  () =>
96
96
  videoModalItem?.content?.type?.includes?.("audio") ||
97
- videoModalItem?.type?.value === "audio",
97
+ videoModalItem?.type?.value?.includes?.("audio"),
98
98
  [videoModalItem]
99
99
  );
100
100
 
@@ -107,7 +107,6 @@ export const AnimationView = ({
107
107
  progressBarHeight,
108
108
  isTablet,
109
109
  isTabletLandscape,
110
- inlineAudioPlayer,
111
110
  tabletLandscapePlayerTopPosition,
112
111
  });
113
112
 
@@ -17,6 +17,7 @@ export enum PlayerAnimationStateEnum {
17
17
  maximize = "maximize",
18
18
  drag_player = "drag_player",
19
19
  drag_scroll = "drag_scroll",
20
+ appear_as_docked = "appear_as_docked",
20
21
  }
21
22
 
22
23
  export type PlayerAnimationStateT = number | PlayerAnimationStateEnum | null;