@applicaster/zapp-react-native-ui-components 14.0.0-rc.1 → 14.0.0-rc.11

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 (25) hide show
  1. package/Components/AudioPlayer/Artwork.tsx +17 -12
  2. package/Components/AudioPlayer/AudioPlayer.tsx +2 -0
  3. package/Components/AudioPlayer/AudioPlayerLayout.tsx +7 -7
  4. package/Components/AudioPlayer/Runtime.tsx +2 -1
  5. package/Components/AudioPlayer/Summary.tsx +12 -9
  6. package/Components/AudioPlayer/Title.tsx +12 -9
  7. package/Components/AudioPlayer/__tests__/__snapshots__/Runtime.test.js.snap +2 -2
  8. package/Components/AudioPlayer/__tests__/__snapshots__/artWork.test.js.snap +9 -4
  9. package/Components/AudioPlayer/__tests__/__snapshots__/summary.test.js.snap +1 -1
  10. package/Components/AudioPlayer/__tests__/__snapshots__/title.test.js.snap +1 -1
  11. package/Components/AudioPlayer/helpers.tsx +2 -2
  12. package/Components/GeneralContentScreen/GeneralContentScreen.tsx +0 -2
  13. package/Components/MasterCell/DefaultComponents/Text/index.tsx +1 -0
  14. package/Components/PlayerContainer/PlayerContainer.tsx +24 -38
  15. package/Components/River/ComponentsMap/ComponentsMap.tsx +1 -5
  16. package/Components/River/RiverItem.tsx +8 -8
  17. package/Components/River/TV/River.tsx +0 -3
  18. package/Components/River/__tests__/__snapshots__/componentsMap.test.js.snap +0 -6
  19. package/Components/TopMarginApplicator/TopMarginApplicator.tsx +16 -15
  20. package/Components/VideoModal/__tests__/__snapshots__/PlayerWrapper.test.tsx.snap +60 -0
  21. package/Components/VideoModal/hooks/__tests__/useDelayedPlayerDetails.test.ts +17 -55
  22. package/Components/VideoModal/hooks/useDelayedPlayerDetails.ts +15 -26
  23. package/index.d.ts +0 -1
  24. package/package.json +5 -6
  25. package/Decorators/Navigator/__tests__/react-router-native-mock.js +0 -11
@@ -1,5 +1,16 @@
1
1
  import React from "react";
2
- import { View, Image } from "react-native";
2
+ import { View, Image, StyleSheet } from "react-native";
3
+ import { toNumberWithDefaultZero } from "@applicaster/zapp-react-native-utils/numberUtils";
4
+
5
+ const styles = StyleSheet.create({
6
+ container: {
7
+ marginHorizontal: 24,
8
+ },
9
+ image: {
10
+ width: 400,
11
+ height: 400,
12
+ },
13
+ });
3
14
 
4
15
  type Props = {
5
16
  srcImage: string;
@@ -9,25 +20,19 @@ type Props = {
9
20
  backgroundColor: string;
10
21
  backgroundImage: string;
11
22
  isRTL: boolean;
23
+ artworkBorderRadius: Option<number>;
12
24
  };
13
25
  };
14
26
 
15
- const containerStyles = {
16
- marginHorizontal: 24,
17
- };
18
-
19
- const imageStyles = {
20
- width: 400,
21
- height: 400,
22
- };
27
+ export function Artwork({ srcImage, config }: Props) {
28
+ const borderRadius = toNumberWithDefaultZero(config.artworkBorderRadius);
23
29
 
24
- export function Artwork({ srcImage }: Props) {
25
30
  return (
26
- <View style={containerStyles}>
31
+ <View style={styles.container}>
27
32
  <Image
28
33
  fadeDuration={0}
29
34
  source={{ uri: srcImage }}
30
- style={imageStyles}
35
+ style={[styles.image, { borderRadius }]}
31
36
  resizeMode="cover"
32
37
  />
33
38
  </View>
@@ -72,6 +72,7 @@ export function AudioPlayer(props: Props) {
72
72
  const artworkAspectRatio = getProp("audio_player_artwork_aspect_ratio");
73
73
  const channelIcon = getProp("audio_player_channel_icon");
74
74
  const rtlFlag = getProp("audio_player_rtl");
75
+ const artworkBorderRadius = getProp("audio_player_artwork_border_radius");
75
76
 
76
77
  const audioPlayerBackgroundImageDefaultColor = getProp(
77
78
  "audio_player_background_image_default_color"
@@ -154,6 +155,7 @@ export function AudioPlayer(props: Props) {
154
155
  artworkAspectRatio,
155
156
  channelIcon,
156
157
  audioPlayerBackgroundImageDefaultColor,
158
+ artworkBorderRadius,
157
159
  };
158
160
  }, [getProp]);
159
161
 
@@ -14,6 +14,7 @@ type Props = {
14
14
  backgroundColor: string;
15
15
  backgroundImage: string;
16
16
  isRTL: boolean;
17
+ artworkBorderRadius: Option<number>;
17
18
  };
18
19
  children: React.ReactNode;
19
20
  style: ViewStyle;
@@ -40,17 +41,16 @@ export function AudioPlayerLayout({ artwork, config, children, style }: Props) {
40
41
 
41
42
  const mainContainerStyles = platformSelect({
42
43
  tvos: {
43
- width: 1920,
44
- height: 1080,
44
+ width: "100%",
45
+ height: "100%",
45
46
  alignItems: "center",
46
47
  justifyContent: "center",
47
48
  flexDirection: directionStyles(isRTL).flexDirection,
48
49
  backgroundColor: backgroundColorStyle,
49
50
  },
50
51
  android_tv: {
51
- position: "absolute",
52
- width: 1920,
53
- height: 1080,
52
+ width: "100%",
53
+ height: "100%",
54
54
  alignItems: "center",
55
55
  justifyContent: "center",
56
56
  flexDirection: directionStyles(isRTL).flexDirection,
@@ -97,8 +97,8 @@ export function AudioPlayerLayout({ artwork, config, children, style }: Props) {
97
97
 
98
98
  const backgroundImgStyles = platformSelect({
99
99
  tvos: {
100
- width: 1920,
101
- height: 1080,
100
+ width: "100%",
101
+ height: "100%",
102
102
  alignItems: "center",
103
103
  justifyContent: "center",
104
104
  },
@@ -1,5 +1,6 @@
1
1
  import React from "react";
2
2
  import { View, Text, ViewStyle, TextStyle } from "react-native";
3
+ import { toNumberWithDefault } from "@applicaster/zapp-react-native-utils/numberUtils";
3
4
  import { directionStyles } from "./helpers";
4
5
 
5
6
  type Props = {
@@ -31,7 +32,7 @@ const textStyles = ({
31
32
  }) => ({
32
33
  color: summaryColor,
33
34
  opacity: 0.8,
34
- fontSize: runTimeFontSize ? Number(runTimeFontSize) : 20,
35
+ fontSize: toNumberWithDefault(20, runTimeFontSize),
35
36
  fontFamily: runTimeFontFamily || null,
36
37
  ...directionStyles(isRTL),
37
38
  });
@@ -1,5 +1,6 @@
1
1
  import React from "react";
2
- import { View, Text, TextStyle } from "react-native";
2
+ import { View, Text, TextStyle, StyleSheet } from "react-native";
3
+ import { toNumberWithDefault } from "@applicaster/zapp-react-native-utils/numberUtils";
3
4
 
4
5
  type Props = {
5
6
  config: {
@@ -14,11 +15,13 @@ type Props = {
14
15
  summary: string | number;
15
16
  };
16
17
 
17
- const containerStyles = {
18
- width: 600,
19
- height: 80,
20
- marginBottom: 30,
21
- };
18
+ const styles = StyleSheet.create({
19
+ container: {
20
+ width: 600,
21
+ height: 80,
22
+ marginBottom: 30,
23
+ },
24
+ });
22
25
 
23
26
  const textStyles = ({
24
27
  summaryColor,
@@ -26,8 +29,8 @@ const textStyles = ({
26
29
  summaryFontFamily,
27
30
  summaryFontSize,
28
31
  }) => ({
29
- textAlign: (isRTL ? "left" : "right") as TextStyle["textAlign"],
30
- fontSize: summaryFontSize ? Number(summaryFontSize) : 20,
32
+ textAlign: (isRTL ? "right" : "left") as TextStyle["textAlign"],
33
+ fontSize: toNumberWithDefault(20, summaryFontSize),
31
34
  color: summaryColor,
32
35
  fontWeight: "600" as TextStyle["fontWeight"],
33
36
  opacity: 0.8,
@@ -36,7 +39,7 @@ const textStyles = ({
36
39
 
37
40
  export function Summary({ summary, config }: Props) {
38
41
  return (
39
- <View style={containerStyles}>
42
+ <View style={styles.container}>
40
43
  <Text style={textStyles(config)} numberOfLines={2}>
41
44
  {summary}
42
45
  </Text>
@@ -1,5 +1,6 @@
1
1
  import React from "react";
2
- import { View, Text, TextStyle } from "react-native";
2
+ import { View, Text, TextStyle, StyleSheet } from "react-native";
3
+ import { toNumberWithDefault } from "@applicaster/zapp-react-native-utils/numberUtils";
3
4
 
4
5
  type Props = {
5
6
  config: {
@@ -14,15 +15,17 @@ type Props = {
14
15
  title: string | number;
15
16
  };
16
17
 
17
- const containerStyles = {
18
- width: 600,
19
- height: 100,
20
- marginBottom: 12,
21
- };
18
+ const styles = StyleSheet.create({
19
+ container: {
20
+ width: 600,
21
+ height: 100,
22
+ marginBottom: 12,
23
+ },
24
+ });
22
25
 
23
26
  const textStyles = ({ titleColor, isRTL, titleFontFamily, titleFontSize }) => ({
24
- textAlign: (isRTL ? "left" : "right") as TextStyle["textAlign"],
25
- fontSize: titleFontSize ? Number(titleFontSize) : 38,
27
+ textAlign: (isRTL ? "right" : "left") as TextStyle["textAlign"],
28
+ fontSize: toNumberWithDefault(38, titleFontSize),
26
29
  fontWeight: "600" as TextStyle["fontWeight"],
27
30
  color: titleColor,
28
31
  fontFamily: titleFontFamily || null,
@@ -30,7 +33,7 @@ const textStyles = ({ titleColor, isRTL, titleFontFamily, titleFontSize }) => ({
30
33
 
31
34
  export function Title({ title, config }: Props) {
32
35
  return (
33
- <View style={containerStyles}>
36
+ <View style={styles.container}>
34
37
  <Text style={textStyles(config)} numberOfLines={2}>
35
38
  {title}
36
39
  </Text>
@@ -20,7 +20,7 @@ exports[`<Runtime /> LTR renders correctly 1`] = `
20
20
  "fontSize": 20,
21
21
  "justifyContent": "flex-start",
22
22
  "opacity": 0.8,
23
- "textAlign": "right",
23
+ "textAlign": "left",
24
24
  }
25
25
  }
26
26
  >
@@ -49,7 +49,7 @@ exports[`<Runtime /> RTL renders correctly 1`] = `
49
49
  "fontSize": 20,
50
50
  "justifyContent": "flex-end",
51
51
  "opacity": 0.8,
52
- "textAlign": "left",
52
+ "textAlign": "right",
53
53
  }
54
54
  }
55
55
  >
@@ -17,10 +17,15 @@ exports[`<Artwork /> renders correctly 1`] = `
17
17
  }
18
18
  }
19
19
  style={
20
- {
21
- "height": 400,
22
- "width": 400,
23
- }
20
+ [
21
+ {
22
+ "height": 400,
23
+ "width": 400,
24
+ },
25
+ {
26
+ "borderRadius": 0,
27
+ },
28
+ ]
24
29
  }
25
30
  />
26
31
  </View>
@@ -19,7 +19,7 @@ exports[`<Summary /> renders correctly 1`] = `
19
19
  "fontSize": 20,
20
20
  "fontWeight": "600",
21
21
  "opacity": 0.8,
22
- "textAlign": "left",
22
+ "textAlign": "right",
23
23
  }
24
24
  }
25
25
  >
@@ -18,7 +18,7 @@ exports[`<Title /> renders correctly 1`] = `
18
18
  "fontFamily": null,
19
19
  "fontSize": 38,
20
20
  "fontWeight": "600",
21
- "textAlign": "left",
21
+ "textAlign": "right",
22
22
  }
23
23
  }
24
24
  >
@@ -26,14 +26,14 @@ export function getPropertyFromEntryOrConfig({ entry, plugin_configuration }) {
26
26
  const LTR = {
27
27
  flexDirection: "row",
28
28
  justifyContent: "flex-start",
29
- textAlign: "right",
29
+ textAlign: "left",
30
30
  alignItems: "flex-end",
31
31
  };
32
32
 
33
33
  const RTL = {
34
34
  flexDirection: "row-reverse",
35
35
  justifyContent: "flex-end",
36
- textAlign: "left",
36
+ textAlign: "right",
37
37
  alignItems: "flex-start",
38
38
  };
39
39
 
@@ -30,7 +30,6 @@ export const GeneralContentScreen = ({
30
30
  isScreenWrappedInContainer,
31
31
  componentsMapExtraProps = {},
32
32
  focused,
33
- extraOffset,
34
33
  parentFocus,
35
34
  containerHeight,
36
35
  preferredFocus = false,
@@ -122,7 +121,6 @@ export const GeneralContentScreen = ({
122
121
  isScreenWrappedInContainer={isScreenWrappedInContainer}
123
122
  parentFocus={parentFocus}
124
123
  focused={focused}
125
- extraOffset={extraOffset}
126
124
  containerHeight={containerHeight}
127
125
  preferredFocus={preferredFocus}
128
126
  {...componentsMapExtraProps}
@@ -52,6 +52,7 @@ const _Text = ({
52
52
  withScaledLineHeight(withFocusedStyles({ style, otherProps })),
53
53
  { height },
54
54
  ]}
55
+ allowFontScaling={false}
55
56
  {...withoutLabel(otherProps)}
56
57
  >
57
58
  {dateTransformEnabled
@@ -6,12 +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 { isAudioItem } from "@applicaster/zapp-react-native-utils/playerUtils";
14
+ import {
15
+ isAudioItem,
16
+ isInlineTV as isInlineTVUtil,
17
+ } from "@applicaster/zapp-react-native-utils/playerUtils";
15
18
 
16
19
  import { TVEventHandlerComponent } from "@applicaster/zapp-react-native-tvos-ui-components/Components/TVEventHandlerComponent";
17
20
  import { usePrevious } from "@applicaster/zapp-react-native-utils/reactHooks/utils";
@@ -22,7 +25,7 @@ import {
22
25
  } from "@applicaster/zapp-react-native-utils/reactHooks";
23
26
 
24
27
  import { PlayerStateContext } from "../../Contexts/PlayerStateContext";
25
- import { isAppleTV } from "../../Helpers/Platform";
28
+
26
29
  import {
27
30
  QUICK_BRICK_EVENTS,
28
31
  QuickBrickEvent,
@@ -97,6 +100,11 @@ const focusableBottomContainerId = "player-container-bottom";
97
100
 
98
101
  const isAndroidTV = isAndroidTVPlatform();
99
102
 
103
+ const isTvOS = isTvOSPlatform();
104
+
105
+ // height for container with additional content below player
106
+ const INLINE_CONTAINER_CONTENT_HEIGHT = 400;
107
+
100
108
  const withBorderHack = () => {
101
109
  if (isAndroidTV) {
102
110
  /* @HACK: see GH#7269 */
@@ -126,7 +134,10 @@ const webStyles = {
126
134
  flex: "initial",
127
135
  },
128
136
  inlineRiver: {
129
- height: 400,
137
+ height: INLINE_CONTAINER_CONTENT_HEIGHT,
138
+
139
+ borderWidth: 4,
140
+ borderColor: "yellow",
130
141
  },
131
142
  };
132
143
 
@@ -144,7 +155,7 @@ const nativeStyles = {
144
155
  flex: 1,
145
156
  },
146
157
  inlineRiver: {
147
- height: 400,
158
+ height: INLINE_CONTAINER_CONTENT_HEIGHT,
148
159
  },
149
160
  };
150
161
 
@@ -164,12 +175,11 @@ const renderApplePlayer = ({
164
175
  videoStyle,
165
176
  playNextData,
166
177
  }) => {
167
- const { title, summary } = item || {};
168
-
169
- if (!isAppleTV() || !player) {
178
+ if (!isTvOS || !player) {
170
179
  return null;
171
180
  }
172
181
 
182
+ // render audio_player for tvos
173
183
  if (isAudioContent) {
174
184
  return (
175
185
  <AudioPlayer
@@ -183,6 +193,8 @@ const renderApplePlayer = ({
183
193
  return null;
184
194
  }
185
195
 
196
+ const { title, summary } = item || {};
197
+
186
198
  return (
187
199
  <ProgramInfo
188
200
  title={title}
@@ -193,21 +205,6 @@ const renderApplePlayer = ({
193
205
  );
194
206
  };
195
207
 
196
- const renderRestPlayers = ({ item, showAudioPlayer, pluginConfiguration }) => {
197
- if (isApplePlatform()) {
198
- return null;
199
- }
200
-
201
- return (
202
- showAudioPlayer && (
203
- <AudioPlayer
204
- audio_item={item}
205
- plugin_configuration={pluginConfiguration}
206
- />
207
- )
208
- );
209
- };
210
-
211
208
  const PlayerContainerComponent = (props: Props) => {
212
209
  const {
213
210
  Player,
@@ -337,7 +334,7 @@ const PlayerContainerComponent = (props: Props) => {
337
334
 
338
335
  setState({ error: errorObj });
339
336
 
340
- if (!isAppleTV()) {
337
+ if (!isTvOS) {
341
338
  setTimeout(() => {
342
339
  close();
343
340
  }, 800);
@@ -568,10 +565,7 @@ const PlayerContainerComponent = (props: Props) => {
568
565
 
569
566
  const uri = item?.content ? item.content?.src : null;
570
567
 
571
- const isInlineTV =
572
- screenData?.ui_components &&
573
- screenData?.ui_components?.length > 0 &&
574
- isTV();
568
+ const isInlineTV = isInlineTVUtil(screenData);
575
569
 
576
570
  const inline =
577
571
  [VideoModalMode.MAXIMIZED, VideoModalMode.MINIMIZED].includes(mode) ||
@@ -626,12 +620,6 @@ const PlayerContainerComponent = (props: Props) => {
626
620
  playNextData,
627
621
  };
628
622
 
629
- const restPlayerProps = {
630
- item,
631
- showAudioPlayer: isAudioContent,
632
- pluginConfiguration,
633
- };
634
-
635
623
  return (
636
624
  <PlayerStateContext.Provider value={value}>
637
625
  <PlayerContainerContextProvider
@@ -707,8 +695,6 @@ const PlayerContainerComponent = (props: Props) => {
707
695
  </Player>
708
696
  </PlayerFocusableWrapperView>
709
697
 
710
- {renderRestPlayers(restPlayerProps)}
711
-
712
698
  {state.error ? <ErrorDisplay error={state.error} /> : null}
713
699
  </View>
714
700
  {/* Components container */}
@@ -732,12 +718,12 @@ const PlayerContainerComponent = (props: Props) => {
732
718
  screenId={screenData.id}
733
719
  key={item.id}
734
720
  groupId={FocusableGroupMainContainerId}
735
- cellTapAction={(event) => onCellTap(event)}
721
+ cellTapAction={onCellTap}
736
722
  extraAnchorPointYOffset={-600}
737
723
  isScreenWrappedInContainer={true}
738
724
  containerHeight={styles.inlineRiver.height}
739
725
  componentsMapExtraProps={{
740
- isNestedComponentsMap: R.T,
726
+ isNestedComponentsMap: true,
741
727
  }}
742
728
  />
743
729
  )}
@@ -281,8 +281,8 @@ function ComponentsMapComponent(props: Props) {
281
281
  scrollIndicatorInsets={scrollIndicatorInsets}
282
282
  extraData={feed}
283
283
  stickyHeaderIndices={stickyHeaderIndices}
284
- onLayout={handleOnLayout}
285
284
  removeClippedSubviews={isAndroid}
285
+ onLayout={handleOnLayout}
286
286
  initialNumToRender={3}
287
287
  maxToRenderPerBatch={10}
288
288
  windowSize={12}
@@ -303,10 +303,6 @@ function ComponentsMapComponent(props: Props) {
303
303
  onMomentumScrollEnd={_onMomentumScrollEnd}
304
304
  onScrollEndDrag={_onScrollEndDrag}
305
305
  scrollEventThrottle={16}
306
- maintainVisibleContentPosition={{
307
- minIndexForVisible: 0,
308
- autoscrollToTopThreshold: 10,
309
- }}
310
306
  {...scrollViewExtraProps}
311
307
  />
312
308
  </ViewportTracker>
@@ -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,24 +52,20 @@ 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
  });
60
64
 
61
- if (loadingState.getValue().index + 1 >= currentIndex) {
62
- setReadyToBeDisplayed(true);
63
- }
64
-
65
65
  return () => {
66
66
  subscription.unsubscribe();
67
67
  };
68
- }, [loadingState, currentIndex]);
68
+ }, [currentIndex]);
69
69
 
70
70
  return readyToBeDisplayed;
71
71
  };
@@ -151,7 +151,7 @@ function RiverItemComponent(props: RiverItemType) {
151
151
  component={item}
152
152
  componentIndex={index}
153
153
  onLoadFailed={onLoadFailed}
154
- onLoadFinished={() => onLoadFinished(index)} // Keeping it here to don't break the plugins.
154
+ onLoadFinished={() => onLoadFinished(index)}
155
155
  groupId={groupId}
156
156
  feedUrl={feedUrl}
157
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}
@@ -135,12 +135,6 @@ exports[`componentsMap renders renders components map correctly 1`] = `
135
135
  getItemCount={[Function]}
136
136
  initialNumToRender={3}
137
137
  keyExtractor={[Function]}
138
- maintainVisibleContentPosition={
139
- {
140
- "autoscrollToTopThreshold": 10,
141
- "minIndexForVisible": 0,
142
- }
143
- }
144
138
  maxToRenderPerBatch={10}
145
139
  onContentSizeChange={[Function]}
146
140
  onLayout={[Function]}
@@ -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
  };
@@ -71,6 +71,36 @@ exports[`PlayerWrapper renders inline 1`] = `
71
71
  }
72
72
  testID="test-player-container"
73
73
  />
74
+ <View
75
+ animationType="componentFade"
76
+ style={
77
+ {
78
+ "flex": 1,
79
+ }
80
+ }
81
+ >
82
+ <View
83
+ configuration={
84
+ {
85
+ "tablet_landscape_player_container_background_color": "red",
86
+ "tablet_landscape_sidebar_width": "35%",
87
+ }
88
+ }
89
+ entry={
90
+ {
91
+ "id": "test",
92
+ }
93
+ }
94
+ isTablet={false}
95
+ isTabletLandscape={false}
96
+ style={
97
+ {
98
+ "flex": 1,
99
+ "paddingTop": 20,
100
+ }
101
+ }
102
+ />
103
+ </View>
74
104
  </View>
75
105
  </RNCSafeAreaView>
76
106
  </RNCSafeAreaProvider>
@@ -239,6 +269,36 @@ exports[`PlayerWrapper renders inline on tablet in landscape orientation 1`] = `
239
269
  }
240
270
  />
241
271
  </View>
272
+ <View
273
+ animationType="componentFade"
274
+ style={
275
+ {
276
+ "flex": 1,
277
+ }
278
+ }
279
+ >
280
+ <View
281
+ configuration={
282
+ {
283
+ "tablet_landscape_player_container_background_color": "red",
284
+ "tablet_landscape_sidebar_width": "35%",
285
+ }
286
+ }
287
+ entry={
288
+ {
289
+ "id": "test",
290
+ }
291
+ }
292
+ isTablet={true}
293
+ isTabletLandscape={true}
294
+ style={
295
+ {
296
+ "flex": 1,
297
+ "paddingTop": 20,
298
+ }
299
+ }
300
+ />
301
+ </View>
242
302
  </View>
243
303
  </RNCSafeAreaView>
244
304
  </RNCSafeAreaProvider>
@@ -1,19 +1,9 @@
1
1
  import { renderHook } from "@testing-library/react-hooks";
2
2
  import { useDelayedPlayerDetails } from "../useDelayedPlayerDetails";
3
- import { withTimeout$ } from "@applicaster/zapp-react-native-utils/idleUtils";
4
- import { showDetails } from "../utils";
5
3
  import { useIsTablet } from "@applicaster/zapp-react-native-utils/reactHooks";
6
4
 
7
- jest.mock("@applicaster/zapp-react-native-utils/idleUtils", () => ({
8
- withTimeout$: jest.fn(),
9
- }));
10
-
11
- jest.mock("../utils", () => ({
12
- showDetails: jest.fn(),
13
- }));
14
-
15
5
  jest.mock("@applicaster/zapp-react-native-utils/reactHooks", () => ({
16
- useIsTablet: jest.fn(),
6
+ useIsTablet: jest.fn().mockReturnValue(false),
17
7
  }));
18
8
 
19
9
  describe("useDelayedPlayerDetails", () => {
@@ -21,69 +11,41 @@ describe("useDelayedPlayerDetails", () => {
21
11
  jest.clearAllMocks();
22
12
  });
23
13
 
24
- it("should return false initially", () => {
25
- (withTimeout$ as jest.Mock).mockReturnValue({
26
- subscribe: jest.fn().mockReturnValue({ unsubscribe: jest.fn() }),
27
- });
28
-
14
+ it("should return true initially", () => {
29
15
  const { result } = renderHook(() =>
30
16
  useDelayedPlayerDetails({ isInline: true, isDocked: false, isPip: false })
31
17
  );
32
18
 
33
- expect(result.current).toBe(false);
19
+ expect(result.current).toBe(true);
34
20
  });
35
21
 
36
- it("should return true if showDetails returns true", () => {
37
- (withTimeout$ as jest.Mock).mockReturnValue({
38
- subscribe: (callback) => {
39
- callback.next();
40
-
41
- return { unsubscribe: jest.fn() };
42
- },
43
- });
44
-
45
- (showDetails as jest.Mock).mockReturnValue(true);
46
- (useIsTablet as jest.Mock).mockReturnValue(false);
47
-
22
+ it("should return false when isPip is true", () => {
48
23
  const { result } = renderHook(() =>
49
- useDelayedPlayerDetails({ isInline: true, isDocked: false, isPip: false })
24
+ useDelayedPlayerDetails({ isInline: true, isDocked: true, isPip: true })
50
25
  );
51
26
 
52
- expect(result.current).toBe(true);
27
+ expect(result.current).toBe(false);
53
28
  });
54
29
 
55
- it("should return false if showDetails returns false", () => {
56
- (withTimeout$ as jest.Mock).mockReturnValue({
57
- subscribe: (callback) => {
58
- callback.next();
59
-
60
- return { unsubscribe: jest.fn() };
61
- },
62
- });
63
-
64
- (showDetails as jest.Mock).mockReturnValue(false);
65
- (useIsTablet as jest.Mock).mockReturnValue(false);
66
-
30
+ it("should return false when isDocked is true", () => {
67
31
  const { result } = renderHook(() =>
68
- useDelayedPlayerDetails({ isInline: true, isDocked: false, isPip: false })
32
+ useDelayedPlayerDetails({ isInline: true, isDocked: true, isPip: false })
69
33
  );
70
34
 
71
35
  expect(result.current).toBe(false);
72
36
  });
73
37
 
74
- it("should unsubscribe on unmount", () => {
75
- const unsubscribeMock = jest.fn();
38
+ it("should return true for tablet regardless of other flags", () => {
39
+ (useIsTablet as jest.Mock).mockReturnValue(true);
76
40
 
77
- (withTimeout$ as jest.Mock).mockReturnValue({
78
- subscribe: jest.fn().mockReturnValue({ unsubscribe: unsubscribeMock }),
79
- });
80
-
81
- const { unmount } = renderHook(() =>
82
- useDelayedPlayerDetails({ isInline: true, isDocked: false, isPip: false })
41
+ const { result } = renderHook(() =>
42
+ useDelayedPlayerDetails({
43
+ isInline: false,
44
+ isDocked: false,
45
+ isPip: false,
46
+ })
83
47
  );
84
48
 
85
- unmount();
86
-
87
- expect(unsubscribeMock).toHaveBeenCalled();
49
+ expect(result.current).toBe(true);
88
50
  });
89
51
  });
@@ -1,13 +1,23 @@
1
- import * as React from "react";
2
1
  import { useIsTablet } from "@applicaster/zapp-react-native-utils/reactHooks";
3
- import { withTimeout$ } from "@applicaster/zapp-react-native-utils/idleUtils";
4
2
 
5
3
  import { showDetails } from "./utils";
6
4
 
7
- const TIMEOUT = 100; // ms
8
-
9
5
  type Props = { isInline: boolean; isDocked: boolean; isPip: boolean };
10
6
 
7
+ const showPlayerDetails = (
8
+ isInline: boolean,
9
+ isDocked: boolean,
10
+ isPip: boolean,
11
+ isTablet: boolean
12
+ ) => {
13
+ return showDetails({
14
+ isMobile: !isTablet,
15
+ isInline,
16
+ isDocked,
17
+ isPip,
18
+ });
19
+ };
20
+
11
21
  /**
12
22
  * Custom hook to determine whether to show player details with a delay.
13
23
  *
@@ -22,28 +32,7 @@ export const useDelayedPlayerDetails = ({
22
32
  isDocked,
23
33
  isPip,
24
34
  }: Props): boolean => {
25
- const [shouldShowDetails, setShouldShowDetails] = React.useState(false);
26
-
27
35
  const isTablet = useIsTablet();
28
36
 
29
- React.useEffect(() => {
30
- const subscription = withTimeout$(TIMEOUT).subscribe({
31
- next: () => {
32
- setShouldShowDetails(() => {
33
- return showDetails({
34
- isMobile: !isTablet,
35
- isInline,
36
- isDocked,
37
- isPip,
38
- });
39
- });
40
- },
41
- });
42
-
43
- return () => {
44
- subscription.unsubscribe();
45
- };
46
- }, [isDocked, isTablet, isInline, isPip]);
47
-
48
- return shouldShowDetails;
37
+ return showPlayerDetails(isInline, isDocked, isPip, isTablet);
49
38
  };
package/index.d.ts CHANGED
@@ -24,7 +24,6 @@ type GeneralContentScreenProps = {
24
24
  } & Record<string, any>;
25
25
  focused?: boolean;
26
26
  parentFocus?: ParentFocus;
27
- extraOffset?: number;
28
27
  containerHeight?: number;
29
28
  };
30
29
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@applicaster/zapp-react-native-ui-components",
3
- "version": "14.0.0-rc.1",
3
+ "version": "14.0.0-rc.11",
4
4
  "description": "Applicaster Zapp React Native ui components for the Quick Brick App",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -31,12 +31,11 @@
31
31
  "redux-mock-store": "^1.5.3"
32
32
  },
33
33
  "dependencies": {
34
- "@applicaster/applicaster-types": "14.0.0-rc.1",
35
- "@applicaster/zapp-react-native-bridge": "14.0.0-rc.1",
36
- "@applicaster/zapp-react-native-redux": "14.0.0-rc.1",
37
- "@applicaster/zapp-react-native-utils": "14.0.0-rc.1",
34
+ "@applicaster/applicaster-types": "14.0.0-rc.11",
35
+ "@applicaster/zapp-react-native-bridge": "14.0.0-rc.11",
36
+ "@applicaster/zapp-react-native-redux": "14.0.0-rc.11",
37
+ "@applicaster/zapp-react-native-utils": "14.0.0-rc.11",
38
38
  "promise": "^8.3.0",
39
- "react-router-native": "^5.1.2",
40
39
  "url": "^0.11.0",
41
40
  "uuid": "^3.3.2"
42
41
  },
@@ -1,11 +0,0 @@
1
- import React from "react";
2
-
3
- const reactRouter = jest.genMockFromModule("react-router-native");
4
-
5
- function withRouter(Component) {
6
- return (props) => <Component {...props} />; // eslint-disable-line react/display-name
7
- }
8
-
9
- reactRouter.withRouter = withRouter;
10
-
11
- module.exports = reactRouter;