@applicaster/zapp-react-native-ui-components 12.0.0-alpha.3788876021 → 12.0.0-alpha.3823240084

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 (99) hide show
  1. package/Components/BaseFocusable/index.tsx +3 -3
  2. package/Components/Cell/Cell.tsx +30 -9
  3. package/Components/Cell/CellWithFocusable.tsx +23 -9
  4. package/Components/Cell/TvOSCellComponent.tsx +3 -7
  5. package/Components/Focusable/Focusable.tsx +6 -1
  6. package/Components/FocusableGroup/index.tsx +11 -2
  7. package/Components/GeneralContentScreen/utils/__tests__/useCurationAPI.test.js +13 -6
  8. package/Components/GeneralContentScreen/utils/useCurationAPI.ts +1 -1
  9. package/Components/HandlePlayable/HandlePlayable.tsx +3 -0
  10. package/Components/Layout/TV/ScreenContainer.tsx +79 -5
  11. package/Components/Layout/TV/ScreenLayoutContextProvider.tsx +2 -2
  12. package/Components/Layout/TV/__tests__/ScreenContainer.test.tsx +38 -28
  13. package/Components/Layout/TV/__tests__/__snapshots__/ScreenContainer.test.tsx.snap +25 -13
  14. package/Components/Layout/TV/__tests__/__snapshots__/index.test.tsx.snap +10 -50
  15. package/Components/Layout/TV/__tests__/index.test.tsx +20 -75
  16. package/Components/Layout/TV/index.tsx +14 -67
  17. package/Components/Layout/TV/index.web.tsx +33 -0
  18. package/Components/Layout/index.tsx +15 -11
  19. package/Components/MasterCell/DefaultComponents/ActionButton.tsx +4 -1
  20. package/Components/MasterCell/DefaultComponents/BorderContainerView/index.tsx +86 -116
  21. package/Components/MasterCell/DefaultComponents/DynamicBadge.tsx +4 -2
  22. package/Components/MasterCell/DefaultComponents/FocusableView/index.tsx +4 -1
  23. package/Components/MasterCell/DefaultComponents/Image/Image.ios.tsx +5 -3
  24. package/Components/MasterCell/DefaultComponents/ImageBorderContainer/index.ts +57 -0
  25. package/Components/MasterCell/DefaultComponents/ImageContainer/index.tsx +5 -1
  26. package/Components/MasterCell/DefaultComponents/LiveImage/index.tsx +34 -1
  27. package/Components/MasterCell/DefaultComponents/Text/index.tsx +14 -2
  28. package/Components/MasterCell/DefaultComponents/__tests__/image.test.js +1 -1
  29. package/Components/MasterCell/DefaultComponents/__tests__/text.test.tsx +24 -9
  30. package/Components/MasterCell/DefaultComponents/index.ts +2 -0
  31. package/Components/MasterCell/DefaultComponents/tv/ButtonContainerView/index.android.tsx +4 -1
  32. package/Components/MasterCell/DefaultComponents/tv/ButtonContainerView/index.tsx +10 -2
  33. package/Components/MasterCell/SharedUI/CollapsibleTextContainer/index.ts +1 -3
  34. package/Components/MasterCell/dataAdapter.ts +21 -7
  35. package/Components/MasterCell/hooks/useAsyncRendering/index.ts +1 -1
  36. package/Components/MasterCell/index.tsx +5 -3
  37. package/Components/MasterCell/utils/__tests__/insertBetween.test.js +9 -0
  38. package/Components/MasterCell/utils/index.ts +17 -30
  39. package/Components/MeasurmentsPortal/BasicMeasurementsPortal.tsx +11 -7
  40. package/Components/MeasurmentsPortal/MeasurementsPortal.tsx +10 -1
  41. package/Components/Navigator/StackNavigator.tsx +57 -0
  42. package/Components/Navigator/index.ts +1 -0
  43. package/Components/PlayerContainer/PlayerContainer.tsx +14 -6
  44. package/Components/River/ComponentsMap/ComponentsMap.tsx +92 -22
  45. package/Components/River/RefreshControl.tsx +55 -1
  46. package/Components/River/TV/River.tsx +0 -23
  47. package/Components/RouteManager/index.tsx +2 -2
  48. package/Components/Screen/TV/hooks/index.ts +3 -0
  49. package/Components/Screen/TV/hooks/useInitialFocus.ts +70 -0
  50. package/Components/Screen/TV/hooks/useRestoreFocus.ts +22 -0
  51. package/Components/Screen/TV/index.web.tsx +165 -0
  52. package/Components/Screen/__tests__/Screen.test.tsx +3 -0
  53. package/Components/Screen/__tests__/__snapshots__/Screen.test.tsx.snap +4 -0
  54. package/Components/Screen/index.tsx +62 -54
  55. package/Components/Screen/navigationHandler.ts +6 -3
  56. package/Components/ScreenResolver/index.tsx +9 -12
  57. package/Components/Transitioner/Scene.tsx +24 -25
  58. package/Components/Transitioner/Transitioner.tsx +38 -43
  59. package/Components/Transitioner/__tests__/__snapshots__/Scene.test.js.snap +12 -4
  60. package/Components/Transitioner/__tests__/__snapshots__/transitioner.test.js.snap +1 -0
  61. package/Components/VideoLive/LiveImageManager.ts +28 -1
  62. package/Components/VideoLive/PlayerLiveImageComponent.tsx +52 -24
  63. package/Components/VideoLive/__tests__/__snapshots__/PlayerLiveImageComponent.test.tsx.snap +25 -28
  64. package/Components/VideoModal/ModalAnimation/AnimatedPlayerModalWrapper.tsx +2 -14
  65. package/Components/VideoModal/ModalAnimation/AnimatedScrollModal.tsx +73 -48
  66. package/Components/VideoModal/ModalAnimation/AnimatedVideoPlayerComponent.tsx +55 -34
  67. package/Components/VideoModal/ModalAnimation/AnimationComponent.tsx +104 -86
  68. package/Components/VideoModal/ModalAnimation/ModalAnimationContext.tsx +44 -5
  69. package/Components/VideoModal/ModalAnimation/utils.ts +7 -4
  70. package/Components/VideoModal/PlayerDetails.tsx +3 -3
  71. package/Components/VideoModal/PlayerWrapper.tsx +67 -60
  72. package/Components/VideoModal/VideoModal.tsx +17 -17
  73. package/Components/VideoModal/__tests__/PlayerWrapper.test.tsx +7 -0
  74. package/Components/VideoModal/__tests__/__snapshots__/PlayerWrapper.test.tsx.snap +80 -14
  75. package/Components/VideoModal/hooks/useModalSize.ts +10 -12
  76. package/Components/VideoModal/utils.ts +5 -2
  77. package/Components/Viewport/ViewportTracker/ViewportTracker.tsx +31 -40
  78. package/Components/Viewport/ViewportTracker/index.tsx +1 -0
  79. package/Components/Viewport/utils.js +1 -1
  80. package/Components/ZappFrameworkComponents/BarView/BarView.tsx +4 -3
  81. package/Components/default-cell-renderer/__tests__/__snapshots__/defaultCellRenderer.test.tsx.snap +4 -4
  82. package/Contexts/FocusableGroupContext/FocusableGroupContext.ts +3 -0
  83. package/Contexts/FocusableGroupContext/FocusableGroupContextProvider.tsx +16 -0
  84. package/Contexts/FocusableGroupContext/__tests__/FocusableGroupContextProvider.test.tsx +22 -0
  85. package/Contexts/FocusableGroupContext/__tests__/withFocusableContext.test.tsx +26 -0
  86. package/Contexts/FocusableGroupContext/index.ts +7 -0
  87. package/Contexts/FocusableGroupContext/withFocusableContext.tsx +17 -0
  88. package/Contexts/MenuToggleContext/{index.js → index.ts} +16 -0
  89. package/Contexts/ScreenContext/__tests__/__snapshots__/index.test.tsx.snap +3 -0
  90. package/Contexts/ScreenContext/__tests__/index.test.tsx +27 -0
  91. package/Contexts/ScreenContext/index.tsx +94 -25
  92. package/Contexts/ScreenDataContext/index.tsx +20 -0
  93. package/Contexts/ZappPipesContext/ZappPipesEntryContext.ts +1 -1
  94. package/events/index.ts +1 -0
  95. package/package.json +5 -5
  96. package/Components/Layout/TV/TransitionOverlay.tsx +0 -64
  97. /package/Components/FocusableGroup/{index.android.js → index.android.ts} +0 -0
  98. /package/Components/FocusableGroup/{index.ios.js → index.ios.ts} +0 -0
  99. /package/Contexts/{index.js → index.ts} +0 -0
@@ -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;
@@ -4,6 +4,7 @@ import { Focusable } from "@applicaster/zapp-react-native-ui-components/Componen
4
4
  import { useActions } from "@applicaster/zapp-react-native-utils/reactHooks/actions";
5
5
  import * as R from "ramda";
6
6
  import { getXray } from "@applicaster/zapp-react-native-utils/logger";
7
+ import { toBooleanWithDefaultFalse } from "@applicaster/zapp-react-native-utils/booleanUtils";
7
8
 
8
9
  const { Logger } = getXray();
9
10
 
@@ -35,7 +36,9 @@ export function FocusableView({ style, children, item, ...otherProps }: Props) {
35
36
 
36
37
  const focusableId = getFocusableId(prefixId, suffixId);
37
38
 
38
- const focused = focusableId === focusedButtonId;
39
+ const focused =
40
+ focusableId === focusedButtonId ||
41
+ toBooleanWithDefaultFalse(otherProps.focused);
39
42
 
40
43
  const additionalStyles = focused ? focusedStyles : normalStyles;
41
44
 
@@ -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,57 @@
1
+ import { ImageStyle } from "react-native";
2
+
3
+ import {
4
+ getImageContainerMarginStyles,
5
+ ifElseFocusedSelected,
6
+ } from "@applicaster/zapp-react-native-utils/cellUtils";
7
+ import { toNumberWithDefaultZero } from "@applicaster/zapp-react-native-utils/numberUtils";
8
+
9
+ export const ImageBorderContainer = ({
10
+ value,
11
+ state,
12
+ imageStyles,
13
+ }: {
14
+ value: (key: string) => string;
15
+ state: CellState;
16
+ imageStyles: ImageStyle;
17
+ }) => {
18
+ return {
19
+ type: "BorderContainerView",
20
+ style: {
21
+ ...getImageContainerMarginStyles({ value }),
22
+ position: "absolute",
23
+ top: 0,
24
+ zIndex: 1,
25
+ borderWidth: value("image_border_size"),
26
+ borderColor: ifElseFocusedSelected(
27
+ state,
28
+ value("image_focused_border_color"),
29
+ value("image_selected_border_color"),
30
+ value("image_focused_selected_border_color"),
31
+ value("image_border_color")
32
+ ),
33
+ borderRadius: toNumberWithDefaultZero(value("image_corner_radius")),
34
+ },
35
+ additionalProps: {
36
+ borderPosition: value("image_border_position"),
37
+ borderPaddingTop: toNumberWithDefaultZero(
38
+ value("image_border_padding_top")
39
+ ),
40
+ borderPaddingRight: toNumberWithDefaultZero(
41
+ value("image_border_padding_right")
42
+ ),
43
+ borderPaddingBottom: toNumberWithDefaultZero(
44
+ value("image_border_padding_bottom")
45
+ ),
46
+ borderPaddingLeft: toNumberWithDefaultZero(
47
+ value("image_border_padding_left")
48
+ ),
49
+ },
50
+ elements: [
51
+ {
52
+ type: "View",
53
+ style: imageStyles,
54
+ },
55
+ ],
56
+ };
57
+ };
@@ -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
  };
@@ -108,6 +108,26 @@ const prepareEntry = (entry) => {
108
108
  };
109
109
  }
110
110
 
111
+ const previewPlayback =
112
+ entry.extensions?.["brightcove"]?.["preview_playback"];
113
+
114
+ if (previewPlayback) {
115
+ return {
116
+ ...entry,
117
+ extensions: {
118
+ ...entry.extensions,
119
+ brightcove: {
120
+ ...entry?.extensions?.["brightcove"],
121
+ video_id: previewPlayback,
122
+ },
123
+ },
124
+ };
125
+ }
126
+
127
+ if (entry.extensions?.["brightcove"]?.["video_id"]) {
128
+ return entry;
129
+ }
130
+
111
131
  const src = entry.content?.src;
112
132
 
113
133
  if (!src) {
@@ -177,10 +197,23 @@ const getPlayerConfig = (player_screen_id, actionIdentifier) => {
177
197
  const positionAbsolute: ViewStyle = { position: "absolute" };
178
198
 
179
199
  const LiveImageComponent = (props: LiveImageProps) => {
180
- const { item, style, cellUUID, imageKey, actionIdentifier, state } = props;
200
+ const {
201
+ item,
202
+ style: componentStyle,
203
+ cellUUID,
204
+ imageKey,
205
+ actionIdentifier,
206
+ state,
207
+ } = props;
181
208
 
182
209
  const component = useUIComponentContext();
183
210
 
211
+ // Fix for blinking on state change
212
+ const style = React.useMemo(
213
+ () => ({ ...componentStyle, backgroundColor: "transparent" }),
214
+ [componentStyle]
215
+ );
216
+
184
217
  const componentType = React.useMemo(
185
218
  () => getPropComponentType(component),
186
219
  [component?.id]
@@ -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
@@ -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
  });
@@ -1,11 +1,23 @@
1
1
  import React from "react";
2
- import { Text } from "react-native";
2
+ import RN from "react-native";
3
3
  import { Provider } from "react-redux";
4
4
  import TestRenderer from "react-test-renderer";
5
- import configureStore from "redux-mock-store";
6
- import CustomText from "../Text";
5
+ import configureStoreFn from "redux-mock-store";
7
6
 
8
- const mockStore = configureStore();
7
+ const mockUseIsRTL = jest.fn(() => true);
8
+ const mockGetIsRTL = jest.fn(() => true);
9
+ const mockUseLocalizedStrings = jest.fn(() => ({}));
10
+ const mockGetUILanguage = jest.fn(() => "he-HE");
11
+
12
+ jest.mock("@applicaster/zapp-react-native-utils/localizationUtils", () => ({
13
+ useIsRTL: mockUseIsRTL,
14
+ getIsRTL: mockGetIsRTL,
15
+ useLocalizedStrings: mockUseLocalizedStrings,
16
+ getUILanguage: mockGetUILanguage,
17
+ }));
18
+
19
+ const CustomText = require("../Text").default;
20
+ const mockStore = configureStoreFn();
9
21
 
10
22
  const defaultProps = {
11
23
  entry: {},
@@ -22,7 +34,7 @@ const getRenderedText = (label: string, store: any) => {
22
34
  </Provider>
23
35
  );
24
36
 
25
- return testRenderer.root.findByType(Text).props.children;
37
+ return testRenderer.root.findByType(RN.Text).props.children;
26
38
  };
27
39
 
28
40
  describe("RTL app: Hebrew text contains english word", () => {
@@ -34,7 +46,7 @@ describe("RTL app: Hebrew text contains english word", () => {
34
46
  remoteConfigurations: { localizations: { he: {} } },
35
47
  appData: {
36
48
  languageCode: "he",
37
- countryCode: "HE",
49
+ countryCode: "IL",
38
50
  },
39
51
  });
40
52
 
@@ -47,18 +59,22 @@ describe("RTL app: Hebrew text contains english word", () => {
47
59
 
48
60
  it("Hebrew text contains not first english word", () => {
49
61
  const renderedText = getRenderedText(textWithNotFirstEnglishWord, store);
50
-
51
62
  expect(renderedText).toEqual(textWithNotFirstEnglishWord);
52
63
  });
53
64
 
54
65
  it("Hebrew text doesn't contain english word", () => {
55
66
  const renderedText = getRenderedText(textWithoutEnglishWord, store);
56
-
57
67
  expect(renderedText).toEqual(textWithoutEnglishWord);
58
68
  });
59
69
  });
60
70
 
61
71
  describe("LTR app: English text", () => {
72
+ beforeAll(() => {
73
+ mockUseIsRTL.mockReturnValue(false);
74
+ mockGetIsRTL.mockReturnValue(false);
75
+ mockGetUILanguage.mockReturnValue("en-US");
76
+ });
77
+
62
78
  const englishText = "Test sentence";
63
79
 
64
80
  const store = mockStore({
@@ -71,7 +87,6 @@ describe("LTR app: English text", () => {
71
87
 
72
88
  it("English text", () => {
73
89
  const renderedText = getRenderedText(englishText, store);
74
-
75
90
  expect(renderedText).toEqual(englishText);
76
91
  });
77
92
  });
@@ -15,6 +15,7 @@ import { BorderContainerView } from "./BorderContainerView";
15
15
  import { CellBadge } from "./CellBadge";
16
16
  import { TvActionButtons } from "./tv/TvActionButtons";
17
17
  import { ButtonContainerView } from "./tv/ButtonContainerView";
18
+ import { ImageBorderContainer } from "./ImageBorderContainer";
18
19
 
19
20
  export const defaultComponents = {
20
21
  View,
@@ -28,6 +29,7 @@ export const defaultComponents = {
28
29
  ProgressBar,
29
30
  Toggle,
30
31
  LiveImage,
32
+ ImageBorderContainer,
31
33
  BorderContainerView,
32
34
  DynamicBadge,
33
35
  SecondaryImage,
@@ -61,7 +61,10 @@ export function ButtonContainerView({
61
61
  <View style={applyRTLStylesIfNeeded(style, isRTL)}>
62
62
  {insertBetween(
63
63
  (index) => (
64
- <HorizontalSeparator key={index} width={horizontalGutter} />
64
+ <HorizontalSeparator
65
+ key={`separator_${index}`}
66
+ width={horizontalGutter}
67
+ />
65
68
  ),
66
69
  cloneElementsWithIds(buttonIds, filteredChildren)
67
70
  )}
@@ -7,6 +7,10 @@ import type {
7
7
  ContainerProps,
8
8
  ContainerChildren,
9
9
  } from "./types";
10
+ import {
11
+ useIsRTL,
12
+ applyRTLStylesIfNeeded,
13
+ } from "@applicaster/zapp-react-native-utils/localizationUtils";
10
14
 
11
15
  const HorizontalSeparator = ({ width }: HorizontalSeparatorProps) => (
12
16
  <View style={{ width }} />
@@ -17,6 +21,7 @@ export function ButtonContainerView({
17
21
  children,
18
22
  ...otherProps
19
23
  }: ContainerProps) {
24
+ const isRTL = useIsRTL();
20
25
  const horizontalGutter = R.pathOr(0, ["horizontalGutter"], otherProps);
21
26
 
22
27
  const filteredChildren = useFilterChildren<ContainerChildren>(children);
@@ -26,10 +31,13 @@ export function ButtonContainerView({
26
31
  }
27
32
 
28
33
  return (
29
- <View style={style}>
34
+ <View style={applyRTLStylesIfNeeded(style, isRTL)}>
30
35
  {insertBetween(
31
36
  (index) => (
32
- <HorizontalSeparator key={index} width={horizontalGutter} />
37
+ <HorizontalSeparator
38
+ key={`separator_${index}`}
39
+ width={horizontalGutter}
40
+ />
33
41
  ),
34
42
  filteredChildren
35
43
  )}
@@ -51,9 +51,7 @@ export const CollapsibleTextContainer = ({
51
51
  func: (data) => {
52
52
  return getColorFromData({
53
53
  data,
54
- getValue,
55
- key: "background_color",
56
- defaultColor: additionalStyles.backgroundColor,
54
+ valueFromLayout: additionalStyles.backgroundColor,
57
55
  });
58
56
  },
59
57
  propName: "backgroundColor",
@@ -37,14 +37,28 @@ function retrieveData(entry, func, args) {
37
37
  */
38
38
 
39
39
  export function configInflater(
40
- entry,
41
- { type, style, additionalProps = {}, data = [], elements }
40
+ entry: any,
41
+ {
42
+ type,
43
+ style,
44
+ additionalProps = {},
45
+ data = [],
46
+ elements,
47
+ }: {
48
+ type: any;
49
+ style: any;
50
+ additionalProps?: Record<string, any>;
51
+ data?: Array<{ propName: string; func: Function; args: any[] }>;
52
+ elements?: any[];
53
+ }
42
54
  ) {
43
- const props = R.reduce(
44
- (acc, curr) =>
45
- R.assoc(curr.propName, retrieveData(entry, curr.func, curr.args), acc),
46
- additionalProps,
47
- data
55
+ const props = data.reduce(
56
+ (acc, curr) => {
57
+ acc[curr.propName] = retrieveData(entry, curr.func, curr.args);
58
+
59
+ return acc;
60
+ },
61
+ { ...additionalProps }
48
62
  );
49
63
 
50
64
  let adjustedElements;
@@ -53,7 +53,7 @@ export const useAsyncRendering = (viewRef: React.RefObject<View>): Return => {
53
53
  measure(viewRef?.current, ({ width, height }) => {
54
54
  setDimensions({
55
55
  width,
56
- height,
56
+ height: Math.ceil(height),
57
57
  });
58
58
  });
59
59
  })
@@ -52,6 +52,8 @@ export function masterCellBuilder({
52
52
  const { View } = componentsMap;
53
53
  const elementsBuilder = dataAdapter(cellConfiguration);
54
54
 
55
+ // This is very expensive operation
56
+ // Keep calls to minimum
55
57
  const hasFocusableInside = hasFocusableInsideBuilder(elementsBuilder);
56
58
 
57
59
  /**
@@ -74,8 +76,8 @@ export function masterCellBuilder({
74
76
  const selectedState = screen?.selectedEntry;
75
77
 
76
78
  const entryIsSelected = React.useMemo(
77
- () => selectedState?.id === item?.id,
78
- [selectedState?.id]
79
+ () => !!(selectedState?.id && selectedState?.id === item?.id),
80
+ [selectedState?.id, item?.id]
79
81
  );
80
82
 
81
83
  const elements = React.useMemo(
@@ -84,7 +86,7 @@ export function masterCellBuilder({
84
86
  entry: item,
85
87
  state: getEntryState(state, entryIsSelected),
86
88
  }),
87
- [state, item, entryIsSelected]
89
+ [state, item?.id, entryIsSelected] // Assuming that item won't mutate
88
90
  );
89
91
 
90
92
  const wrapperRef = React.useRef(null);
@@ -9,4 +9,13 @@ describe("insertBetween", () => {
9
9
 
10
10
  expect(result).toEqual([1, "|", 2, "|", 3]);
11
11
  });
12
+
13
+ it("insertBetween", () => {
14
+ const separator = (index) => `separator:${index}`;
15
+ const items = [1, 2, 3];
16
+
17
+ const result = insertBetween(separator, items);
18
+
19
+ expect(result).toEqual([1, "separator:0", 2, "separator:1", 3]);
20
+ });
12
21
  });
@@ -1,5 +1,6 @@
1
1
  import React, { useEffect, useMemo } from "react";
2
2
  import * as R from "ramda";
3
+ import validateColor from "validate-color";
3
4
  import { platformSelect } from "@applicaster/zapp-react-native-utils/reactUtils";
4
5
  import { useActions } from "@applicaster/zapp-react-native-utils/reactHooks/actions";
5
6
 
@@ -9,6 +10,7 @@ import { usePlayer } from "@applicaster/zapp-react-native-utils/appUtils/playerM
9
10
  import { PushTopicManager } from "@applicaster/zapp-react-native-bridge/PushNotifications/PushTopicManager";
10
11
  import { StorageMultiSelectProvider } from "@applicaster/zapp-react-native-bridge/ZappStorage/StorageMultiSelectProvider";
11
12
  import { getCellState } from "../../Cell/utils";
13
+ import { getColorFromData } from "@applicaster/zapp-react-native-utils/cellUtils";
12
14
 
13
15
  const hasElementSpecificViewType = (viewType) => (element) => {
14
16
  if (R.isNil(element)) {
@@ -47,44 +49,29 @@ export const hasElementsSpecificViewType = (viewType) => (elements) => {
47
49
  return R.any(hasElementSpecificViewType(viewType))(elements);
48
50
  };
49
51
 
50
- const isColorOrEmpty = (value) =>
51
- value === null ||
52
- value === undefined ||
53
- value === "" ||
54
- value.startsWith("#") ||
55
- value.startsWith("rgba") ||
56
- value === "transparent";
57
-
58
52
  function resolveColorForProp(entry, style, colorProp) {
59
- const colorValue = style[colorProp];
60
-
61
- if (isColorOrEmpty(colorValue)) {
62
- return style;
53
+ const colorFromProp = style[colorProp];
54
+ const nestedEntryValue = R.path(colorFromProp.split("."), entry);
55
+
56
+ if (
57
+ nestedEntryValue === undefined &&
58
+ !validateColor(colorFromProp.replace(".00", "")) // https://github.com/dreamyguy/validate-color/issues/44
59
+ ) {
60
+ logWarning(colorFromProp, style, entry, nestedEntryValue);
63
61
  }
64
62
 
65
- const pathParts = colorValue.split(".");
66
- let nestedEntryValue = entry;
67
-
68
- for (const part of pathParts) {
69
- if (nestedEntryValue === null || typeof nestedEntryValue !== "object") {
70
- logWarning(colorValue, style, entry, nestedEntryValue);
71
-
72
- return style;
73
- }
74
-
75
- nestedEntryValue = nestedEntryValue[part];
76
- }
63
+ const colorValue = getColorFromData({
64
+ data: entry,
65
+ valueFromLayout: colorFromProp,
66
+ });
77
67
 
78
- if (nestedEntryValue === undefined) {
79
- logWarning(colorValue, style, entry, nestedEntryValue);
68
+ if (!colorValue) {
69
+ logWarning(colorProp, style, entry, colorValue);
80
70
 
81
71
  return style;
82
72
  }
83
73
 
84
- // After successful traversal, set the value.
85
- style[colorProp] = nestedEntryValue;
86
-
87
- return style;
74
+ return { ...style, [colorProp]: colorValue };
88
75
  }
89
76
 
90
77
  export function resolveColor(entry, style) {
@@ -1,5 +1,6 @@
1
1
  import React from "react";
2
2
  import { View, StyleSheet } from "react-native";
3
+ import { MeasurementPortalContext } from "./MeasurementsPortal";
3
4
 
4
5
  type Props = {
5
6
  Component: React.ElementType;
@@ -19,13 +20,16 @@ const _MeasurementsPortal = (
19
20
  { Component, onLayout, componentProps, containerStyle }: Props,
20
21
  ref
21
22
  ) => (
22
- <View
23
- onLayout={onLayout}
24
- style={[styles.container, containerStyle]}
25
- ref={ref}
26
- >
27
- <Component {...componentProps} />
28
- </View>
23
+ // hack for cell to determine if cell is in measurement mode
24
+ <MeasurementPortalContext.Provider value={{}}>
25
+ <View
26
+ onLayout={onLayout}
27
+ style={[styles.container, containerStyle]}
28
+ ref={ref}
29
+ >
30
+ <Component {...componentProps} />
31
+ </View>
32
+ </MeasurementPortalContext.Provider>
29
33
  );
30
34
 
31
35
  export const MeasurementsPortal = React.forwardRef(_MeasurementsPortal);
@@ -35,7 +35,16 @@ const MeasurementsPortal = ({ Component, onLayout, componentProps }: Props) => {
35
35
  );
36
36
  };
37
37
 
38
- const MeasurementPortalContext = React.createContext(null);
38
+ type MeasurementPortalContextType = {
39
+ measureComponent?: (
40
+ comp: React.ElementType,
41
+ props: Record<any, any>
42
+ ) => Promise<any>;
43
+ measuringInProgress?: boolean;
44
+ };
45
+
46
+ const MeasurementPortalContext =
47
+ React.createContext<null | MeasurementPortalContextType>(null);
39
48
 
40
49
  const MeasurementsPortalContextProvider = ({ children }) => {
41
50
  const Component = React.useRef(View);