@applicaster/zapp-react-native-ui-components 15.0.0-rc.1 → 15.0.0-rc.100

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 (123) hide show
  1. package/Components/AnimatedInOut/index.tsx +69 -26
  2. package/Components/BaseFocusable/index.ios.ts +12 -2
  3. package/Components/Cell/Cell.tsx +14 -3
  4. package/Components/Cell/CellWithFocusable.tsx +9 -0
  5. package/Components/Cell/FocusableWrapper.tsx +47 -0
  6. package/Components/Cell/TvOSCellComponent.tsx +106 -19
  7. package/Components/Focusable/Focusable.tsx +4 -2
  8. package/Components/Focusable/FocusableTvOS.tsx +18 -1
  9. package/Components/Focusable/__tests__/__snapshots__/FocusableTvOS.test.tsx.snap +1 -0
  10. package/Components/FocusableGroup/FocusableTvOS.tsx +32 -1
  11. package/Components/GeneralContentScreen/utils/__tests__/useCurationAPI.test.js +1 -1
  12. package/Components/GeneralContentScreen/utils/useCurationAPI.ts +31 -17
  13. package/Components/HandlePlayable/HandlePlayable.tsx +17 -65
  14. package/Components/HandlePlayable/const.ts +3 -0
  15. package/Components/HandlePlayable/utils.ts +74 -0
  16. package/Components/Layout/TV/LayoutBackground.tsx +5 -2
  17. package/Components/Layout/TV/ScreenContainer.tsx +2 -6
  18. package/Components/Layout/TV/index.tsx +3 -4
  19. package/Components/Layout/TV/index.web.tsx +3 -4
  20. package/Components/LinkHandler/LinkHandler.tsx +2 -2
  21. package/Components/MasterCell/DefaultComponents/BorderContainerView/__tests__/index.test.tsx +16 -1
  22. package/Components/MasterCell/DefaultComponents/BorderContainerView/index.tsx +30 -2
  23. package/Components/MasterCell/DefaultComponents/Image/Image.android.tsx +5 -1
  24. package/Components/MasterCell/DefaultComponents/Image/Image.ios.tsx +11 -3
  25. package/Components/MasterCell/DefaultComponents/Image/Image.web.tsx +9 -1
  26. package/Components/MasterCell/DefaultComponents/Image/hooks/useImage.ts +15 -14
  27. package/Components/MasterCell/DefaultComponents/LiveImage/index.tsx +10 -6
  28. package/Components/MasterCell/DefaultComponents/SecondaryImage/Image.tsx +40 -39
  29. package/Components/MasterCell/DefaultComponents/SecondaryImage/__tests__/Image.test.tsx +95 -0
  30. package/Components/MasterCell/DefaultComponents/SecondaryImage/__tests__/__snapshots__/Image.test.tsx.snap +86 -0
  31. package/Components/MasterCell/DefaultComponents/SecondaryImage/__tests__/index.test.ts +141 -0
  32. package/Components/MasterCell/DefaultComponents/SecondaryImage/hooks/__tests__/useGetImageDimensions.test.ts +7 -6
  33. package/Components/MasterCell/DefaultComponents/SecondaryImage/index.ts +1 -1
  34. package/Components/MasterCell/DefaultComponents/Text/index.tsx +8 -8
  35. package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/index.ts +6 -2
  36. package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/utils/__tests__/getPluginIdentifier.test.ts +233 -11
  37. package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/utils/index.ts +19 -15
  38. package/Components/MasterCell/hoc/__tests__/withAsyncRender.test.tsx +219 -0
  39. package/Components/MasterCell/hoc/withAsyncRender.tsx +9 -7
  40. package/Components/MasterCell/index.tsx +2 -0
  41. package/Components/MasterCell/utils/__tests__/resolveColor.test.js +82 -3
  42. package/Components/MasterCell/utils/index.ts +61 -31
  43. package/Components/MeasurmentsPortal/MeasurementsPortal.tsx +102 -87
  44. package/Components/MeasurmentsPortal/__tests__/MeasurementsPortal.test.tsx +355 -0
  45. package/Components/OfflineHandler/NotificationView/NotificationView.lg.tsx +17 -9
  46. package/Components/OfflineHandler/NotificationView/NotificationView.samsung.tsx +16 -8
  47. package/Components/OfflineHandler/NotificationView/NotificationView.tsx +2 -2
  48. package/Components/OfflineHandler/NotificationView/__tests__/index.test.tsx +17 -18
  49. package/Components/OfflineHandler/NotificationView/utils.ts +34 -0
  50. package/Components/OfflineHandler/__tests__/index.test.tsx +27 -18
  51. package/Components/PlayerContainer/PlayerContainer.tsx +51 -55
  52. package/Components/PlayerContainer/useRestrictMobilePlayback.tsx +101 -0
  53. package/Components/PlayerImageBackground/index.tsx +3 -22
  54. package/Components/River/ComponentsMap/ComponentsMap.tsx +65 -42
  55. package/Components/River/ComponentsMap/ContextProviders/ComponentsMapHeightContext.ts +8 -0
  56. package/Components/River/ComponentsMap/ContextProviders/ComponentsMapRefContext.ts +8 -0
  57. package/Components/River/ComponentsMap/hooks/__tests__/useLoadingState.test.ts +1 -1
  58. package/Components/River/TV/River.tsx +31 -14
  59. package/Components/River/TV/index.tsx +8 -4
  60. package/Components/River/TV/utils/__tests__/toStringOrEmpty.test.ts +30 -0
  61. package/Components/River/TV/utils/index.ts +4 -0
  62. package/Components/River/TV/withFocusableGroupForContent.tsx +71 -0
  63. package/Components/River/__tests__/__snapshots__/componentsMap.test.js.snap +2 -0
  64. package/Components/River/__tests__/componentsMap.test.js +38 -0
  65. package/Components/Screen/TV/hooks/useInitialFocus.ts +14 -4
  66. package/Components/Screen/TV/index.web.tsx +4 -2
  67. package/Components/Screen/__tests__/Screen.test.tsx +65 -42
  68. package/Components/Screen/__tests__/__snapshots__/Screen.test.tsx.snap +68 -42
  69. package/Components/Screen/hooks.ts +2 -3
  70. package/Components/Screen/index.tsx +24 -8
  71. package/Components/Screen/navigationHandler.ts +49 -24
  72. package/Components/Screen/orientationHandler.ts +10 -13
  73. package/Components/ScreenResolver/index.tsx +21 -9
  74. package/Components/ScreenRevealManager/ScreenRevealManager.ts +40 -8
  75. package/Components/ScreenRevealManager/__tests__/ScreenRevealManager.test.ts +86 -69
  76. package/Components/ScreenRevealManager/utils/index.ts +23 -0
  77. package/Components/ScreenRevealManager/withScreenRevealManager.tsx +54 -24
  78. package/Components/Tabs/TV/Tabs.tsx +20 -3
  79. package/Components/Tabs/TabContent.tsx +7 -4
  80. package/Components/Transitioner/Scene.tsx +15 -2
  81. package/Components/Transitioner/index.js +3 -3
  82. package/Components/VideoLive/__tests__/__snapshots__/PlayerLiveImageComponent.test.tsx.snap +1 -0
  83. package/Components/VideoModal/ModalAnimation/ModalAnimationContext.tsx +118 -171
  84. package/Components/VideoModal/ModalAnimation/index.ts +2 -13
  85. package/Components/VideoModal/ModalAnimation/utils.ts +1 -327
  86. package/Components/VideoModal/PlayerDetails.tsx +5 -5
  87. package/Components/VideoModal/PlayerWrapper.tsx +14 -88
  88. package/Components/VideoModal/VideoModal.tsx +1 -5
  89. package/Components/VideoModal/__tests__/PlayerWrapper.test.tsx +1 -0
  90. package/Components/VideoModal/hooks/__tests__/useDelayedPlayerDetails.test.ts +15 -7
  91. package/Components/VideoModal/hooks/useModalSize.ts +10 -5
  92. package/Components/VideoModal/playerWrapperStyle.ts +70 -0
  93. package/Components/VideoModal/playerWrapperUtils.ts +91 -0
  94. package/Components/VideoModal/utils.ts +19 -9
  95. package/Components/Viewport/ViewportEvents/__tests__/viewportEvents.test.js +1 -1
  96. package/Components/ZappFrameworkComponents/BarView/BarView.tsx +4 -6
  97. package/Components/ZappFrameworkComponents/BarView/__tests__/BarView.test.tsx +2 -2
  98. package/Contexts/ScreenContext/index.tsx +25 -18
  99. package/Contexts/ScreenTrackedViewPositionsContext/__tests__/index.test.tsx +1 -1
  100. package/Contexts/ZappHookModalContext/index.tsx +37 -61
  101. package/Contexts/index.ts +0 -2
  102. package/Decorators/Analytics/index.tsx +6 -5
  103. package/Decorators/ConfigurationWrapper/__tests__/__snapshots__/withConfigurationProvider.test.tsx.snap +1 -0
  104. package/Decorators/ConfigurationWrapper/const.ts +1 -0
  105. package/Decorators/RiverFeedLoader/utils/getDatasourceUrl.ts +6 -10
  106. package/Decorators/ZappPipesDataConnector/__tests__/zappPipesDataConnector.test.js +1 -1
  107. package/Decorators/ZappPipesDataConnector/index.tsx +2 -2
  108. package/Decorators/ZappPipesDataConnector/resolvers/StaticFeedResolver.tsx +1 -1
  109. package/Helpers/DataSourceHelper/__tests__/itemLimitForData.test.ts +80 -0
  110. package/Helpers/DataSourceHelper/index.ts +19 -0
  111. package/events/index.ts +3 -0
  112. package/events/scrollEndReached.ts +15 -0
  113. package/index.d.ts +7 -0
  114. package/package.json +6 -5
  115. package/Components/River/TV/withTVEventHandler.tsx +0 -27
  116. package/Components/VideoModal/ModalAnimation/AnimatedPlayerModalWrapper.tsx +0 -60
  117. package/Components/VideoModal/ModalAnimation/AnimatedScrollModal.tsx +0 -415
  118. package/Components/VideoModal/ModalAnimation/AnimatedScrollModal.web.tsx +0 -294
  119. package/Components/VideoModal/ModalAnimation/AnimatedVideoPlayerComponent.tsx +0 -176
  120. package/Components/VideoModal/ModalAnimation/AnimatedVideoPlayerComponent.web.tsx +0 -93
  121. package/Components/VideoModal/ModalAnimation/AnimationComponent.tsx +0 -500
  122. package/Components/VideoModal/ModalAnimation/__tests__/getMoveUpValue.test.ts +0 -108
  123. package/Helpers/DataSourceHelper/index.js +0 -19
@@ -1,4 +1,4 @@
1
- import { all, equals, path, prop, isEmpty, pluck, values } from "ramda";
1
+ import { all, equals, isEmpty, path, pluck, prop, values } from "ramda";
2
2
 
3
3
  import { useEffect, useMemo } from "react";
4
4
 
@@ -9,10 +9,9 @@ import {
9
9
  import { isEmptyOrNil } from "@applicaster/zapp-react-native-utils/cellUtils";
10
10
  import { Categories } from "./logger";
11
11
  import { createLogger } from "@applicaster/zapp-react-native-utils/logger";
12
- import { useRoute } from "@applicaster/zapp-react-native-utils/reactHooks/navigation/useRoute";
12
+ import { useScreenContext } from "@applicaster/zapp-react-native-utils/reactHooks/screen/useScreenContext";
13
13
 
14
14
  import {
15
- ZappPipesEntryContext,
16
15
  ZappPipesScreenContext,
17
16
  ZappPipesSearchContext,
18
17
  } from "@applicaster/zapp-react-native-ui-components/Contexts";
@@ -24,6 +23,7 @@ import {
24
23
 
25
24
  import { produce } from "immer";
26
25
  import { useLoadPipesDataDispatch } from "@applicaster/zapp-react-native-utils/reactHooks";
26
+
27
27
  // types reference
28
28
 
29
29
  declare interface CurationEntry {
@@ -35,6 +35,8 @@ type Feeds = Record<string, ZappPipesData>;
35
35
 
36
36
  type LayoutPresets = PresetsMapping["presets_mappings"];
37
37
 
38
+ const TABS_SCREEN_TYPE = "tabs_screen";
39
+ const QB_TABS_SCREEN_TYPE = "quick-brick-tabs";
38
40
  const SMART_COMPONENT_TYPE = "quick-brick-smart-component";
39
41
  const SOURCE_PATH = ["data", "source"];
40
42
  const MAPPING_PATH = ["data", "mapping"];
@@ -53,7 +55,10 @@ export const getTransformedPreset = (
53
55
  const presetComponent = layoutPresets?.[preset?.preset_name];
54
56
 
55
57
  if (!presetComponent) {
56
- logger.log_error("Preset missing or wrong data format", { entry: preset });
58
+ logger.log_error(
59
+ `Preset "${preset?.preset_name}" missing or wrong data format`,
60
+ { entry: preset }
61
+ );
57
62
 
58
63
  return;
59
64
  }
@@ -130,11 +135,22 @@ export const useCurationAPI = (
130
135
  [components]
131
136
  );
132
137
 
133
- const { pathname } = useRoute();
134
- const [entryContext] = ZappPipesEntryContext.useZappPipesContext(pathname);
135
138
  const [searchContext] = ZappPipesSearchContext.useZappPipesContext();
136
139
  const [screenContext] = ZappPipesScreenContext.useZappPipesContext();
137
140
 
141
+ const screenContextType = screenContext?.type;
142
+
143
+ const isNestedScreen =
144
+ screenContextType === TABS_SCREEN_TYPE ||
145
+ screenContextType === QB_TABS_SCREEN_TYPE;
146
+
147
+ const screenContextData = useScreenContext();
148
+
149
+ const entryContext = ((isNestedScreen && screenContextData?.nested?.entry
150
+ ? screenContextData?.nested?.entry
151
+ : (screenContextData?.entry?.payload ?? screenContextData?.entry)) ||
152
+ {}) as ZappEntry;
153
+
138
154
  const urlsMap = useMemo<{ [key: string]: string }>(() => {
139
155
  const map = {};
140
156
 
@@ -142,17 +158,15 @@ export const useCurationAPI = (
142
158
  const url = path(SOURCE_PATH, component);
143
159
  const mapping = path(MAPPING_PATH, component);
144
160
 
145
- map[component.id] = mapping
146
- ? getInflatedDataSourceUrl({
147
- source: url,
148
- contexts: {
149
- entry: entryContext,
150
- screen: screenContext,
151
- search: getSearchContext(searchContext, mapping),
152
- },
153
- mapping,
154
- })
155
- : url;
161
+ map[component.id] = getInflatedDataSourceUrl({
162
+ source: url,
163
+ contexts: {
164
+ entry: entryContext,
165
+ screen: screenContext,
166
+ search: getSearchContext(searchContext, mapping),
167
+ },
168
+ mapping,
169
+ });
156
170
  });
157
171
 
158
172
  return map;
@@ -1,14 +1,14 @@
1
1
  import * as React from "react";
2
- import * as R from "ramda";
3
2
  import {
4
- findPluginByType,
5
- findPluginByIdentifier,
6
- } from "@applicaster/zapp-react-native-utils/pluginUtils";
7
- import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
3
+ useAppData,
4
+ useContentTypes,
5
+ usePlugins,
6
+ } from "@applicaster/zapp-react-native-redux/hooks";
8
7
  import {
9
8
  useDimensions,
10
9
  useIsTablet as isTablet,
11
10
  useNavigation,
11
+ useRivers,
12
12
  } from "@applicaster/zapp-react-native-utils/reactHooks";
13
13
 
14
14
  import { BufferAnimation } from "../PlayerContainer/BufferAnimation";
@@ -16,6 +16,7 @@ import { PlayerContainer } from "../PlayerContainer";
16
16
  import { useModalSize } from "../VideoModal/hooks";
17
17
  import { ViewStyle } from "react-native";
18
18
  import { platformSelect } from "@applicaster/zapp-react-native-utils/reactUtils";
19
+ import { findCastPlugin, getPlayer } from "./utils";
19
20
 
20
21
  type Props = {
21
22
  item: ZappEntry;
@@ -26,62 +27,6 @@ type Props = {
26
27
  groupId?: string;
27
28
  };
28
29
 
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
30
  type PlayableComponent = {
86
31
  Component: React.ComponentType<any>;
87
32
  };
@@ -99,14 +44,21 @@ export function HandlePlayable({
99
44
  mode,
100
45
  groupId,
101
46
  }: Props): React.ReactElement | null {
102
- const state = usePickFromState();
47
+ const plugins = usePlugins();
48
+ const contentTypes = useContentTypes();
49
+ const rivers = useRivers();
50
+ const appData = useAppData();
103
51
 
104
52
  const { closeVideoModal } = useNavigation();
105
53
 
106
- const [Player, playerModuleProperties] = getPlayer(item, state);
54
+ const [Player, playerModuleProperties] = getPlayer(item, {
55
+ plugins,
56
+ contentTypes,
57
+ rivers,
58
+ appData,
59
+ });
107
60
 
108
- const { module: CastPlugin } =
109
- findPluginByIdentifier(CHROMECAST_PLUGIN_ID, state.plugins, true) || {};
61
+ const { module: CastPlugin } = findCastPlugin(plugins);
110
62
 
111
63
  const [playable, setPlayable] =
112
64
  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
+ };
@@ -1,7 +1,10 @@
1
1
  import React from "react";
2
- import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
3
2
  import { getBackgroundImageUrl } from "../utils";
4
3
  import { useTheme } from "@applicaster/zapp-react-native-utils/theme";
4
+ import {
5
+ selectRemoteConfigurations,
6
+ useAppSelector,
7
+ } from "@applicaster/zapp-react-native-redux";
5
8
 
6
9
  export const LayoutBackground = ({
7
10
  Background,
@@ -12,7 +15,7 @@ export const LayoutBackground = ({
12
15
  }) => {
13
16
  const theme = useTheme();
14
17
 
15
- const { remoteConfigurations } = usePickFromState(["remoteConfigurations"]);
18
+ const remoteConfigurations = useAppSelector(selectRemoteConfigurations);
16
19
 
17
20
  const backgroundColor = theme.app_background_color;
18
21
  const backgroundImageUrl = getBackgroundImageUrl(remoteConfigurations);
@@ -18,7 +18,7 @@ import {
18
18
  routeIsPlayerScreen,
19
19
  } from "@applicaster/zapp-react-native-utils/navigationUtils";
20
20
  import { isApplePlatform } from "@applicaster/zapp-react-native-utils/reactUtils";
21
- import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
21
+ import { usePlugins } from "@applicaster/zapp-react-native-redux/hooks";
22
22
  import { NavBarContainer } from "./NavBarContainer";
23
23
 
24
24
  type ComponentsExtraProps = {
@@ -111,11 +111,7 @@ export const ScreenContainer = React.memo(function ScreenContainer({
111
111
  const { activeRiver } = navigator;
112
112
  const { title, visible } = useNavbarState();
113
113
 
114
- const { plugins = [] } = usePickFromState([
115
- "appState",
116
- "remoteConfigurations",
117
- "plugins",
118
- ]);
114
+ const plugins = usePlugins();
119
115
 
120
116
  const navigationProps = getNavigationProps({
121
117
  navigator,
@@ -1,5 +1,5 @@
1
1
  import * as React from "react";
2
- import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
2
+ import { useAppSelector } from "@applicaster/zapp-react-native-redux/hooks";
3
3
  import { useNavigation } from "@applicaster/zapp-react-native-utils/reactHooks/navigation";
4
4
 
5
5
  import { LayoutContainer } from "./LayoutContainer";
@@ -10,6 +10,7 @@ import { PathnameContext } from "../../../Contexts/PathnameContext";
10
10
  import { ScreenDataContext } from "../../../Contexts/ScreenDataContext";
11
11
  import { ScreenContextProvider } from "../../../Contexts/ScreenContext";
12
12
  import { LayoutBackground } from "./LayoutBackground";
13
+ import { selectAppReady } from "@applicaster/zapp-react-native-redux";
13
14
 
14
15
  type Components = {
15
16
  NavBar: React.ComponentType<any>;
@@ -29,9 +30,7 @@ type Props = {
29
30
  const Layout = ({ Components, ComponentsExtraProps, children }: Props) => {
30
31
  const navigator = useNavigation();
31
32
 
32
- const { appState: { appReady = false } = {} } = usePickFromState([
33
- "appState",
34
- ]);
33
+ const appReady = useAppSelector(selectAppReady);
35
34
 
36
35
  if (!appReady) {
37
36
  return null;
@@ -1,11 +1,11 @@
1
1
  import * as React from "react";
2
- import { pathOr } from "ramda";
3
2
 
4
- import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
3
+ import { useAppSelector } from "@applicaster/zapp-react-native-redux/hooks";
5
4
 
6
5
  import { ScreenLayoutContextProvider } from "./ScreenLayoutContextProvider";
7
6
  import { StackNavigator } from "../../Navigator";
8
7
  import { LayoutBackground } from "./LayoutBackground";
8
+ import { selectAppReady } from "@applicaster/zapp-react-native-redux";
9
9
 
10
10
  type Components = {
11
11
  NavBar: React.ComponentType<any>;
@@ -17,8 +17,7 @@ type Props = {
17
17
  };
18
18
 
19
19
  const Layout = ({ Components }: Props) => {
20
- const { appState } = usePickFromState(["appState"]);
21
- const appReady = pathOr(false, ["appReady"], appState);
20
+ const appReady = useAppSelector(selectAppReady);
22
21
 
23
22
  if (!appReady) {
24
23
  return null;
@@ -2,7 +2,7 @@ import * as React from "react";
2
2
  import * as R from "ramda";
3
3
 
4
4
  import { findPluginByIdentifier } from "@applicaster/zapp-react-native-utils/pluginUtils";
5
- import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
5
+ import { usePlugins } from "@applicaster/zapp-react-native-redux/hooks";
6
6
  import {
7
7
  inflateString,
8
8
  objectToReadableString,
@@ -40,7 +40,7 @@ export async function inflateUrl(url) {
40
40
 
41
41
  export function LinkHandler(props: Props) {
42
42
  const screenData = props?.screenData;
43
- const { plugins } = usePickFromState(["rivers", "plugins"]);
43
+ const plugins = usePlugins();
44
44
 
45
45
  const ScreenPlugin = findPluginByIdentifier(
46
46
  WEBVIEW_SCREEN_IDENTIFIER,
@@ -1,8 +1,8 @@
1
+ import * as React from "react";
1
2
  import {
2
3
  BorderContainerView,
3
4
  getBorderPadding, // Export for testing (using a double underscore prefix is a common convention)
4
5
  } from "../index";
5
- import * as React from "react";
6
6
  import { render } from "@testing-library/react-native";
7
7
  import { toNumberWithDefaultZero } from "@applicaster/zapp-react-native-utils/numberUtils";
8
8
  import { View } from "react-native";
@@ -11,6 +11,15 @@ jest.mock("@applicaster/zapp-react-native-utils/numberUtils", () => ({
11
11
  toNumberWithDefaultZero: jest.fn((value) => Number(value) || 0),
12
12
  }));
13
13
 
14
+ jest.mock(
15
+ "@applicaster/zapp-react-native-utils/appUtils/accessibilityManager/hooks",
16
+ () => ({
17
+ useAccessibilityManager: jest.fn(() => ({
18
+ addHeading: jest.fn(),
19
+ })),
20
+ })
21
+ );
22
+
14
23
  describe("BorderContainerView", () => {
15
24
  describe("getBorderPadding", () => {
16
25
  it("returns 0 for inside", () => {
@@ -42,6 +51,8 @@ describe("BorderContainerView", () => {
42
51
  };
43
52
 
44
53
  const borderPosition = null;
54
+ const mockEntry = { id: "test-entry" } as ZappEntry;
55
+ const mockHasFocusableInside = jest.fn(() => false);
45
56
 
46
57
  const { queryByTestId } = render(
47
58
  <BorderContainerView
@@ -52,6 +63,10 @@ describe("BorderContainerView", () => {
52
63
  borderPaddingRight={toNumberWithDefaultZero(padding.paddingRight)}
53
64
  borderPaddingBottom={toNumberWithDefaultZero(padding.paddingBottom)}
54
65
  borderPaddingLeft={toNumberWithDefaultZero(padding.paddingLeft)}
66
+ hasFocusableInside={mockHasFocusableInside}
67
+ entry={mockEntry}
68
+ state="focused"
69
+ hasTextLabels={false}
55
70
  >
56
71
  <View testID="child" />
57
72
  </BorderContainerView>
@@ -1,10 +1,16 @@
1
- import { toNumberWithDefaultZero } from "@applicaster/zapp-react-native-utils/numberUtils";
2
- import * as React from "react";
1
+ import React, { useMemo, useContext, useEffect } from "react";
3
2
  import { ImageStyle, StyleSheet, View, ViewStyle } from "react-native";
3
+ import { useAccessibilityManager } from "@applicaster/zapp-react-native-utils/appUtils/accessibilityManager/hooks";
4
+ import { toNumberWithDefaultZero } from "@applicaster/zapp-react-native-utils/numberUtils";
5
+ import { MeasurementPortalContext } from "../../../MeasurmentsPortal/MeasurementsPortal";
4
6
 
5
7
  type BorderPosition = "inside" | "outside" | "center";
6
8
 
7
9
  interface Props {
10
+ hasFocusableInside: (entry: ZappEntry) => boolean;
11
+ entry: ZappEntry;
12
+ state: CellState;
13
+ hasTextLabels: boolean;
8
14
  style: ImageStyle | ViewStyle;
9
15
  borderPosition: BorderPosition;
10
16
  borderPaddingTop: number;
@@ -118,8 +124,30 @@ export const BorderContainerView = (props: Props) => {
118
124
  borderPaddingLeft,
119
125
  style,
120
126
  children,
127
+ hasFocusableInside,
128
+ entry,
129
+ state,
130
+ hasTextLabels,
121
131
  } = props;
122
132
 
133
+ const accessibilityManager = useAccessibilityManager();
134
+ const isMeasurement = useContext(MeasurementPortalContext);
135
+
136
+ const isImageOnlyCell = useMemo(
137
+ () =>
138
+ state === "focused" &&
139
+ !hasTextLabels &&
140
+ !isMeasurement?.measuringInProgress &&
141
+ !hasFocusableInside(entry),
142
+ [entry, hasTextLabels, state, isMeasurement?.measuringInProgress]
143
+ );
144
+
145
+ useEffect(() => {
146
+ if (isImageOnlyCell && entry?.title) {
147
+ accessibilityManager.addHeading(String(entry.title));
148
+ }
149
+ }, [isImageOnlyCell, entry?.title]);
150
+
123
151
  const padding =
124
152
  borderPosition === "outside"
125
153
  ? {
@@ -32,6 +32,7 @@ export default function Image({
32
32
  placeholderImage,
33
33
  entry,
34
34
  withDimensions,
35
+ source: sourceProp,
35
36
  ...otherProps
36
37
  }: Props) {
37
38
  const [showDefault, setShowDefault] = React.useState(false);
@@ -48,7 +49,10 @@ export default function Image({
48
49
  entry,
49
50
  showDefault,
50
51
  placeholderImage: placeholderImage || "",
51
- otherProps,
52
+ otherProps: {
53
+ source: sourceProp,
54
+ state: otherProps.state,
55
+ },
52
56
  });
53
57
 
54
58
  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
  };