@applicaster/zapp-react-native-ui-components 12.0.0-rc.8 → 12.0.0-rc.80

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 (135) 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/BaseFocusable/index.tsx +1 -1
  5. package/Components/Cell/Cell.tsx +7 -7
  6. package/Components/Cell/CellWithFocusable.tsx +38 -19
  7. package/Components/Cell/TvOSCellComponent.tsx +2 -2
  8. package/Components/ErrorScreen/index.tsx +1 -1
  9. package/Components/FocusableCell/index.tsx +7 -7
  10. package/Components/FocusableGroup/index.tsx +1 -0
  11. package/Components/FocusableList/FocusableChild.ts +24 -14
  12. package/Components/FocusableList/FocusableItem.tsx +1 -1
  13. package/Components/FocusableList/FocusableListItemWrapper.tsx +76 -0
  14. package/Components/FocusableList/hooks/useCellState.android.ts +3 -1
  15. package/Components/FocusableList/index.tsx +26 -25
  16. package/Components/GeneralContentScreen/GeneralContentScreen.tsx +11 -8
  17. package/Components/GeneralContentScreen/utils/__tests__/useCurationAPI.test.js +13 -6
  18. package/Components/GeneralContentScreen/utils/useCurationAPI.ts +1 -1
  19. package/Components/HandlePlayable/HandlePlayable.tsx +4 -1
  20. package/Components/HookRenderer/index.tsx +1 -6
  21. package/Components/Image/Image.android.tsx +3 -26
  22. package/Components/Image/Image.tsx +18 -2
  23. package/Components/Image/utils/index.ts +39 -0
  24. package/Components/Layout/TV/ScreenLayoutContextProvider.tsx +2 -2
  25. package/Components/Layout/TV/__tests__/__snapshots__/index.test.tsx.snap +10 -50
  26. package/Components/Layout/TV/__tests__/index.test.tsx +19 -108
  27. package/Components/Layout/TV/index.tsx +28 -43
  28. package/Components/Layout/TV/index.web.tsx +33 -0
  29. package/Components/Layout/index.tsx +15 -11
  30. package/Components/MasterCell/DefaultComponents/ActionButton.tsx +2 -0
  31. package/Components/MasterCell/DefaultComponents/BorderContainerView/index.tsx +80 -110
  32. package/Components/MasterCell/DefaultComponents/CellBadge/index.tsx +21 -8
  33. package/Components/MasterCell/DefaultComponents/DynamicBadge.tsx +4 -2
  34. package/Components/MasterCell/DefaultComponents/Image/Image.android.tsx +9 -26
  35. package/Components/MasterCell/DefaultComponents/Image/Image.ios.tsx +5 -3
  36. package/Components/MasterCell/DefaultComponents/Image/hooks/useImageSize.ts +65 -0
  37. package/Components/MasterCell/DefaultComponents/ImageContainer/index.tsx +5 -1
  38. package/Components/MasterCell/DefaultComponents/LiveImage/index.tsx +17 -2
  39. package/Components/MasterCell/DefaultComponents/SecondaryImage/Image.tsx +3 -2
  40. package/Components/MasterCell/DefaultComponents/Text/index.tsx +14 -2
  41. package/Components/MasterCell/DefaultComponents/Toggle.tsx +5 -1
  42. package/Components/MasterCell/DefaultComponents/__tests__/image.test.js +1 -1
  43. package/Components/MasterCell/DefaultComponents/__tests__/text.test.tsx +24 -9
  44. package/Components/MasterCell/DefaultComponents/tv/ButtonContainerView/index.android.tsx +4 -1
  45. package/Components/MasterCell/DefaultComponents/tv/ButtonContainerView/index.tsx +4 -1
  46. package/Components/MasterCell/SharedUI/CollapsibleTextContainer/index.ts +6 -10
  47. package/Components/MasterCell/hooks/useAsyncRendering/index.ts +1 -1
  48. package/Components/MasterCell/utils/index.ts +33 -35
  49. package/Components/MeasurmentsPortal/BasicMeasurementsPortal.tsx +11 -7
  50. package/Components/MeasurmentsPortal/MeasurementsPortal.tsx +10 -1
  51. package/Components/ModalComponent/BottomSheetModalContent.tsx +121 -0
  52. package/Components/ModalComponent/Button/Item.tsx +82 -0
  53. package/Components/ModalComponent/Button/ItemIcon.tsx +60 -0
  54. package/Components/ModalComponent/Button/ItemLabel.tsx +101 -0
  55. package/Components/ModalComponent/Button/assets.ts +4 -0
  56. package/Components/ModalComponent/Button/index.tsx +111 -0
  57. package/Components/ModalComponent/Header/CloseButton.tsx +59 -0
  58. package/Components/ModalComponent/Header/Title.tsx +70 -0
  59. package/Components/ModalComponent/Header/assets.ts +4 -0
  60. package/Components/ModalComponent/Header/index.tsx +71 -0
  61. package/Components/ModalComponent/Header/utils.ts +79 -0
  62. package/Components/ModalComponent/index.tsx +38 -0
  63. package/Components/ModalComponent/utils.ts +126 -0
  64. package/Components/Navigator/StackNavigator.tsx +48 -0
  65. package/Components/Navigator/index.ts +1 -0
  66. package/Components/PlayerContainer/PlayerContainer.tsx +69 -31
  67. package/Components/PlayerContainer/ProgramInfo/index.tsx +3 -1
  68. package/Components/PlayerImageBackground/index.tsx +34 -8
  69. package/Components/River/ComponentsMap/ComponentsMap.tsx +97 -2
  70. package/Components/River/RefreshControl.tsx +55 -1
  71. package/Components/River/River.tsx +8 -5
  72. package/Components/River/TV/River.tsx +2 -25
  73. package/Components/River/__tests__/__snapshots__/componentsMap.test.js.snap +1 -1
  74. package/Components/River/__tests__/componentsMap.test.js +7 -0
  75. package/Components/River/useScreenConfiguration.ts +5 -6
  76. package/Components/RouteManager/__tests__/__snapshots__/routeManager.test.js.snap +1 -0
  77. package/Components/RouteManager/__tests__/routeManager.test.js +9 -2
  78. package/Components/RouteManager/index.tsx +4 -2
  79. package/Components/Screen/TV/hooks/index.ts +3 -0
  80. package/Components/Screen/TV/hooks/useInitialFocus.ts +70 -0
  81. package/Components/Screen/TV/hooks/useRestoreFocus.ts +22 -0
  82. package/Components/Screen/TV/index.web.tsx +179 -0
  83. package/Components/Screen/__tests__/Screen.test.tsx +51 -36
  84. package/Components/Screen/__tests__/__snapshots__/Screen.test.tsx.snap +24 -6
  85. package/Components/Screen/__tests__/navigationHandler.test.ts +1 -178
  86. package/Components/Screen/index.tsx +131 -44
  87. package/Components/Screen/navigationHandler.ts +0 -82
  88. package/Components/Screen/orientationHandler.ts +1 -1
  89. package/Components/ScreenResolver/index.tsx +4 -2
  90. package/Components/Tabs/TV/styles.ts +1 -1
  91. package/Components/TrackedView/index.tsx +6 -3
  92. package/Components/Transitioner/Scene.tsx +24 -19
  93. package/Components/Transitioner/Transitioner.tsx +21 -28
  94. package/Components/Transitioner/__tests__/__snapshots__/Scene.test.js.snap +6 -2
  95. package/Components/Transitioner/__tests__/__snapshots__/transitioner.test.js.snap +1 -0
  96. package/Components/VideoLive/LiveImageManager.ts +60 -14
  97. package/Components/VideoLive/PlayerLiveImageComponent.tsx +81 -72
  98. package/Components/VideoLive/__tests__/PlayerLiveImageComponent.test.tsx +45 -3
  99. package/Components/VideoLive/__tests__/__snapshots__/PlayerLiveImageComponent.test.tsx.snap +18 -28
  100. package/Components/VideoModal/ModalAnimation/AnimatedPlayerModalWrapper.tsx +78 -0
  101. package/Components/VideoModal/ModalAnimation/AnimatedScrollModal.tsx +352 -0
  102. package/Components/VideoModal/ModalAnimation/AnimatedVideoPlayerComponent.tsx +158 -0
  103. package/Components/VideoModal/ModalAnimation/AnimationComponent.tsx +461 -0
  104. package/Components/VideoModal/ModalAnimation/ModalAnimationContext.tsx +154 -0
  105. package/Components/VideoModal/ModalAnimation/index.ts +15 -0
  106. package/Components/VideoModal/ModalAnimation/utils.ts +299 -0
  107. package/Components/VideoModal/PlayerDetails.tsx +6 -3
  108. package/Components/VideoModal/PlayerWrapper.tsx +82 -50
  109. package/Components/VideoModal/VideoModal.tsx +23 -40
  110. package/Components/VideoModal/__tests__/PlayerDetails.test.tsx +0 -2
  111. package/Components/VideoModal/__tests__/PlayerWrapper.test.tsx +12 -1
  112. package/Components/VideoModal/__tests__/__snapshots__/PlayerWrapper.test.tsx.snap +246 -166
  113. package/Components/VideoModal/hooks/useModalSize.ts +13 -4
  114. package/Components/VideoModal/utils.ts +8 -5
  115. package/Components/Viewport/ViewportAware/__tests__/viewportAware.test.js +26 -21
  116. package/Components/Viewport/ViewportTracker/ViewportTracker.tsx +31 -40
  117. package/Components/Viewport/ViewportTracker/__tests__/viewportTracker.test.js +4 -5
  118. package/Components/Viewport/ViewportTracker/index.tsx +1 -0
  119. package/Components/Viewport/utils.js +1 -1
  120. package/Components/ZappUIComponent/index.tsx +22 -12
  121. package/Components/index.js +2 -0
  122. package/Contexts/MenuToggleContext/{index.js → index.ts} +16 -0
  123. package/Contexts/ScreenContext/__tests__/__snapshots__/index.test.tsx.snap +3 -0
  124. package/Contexts/ScreenContext/__tests__/index.test.tsx +27 -0
  125. package/Contexts/ScreenContext/index.tsx +95 -29
  126. package/Contexts/ScreenDataContext/index.tsx +20 -0
  127. package/Contexts/ZappPipesContext/ZappPipesEntryContext.ts +1 -1
  128. package/Decorators/ComponentsMapWrapper/withComponentsMapProvider.tsx +7 -2
  129. package/Decorators/RiverResolver/index.tsx +0 -4
  130. package/Decorators/index.tsx +0 -4
  131. package/events/index.ts +1 -0
  132. package/package.json +5 -6
  133. package/Components/Layout/TV/TransitionOverlay.tsx +0 -64
  134. package/Components/VideoModal/hooks/usePosition.ts +0 -50
  135. /package/Contexts/{index.js → index.ts} +0 -0
@@ -7,50 +7,24 @@ type BorderPosition = "inside" | "outside" | "center";
7
7
  interface Props {
8
8
  style: ImageStyle | ViewStyle;
9
9
  borderPosition: BorderPosition;
10
+ borderPaddingTop: number;
11
+ borderPaddingRight: number;
12
+ borderPaddingBottom: number;
13
+ borderPaddingLeft: number;
10
14
  children: React.ReactNode;
11
15
  }
12
16
 
13
- const MARGINS = [
14
- "marginTop",
15
- "marginBottom",
16
- "marginLeft",
17
- "marginRight",
18
- ] as const;
17
+ const COLOR_TRANSPARENT = "transparent";
19
18
 
20
- const PADDINGS = [
21
- "paddingTop",
22
- "paddingBottom",
23
- "paddingLeft",
24
- "paddingRight",
25
- ] as const;
19
+ const styles = StyleSheet.create({
20
+ container: {
21
+ overflow: "visible",
22
+ borderWidth: 0,
23
+ borderColor: COLOR_TRANSPARENT,
24
+ },
25
+ });
26
26
 
27
- const isPercentageValue = (value: number | string) => {
28
- if (typeof value === "string" && value.endsWith("%")) {
29
- return true;
30
- }
31
-
32
- return false;
33
- };
34
-
35
- const calculateContainerSpacing = ({
36
- spacingKey,
37
- style,
38
- additionalSpacing,
39
- }: {
40
- spacingKey: typeof MARGINS[number] | typeof PADDINGS[number];
41
- style: ImageStyle | ViewStyle;
42
- additionalSpacing: number;
43
- }) => {
44
- return {
45
- [spacingKey]:
46
- toNumberWithDefaultZero(style[spacingKey]) + additionalSpacing,
47
- };
48
- };
49
-
50
- const getContainerBorderWidth = (
51
- borderPosition: BorderPosition,
52
- borderWidth
53
- ) => {
27
+ const getBorderPadding = (borderPosition: BorderPosition, borderWidth) => {
54
28
  switch (borderPosition) {
55
29
  case "inside":
56
30
  return 0;
@@ -63,105 +37,101 @@ const getContainerBorderWidth = (
63
37
  }
64
38
  };
65
39
 
66
- const getContainerPadding = (borderPosition: BorderPosition, borderWidth) => {
67
- switch (borderPosition) {
68
- case "inside":
69
- return borderWidth;
70
- case "center":
71
- return borderWidth / 2;
72
- case "outside":
73
- return 0;
74
- default:
75
- return 0;
76
- }
77
- };
78
-
79
- const InsideBorder = ({
40
+ const Border = ({
80
41
  style,
42
+ padding,
81
43
  borderPosition,
82
44
  }: {
83
45
  style: ViewStyle;
46
+ padding: ViewStyle;
84
47
  borderPosition: BorderPosition;
85
48
  }) => {
86
- if (borderPosition === "outside") {
49
+ if (!borderPosition) {
87
50
  return null;
88
51
  }
89
52
 
90
- const insideBorderWidth =
91
- borderPosition === "center" ? style.borderWidth / 2 : style.borderWidth;
53
+ const borderWidth = toNumberWithDefaultZero(style.borderWidth);
54
+ const containerPadding = getBorderPadding(borderPosition, borderWidth);
55
+
56
+ const initialBorderRadius = toNumberWithDefaultZero(style.borderRadius);
57
+ const paddingTop = toNumberWithDefaultZero(padding.paddingTop);
58
+ const paddingRight = toNumberWithDefaultZero(padding.paddingRight);
59
+ const paddingBottom = toNumberWithDefaultZero(padding.paddingBottom);
60
+ const paddingLeft = toNumberWithDefaultZero(padding.paddingLeft);
61
+
62
+ const borderRadiusStyle = initialBorderRadius
63
+ ? {
64
+ borderTopLeftRadius:
65
+ initialBorderRadius +
66
+ containerPadding +
67
+ Math.min(paddingTop, paddingLeft),
68
+ borderTopRightRadius:
69
+ initialBorderRadius +
70
+ containerPadding +
71
+ Math.min(paddingTop, paddingRight),
72
+ borderBottomLeftRadius:
73
+ initialBorderRadius +
74
+ containerPadding +
75
+ Math.min(paddingBottom, paddingLeft),
76
+ borderBottomRightRadius:
77
+ initialBorderRadius +
78
+ containerPadding +
79
+ Math.min(paddingBottom, paddingRight),
80
+ }
81
+ : {
82
+ borderTopLeftRadius: 0,
83
+ borderTopRightRadius: 0,
84
+ borderBottomLeftRadius: 0,
85
+ borderBottomRightRadius: 0,
86
+ };
92
87
 
93
88
  return (
94
89
  <View
95
90
  style={{
96
91
  ...StyleSheet.absoluteFillObject,
97
- borderWidth: insideBorderWidth,
92
+ right: -containerPadding - paddingRight,
93
+ bottom: -containerPadding - paddingBottom,
94
+ left: -containerPadding - paddingLeft,
95
+ top: -containerPadding - paddingTop,
96
+ borderWidth,
98
97
  borderColor: style.borderColor,
99
- borderRadius: style.borderRadius,
98
+ ...borderRadiusStyle,
100
99
  }}
101
100
  />
102
101
  );
103
102
  };
104
103
 
105
104
  export const BorderContainerView = (props: Props) => {
106
- const { style, children } = props;
107
- // Return border position prop after re-implementing
108
- const borderPosition = "outside";
109
-
110
- const borderWidth = toNumberWithDefaultZero(style.borderWidth);
111
- const spacing = getContainerPadding(borderPosition, borderWidth);
105
+ const {
106
+ borderPosition,
107
+ borderPaddingTop,
108
+ borderPaddingRight,
109
+ borderPaddingBottom,
110
+ borderPaddingLeft,
111
+ style,
112
+ children,
113
+ } = props;
112
114
 
113
115
  const borderStyleForMissingBorder =
114
116
  style?.borderWidth === 0 || !style?.borderColor ? { borderRadius: 0 } : {};
115
117
 
116
- const updatedMargins = MARGINS.reduce((acc, margin) => {
117
- const marginValue = calculateContainerSpacing({
118
- spacingKey: margin,
119
- style,
120
- additionalSpacing: spacing,
121
- });
122
-
123
- return { ...acc, ...marginValue };
124
- }, {});
125
-
126
- const updatedPaddings = PADDINGS.reduce((acc, padding) => {
127
- const paddingValue = calculateContainerSpacing({
128
- spacingKey: padding,
129
- style,
130
- additionalSpacing: spacing,
131
- });
132
-
133
- return { ...acc, ...paddingValue };
134
- }, {});
135
-
136
- const updatedWidth = style.width
137
- ? isPercentageValue(style.width)
138
- ? style.width
139
- : toNumberWithDefaultZero(style.width) - spacing * 2
140
- : undefined;
141
-
142
- const updatedHeight = style.height
143
- ? isPercentageValue(style.height)
144
- ? style.height
145
- : toNumberWithDefaultZero(style.height) - spacing * 2
146
- : undefined;
147
-
148
- const containerStyle = {
149
- borderWidth: getContainerBorderWidth(borderPosition, borderWidth),
150
- padding: spacing,
151
- ...updatedMargins,
152
- ...updatedPaddings,
153
- width: updatedWidth,
154
- height: updatedHeight,
155
- ...borderStyleForMissingBorder,
156
- };
118
+ const padding =
119
+ borderPosition === "outside"
120
+ ? {
121
+ paddingTop: borderPaddingTop,
122
+ paddingRight: borderPaddingRight,
123
+ paddingBottom: borderPaddingBottom,
124
+ paddingLeft: borderPaddingLeft,
125
+ }
126
+ : {};
157
127
 
158
128
  return (
159
- <View {...props} style={[style, containerStyle]}>
129
+ <View
130
+ {...props}
131
+ style={[style, styles.container, borderStyleForMissingBorder]}
132
+ >
160
133
  {children}
161
- <InsideBorder
162
- style={{ ...style, ...borderStyleForMissingBorder }}
163
- borderPosition={borderPosition}
164
- />
134
+ <Border style={style} padding={padding} borderPosition={borderPosition} />
165
135
  </View>
166
136
  );
167
137
  };
@@ -1,6 +1,7 @@
1
1
  import {
2
2
  compact,
3
3
  ifElseFocusedSelected,
4
+ ifElseSelected,
4
5
  } from "@applicaster/zapp-react-native-utils/cellUtils";
5
6
 
6
7
  import { getPositionStyles } from "./utils";
@@ -12,9 +13,15 @@ type Props = {
12
13
  value: Function;
13
14
  state: string;
14
15
  visible?: Boolean;
16
+ isMobile?: Boolean;
15
17
  };
16
18
 
17
- export const CellBadge = ({ value, state, visible = true }: Props) => {
19
+ export const CellBadge = ({
20
+ value,
21
+ state,
22
+ visible = true,
23
+ isMobile = false,
24
+ }: Props) => {
18
25
  if (!value("cell_badge_switch") || !visible) {
19
26
  return null;
20
27
  }
@@ -45,13 +52,19 @@ export const CellBadge = ({ value, state, visible = true }: Props) => {
45
52
  data: [
46
53
  {
47
54
  func: () => {
48
- return ifElseFocusedSelected(
49
- state,
50
- value("cell_badge_focused"),
51
- value("cell_badge_selected"),
52
- value("cell_badge_focused_selected"),
53
- value("cell_badge_default")
54
- );
55
+ return isMobile
56
+ ? ifElseSelected(
57
+ state,
58
+ value("cell_badge_selected"),
59
+ value("cell_badge_default")
60
+ )
61
+ : ifElseFocusedSelected(
62
+ state,
63
+ value("cell_badge_focused"),
64
+ value("cell_badge_selected"),
65
+ value("cell_badge_focused_selected"),
66
+ value("cell_badge_default")
67
+ );
55
68
  },
56
69
  args: [],
57
70
  propName: "uri",
@@ -4,6 +4,7 @@ import { usePlayer } from "@applicaster/zapp-react-native-utils/appUtils/playerM
4
4
 
5
5
  type DynamicBadgeProps = {
6
6
  cellUUID?: string;
7
+ uri?: string;
7
8
  };
8
9
 
9
10
  const DynamicBadgeComponent = (props: DynamicBadgeProps) => {
@@ -12,11 +13,12 @@ const DynamicBadgeComponent = (props: DynamicBadgeProps) => {
12
13
  // TODO: Initial value should depends on player state (playing or not)
13
14
  const [showImage, setShowImage] = React.useState(true);
14
15
  const player = usePlayer(playerId);
16
+ const uri = props?.uri;
15
17
 
16
18
  React.useEffect(() => {
17
19
  if (playerId && player) {
18
20
  return player.addListener({
19
- id: "dynamic-badges",
21
+ id: `dynamic-badges-${uri}`,
20
22
  listener: {
21
23
  onPlayerClose: () => {
22
24
  setShowImage(true);
@@ -35,7 +37,7 @@ const DynamicBadgeComponent = (props: DynamicBadgeProps) => {
35
37
  } else {
36
38
  setShowImage(true);
37
39
  }
38
- }, [player]);
40
+ }, [player, uri]);
39
41
 
40
42
  if (!showImage) {
41
43
  return null;
@@ -1,11 +1,11 @@
1
1
  import * as React from "react";
2
2
  import { ImageStyle, View } from "react-native";
3
3
  import * as R from "ramda";
4
- import ImageComponent from "@applicaster/zapp-react-native-ui-components/Components/FastImage";
4
+ import { QBImage } from "@applicaster/zapp-react-native-ui-components/Components/Image";
5
5
  import { toBooleanWithDefaultFalse } from "@applicaster/zapp-react-native-utils/booleanUtils";
6
- import { toFiniteNumberWithDefault } from "@applicaster/zapp-react-native-utils/numberUtils";
7
6
 
8
7
  import { useImageSourceWithDefault, useCheckFailedUri } from "./hooks";
8
+ import useImageSize from "./hooks/useImageSize";
9
9
 
10
10
  type Source = {
11
11
  uri: string;
@@ -19,32 +19,13 @@ type Props = Record<string, any> & {
19
19
  withDimensions: (source: Source) => Source;
20
20
  };
21
21
 
22
- const MemoizedImage = React.memo(ImageComponent, R.equals);
23
-
24
- const normalize = Math.ceil;
22
+ const MemoizedImage = React.memo(QBImage, R.equals);
25
23
 
26
24
  const isValidExternalSource = (source): boolean =>
27
25
  source?.uri?.startsWith("http") ||
28
26
  source?.uri?.startsWith("data:image") ||
29
27
  source?.uri?.startsWith("file://");
30
28
 
31
- const isValidSize = (size: unknown): boolean =>
32
- toFiniteNumberWithDefault(0, size) > 0;
33
-
34
- const getSourceWithMaxSizes = (applyMaxSize, style, source) => {
35
- const { width, height } = style;
36
-
37
- if (!applyMaxSize || !isValidSize(width) || !isValidSize(height)) {
38
- return source;
39
- }
40
-
41
- return {
42
- ...source,
43
- maxWidth: normalize(width),
44
- maxHeight: normalize(height),
45
- };
46
- };
47
-
48
29
  export default function Image({
49
30
  style,
50
31
  uri,
@@ -82,10 +63,12 @@ export default function Image({
82
63
 
83
64
  const applyMaxSize = toBooleanWithDefaultFalse(otherProps?.applyMaxSize);
84
65
 
85
- const sourceWithMaxSizes = React.useMemo(
86
- () => withDimensions(getSourceWithMaxSizes(applyMaxSize, style, source)),
87
- [applyMaxSize, style?.height, style?.width, source?.uri, withDimensions]
88
- );
66
+ const sourceWithMaxSizes = useImageSize({
67
+ style,
68
+ applyMaxSize,
69
+ source,
70
+ withDimensions,
71
+ });
89
72
 
90
73
  if (isFailedToLoadUri(uri) || !isValidExternalSource(source)) {
91
74
  return <View style={style} />;
@@ -43,14 +43,16 @@ function Image({
43
43
  [source, error]
44
44
  );
45
45
 
46
+ const _source = shouldRenderImg
47
+ ? withDimensions(source)
48
+ : defaultPlaceHolderImage;
49
+
46
50
  return (
47
51
  // @ts-ignore
48
52
  <MemoizedImage
49
53
  style={style as ImageStyle}
50
54
  onError={() => setErrorState(true)}
51
- source={
52
- shouldRenderImg ? withDimensions(source) : defaultPlaceHolderImage
53
- }
55
+ source={_source?.uri ? _source : undefined}
54
56
  {...R.omit(["source"], otherProps)}
55
57
  />
56
58
  );
@@ -0,0 +1,65 @@
1
+ import * as React from "react";
2
+ import { ImageStyle } from "react-native";
3
+ import { toFiniteNumberWithDefault } from "@applicaster/zapp-react-native-utils/numberUtils";
4
+
5
+ type Source = {
6
+ uri: string;
7
+ };
8
+
9
+ type Props = Record<string, any> & {
10
+ style: ImageStyle;
11
+ uri?: string;
12
+ placeholderImage?: string;
13
+ entry?: ZappEntry | ZappFeed;
14
+ withDimensions: (source: Source) => Source;
15
+ };
16
+
17
+ const normalize = Math.ceil;
18
+
19
+ const isValidSize = (size: unknown): boolean =>
20
+ toFiniteNumberWithDefault(0, size) > 0;
21
+
22
+ type WidthDimensions = { aspectRatio?: number; width: number; height?: number };
23
+ type HeightDimensions = {
24
+ aspectRatio?: number;
25
+ width?: number;
26
+ height: number;
27
+ };
28
+ type FullDimensions = { aspectRatio?: number; width: number; height: number };
29
+ type Dimensions = WidthDimensions | HeightDimensions | FullDimensions;
30
+
31
+ const calculateDimensions = ({ aspectRatio, width, height }: Dimensions) => {
32
+ if (aspectRatio) {
33
+ return {
34
+ width: width || height * aspectRatio,
35
+ height: height || width / aspectRatio,
36
+ };
37
+ }
38
+
39
+ return { width, height };
40
+ };
41
+
42
+ const getSourceWithMaxSizes = (applyMaxSize, style, source) => {
43
+ const { width, height } = calculateDimensions(style);
44
+
45
+ if (!applyMaxSize || !isValidSize(width) || !isValidSize(height)) {
46
+ return source;
47
+ }
48
+
49
+ return {
50
+ ...source,
51
+ maxWidth: normalize(width),
52
+ maxHeight: normalize(height),
53
+ };
54
+ };
55
+
56
+ export default function useImageSize(props: Props) {
57
+ const { style, applyMaxSize, source, withDimensions } = props;
58
+
59
+ const sourceWithMaxSizes = React.useMemo(
60
+ () => withDimensions(getSourceWithMaxSizes(applyMaxSize, style, source)),
61
+ [applyMaxSize, style?.height, style?.width, source?.uri, withDimensions]
62
+ );
63
+
64
+ return sourceWithMaxSizes;
65
+ }
@@ -2,6 +2,7 @@ import React from "react";
2
2
  import { isVideoPreviewEnabled } from "@applicaster/zapp-react-native-ui-components/Components/MasterCell/utils";
3
3
  import { LiveImage } from "../LiveImage";
4
4
  import PureImage from "../Image";
5
+ import { useIsScreenActive } from "@applicaster/zapp-react-native-utils/reactHooks";
5
6
 
6
7
  type Props = {
7
8
  enable_video_preview: boolean;
@@ -9,7 +10,10 @@ type Props = {
9
10
  };
10
11
 
11
12
  export const ImageContainer = (props: Props) => {
12
- const Component = isVideoPreviewEnabled(props) ? LiveImage : PureImage;
13
+ const isActive = useIsScreenActive();
14
+
15
+ const Component =
16
+ isVideoPreviewEnabled(props) && isActive ? LiveImage : PureImage;
13
17
 
14
18
  return <Component {...props} />;
15
19
  };
@@ -18,6 +18,7 @@ type LiveImageProps = {
18
18
  imageKey?: string;
19
19
  state: "focused" | "unfocused" | "selected";
20
20
  audio_muted_by_default?: boolean;
21
+ uri: string; // cover image url
21
22
  };
22
23
 
23
24
  const DEFAULT_PLAYER_IDENTIFIER = "QuickBrickPlayerPlugin";
@@ -176,10 +177,23 @@ const getPlayerConfig = (player_screen_id, actionIdentifier) => {
176
177
  const positionAbsolute: ViewStyle = { position: "absolute" };
177
178
 
178
179
  const LiveImageComponent = (props: LiveImageProps) => {
179
- const { item, style, cellUUID, imageKey, actionIdentifier, state } = props;
180
+ const {
181
+ item,
182
+ style: componentStyle,
183
+ cellUUID,
184
+ imageKey,
185
+ actionIdentifier,
186
+ state,
187
+ } = props;
180
188
 
181
189
  const component = useUIComponentContext();
182
190
 
191
+ // Fix for blinking on state change
192
+ const style = React.useMemo(
193
+ () => ({ ...componentStyle, backgroundColor: "transparent" }),
194
+ [componentStyle]
195
+ );
196
+
183
197
  const componentType = React.useMemo(
184
198
  () => getPropComponentType(component),
185
199
  [component?.id]
@@ -209,10 +223,11 @@ const LiveImageComponent = (props: LiveImageProps) => {
209
223
 
210
224
  return (
211
225
  <>
212
- <Image {...props} />
226
+ <Image {...props} applyMaxSize />
213
227
  {isShouldRender && (
214
228
  <View style={[style, positionAbsolute]}>
215
229
  <PlayerLiveImage
230
+ uri={props.uri}
216
231
  playerId={cellUUID}
217
232
  playerPluginId={playerPluginId}
218
233
  screenConfig={screenConfig}
@@ -1,11 +1,12 @@
1
1
  import * as React from "react";
2
2
  import { isNil } from "ramda";
3
- import { Image as RNImage, ImageStyle, View } from "react-native";
3
+ import { ImageStyle, View } from "react-native";
4
4
  import {
5
5
  FIT_POSITION,
6
6
  IMAGE_SIZING_FIT,
7
7
  IMAGE_SIZING_FILL,
8
8
  } from "@applicaster/zapp-react-native-utils/manifestUtils/secondaryImage";
9
+ import { QBImage as Image } from "@applicaster/zapp-react-native-ui-components/Components/Image";
9
10
 
10
11
  import { useGetImageDimensions } from "./hooks";
11
12
  import {
@@ -59,7 +60,7 @@ const SecondaryImageComponent = (props: Props) => {
59
60
 
60
61
  return (
61
62
  <View style={style} onLayout={onAsyncRender}>
62
- <RNImage
63
+ <Image
63
64
  {...props}
64
65
  source={{ uri }}
65
66
  style={{
@@ -1,7 +1,6 @@
1
1
  import * as React from "react";
2
2
  import { Text } from "react-native";
3
3
  import { omit } from "ramda";
4
- import { isNilOrEmpty } from "@applicaster/zapp-react-native-utils/reactUtils/helpers";
5
4
  import {
6
5
  textTransform,
7
6
  dateFormat,
@@ -9,6 +8,9 @@ import {
9
8
 
10
9
  import { useTextLabel, withFocusedStyles } from "./hooks";
11
10
  import { withScaledLineHeight } from "./utils";
11
+ import { toNumber } from "@applicaster/zapp-react-native-utils/numberUtils";
12
+ import { MeasurementPortalContext } from "../../../MeasurmentsPortal";
13
+ import { isNilOrEmpty } from "@applicaster/zapp-react-native-utils/reactUtils/helpers";
12
14
 
13
15
  type Props = {
14
16
  style: any;
@@ -32,14 +34,24 @@ const _Text = ({
32
34
  ...otherProps
33
35
  }: Props) => {
34
36
  const _label = useTextLabel({ label, entry });
37
+ const isMeasurement = React.useContext(MeasurementPortalContext);
35
38
 
36
39
  if (isNilOrEmpty(_label)) {
37
40
  return null;
38
41
  }
39
42
 
43
+ // set maximum possible height for the text in case of measurement
44
+ const height =
45
+ isMeasurement && otherProps.numberOfLines && style.lineHeight
46
+ ? toNumber(otherProps.numberOfLines) * toNumber(style.lineHeight)
47
+ : undefined;
48
+
40
49
  return (
41
50
  <Text
42
- style={withScaledLineHeight(withFocusedStyles({ style, otherProps }))}
51
+ style={[
52
+ withScaledLineHeight(withFocusedStyles({ style, otherProps })),
53
+ { height },
54
+ ]}
43
55
  {...withoutLabel(otherProps)}
44
56
  >
45
57
  {dateTransformEnabled
@@ -23,7 +23,11 @@ export const Toggle = (props: Props) => {
23
23
  iosBackgroundColor,
24
24
  } = style;
25
25
 
26
- const isSelected = React.useMemo(() => (cellState === "selected"), [item?.id, cellState]);
26
+ const isSelected = React.useMemo(
27
+ () => cellState === "selected",
28
+ [item?.id, cellState]
29
+ );
30
+
27
31
  const actionContext = useActions(action?.identifier);
28
32
 
29
33
  const [actionState, setActionState] = useState(
@@ -39,6 +39,6 @@ describe("image with no source", () => {
39
39
  );
40
40
 
41
41
  const testInstance = testRenderer.root;
42
- expect(testInstance.findByType(Image).props.source).toEqual({ uri: "" });
42
+ expect(testInstance.findByType(Image).props.source).toBeUndefined();
43
43
  });
44
44
  });