@applicaster/zapp-react-native-ui-components 15.1.0-rc.8 → 16.0.0-alpha.1833861900

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 (157) hide show
  1. package/Components/BackgroundImage/BackgroundImage.tsx +42 -0
  2. package/Components/BackgroundImage/BackgroundImage.tv.android.tsx +28 -0
  3. package/Components/BackgroundImage/BackgroundImage.tv.ios.tsx +24 -0
  4. package/Components/BackgroundImage/index.ts +1 -0
  5. package/Components/BaseFocusable/index.ios.ts +12 -2
  6. package/Components/Cell/FocusableWrapper.tsx +3 -0
  7. package/Components/Cell/TvOSCellComponent.tsx +6 -3
  8. package/Components/CellRendererResolver/index.ts +1 -1
  9. package/Components/ComponentResolver/__tests__/componentResolver.test.js +1 -1
  10. package/Components/Focusable/Focusable.tsx +4 -2
  11. package/Components/Focusable/FocusableTvOS.tsx +18 -1
  12. package/Components/Focusable/__tests__/__snapshots__/FocusableTvOS.test.tsx.snap +1 -0
  13. package/Components/FocusableGroup/FocusableTvOS.tsx +41 -8
  14. package/Components/GeneralContentScreen/utils/__tests__/useCurationAPI.test.js +1 -1
  15. package/Components/HandlePlayable/HandlePlayable.tsx +13 -8
  16. package/Components/Layout/TV/NavBarContainer.tsx +1 -10
  17. package/Components/Layout/TV/ScreenContainer.tsx +2 -6
  18. package/Components/Layout/TV/__tests__/__snapshots__/NavBarContainer.test.tsx.snap +7 -12
  19. package/Components/Layout/TV/__tests__/__snapshots__/ScreenContainer.test.tsx.snap +7 -12
  20. package/Components/Layout/TV/__tests__/__snapshots__/index.test.tsx.snap +0 -1
  21. package/Components/Layout/TV/index.tsx +5 -7
  22. package/Components/Layout/TV/index.web.tsx +5 -7
  23. package/Components/LinkHandler/LinkHandler.tsx +2 -2
  24. package/Components/MasterCell/CONFIG_BUILDER_TO_REACT_COMPONENT.md +144 -0
  25. package/Components/MasterCell/DefaultComponents/ActionButton.tsx +16 -5
  26. package/Components/MasterCell/DefaultComponents/ActionButtonsCore/__tests__/model.test.ts +80 -0
  27. package/Components/MasterCell/DefaultComponents/ActionButtonsCore/__tests__/placement.test.ts +187 -0
  28. package/Components/MasterCell/DefaultComponents/ActionButtonsCore/__tests__/selectors.test.ts +45 -0
  29. package/Components/MasterCell/DefaultComponents/ActionButtonsCore/__tests__/style.test.ts +49 -0
  30. package/Components/MasterCell/DefaultComponents/ActionButtonsCore/components/ActionButtonController.tsx +165 -0
  31. package/Components/MasterCell/DefaultComponents/ActionButtonsCore/components/__tests__/ActionButtonController.test.tsx +405 -0
  32. package/Components/MasterCell/DefaultComponents/ActionButtonsCore/components/index.ts +1 -0
  33. package/Components/MasterCell/DefaultComponents/ActionButtonsCore/model.ts +47 -0
  34. package/Components/MasterCell/DefaultComponents/ActionButtonsCore/placement.ts +170 -0
  35. package/Components/MasterCell/DefaultComponents/ActionButtonsCore/selectors.ts +26 -0
  36. package/Components/MasterCell/DefaultComponents/ActionButtonsCore/style.ts +29 -0
  37. package/Components/MasterCell/DefaultComponents/ActionButtonsCore/types.ts +37 -0
  38. package/Components/MasterCell/DefaultComponents/BorderContainerView/index.tsx +4 -10
  39. package/Components/MasterCell/DefaultComponents/Button.tsx +0 -15
  40. package/Components/MasterCell/DefaultComponents/ButtonContainerView/components/HorizontalSeparator.tsx +8 -0
  41. package/Components/MasterCell/DefaultComponents/ButtonContainerView/index.tsx +15 -0
  42. package/Components/MasterCell/DefaultComponents/ButtonContainerView/index.tv.android.tsx +58 -0
  43. package/Components/MasterCell/DefaultComponents/{tv/ButtonContainerView/index.tsx → ButtonContainerView/index.tv.tsx} +3 -11
  44. package/Components/MasterCell/DefaultComponents/ButtonContainerView/index.web.ts +1 -0
  45. package/Components/MasterCell/DefaultComponents/ButtonContainerView/types.ts +40 -0
  46. package/Components/MasterCell/DefaultComponents/DataProvider/index.tsx +163 -0
  47. package/Components/MasterCell/DefaultComponents/FocusableView/index.android.tsx +2 -23
  48. package/Components/MasterCell/DefaultComponents/FocusableView/index.tsx +4 -22
  49. package/Components/MasterCell/DefaultComponents/Image/Image.android.tsx +8 -2
  50. package/Components/MasterCell/DefaultComponents/Image/Image.ios.tsx +11 -3
  51. package/Components/MasterCell/DefaultComponents/Image/Image.web.tsx +9 -1
  52. package/Components/MasterCell/DefaultComponents/Image/hooks/useImage.ts +15 -14
  53. package/Components/MasterCell/DefaultComponents/LiveImage/index.tsx +1 -2
  54. package/Components/MasterCell/DefaultComponents/PressableView.tsx +34 -0
  55. package/Components/MasterCell/DefaultComponents/SecondaryImage/hooks/__tests__/useGetImageDimensions.test.ts +7 -6
  56. package/Components/MasterCell/DefaultComponents/Text/hooks/useText.ts +11 -0
  57. package/Components/MasterCell/DefaultComponents/__tests__/DataProvider.test.tsx +141 -0
  58. package/Components/MasterCell/DefaultComponents/index.ts +9 -3
  59. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/ActionButton.tsx +135 -0
  60. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/Asset.ts +33 -0
  61. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/AssetComponent.tsx +22 -0
  62. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/Button.ts +125 -0
  63. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/Spacer.ts +16 -0
  64. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/TextLabel.ts +67 -0
  65. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/TextLabelsContainer.ts +37 -0
  66. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/__tests__/PressableView.test.tsx +393 -0
  67. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/__tests__/builders.test.ts +141 -0
  68. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/__tests__/index.test.ts +343 -0
  69. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/helpers.ts +105 -0
  70. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/index.ts +122 -0
  71. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/utils/__tests__/insertButtons.test.ts +118 -0
  72. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/utils/index.ts +238 -0
  73. package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/Asset.ts +4 -18
  74. package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/Button.ts +24 -73
  75. package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/TextLabelsContainer.ts +37 -18
  76. package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/TvActionButton.tsx +27 -0
  77. package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/__tests__/index.test.ts +89 -0
  78. package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/__tests__/renderedTree.test.tsx +231 -0
  79. package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/index.ts +47 -48
  80. package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/utils/__tests__/getPluginIdentifier.test.ts +115 -29
  81. package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/utils/index.ts +101 -144
  82. package/Components/MasterCell/MappingFunctions/index.js +3 -2
  83. package/Components/MasterCell/README.md +4 -0
  84. package/Components/MasterCell/__tests__/__snapshots__/dataAdapter.test.js.snap +24 -0
  85. package/Components/MasterCell/__tests__/configInflater.test.js +1 -0
  86. package/Components/MasterCell/__tests__/elementMapper.test.js +46 -0
  87. package/Components/MasterCell/dataAdapter.ts +4 -1
  88. package/Components/MasterCell/elementMapper.tsx +52 -7
  89. package/Components/MasterCell/utils/__tests__/cloneChildrenWithIds.test.tsx +43 -0
  90. package/Components/MasterCell/utils/__tests__/useFilterChildren.test.tsx +80 -0
  91. package/Components/MasterCell/utils/index.ts +85 -15
  92. package/Components/OfflineHandler/NotificationView/NotificationView.tsx +2 -2
  93. package/Components/OfflineHandler/NotificationView/__tests__/index.test.tsx +17 -18
  94. package/Components/OfflineHandler/__tests__/index.test.tsx +27 -18
  95. package/Components/PlayerContainer/PlayerContainer.tsx +15 -14
  96. package/Components/PlayerContainer/__tests__/PlayerContainer.test.tsx +284 -0
  97. package/Components/River/ComponentsMap/ComponentsMap.tsx +6 -19
  98. package/Components/River/ComponentsMap/hooks/__tests__/useLoadingState.test.ts +1 -1
  99. package/Components/River/RefreshControl.tsx +19 -88
  100. package/Components/River/River.tsx +9 -82
  101. package/Components/River/TV/River.tsx +31 -14
  102. package/Components/River/TV/index.tsx +8 -4
  103. package/Components/River/TV/utils/__tests__/toStringOrEmpty.test.ts +30 -0
  104. package/Components/River/TV/utils/index.ts +4 -0
  105. package/Components/River/TV/withFocusableGroupForContent.tsx +71 -0
  106. package/Components/River/__tests__/__snapshots__/componentsMap.test.js.snap +1 -0
  107. package/Components/River/__tests__/componentsMap.test.js +38 -0
  108. package/Components/River/hooks/__tests__/usePullToRefresh.test.ts +132 -0
  109. package/Components/River/hooks/index.ts +1 -0
  110. package/Components/River/hooks/usePullToRefresh.ts +51 -0
  111. package/Components/Screen/TV/index.web.tsx +4 -2
  112. package/Components/Screen/__tests__/Screen.test.tsx +65 -42
  113. package/Components/Screen/__tests__/__snapshots__/Screen.test.tsx.snap +68 -44
  114. package/Components/Screen/hooks.ts +2 -3
  115. package/Components/Screen/index.tsx +2 -3
  116. package/Components/Screen/orientationHandler.ts +3 -3
  117. package/Components/ScreenResolver/index.tsx +9 -5
  118. package/Components/ScreenRevealManager/Overlay.tsx +34 -0
  119. package/Components/ScreenRevealManager/ScreenRevealManager.ts +40 -8
  120. package/Components/ScreenRevealManager/__tests__/Overlay.test.tsx +88 -0
  121. package/Components/ScreenRevealManager/__tests__/ScreenRevealManager.test.ts +86 -69
  122. package/Components/ScreenRevealManager/withScreenRevealManager.tsx +9 -20
  123. package/Components/Tabs/TabContent.tsx +7 -4
  124. package/Components/TopCutoffOverlay/__tests__/TopCutoffOverlay.test.tsx +201 -0
  125. package/Components/TopCutoffOverlay/hooks/__tests__/useMarginTop.test.ts +130 -0
  126. package/Components/TopCutoffOverlay/hooks/index.ts +1 -0
  127. package/Components/TopCutoffOverlay/hooks/useMarginTop.ts +59 -0
  128. package/Components/TopCutoffOverlay/index.tsx +55 -0
  129. package/Components/Transitioner/index.js +3 -3
  130. package/Components/VideoModal/ModalAnimation/ModalAnimationContext.tsx +5 -5
  131. package/Components/VideoModal/hooks/__tests__/useDelayedPlayerDetails.test.ts +15 -7
  132. package/Components/VideoModal/utils.ts +18 -10
  133. package/Components/Viewport/ViewportAware/__tests__/viewportAware.test.js +0 -2
  134. package/Components/Viewport/ViewportAware/index.tsx +16 -7
  135. package/Components/Viewport/ViewportEvents/__tests__/viewportEvents.test.js +1 -1
  136. package/Components/ZappFrameworkComponents/BarView/BarView.tsx +4 -6
  137. package/Components/ZappFrameworkComponents/BarView/__tests__/BarView.test.tsx +2 -2
  138. package/Components/default-cell-renderer/viewTrees/mobile/index.ts +0 -3
  139. package/Contexts/ScreenContext/index.tsx +25 -18
  140. package/Contexts/ScreenTrackedViewPositionsContext/__tests__/index.test.tsx +1 -1
  141. package/Decorators/Analytics/index.tsx +6 -5
  142. package/Decorators/ConfigurationWrapper/__tests__/__snapshots__/withConfigurationProvider.test.tsx.snap +1 -0
  143. package/Decorators/ConfigurationWrapper/const.ts +1 -0
  144. package/Decorators/ZappPipesDataConnector/__tests__/UrlFeedResolver.test.tsx +39 -21
  145. package/Decorators/ZappPipesDataConnector/__tests__/zappPipesDataConnector.test.js +1 -1
  146. package/Decorators/ZappPipesDataConnector/index.tsx +2 -2
  147. package/Decorators/ZappPipesDataConnector/resolvers/StaticFeedResolver.tsx +1 -1
  148. package/Decorators/ZappPipesDataConnector/resolvers/UrlFeedResolver.tsx +18 -7
  149. package/Helpers/DataSourceHelper/__tests__/itemLimitForData.test.ts +80 -0
  150. package/Helpers/DataSourceHelper/index.ts +19 -0
  151. package/Helpers/index.js +7 -1
  152. package/package.json +5 -5
  153. package/Components/Layout/TV/LayoutBackground.tsx +0 -28
  154. package/Components/MasterCell/DefaultComponents/tv/ButtonContainerView/index.android.tsx +0 -135
  155. package/Components/MasterCell/DefaultComponents/tv/ButtonContainerView/types.ts +0 -25
  156. package/Components/River/TV/withTVEventHandler.tsx +0 -36
  157. package/Helpers/DataSourceHelper/index.js +0 -19
@@ -1,17 +1,11 @@
1
1
  import React from "react";
2
2
  import { View, ImageStyle } from "react-native";
3
3
  import { Focusable } from "@applicaster/zapp-react-native-ui-components/Components/Focusable";
4
- import { useActions } from "@applicaster/zapp-react-native-utils/reactHooks/actions";
5
- import { getXray } from "@applicaster/zapp-react-native-utils/logger";
6
4
  import { useFocusable } from "@applicaster/zapp-react-native-ui-components/Components/Focusable/index.android";
7
5
  import { useIsRTL } from "@applicaster/zapp-react-native-utils/localizationUtils";
8
6
 
9
- const { Logger } = getXray();
10
-
11
7
  import { recursiveCloneElementsWithState } from "../../utils";
12
8
 
13
- const logger = new Logger("plugin", "plugins/navigation-action");
14
-
15
9
  type ButtonProps = Record<string, any> & {
16
10
  style: ImageStyle;
17
11
  };
@@ -33,7 +27,7 @@ const getNextFocusRight = ({ nextFocusRight, parentFocus, isRTL }) => {
33
27
  };
34
28
 
35
29
  export function FocusableViewComponent(
36
- { style, children, item, ...otherProps }: ButtonProps,
30
+ { style, children, ...otherProps }: ButtonProps,
37
31
  ref
38
32
  ) {
39
33
  const {
@@ -44,7 +38,6 @@ export function FocusableViewComponent(
44
38
  focusedStyles,
45
39
  nextFocusLeft,
46
40
  nextFocusRight,
47
- pluginIdentifier,
48
41
  disableFocus,
49
42
  onButtonFocus,
50
43
  } = otherProps;
@@ -52,20 +45,6 @@ export function FocusableViewComponent(
52
45
  const parentFocus = useFocusable();
53
46
  const isRTL = useIsRTL();
54
47
 
55
- const actionContext = useActions(pluginIdentifier);
56
-
57
- const onPress = () => {
58
- if (!actionContext) {
59
- logger.warning(
60
- `Cannot resolve action context for ${pluginIdentifier} - please make sure the plugin is installed and up to date`
61
- );
62
-
63
- return;
64
- }
65
-
66
- actionContext?.invokeAction?.(item);
67
- };
68
-
69
48
  const onFocus = React.useCallback(
70
49
  (ref) => {
71
50
  onButtonFocus?.(ref);
@@ -82,7 +61,7 @@ export function FocusableViewComponent(
82
61
  id={generateId(cellUUID, suffixId)}
83
62
  disableFocus={disableFocus}
84
63
  groupId={groupId}
85
- onPress={onPress}
64
+ onPress={otherProps.onPress}
86
65
  nextFocusUp={parentFocus?.nextFocusUp}
87
66
  nextFocusDown={parentFocus?.nextFocusDown}
88
67
  nextFocusLeft={getNextFocusLeft({ nextFocusLeft, parentFocus, isRTL })}
@@ -1,26 +1,20 @@
1
1
  import React, { useMemo } from "react";
2
2
  import { ImageStyle } from "react-native";
3
3
  import { Focusable } from "@applicaster/zapp-react-native-ui-components/Components/Focusable";
4
- import { useActions } from "@applicaster/zapp-react-native-utils/reactHooks/actions";
5
- import { getXray } from "@applicaster/zapp-react-native-utils/logger";
6
4
  import { toBooleanWithDefaultFalse } from "@applicaster/zapp-react-native-utils/booleanUtils";
7
5
 
8
- const { Logger } = getXray();
9
-
10
6
  import {
11
7
  recursiveCloneElementsWithState,
12
8
  getFocusedButtonId,
13
9
  } from "../../utils";
14
10
 
15
- const logger = new Logger("plugin", "plugins/navigation-action");
16
-
17
11
  type Props = Record<string, any> & {
18
12
  style: ImageStyle;
19
13
  };
20
14
 
21
15
  const getFocusableId = (prefixId, suffixId) => `${prefixId}___${suffixId}`;
22
16
 
23
- export function FocusableView({ style, children, item, ...otherProps }: Props) {
17
+ export function FocusableView({ style, children, ...otherProps }: Props) {
24
18
  const {
25
19
  groupId,
26
20
  prefixId,
@@ -29,7 +23,6 @@ export function FocusableView({ style, children, item, ...otherProps }: Props) {
29
23
  focusedButtonId,
30
24
  normalStyles,
31
25
  focusedStyles,
32
- pluginIdentifier,
33
26
  preferredFocus,
34
27
  } = otherProps;
35
28
 
@@ -41,20 +34,9 @@ export function FocusableView({ style, children, item, ...otherProps }: Props) {
41
34
 
42
35
  const additionalStyles = focused ? focusedStyles : normalStyles;
43
36
 
44
- const actionContext = useActions(pluginIdentifier);
45
-
46
- const onPress = (event) => {
37
+ const handlePress = (event) => {
47
38
  event?.preventDefault?.();
48
-
49
- if (!actionContext) {
50
- logger.warning(
51
- `Cannot resolve action context for ${pluginIdentifier} - please make sure the plugin is installed and up to date`
52
- );
53
-
54
- return;
55
- }
56
-
57
- actionContext?.invokeAction?.(item);
39
+ otherProps?.onPress?.(event);
58
40
  };
59
41
 
60
42
  const handleFocus = (focusable) => {
@@ -83,7 +65,7 @@ export function FocusableView({ style, children, item, ...otherProps }: Props) {
83
65
  style={styles}
84
66
  onFocus={handleFocus}
85
67
  onBlur={handleBlur}
86
- onPress={onPress}
68
+ onPress={handlePress}
87
69
  preferredFocus={preferredFocus}
88
70
  skipFocusManagerRegistration={otherProps.skipFocusManagerRegistration}
89
71
  isFocusable={otherProps.isFocusable}
@@ -24,7 +24,9 @@ const MemoizedImage = React.memo(QBImage, R.equals);
24
24
  const isValidExternalSource = (source): boolean =>
25
25
  source?.uri?.startsWith("http") ||
26
26
  source?.uri?.startsWith("data:image") ||
27
- source?.uri?.startsWith("file://");
27
+ source?.uri?.startsWith("file://") ||
28
+ source?.uri?.startsWith("asset:/") ||
29
+ source?.uri?.startsWith("node_modules_");
28
30
 
29
31
  export default function Image({
30
32
  style,
@@ -32,6 +34,7 @@ export default function Image({
32
34
  placeholderImage,
33
35
  entry,
34
36
  withDimensions,
37
+ source: sourceProp,
35
38
  ...otherProps
36
39
  }: Props) {
37
40
  const [showDefault, setShowDefault] = React.useState(false);
@@ -48,7 +51,10 @@ export default function Image({
48
51
  entry,
49
52
  showDefault,
50
53
  placeholderImage: placeholderImage || "",
51
- otherProps,
54
+ otherProps: {
55
+ source: sourceProp,
56
+ state: otherProps.state,
57
+ },
52
58
  });
53
59
 
54
60
  const onError = React.useCallback(() => {
@@ -1,8 +1,8 @@
1
1
  import * as React from "react";
2
2
  import { Image as RnImage, ImageStyle } from "react-native";
3
- import { equals, omit } from "ramda";
4
3
 
5
4
  import { useImageSource } from "./hooks";
5
+ import { equals } from "@applicaster/zapp-react-native-utils/utils";
6
6
 
7
7
  type Source = {
8
8
  uri: string;
@@ -25,11 +25,19 @@ function Image({
25
25
  placeholderImage,
26
26
  entry,
27
27
  withDimensions,
28
+ source: sourceProp,
28
29
  ...otherProps
29
30
  }: Props) {
30
31
  const [error, setErrorState] = React.useState(null);
31
32
 
32
- const source = useImageSource({ uri, entry, otherProps });
33
+ const source = useImageSource({
34
+ uri,
35
+ entry,
36
+ otherProps: {
37
+ source: sourceProp,
38
+ state: otherProps.state,
39
+ },
40
+ });
33
41
 
34
42
  React.useEffect(() => {
35
43
  // reset error state on URI change as the error is referencing previous uri
@@ -49,7 +57,7 @@ function Image({
49
57
  onError={React.useCallback(() => setErrorState(true), [])}
50
58
  // as we have defaults as "" for placeholder image, we need to pass undefined to source to not throw warnings
51
59
  source={_source?.uri ? _source : undefined}
52
- {...omit(["source"], otherProps)}
60
+ {...otherProps}
53
61
  />
54
62
  );
55
63
  }
@@ -23,9 +23,17 @@ function Image({
23
23
  placeholderImage,
24
24
  entry,
25
25
  withDimensions,
26
+ source: sourceProp,
26
27
  ...otherProps
27
28
  }: Props) {
28
- const source = useImageSource({ uri, entry, otherProps });
29
+ const source = useImageSource({
30
+ uri,
31
+ entry,
32
+ otherProps: {
33
+ source: sourceProp,
34
+ state: otherProps.state,
35
+ },
36
+ });
29
37
 
30
38
  const updatedSource = source ? withDimensions(source) : { uri: "" };
31
39
 
@@ -1,19 +1,21 @@
1
1
  import * as React from "react";
2
- import { path } from "ramda";
3
2
 
4
3
  import { isTV } from "@applicaster/zapp-react-native-utils/reactUtils";
5
4
  import { useActions } from "@applicaster/zapp-react-native-utils/reactHooks/actions";
6
5
  import { extractAsset } from "./utils";
7
6
 
8
7
  type Return = { uri: string } | null;
8
+ type Source = { context?: string; uri?: string } | null | undefined;
9
9
 
10
- const getSourceContext = path(["source", "context"]);
11
- const getSourceUri = path(["source", "uri"]);
12
- const getState = path(["state"]);
10
+ const getSourceContext = (source: Source) => source?.context;
11
+ const getSourceUri = (source: Source) => source?.uri;
13
12
 
14
- export const useImageSource = ({ uri, entry, otherProps }): Return => {
15
- const uriContext = getSourceContext(otherProps);
16
- const uriState = getState(otherProps);
13
+ export const useImageSource = ({
14
+ uri,
15
+ entry,
16
+ otherProps: { source, state: uriState },
17
+ }): Return => {
18
+ const uriContext = getSourceContext(source);
17
19
 
18
20
  const action = useActions(uriContext);
19
21
 
@@ -38,7 +40,7 @@ export const useImageSource = ({ uri, entry, otherProps }): Return => {
38
40
  return { uri };
39
41
  }
40
42
 
41
- const uriFromSource = getSourceUri(otherProps);
43
+ const uriFromSource = getSourceUri(source);
42
44
 
43
45
  if (uriFromSource) {
44
46
  return { uri: uriFromSource };
@@ -47,7 +49,7 @@ export const useImageSource = ({ uri, entry, otherProps }): Return => {
47
49
  return null;
48
50
  };
49
51
 
50
- const getSource = (uri, showDefault, placeholderImage, otherProps) => {
52
+ const getSource = (uri, showDefault, placeholderImage, source) => {
51
53
  const placeholderName = placeholderImage || "";
52
54
 
53
55
  const defaultPath = {
@@ -60,7 +62,7 @@ const getSource = (uri, showDefault, placeholderImage, otherProps) => {
60
62
  return { uri };
61
63
  }
62
64
 
63
- const uriFromSource = getSourceUri(otherProps);
65
+ const uriFromSource = getSourceUri(source);
64
66
 
65
67
  if (uriFromSource) {
66
68
  return { uri: uriFromSource };
@@ -74,10 +76,9 @@ export const useImageSourceWithDefault = ({
74
76
  entry,
75
77
  showDefault,
76
78
  placeholderImage,
77
- otherProps,
79
+ otherProps: { state: uriState, source },
78
80
  }): Return => {
79
- const uriContext = getSourceContext(otherProps);
80
- const uriState = getState(otherProps);
81
+ const uriContext = getSourceContext(source);
81
82
 
82
83
  const action = useActions(uriContext);
83
84
 
@@ -98,5 +99,5 @@ export const useImageSourceWithDefault = ({
98
99
  return extractAsset(!isTV(), entryStateLocal.asset, uriState);
99
100
  }
100
101
 
101
- return getSource(uri, showDefault, placeholderImage, otherProps);
102
+ return getSource(uri, showDefault, placeholderImage, source);
102
103
  };
@@ -1,6 +1,5 @@
1
1
  import * as React from "react";
2
- import merge from "lodash/merge";
3
- import { clone } from "@applicaster/zapp-react-native-utils/utils";
2
+ import { merge, clone } from "@applicaster/zapp-react-native-utils/utils";
4
3
  import { Platform, View, ViewStyle } from "react-native";
5
4
  import { appStore } from "@applicaster/zapp-react-native-redux/AppStore";
6
5
  import { isTV, isWeb } from "@applicaster/zapp-react-native-utils/reactUtils";
@@ -0,0 +1,34 @@
1
+ import React from "react";
2
+ import { TouchableOpacity } from "react-native";
3
+
4
+ type Props = {
5
+ children?: React.ReactNode;
6
+ style?: Record<string, unknown>;
7
+ testID?: string;
8
+ accessibilityLabel?: string;
9
+ accessibilityHint?: string;
10
+ onPress?: () => void;
11
+ };
12
+
13
+ export function PressableView({
14
+ children,
15
+ style = {},
16
+ testID,
17
+ accessibilityLabel,
18
+ accessibilityHint,
19
+ onPress,
20
+ }: Props) {
21
+ return (
22
+ <TouchableOpacity
23
+ activeOpacity={1}
24
+ onPress={onPress}
25
+ testID={testID}
26
+ accessibilityLabel={accessibilityLabel}
27
+ accessibilityHint={accessibilityHint}
28
+ accessible={!!(testID || accessibilityLabel)}
29
+ style={style}
30
+ >
31
+ {children}
32
+ </TouchableOpacity>
33
+ );
34
+ }
@@ -1,4 +1,4 @@
1
- import { renderHook } from "@testing-library/react-hooks";
1
+ import { renderHook, waitFor } from "@testing-library/react-native";
2
2
  import { Image } from "react-native";
3
3
 
4
4
  import { useGetImageDimensions } from "../useGetImageDimensions";
@@ -13,15 +13,16 @@ jest.spyOn(Image, "getSize").mockImplementation((_uri, success) => {
13
13
 
14
14
  describe("useGetImageDimensions", () => {
15
15
  it("should return aspect ration initially when known dimensions", async () => {
16
- const { result, waitForNextUpdate } = renderHook(() =>
16
+ const { result } = renderHook(() =>
17
17
  useGetImageDimensions("https://some_url.com", WIDTH, undefined)
18
18
  );
19
19
 
20
20
  expect(result.current).toBeUndefined();
21
- await waitForNextUpdate();
22
21
 
23
- expect(result.current).toEqual(
24
- getDimension({ width: WIDTH, height: HEIGTH })
25
- );
22
+ await waitFor(() => {
23
+ expect(result.current).toEqual(
24
+ getDimension({ width: WIDTH, height: HEIGTH })
25
+ );
26
+ });
26
27
  });
27
28
  });
@@ -45,6 +45,7 @@ export const useTextLabel = ({ label, entry }): string => {
45
45
  const [entryStateLocal, setEntryStateLocal] =
46
46
  React.useState(initialEntryState);
47
47
 
48
+ // For favourites
48
49
  React.useEffect(() => {
49
50
  return action?.addListeners?.(({ entryState, entry: actionEntry }) => {
50
51
  if (entry.id === actionEntry.id) {
@@ -53,6 +54,16 @@ export const useTextLabel = ({ label, entry }): string => {
53
54
  });
54
55
  }, []);
55
56
 
57
+ // For rest actions
58
+ React.useEffect(() => {
59
+ // Update entryStateLocal when action state changes. Example: state change when pressing the download button.
60
+ if (typeof action?.addListener === "function") {
61
+ return action.addListener(String(entry?.id), (nextState) => {
62
+ setEntryStateLocal(nextState);
63
+ });
64
+ }
65
+ }, []);
66
+
56
67
  if (context && name && action) {
57
68
  return prepareHebrewText(extractLabel(entryStateLocal.label, name), isRTL);
58
69
  }
@@ -0,0 +1,141 @@
1
+ import React from "react";
2
+ import { render } from "@testing-library/react-native";
3
+
4
+ import { defaultComponents } from "../index";
5
+ import { elementMapper } from "../../elementMapper";
6
+
7
+ const WrapperProbe = jest.fn(({ children }) => <>{children}</>);
8
+ const LeafProbe = jest.fn(() => null);
9
+
10
+ const components = {
11
+ ...defaultComponents,
12
+ View: WrapperProbe,
13
+ Text: LeafProbe,
14
+ };
15
+
16
+ const entry = { id: "entry-1" };
17
+ const item = { id: "item-1" };
18
+
19
+ const renderNode = (node) =>
20
+ render(
21
+ <React.Fragment>{elementMapper(components)(node as never)}</React.Fragment>
22
+ );
23
+
24
+ describe("DataProvider", () => {
25
+ beforeEach(() => {
26
+ jest.clearAllMocks();
27
+ });
28
+
29
+ it("injects resolved runtime props under dataProviderProps into the direct child and its direct children only", () => {
30
+ renderNode({
31
+ type: "DataProvider",
32
+ props: { _dataKey: "entry", entry },
33
+ elements: [
34
+ {
35
+ type: "View",
36
+ props: {},
37
+ elements: [
38
+ {
39
+ type: "View",
40
+ props: {},
41
+ elements: [{ type: "Text", props: {} }],
42
+ },
43
+ ],
44
+ },
45
+ ],
46
+ });
47
+
48
+ expect(WrapperProbe).toHaveBeenNthCalledWith(
49
+ 1,
50
+ expect.objectContaining({
51
+ dataProviderProps: expect.objectContaining({ entry }),
52
+ }),
53
+ expect.anything()
54
+ );
55
+
56
+ expect(WrapperProbe).toHaveBeenNthCalledWith(
57
+ 2,
58
+ expect.objectContaining({
59
+ dataProviderProps: expect.objectContaining({ entry }),
60
+ }),
61
+ expect.anything()
62
+ );
63
+
64
+ expect(LeafProbe).toHaveBeenCalledWith(
65
+ expect.not.objectContaining({
66
+ dataProviderProps: expect.anything(),
67
+ }),
68
+ expect.anything()
69
+ );
70
+ });
71
+
72
+ it("derives the namespaced values from the resolved runtime props", () => {
73
+ renderNode({
74
+ type: "DataProvider",
75
+ props: { _dataKey: "item", item },
76
+ elements: [
77
+ {
78
+ type: "View",
79
+ props: {},
80
+ elements: [{ type: "View", props: {} }],
81
+ },
82
+ ],
83
+ });
84
+
85
+ expect(WrapperProbe).toHaveBeenNthCalledWith(
86
+ 1,
87
+ expect.objectContaining({
88
+ dataProviderProps: expect.objectContaining({ item }),
89
+ }),
90
+ expect.anything()
91
+ );
92
+
93
+ expect(WrapperProbe).toHaveBeenNthCalledWith(
94
+ 2,
95
+ expect.objectContaining({
96
+ dataProviderProps: expect.objectContaining({ item }),
97
+ }),
98
+ expect.anything()
99
+ );
100
+ });
101
+
102
+ it("does not overwrite explicit dataProviderProps on the direct child", () => {
103
+ const explicitEntry = { id: "explicit" };
104
+
105
+ renderNode({
106
+ type: "DataProvider",
107
+ props: { _dataKey: "entry", entry },
108
+ elements: [
109
+ {
110
+ type: "View",
111
+ props: {
112
+ dataProviderProps: {
113
+ entry: explicitEntry,
114
+ source: "child",
115
+ },
116
+ },
117
+ elements: [{ type: "View", props: {} }],
118
+ },
119
+ ],
120
+ });
121
+
122
+ expect(WrapperProbe).toHaveBeenNthCalledWith(
123
+ 1,
124
+ expect.objectContaining({
125
+ dataProviderProps: expect.objectContaining({
126
+ entry: explicitEntry,
127
+ source: "child",
128
+ }),
129
+ }),
130
+ expect.anything()
131
+ );
132
+
133
+ expect(WrapperProbe).toHaveBeenNthCalledWith(
134
+ 2,
135
+ expect.objectContaining({
136
+ dataProviderProps: expect.objectContaining({ entry }),
137
+ }),
138
+ expect.anything()
139
+ );
140
+ });
141
+ });
@@ -6,26 +6,29 @@ import PureImage from "./Image";
6
6
  import { CollapsibleTextContainer } from "../SharedUI/CollapsibleTextContainer/CollapsibleTextContainer";
7
7
  import { Toggle } from "./Toggle";
8
8
  import { Button } from "./Button";
9
- import { FocusableView } from "./FocusableView";
10
9
  import ProgressBar from "../SharedUI/ProgressBar/ProgressBar";
11
10
  import { LiveImage } from "./LiveImage";
12
11
  import { DynamicBadge } from "./DynamicBadge";
13
12
  import { SecondaryImage } from "./SecondaryImage/Image";
14
13
  import { BorderContainerView } from "./BorderContainerView";
15
14
  import { CellBadge } from "./CellBadge";
15
+ import { DataProvider } from "./DataProvider";
16
16
  import { TvActionButtons } from "./tv/TvActionButtons";
17
- import { ButtonContainerView } from "./tv/ButtonContainerView";
17
+ import { TvActionButton } from "./tv/TvActionButtons/TvActionButton";
18
+ import { ButtonContainerView } from "./ButtonContainerView";
18
19
  import { ImageBorderContainer } from "./ImageBorderContainer";
20
+ import { PressableView } from "./PressableView";
21
+ import { ActionButton as MobileActionButton } from "./mobile/MobileActionButtons/ActionButton";
19
22
 
20
23
  export const defaultComponents = {
21
24
  View,
22
25
  CollapsibleTextContainer,
23
26
  Text,
24
27
  Button,
28
+ PressableView,
25
29
  Image,
26
30
  PureImage,
27
31
  ButtonContainerView,
28
- FocusableView,
29
32
  ProgressBar,
30
33
  Toggle,
31
34
  LiveImage,
@@ -34,5 +37,8 @@ export const defaultComponents = {
34
37
  DynamicBadge,
35
38
  SecondaryImage,
36
39
  TvActionButtons,
40
+ TvActionButton,
41
+ MobileActionButton,
37
42
  CellBadge,
43
+ DataProvider,
38
44
  };