@applicaster/zapp-react-native-ui-components 14.0.0-alpha.5974411329 → 14.0.0-alpha.6000342231

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 (95) hide show
  1. package/Components/AnimatedInOut/index.tsx +69 -26
  2. package/Components/BaseFocusable/index.tsx +23 -12
  3. package/Components/Cell/Cell.tsx +91 -64
  4. package/Components/Cell/CellWithFocusable.tsx +3 -0
  5. package/Components/Cell/FocusableWrapper.tsx +44 -0
  6. package/Components/Cell/TvOSCellComponent.tsx +80 -14
  7. package/Components/Cell/__tests__/CellWIthFocusable.test.js +3 -2
  8. package/Components/FeedLoader/FeedLoader.tsx +7 -16
  9. package/Components/FeedLoader/FeedLoaderHOC.tsx +21 -0
  10. package/Components/FeedLoader/index.js +2 -8
  11. package/Components/Focusable/Focusable.tsx +10 -3
  12. package/Components/Focusable/FocusableTvOS.tsx +2 -2
  13. package/Components/Focusable/Touchable.tsx +5 -3
  14. package/Components/Focusable/index.android.tsx +8 -4
  15. package/Components/FocusableGroup/FocusableTvOS.tsx +1 -1
  16. package/Components/FocusableList/FocusableItem.tsx +4 -3
  17. package/Components/FocusableList/FocusableListItemWrapper.tsx +2 -1
  18. package/Components/FocusableList/hooks/useCellState.android.ts +13 -3
  19. package/Components/FocusableList/index.tsx +16 -9
  20. package/Components/FreezeWithCallback/__tests__/index.test.tsx +67 -43
  21. package/Components/GeneralContentScreen/utils/useCurationAPI.ts +14 -17
  22. package/Components/HandlePlayable/HandlePlayable.tsx +14 -65
  23. package/Components/HandlePlayable/const.ts +3 -0
  24. package/Components/HandlePlayable/utils.ts +74 -0
  25. package/Components/Layout/TV/__tests__/index.test.tsx +0 -1
  26. package/Components/MasterCell/DefaultComponents/ActionButton.tsx +6 -2
  27. package/Components/MasterCell/DefaultComponents/FocusableView/index.tsx +0 -12
  28. package/Components/MasterCell/DefaultComponents/SecondaryImage/Image.tsx +65 -17
  29. package/Components/MasterCell/DefaultComponents/SecondaryImage/__tests__/Image.test.tsx +21 -3
  30. package/Components/MasterCell/DefaultComponents/SecondaryImage/__tests__/__snapshots__/Image.test.tsx.snap +6 -3
  31. package/Components/MasterCell/DefaultComponents/Text/index.tsx +26 -6
  32. package/Components/MasterCell/DefaultComponents/__tests__/image.test.js +10 -10
  33. package/Components/MasterCell/DefaultComponents/__tests__/text.test.tsx +18 -18
  34. package/Components/MasterCell/SharedUI/CollapsibleTextContainer/__tests__/index.test.tsx +10 -10
  35. package/Components/MasterCell/utils/behaviorProvider.ts +2 -2
  36. package/Components/MasterCell/utils/index.ts +1 -19
  37. package/Components/OfflineHandler/__tests__/index.test.tsx +6 -13
  38. package/Components/PlayerContainer/PlayerContainer.tsx +5 -17
  39. package/Components/PlayerImageBackground/index.tsx +3 -22
  40. package/Components/River/ComponentsMap/ComponentsMap.tsx +49 -42
  41. package/Components/River/ComponentsMap/ContextProviders/ComponentsMapHeightContext.ts +8 -0
  42. package/Components/River/ComponentsMap/ContextProviders/ComponentsMapRefContext.ts +8 -0
  43. package/Components/River/ComponentsMap/hooks/__tests__/useLoadingState.test.ts +0 -1
  44. package/Components/River/RefreshControl.tsx +11 -19
  45. package/Components/River/__tests__/river.test.js +12 -26
  46. package/Components/Screen/TV/hooks/useInitialFocus.ts +14 -4
  47. package/Components/Screen/__tests__/Screen.test.tsx +5 -17
  48. package/Components/Screen/__tests__/__snapshots__/Screen.test.tsx.snap +2 -0
  49. package/Components/Screen/__tests__/navigationHandler.test.ts +133 -22
  50. package/Components/Screen/index.tsx +22 -5
  51. package/Components/Screen/navigationHandler.ts +20 -2
  52. package/Components/ScreenRevealManager/__tests__/ScreenRevealManager.test.ts +2 -2
  53. package/Components/ScreenRevealManager/utils/index.ts +23 -0
  54. package/Components/ScreenRevealManager/withScreenRevealManager.tsx +54 -24
  55. package/Components/Tabs/TV/Tabs.android.tsx +1 -1
  56. package/Components/Tabs/Tabs.tsx +2 -3
  57. package/Components/TextInputTv/__tests__/__snapshots__/TextInputTv.test.js.snap +13 -0
  58. package/Components/TextInputTv/index.tsx +11 -0
  59. package/Components/Touchable/__tests__/touchable.test.tsx +12 -17
  60. package/Components/VideoLive/__tests__/__snapshots__/PlayerLiveImageComponent.test.tsx.snap +1 -0
  61. package/Components/VideoModal/ModalAnimation/ModalAnimationContext.tsx +117 -157
  62. package/Components/VideoModal/ModalAnimation/index.ts +2 -13
  63. package/Components/VideoModal/ModalAnimation/utils.ts +1 -327
  64. package/Components/VideoModal/PlayerDetails.tsx +5 -5
  65. package/Components/VideoModal/PlayerWrapper.tsx +14 -88
  66. package/Components/VideoModal/__tests__/PlayerDetails.test.tsx +5 -5
  67. package/Components/VideoModal/__tests__/PlayerWrapper.test.tsx +1 -0
  68. package/Components/VideoModal/hooks/__tests__/useDelayedPlayerDetails.test.ts +9 -1
  69. package/Components/VideoModal/hooks/useDelayedPlayerDetails.ts +40 -15
  70. package/Components/VideoModal/hooks/useModalSize.ts +10 -5
  71. package/Components/VideoModal/hooks/utils/__tests__/showDetails.test.ts +2 -2
  72. package/Components/VideoModal/hooks/utils/index.ts +4 -0
  73. package/Components/VideoModal/playerWrapperStyle.ts +70 -0
  74. package/Components/VideoModal/playerWrapperUtils.ts +91 -0
  75. package/Contexts/CellFocusedStateContext/index.tsx +27 -0
  76. package/Contexts/ConfigutaionContext/__tests__/ConfigurationProvider.test.tsx +3 -3
  77. package/Contexts/ScreenContext/index.tsx +28 -32
  78. package/Decorators/ConfigurationWrapper/__tests__/withConfigurationProvider.test.tsx +3 -3
  79. package/Decorators/RiverFeedLoader/__tests__/__snapshots__/riverFeedLoader.test.tsx.snap +221 -209
  80. package/Decorators/RiverFeedLoader/__tests__/riverFeedLoader.test.tsx +14 -16
  81. package/Decorators/RiverFeedLoader/__tests__/utils.test.ts +0 -20
  82. package/Decorators/RiverFeedLoader/index.tsx +21 -13
  83. package/Decorators/RiverFeedLoader/utils/getDatasourceUrl.ts +6 -10
  84. package/Decorators/RiverFeedLoader/utils/index.ts +0 -35
  85. package/Decorators/ZappPipesDataConnector/__tests__/UrlFeedResolver.test.tsx +27 -27
  86. package/Decorators/ZappPipesDataConnector/resolvers/UrlFeedResolver.tsx +3 -5
  87. package/Decorators/ZappPipesDataConnector/utils/useFilter.tsx +68 -76
  88. package/events/index.ts +3 -0
  89. package/package.json +5 -5
  90. package/Components/River/__tests__/__snapshots__/river.test.js.snap +0 -27
  91. package/Components/VideoModal/ModalAnimation/AnimatedPlayerModalWrapper.tsx +0 -60
  92. package/Components/VideoModal/ModalAnimation/AnimatedScrollModal.tsx +0 -421
  93. package/Components/VideoModal/ModalAnimation/AnimatedVideoPlayerComponent.tsx +0 -176
  94. package/Components/VideoModal/ModalAnimation/AnimationComponent.tsx +0 -500
  95. package/Components/VideoModal/ModalAnimation/__tests__/getMoveUpValue.test.ts +0 -108
@@ -1,9 +1,4 @@
1
1
  import * as React from "react";
2
- import * as R from "ramda";
3
- import {
4
- findPluginByType,
5
- findPluginByIdentifier,
6
- } from "@applicaster/zapp-react-native-utils/pluginUtils";
7
2
  import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
8
3
  import {
9
4
  useDimensions,
@@ -16,6 +11,7 @@ import { PlayerContainer } from "../PlayerContainer";
16
11
  import { useModalSize } from "../VideoModal/hooks";
17
12
  import { ViewStyle } from "react-native";
18
13
  import { platformSelect } from "@applicaster/zapp-react-native-utils/reactUtils";
14
+ import { findCastPlugin, getPlayer } from "./utils";
19
15
 
20
16
  type Props = {
21
17
  item: ZappEntry;
@@ -26,62 +22,6 @@ type Props = {
26
22
  groupId?: string;
27
23
  };
28
24
 
29
- const YOUTUBE_PLUGIN_ID = "youtube-player-qb";
30
- const CHROMECAST_PLUGIN_ID = "chromecast_qb";
31
-
32
- const getPlayerWithModuleProperties = (
33
- PlayerModule: ZappPlugin
34
- ): [ZappPlugin, PlayerModuleProperties] => {
35
- const getPlayerModuleProperties = R.ifElse(
36
- R.is(Object) && R.has("Component"),
37
- R.omit(["Component"]),
38
- () => ({})
39
- );
40
-
41
- return [
42
- PlayerModule?.Component || PlayerModule,
43
- getPlayerModuleProperties(PlayerModule),
44
- ];
45
- };
46
-
47
- const getPlayer = (
48
- item: ZappEntry,
49
- state
50
- ): [ZappPlugin, PlayerModuleProperties] => {
51
- const {
52
- plugins,
53
- contentTypes,
54
- rivers,
55
- appData: { layoutVersion },
56
- } = state;
57
-
58
- let PlayerModule;
59
-
60
- if (layoutVersion === "v2") {
61
- const { screen_id } = contentTypes?.[item?.type?.value] || {};
62
- const { type } = rivers?.[screen_id] || {};
63
-
64
- if (type) {
65
- PlayerModule = findPluginByIdentifier(type, plugins)?.module;
66
-
67
- return getPlayerWithModuleProperties(PlayerModule);
68
- }
69
- }
70
-
71
- if (item?.content?.type === "youtube-id") {
72
- PlayerModule = findPluginByIdentifier(YOUTUBE_PLUGIN_ID, plugins)?.module;
73
-
74
- return getPlayerWithModuleProperties(PlayerModule);
75
- }
76
-
77
- PlayerModule = findPluginByType(
78
- "playable",
79
- plugins.filter(({ identifier }) => identifier !== YOUTUBE_PLUGIN_ID)
80
- );
81
-
82
- return getPlayerWithModuleProperties(PlayerModule);
83
- };
84
-
85
25
  type PlayableComponent = {
86
26
  Component: React.ComponentType<any>;
87
27
  };
@@ -99,14 +39,23 @@ export function HandlePlayable({
99
39
  mode,
100
40
  groupId,
101
41
  }: Props): React.ReactElement | null {
102
- const state = usePickFromState();
42
+ const { plugins, contentTypes, rivers, appData } = usePickFromState([
43
+ "plugins",
44
+ "contentTypes",
45
+ "rivers",
46
+ "appData",
47
+ ]);
103
48
 
104
49
  const { closeVideoModal } = useNavigation();
105
50
 
106
- const [Player, playerModuleProperties] = getPlayer(item, state);
51
+ const [Player, playerModuleProperties] = getPlayer(item, {
52
+ plugins,
53
+ contentTypes,
54
+ rivers,
55
+ appData,
56
+ });
107
57
 
108
- const { module: CastPlugin } =
109
- findPluginByIdentifier(CHROMECAST_PLUGIN_ID, state.plugins, true) || {};
58
+ const { module: CastPlugin } = findCastPlugin(plugins);
110
59
 
111
60
  const [playable, setPlayable] =
112
61
  React.useState<Nullable<PlayableComponent>>(null);
@@ -0,0 +1,3 @@
1
+ export const YOUTUBE_PLUGIN_ID = "youtube-player-qb";
2
+
3
+ export const CHROMECAST_PLUGIN_ID = "chromecast_qb";
@@ -0,0 +1,74 @@
1
+ import {
2
+ findPluginByIdentifier,
3
+ findPluginByType,
4
+ } from "@applicaster/zapp-react-native-utils/pluginUtils";
5
+
6
+ import { CHROMECAST_PLUGIN_ID, YOUTUBE_PLUGIN_ID } from "./const";
7
+ import { omit } from "@applicaster/zapp-react-native-utils/utils";
8
+
9
+ const getPlayerModuleProperties = (PlayerModule: ZappPlugin) => {
10
+ if (PlayerModule?.Component && typeof PlayerModule.Component === "object") {
11
+ return omit(["Component"], PlayerModule);
12
+ }
13
+
14
+ return {};
15
+ };
16
+
17
+ export const getPlayerWithModuleProperties = (
18
+ PlayerModule: ZappPlugin
19
+ ): [ZappPlugin, PlayerModuleProperties] => {
20
+ return [
21
+ PlayerModule?.Component || PlayerModule,
22
+ getPlayerModuleProperties(PlayerModule),
23
+ ];
24
+ };
25
+
26
+ export const findCastPlugin = (plugins: ZappPlugin[]) =>
27
+ findPluginByIdentifier(CHROMECAST_PLUGIN_ID, plugins, true) || {};
28
+
29
+ export const findYoutubePlugin = (plugins: ZappPlugin[]) =>
30
+ findPluginByIdentifier(YOUTUBE_PLUGIN_ID, plugins, true) || {};
31
+
32
+ export const getPlayer = (
33
+ item: ZappEntry,
34
+ {
35
+ plugins,
36
+ contentTypes,
37
+ rivers,
38
+ appData: { layoutVersion },
39
+ }: {
40
+ plugins: ZappPlugin[];
41
+ contentTypes: Record<string, any>;
42
+ rivers: Record<string, any>;
43
+ appData: { layoutVersion: string };
44
+ }
45
+ ): [ZappPlugin, PlayerModuleProperties] => {
46
+ let PlayerModule;
47
+
48
+ if (layoutVersion === "v2") {
49
+ const screen_id = contentTypes?.[item?.type?.value]?.screen_id;
50
+ const type = rivers?.[screen_id]?.type;
51
+
52
+ if (type) {
53
+ PlayerModule = findPluginByIdentifier(type, plugins)?.module;
54
+
55
+ return getPlayerWithModuleProperties(PlayerModule);
56
+ }
57
+ }
58
+
59
+ if (item?.content?.type === "youtube-id") {
60
+ PlayerModule = findYoutubePlugin(plugins)?.module;
61
+
62
+ return getPlayerWithModuleProperties(PlayerModule);
63
+ }
64
+
65
+ PlayerModule = findPluginByType(
66
+ "playable",
67
+ (plugins as any[]).filter(
68
+ ({ identifier }: { identifier: string }) =>
69
+ identifier !== YOUTUBE_PLUGIN_ID
70
+ )
71
+ );
72
+
73
+ return getPlayerWithModuleProperties(PlayerModule);
74
+ };
@@ -7,7 +7,6 @@ import { NavigationContext } from "@applicaster/zapp-react-native-ui-components/
7
7
  import configureStore from "redux-mock-store";
8
8
  import Layout from "../index.web";
9
9
 
10
- // mock useTheme to provide app_background_color
11
10
  jest.mock("@applicaster/zapp-react-native-utils/theme", () => ({
12
11
  useTheme: () => ({
13
12
  app_background_color: "#000000",
@@ -23,6 +23,7 @@ type Props = {
23
23
  style: ViewStyle;
24
24
  testID?: string;
25
25
  accessibilityLabel?: string;
26
+ accessibilityHint?: string;
26
27
  cellUUID?: string;
27
28
  extraProps?: Record<string, any>;
28
29
  };
@@ -48,7 +49,9 @@ function getAssetValue(asset, flavour, fallbackAsset = null) {
48
49
  return asset.src || fallbackAsset;
49
50
  }
50
51
 
51
- export function ActionButton(props: Props) {
52
+ export const ActionButton = React.memo(function ActionButtonComponent(
53
+ props: Props
54
+ ) {
52
55
  const { item, action, asset, flavour = "flavour_1", cellUUID } = props;
53
56
  const actionContext = useActions(action?.identifier);
54
57
 
@@ -98,6 +101,7 @@ export function ActionButton(props: Props) {
98
101
  onPress={onPress}
99
102
  testID={props?.testID || `${item?.id}`}
100
103
  accessibilityLabel={props?.accessibilityLabel || `${item?.id}`}
104
+ accessibilityHint={props?.accessibilityHint}
101
105
  accessible={!!(props?.testID || props?.accessibilityLabel)}
102
106
  style={props?.style}
103
107
  >
@@ -118,4 +122,4 @@ export function ActionButton(props: Props) {
118
122
  )}
119
123
  </TouchableOpacity>
120
124
  );
121
- }
125
+ });
@@ -4,7 +4,6 @@ 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 { getXray } from "@applicaster/zapp-react-native-utils/logger";
6
6
  import { toBooleanWithDefaultFalse } from "@applicaster/zapp-react-native-utils/booleanUtils";
7
- import { useAccessibilityManager } from "@applicaster/zapp-react-native-utils/appUtils/accessibilityManager/hooks";
8
7
 
9
8
  const { Logger } = getXray();
10
9
 
@@ -44,11 +43,6 @@ export function FocusableView({ style, children, item, ...otherProps }: Props) {
44
43
 
45
44
  const actionContext = useActions(pluginIdentifier);
46
45
 
47
- const accessibilityManager = useAccessibilityManager({});
48
-
49
- const { ttsLabel = "" } =
50
- actionContext?.initialEntryState(item)?.getAccessibility?.(item) || {};
51
-
52
46
  const onPress = (event) => {
53
47
  event?.preventDefault?.();
54
48
 
@@ -71,12 +65,6 @@ export function FocusableView({ style, children, item, ...otherProps }: Props) {
71
65
  focusedButtonId,
72
66
  mouse: focusable.mouse,
73
67
  });
74
-
75
- if (ttsLabel) {
76
- accessibilityManager.readText({
77
- text: ttsLabel,
78
- });
79
- }
80
68
  };
81
69
 
82
70
  const handleBlur = (_focusable, _direction) => {
@@ -28,17 +28,10 @@ interface Props {
28
28
  onAsyncRender: () => void;
29
29
  }
30
30
 
31
- const SecondaryImageComponent = (props: Props) => {
32
- const {
33
- uri,
34
- style,
35
- displayMode,
36
- imageSizing,
37
- fitPosition,
38
- fixedHeight,
39
- fixedWidth,
40
- onAsyncRender,
41
- } = props;
31
+ /** Secondary Image Dynamic does not render until the image is loaded */
32
+ const SecondaryImageDynamic = (props: Props) => {
33
+ const { uri, style, displayMode, imageSizing, fitPosition, onAsyncRender } =
34
+ props;
42
35
 
43
36
  const imageDimension = useGetImageDimensions(
44
37
  uri,
@@ -46,13 +39,9 @@ const SecondaryImageComponent = (props: Props) => {
46
39
  isImageSizingFit(imageSizing) ? undefined : (style.height as number)
47
40
  );
48
41
 
49
- const containerHeight = isDisplayModeFixed(displayMode)
50
- ? fixedHeight
51
- : imageDimension?.height;
42
+ const containerHeight = imageDimension?.height;
52
43
 
53
- const containerWidth = isDisplayModeFixed(displayMode)
54
- ? fixedWidth
55
- : style?.width;
44
+ const containerWidth = style?.width;
56
45
 
57
46
  if (isNil(imageDimension?.aspectRatio)) {
58
47
  return null;
@@ -80,4 +69,63 @@ const SecondaryImageComponent = (props: Props) => {
80
69
  );
81
70
  };
82
71
 
72
+ /** Secondary Image Fixed does not render the image until the image is loaded, but keep container rendered */
73
+ const SecondaryImageFixed = (props: Props) => {
74
+ const {
75
+ uri,
76
+ style,
77
+ displayMode,
78
+ imageSizing,
79
+ fitPosition,
80
+ fixedHeight,
81
+ fixedWidth,
82
+ onAsyncRender,
83
+ } = props;
84
+
85
+ const imageDimension = useGetImageDimensions(
86
+ uri,
87
+ style.width as number,
88
+ isImageSizingFit(imageSizing) ? undefined : (style.height as number)
89
+ );
90
+
91
+ return (
92
+ <View style={style} onLayout={onAsyncRender}>
93
+ {isNil(imageDimension?.aspectRatio) ? null : (
94
+ <Image
95
+ {...props}
96
+ source={{ uri }}
97
+ style={{
98
+ ...getStyle({
99
+ imageSizing,
100
+ fitPosition,
101
+ displayMode,
102
+ imageDimension,
103
+ containerHeight: fixedHeight,
104
+ containerWidth: fixedWidth,
105
+ }),
106
+ borderRadius: style.borderRadius,
107
+ aspectRatio: imageDimension.aspectRatio,
108
+ }}
109
+ />
110
+ )}
111
+ </View>
112
+ );
113
+ };
114
+
115
+ const SecondaryImageComponent = (props: Props) => {
116
+ const { uri, displayMode } = props;
117
+
118
+ if (!uri) {
119
+ return null;
120
+ }
121
+
122
+ const isFixed = isDisplayModeFixed(displayMode);
123
+
124
+ return isFixed ? (
125
+ <SecondaryImageFixed {...props} />
126
+ ) : (
127
+ <SecondaryImageDynamic {...props} />
128
+ );
129
+ };
130
+
83
131
  export const SecondaryImage = withAsyncRenderHOC(SecondaryImageComponent);
@@ -4,9 +4,26 @@ import { render } from "@testing-library/react-native";
4
4
  import { SecondaryImage } from "../Image";
5
5
 
6
6
  describe("SecondaryImage - Image", () => {
7
- it("SecondaryImage should not render if no aspect ratio", async () => {
7
+ it("SecondaryImage should not render if no uri", async () => {
8
8
  const wrapper = await render(
9
- <SecondaryImage uri="" style={{ width: 100 }} />
9
+ <SecondaryImage
10
+ displayMode="dynamic"
11
+ uri={undefined}
12
+ style={{ width: 100 }}
13
+ />
14
+ );
15
+
16
+ expect(wrapper.toJSON()).toEqual(null);
17
+ expect(wrapper.toJSON()).toMatchSnapshot();
18
+ });
19
+
20
+ it("SecondaryImage should not render if no aspect ratio (dynamic)", async () => {
21
+ const wrapper = await render(
22
+ <SecondaryImage
23
+ displayMode="dynamic"
24
+ uri="someurl"
25
+ style={{ width: 100 }}
26
+ />
10
27
  );
11
28
 
12
29
  expect(wrapper.toJSON()).toEqual(null);
@@ -16,7 +33,8 @@ describe("SecondaryImage - Image", () => {
16
33
  it("SecondaryImage should render if known dimensions", async () => {
17
34
  const wrapper = await render(
18
35
  <SecondaryImage
19
- uri=""
36
+ uri="someUrl"
37
+ displayMode="dynamic"
20
38
  style={{ width: 100, height: 100, borderRadius: 10 }}
21
39
  />
22
40
  );
@@ -1,6 +1,8 @@
1
1
  // Jest Snapshot v1, https://goo.gl/fbAQLP
2
2
 
3
- exports[`SecondaryImage - Image SecondaryImage should not render if no aspect ratio 1`] = `null`;
3
+ exports[`SecondaryImage - Image SecondaryImage should not render if no aspect ratio (dynamic) 1`] = `null`;
4
+
5
+ exports[`SecondaryImage - Image SecondaryImage should not render if no uri 1`] = `null`;
4
6
 
5
7
  exports[`SecondaryImage - Image SecondaryImage should render if known dimensions 1`] = `
6
8
  <View
@@ -14,10 +16,11 @@ exports[`SecondaryImage - Image SecondaryImage should render if known dimensions
14
16
  }
15
17
  >
16
18
  <Image
19
+ displayMode="dynamic"
17
20
  onAsyncRender={[Function]}
18
21
  source={
19
22
  {
20
- "uri": "",
23
+ "uri": "someUrl",
21
24
  }
22
25
  }
23
26
  style={
@@ -28,7 +31,7 @@ exports[`SecondaryImage - Image SecondaryImage should render if known dimensions
28
31
  "width": 100,
29
32
  }
30
33
  }
31
- uri=""
34
+ uri="someUrl"
32
35
  />
33
36
  </View>
34
37
  `;
@@ -11,6 +11,8 @@ import { withScaledLineHeight } from "./utils";
11
11
  import { toNumber } from "@applicaster/zapp-react-native-utils/numberUtils";
12
12
  import { MeasurementPortalContext } from "../../../MeasurmentsPortal";
13
13
  import { isNilOrEmpty } from "@applicaster/zapp-react-native-utils/reactUtils/helpers";
14
+ import { CellFocusedStateContext } from "@applicaster/zapp-react-native-ui-components/Contexts/CellFocusedStateContext";
15
+ import { useAccessibilityManager } from "@applicaster/zapp-react-native-utils/appUtils/accessibilityManager/hooks";
14
16
 
15
17
  type Props = {
16
18
  style: any;
@@ -35,10 +37,9 @@ const _Text = ({
35
37
  }: Props) => {
36
38
  const _label = useTextLabel({ label, entry });
37
39
  const isMeasurement = React.useContext(MeasurementPortalContext);
40
+ const cellFocused = React.useContext(CellFocusedStateContext);
38
41
 
39
- if (isNilOrEmpty(_label)) {
40
- return null;
41
- }
42
+ const accessibilityManager = useAccessibilityManager({});
42
43
 
43
44
  // set maximum possible height for the text in case of measurement
44
45
  const height =
@@ -46,6 +47,27 @@ const _Text = ({
46
47
  ? toNumber(otherProps.numberOfLines) * toNumber(style.lineHeight)
47
48
  : undefined;
48
49
 
50
+ const textLabel = dateTransformEnabled
51
+ ? dateFormat(dateTransform, label)
52
+ : textTransform(transformText, _label);
53
+
54
+ React.useLayoutEffect(() => {
55
+ // For FocusableCells with action buttons
56
+ if (otherProps.state) {
57
+ if (otherProps.state === "focused" && cellFocused === true) {
58
+ accessibilityManager.addHeading(textLabel);
59
+ }
60
+ } else {
61
+ if (cellFocused === true) {
62
+ accessibilityManager.addHeading(textLabel);
63
+ }
64
+ }
65
+ }, [cellFocused, otherProps.state, textLabel]);
66
+
67
+ if (isNilOrEmpty(_label)) {
68
+ return null;
69
+ }
70
+
49
71
  return (
50
72
  <Text
51
73
  style={[
@@ -55,9 +77,7 @@ const _Text = ({
55
77
  allowFontScaling={false}
56
78
  {...withoutLabel(otherProps)}
57
79
  >
58
- {dateTransformEnabled
59
- ? dateFormat(dateTransform, label)
60
- : textTransform(transformText, _label)}
80
+ {textLabel}
61
81
  </Text>
62
82
  );
63
83
  };
@@ -1,5 +1,5 @@
1
1
  import React from "react";
2
- import TestRenderer from "react-test-renderer";
2
+ import { render } from "@testing-library/react-native";
3
3
  import { Image } from "react-native";
4
4
 
5
5
  jest.mock("@applicaster/zapp-react-native-utils/theme", () => ({
@@ -10,35 +10,35 @@ const CustomImage = require("../Image").default;
10
10
 
11
11
  describe("image with no source", () => {
12
12
  it("Uses provided placeholder image string", () => {
13
- const testRenderer = TestRenderer.create(
13
+ const { UNSAFE_getByType } = render(
14
14
  <CustomImage placeholderImage={"foo"} />
15
15
  );
16
16
 
17
- const testInstance = testRenderer.root;
17
+ const imageComponent = UNSAFE_getByType(Image);
18
18
 
19
- expect(testInstance.findByType(Image).props.source).toEqual({
19
+ expect(imageComponent.props.source).toEqual({
20
20
  uri: "foo",
21
21
  });
22
22
  });
23
23
 
24
24
  it("Uses provided placeholder image object", () => {
25
- const testRenderer = TestRenderer.create(
25
+ const { UNSAFE_getByType } = render(
26
26
  <CustomImage placeholderImage={"foo"} />
27
27
  );
28
28
 
29
- const testInstance = testRenderer.root;
29
+ const imageComponent = UNSAFE_getByType(Image);
30
30
 
31
- expect(testInstance.findByType(Image).props.source).toEqual({
31
+ expect(imageComponent.props.source).toEqual({
32
32
  uri: "foo",
33
33
  });
34
34
  });
35
35
 
36
36
  it("Returns empty string if no image or placeholder defined", () => {
37
- const testRenderer = TestRenderer.create(
37
+ const { UNSAFE_getByType } = render(
38
38
  <CustomImage placeholderImage={null} />
39
39
  );
40
40
 
41
- const testInstance = testRenderer.root;
42
- expect(testInstance.findByType(Image).props.source).toBeUndefined();
41
+ const imageComponent = UNSAFE_getByType(Image);
42
+ expect(imageComponent.props.source).toBeUndefined();
43
43
  });
44
44
  });
@@ -1,8 +1,6 @@
1
1
  import React from "react";
2
2
  import RN from "react-native";
3
- import { Provider } from "react-redux";
4
- import TestRenderer from "react-test-renderer";
5
- import configureStoreFn from "redux-mock-store";
3
+ import { renderWithProviders } from "@applicaster/zapp-react-native-utils/testUtils";
6
4
 
7
5
  const mockUseIsRTL = jest.fn(() => true);
8
6
  const mockGetIsRTL = jest.fn(() => true);
@@ -17,7 +15,6 @@ jest.mock("@applicaster/zapp-react-native-utils/localizationUtils", () => ({
17
15
  }));
18
16
 
19
17
  const CustomText = require("../Text").default;
20
- const mockStore = configureStoreFn();
21
18
 
22
19
  const defaultProps = {
23
20
  entry: {},
@@ -25,16 +22,15 @@ const defaultProps = {
25
22
  transformText: "default",
26
23
  };
27
24
 
28
- const getRenderedText = (label: string, store: any) => {
25
+ const getRenderedText = (label: string, storeConfig: any) => {
29
26
  const props = { ...{ ...defaultProps, label } };
30
27
 
31
- const testRenderer = TestRenderer.create(
32
- <Provider store={store}>
33
- <CustomText {...props} />
34
- </Provider>
28
+ const { UNSAFE_getByType } = renderWithProviders(
29
+ <CustomText {...props} />,
30
+ storeConfig
35
31
  );
36
32
 
37
- return testRenderer.root.findByType(RN.Text).props.children;
33
+ return UNSAFE_getByType(RN.Text).props.children;
38
34
  };
39
35
 
40
36
  describe("RTL app: Hebrew text contains english word", () => {
@@ -42,28 +38,32 @@ describe("RTL app: Hebrew text contains english word", () => {
42
38
  const textWithNotFirstEnglishWord = "השיר של נועה נועה קירל באירוויזיון Word";
43
39
  const textWithoutEnglishWord = "השיר של נועה נועה קירל באירוויזיון";
44
40
 
45
- const store = mockStore({
41
+ const storeConfig = {
46
42
  remoteConfigurations: { localizations: { he: {} } },
47
43
  appData: {
48
44
  languageCode: "he",
49
45
  countryCode: "IL",
50
46
  },
51
- });
47
+ };
52
48
 
53
49
  it("Hebrew text contains first english word", () => {
54
- const renderedText = getRenderedText(textWithFirstEnglishWord, store);
50
+ const renderedText = getRenderedText(textWithFirstEnglishWord, storeConfig);
55
51
  const desiredText = "\u200fWord\u202c השיר של נועה נועה קירל באירוויזיון";
56
52
 
57
53
  expect(renderedText).toEqual(desiredText);
58
54
  });
59
55
 
60
56
  it("Hebrew text contains not first english word", () => {
61
- const renderedText = getRenderedText(textWithNotFirstEnglishWord, store);
57
+ const renderedText = getRenderedText(
58
+ textWithNotFirstEnglishWord,
59
+ storeConfig
60
+ );
61
+
62
62
  expect(renderedText).toEqual(textWithNotFirstEnglishWord);
63
63
  });
64
64
 
65
65
  it("Hebrew text doesn't contain english word", () => {
66
- const renderedText = getRenderedText(textWithoutEnglishWord, store);
66
+ const renderedText = getRenderedText(textWithoutEnglishWord, storeConfig);
67
67
  expect(renderedText).toEqual(textWithoutEnglishWord);
68
68
  });
69
69
  });
@@ -77,16 +77,16 @@ describe("LTR app: English text", () => {
77
77
 
78
78
  const englishText = "Test sentence";
79
79
 
80
- const store = mockStore({
80
+ const storeConfig = {
81
81
  remoteConfigurations: { localizations: { en: {} } },
82
82
  appData: {
83
83
  languageCode: "en",
84
84
  countryCode: "US",
85
85
  },
86
- });
86
+ };
87
87
 
88
88
  it("English text", () => {
89
- const renderedText = getRenderedText(englishText, store);
89
+ const renderedText = getRenderedText(englishText, storeConfig);
90
90
  expect(renderedText).toEqual(englishText);
91
91
  });
92
92
  });