@applicaster/zapp-react-native-ui-components 13.0.0-rc.10 → 13.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 (209) hide show
  1. package/Components/AppContainer/__tests__/AppContainer.test.js +4 -6
  2. package/Components/AppContainer/__tests__/__snapshots__/AppContainer.test.js.snap +1 -1
  3. package/Components/AudioPlayer/AudioPlayer.tsx +7 -0
  4. package/Components/AudioPlayer/__tests__/Runtime.test.js +5 -8
  5. package/Components/AudioPlayer/__tests__/__snapshots__/Runtime.test.js.snap +4 -4
  6. package/Components/AudioPlayer/__tests__/__snapshots__/artWork.test.js.snap +3 -3
  7. package/Components/AudioPlayer/__tests__/__snapshots__/audioPlayer.test.js.snap +56 -113
  8. package/Components/AudioPlayer/__tests__/__snapshots__/audioPlayerLayout.test.js.snap +39 -23
  9. package/Components/AudioPlayer/__tests__/__snapshots__/channel.test.js.snap +3 -3
  10. package/Components/AudioPlayer/__tests__/__snapshots__/summary.test.js.snap +2 -2
  11. package/Components/AudioPlayer/__tests__/__snapshots__/title.test.js.snap +2 -2
  12. package/Components/AudioPlayer/__tests__/artWork.test.js +3 -5
  13. package/Components/AudioPlayer/__tests__/audioPlayer.test.js +3 -5
  14. package/Components/AudioPlayer/__tests__/audioPlayerLayout.test.js +7 -8
  15. package/Components/AudioPlayer/__tests__/channel.test.js +3 -5
  16. package/Components/AudioPlayer/__tests__/summary.test.js +3 -5
  17. package/Components/AudioPlayer/__tests__/title.test.js +3 -5
  18. package/Components/AudioPlayer/helpers.tsx +1 -0
  19. package/Components/BaseFocusable/index.ios.ts +1 -1
  20. package/Components/BaseFocusable/index.tsx +67 -31
  21. package/Components/Cell/Cell.tsx +18 -22
  22. package/Components/Cell/CellWithFocusable.tsx +51 -60
  23. package/Components/Cell/CellWrapper.tsx +18 -0
  24. package/Components/Cell/TvOSCellComponent.tsx +23 -30
  25. package/Components/Cell/__tests__/CellWIthFocusable.test.js +13 -6
  26. package/Components/Cell/index.js +3 -1
  27. package/Components/Cell/styles.ts +17 -0
  28. package/Components/CellRendererResolver/__tests__/cellRendererResolver.test.js +50 -50
  29. package/Components/CellRendererResolver/index.ts +2 -1
  30. package/Components/ComponentResolver/__tests__/__snapshots__/componentResolver.test.js.snap +1 -42
  31. package/Components/ComponentResolver/__tests__/componentResolver.test.js +26 -30
  32. package/Components/ContentScreen/__tests__/contentScreen.test.js +3 -3
  33. package/Components/DisplayState/__tests__/__snapshots__/displayState.test.js.snap +2 -2
  34. package/Components/ErrorScreen/index.tsx +14 -6
  35. package/Components/Focusable/Focusable.tsx +1 -54
  36. package/Components/Focusable/FocusableTvOS.tsx +6 -2
  37. package/Components/Focusable/Touchable.tsx +19 -20
  38. package/Components/Focusable/index.android.tsx +10 -3
  39. package/Components/FocusableCell/index.tsx +1 -1
  40. package/Components/FocusableGroup/FocusableTvOS.tsx +34 -86
  41. package/Components/FocusableGroup/index.tsx +0 -3
  42. package/Components/FocusableList/index.tsx +26 -10
  43. package/Components/FocusableScrollView/index.tsx +43 -13
  44. package/Components/GeneralContentScreen/utils/__tests__/useCurationAPI.test.js +76 -7
  45. package/Components/GeneralContentScreen/utils/useCurationAPI.ts +53 -9
  46. package/Components/HandlePlayable/HandlePlayable.tsx +21 -27
  47. package/Components/Layout/TV/LayoutBackground.tsx +28 -0
  48. package/Components/Layout/TV/NavBarContainer.tsx +19 -23
  49. package/Components/Layout/TV/ScreenContainer.tsx +8 -2
  50. package/Components/Layout/TV/ScreenLayoutContextProvider.tsx +5 -0
  51. package/Components/Layout/TV/__tests__/ScreenContainer.test.tsx +3 -1
  52. package/Components/Layout/TV/__tests__/__snapshots__/LayoutContainer.test.tsx.snap +1 -1
  53. package/Components/Layout/TV/__tests__/__snapshots__/NavBarContainer.test.tsx.snap +6 -5
  54. package/Components/Layout/TV/__tests__/__snapshots__/ScreenContainer.test.tsx.snap +12 -11
  55. package/Components/Layout/TV/__tests__/__snapshots__/index.test.tsx.snap +15 -10
  56. package/Components/Layout/TV/__tests__/index.test.tsx +14 -4
  57. package/Components/Layout/TV/index.tsx +6 -20
  58. package/Components/Layout/TV/index.web.tsx +4 -1
  59. package/Components/MasterCell/DefaultComponents/ActionButton.tsx +2 -3
  60. package/Components/MasterCell/DefaultComponents/BorderContainerView/__tests__/index.test.tsx +66 -0
  61. package/Components/MasterCell/DefaultComponents/BorderContainerView/index.tsx +4 -1
  62. package/Components/MasterCell/DefaultComponents/Image/Image.ios.tsx +10 -15
  63. package/Components/MasterCell/DefaultComponents/Image/hooks/useImage.ts +11 -7
  64. package/Components/MasterCell/DefaultComponents/ImageBorderContainer/__tests__/index.test.ts +93 -0
  65. package/Components/MasterCell/DefaultComponents/LiveImage/index.tsx +2 -2
  66. package/Components/MasterCell/DefaultComponents/SecondaryImage/__tests__/__snapshots__/Image.test.tsx.snap +3 -3
  67. package/Components/MasterCell/DefaultComponents/SecondaryImage/utils.ts +1 -1
  68. package/Components/MasterCell/DefaultComponents/__tests__/image.test.js +1 -1
  69. package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/const.ts +3 -0
  70. package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/index.ts +6 -6
  71. package/Components/MasterCell/SharedUI/CollapsibleTextContainer/__tests__/__snapshots__/index.test.tsx.snap +1 -1
  72. package/Components/MasterCell/SharedUI/ProgressBar/hooks/useFillInPercent.ts +2 -8
  73. package/Components/MasterCell/__tests__/__snapshots__/dataAdapter.test.js.snap +180 -180
  74. package/Components/MasterCell/__tests__/__snapshots__/elementMapper.test.js.snap +11 -19
  75. package/Components/MasterCell/__tests__/__snapshots__/masterCell.test.js.snap +6 -235
  76. package/Components/MasterCell/__tests__/elementMapper.test.js +18 -5
  77. package/Components/MasterCell/__tests__/masterCell.test.js +26 -26
  78. package/Components/MasterCell/hooks/useAsyncRendering/MasterCellAsyncRenderManager.ts +2 -2
  79. package/Components/MasterCell/hooks/useAsyncRendering/index.ts +2 -2
  80. package/Components/MasterCell/utils/behaviorProvider.ts +136 -0
  81. package/Components/MasterCell/utils/index.ts +9 -135
  82. package/Components/ModalComponent/BottomSheetModalContent.tsx +45 -19
  83. package/Components/ModalComponent/Button/Item.tsx +6 -5
  84. package/Components/ModalComponent/Button/assets.ts +1 -1
  85. package/Components/ModalComponent/Button/index.tsx +30 -43
  86. package/Components/ModalComponent/Header/index.tsx +3 -3
  87. package/Components/ModalComponent/utils.ts +55 -7
  88. package/Components/NativeFocusables/{index.js → index.ts} +4 -2
  89. package/Components/OfflineHandler/NotificationView/NotificationView.lg.tsx +2 -2
  90. package/Components/OfflineHandler/NotificationView/NotificationView.samsung.tsx +2 -2
  91. package/Components/OfflineHandler/NotificationView/__tests__/index.test.tsx +0 -5
  92. package/Components/OfflineHandler/__tests__/__snapshots__/index.test.tsx.snap +7 -7
  93. package/Components/OfflineHandler/__tests__/index.test.tsx +28 -25
  94. package/Components/OfflineHandler/utils/index.ts +1 -1
  95. package/Components/PlayerContainer/PlayerContainer.tsx +45 -25
  96. package/Components/PlayerContainer/PlayerContainerContext.tsx +9 -0
  97. package/Components/PlayerContainer/ProgramInfo/index.tsx +2 -2
  98. package/Components/PlayerImageBackground/index.tsx +1 -1
  99. package/Components/River/ComponentsMap/ComponentsMap.tsx +42 -65
  100. package/Components/River/ComponentsMap/hooks/useLoadingState.ts +78 -51
  101. package/Components/River/RefreshControl.tsx +1 -1
  102. package/Components/River/RiverFooter.tsx +39 -9
  103. package/Components/River/RiverItem.tsx +39 -3
  104. package/Components/River/TV/index.tsx +6 -1
  105. package/Components/River/__tests__/__snapshots__/componentsMap.test.js.snap +114 -45
  106. package/Components/River/__tests__/__snapshots__/river.test.js.snap +21 -83
  107. package/Components/River/__tests__/componentsMap.test.js +64 -17
  108. package/Components/River/__tests__/river.test.js +75 -40
  109. package/Components/RouteManager/__tests__/__snapshots__/routeManager.test.js.snap +12 -5
  110. package/Components/RouteManager/__tests__/routeManager.test.js +29 -14
  111. package/Components/RouteManager/__tests__/testId.test.js +8 -6
  112. package/Components/Screen/TV/index.web.tsx +5 -6
  113. package/Components/Screen/__tests__/Screen.test.tsx +41 -27
  114. package/Components/Screen/__tests__/__snapshots__/Screen.test.tsx.snap +4 -4
  115. package/Components/Screen/hooks.ts +53 -0
  116. package/Components/Screen/index.tsx +16 -42
  117. package/Components/ScreenResolver/__tests__/screenResolver.test.js +95 -70
  118. package/Components/Tabs/Tab.tsx +12 -9
  119. package/Components/TextInputTv/__tests__/TextInputTv.test.js +42 -42
  120. package/Components/TextInputTv/__tests__/__snapshots__/TextInputTv.test.js.snap +7 -0
  121. package/Components/TextInputTv/index.tsx +6 -5
  122. package/Components/TopMarginApplicator/TopMarginApplicator.tsx +2 -3
  123. package/Components/Touchable/__tests__/__snapshots__/touchable.test.tsx.snap +2 -2
  124. package/Components/TrackedView/index.tsx +1 -0
  125. package/Components/Transitioner/AnimationManager.js +15 -15
  126. package/Components/Transitioner/Scene.tsx +53 -24
  127. package/Components/Transitioner/Transitioner.tsx +3 -3
  128. package/Components/Transitioner/__tests__/Scene.test.js +25 -14
  129. package/Components/Transitioner/__tests__/__snapshots__/AnimationManager.test.js.snap +26 -26
  130. package/Components/Transitioner/__tests__/__snapshots__/Scene.test.js.snap +10 -50
  131. package/Components/Transitioner/__tests__/__snapshots__/config.test.js.snap +20 -20
  132. package/Components/Transitioner/__tests__/__snapshots__/transitioner.test.js.snap +4 -4
  133. package/Components/Transitioner/__tests__/transitioner.test.js +13 -4
  134. package/Components/Transitioner/index.js +8 -4
  135. package/Components/VideoLive/LiveImageManager.ts +27 -1
  136. package/Components/VideoLive/PlayerLiveImageComponent.tsx +36 -24
  137. package/Components/VideoLive/__tests__/PlayerLiveImageComponent.test.tsx +63 -8
  138. package/Components/VideoLive/__tests__/__snapshots__/PlayerLiveImageComponent.test.tsx.snap +6 -10
  139. package/Components/VideoModal/ModalAnimation/AnimatedPlayerModalWrapper.tsx +1 -1
  140. package/Components/VideoModal/ModalAnimation/AnimatedScrollModal.tsx +51 -31
  141. package/Components/VideoModal/ModalAnimation/AnimatedVideoPlayerComponent.tsx +8 -4
  142. package/Components/VideoModal/ModalAnimation/AnimationComponent.tsx +48 -22
  143. package/Components/VideoModal/ModalAnimation/ModalAnimationContext.tsx +15 -15
  144. package/Components/VideoModal/ModalAnimation/__tests__/getMoveUpValue.test.ts +108 -0
  145. package/Components/VideoModal/ModalAnimation/const.ts +5 -0
  146. package/Components/VideoModal/ModalAnimation/index.ts +4 -1
  147. package/Components/VideoModal/ModalAnimation/useModalAnimationContext.ts +6 -0
  148. package/Components/VideoModal/ModalAnimation/utils.ts +38 -2
  149. package/Components/VideoModal/OpaqueLayer.tsx +33 -0
  150. package/Components/VideoModal/PlayerDetails.tsx +18 -10
  151. package/Components/VideoModal/PlayerWrapper.tsx +43 -39
  152. package/Components/VideoModal/VideoModal.tsx +17 -11
  153. package/Components/VideoModal/__tests__/PlayerDetails.test.tsx +5 -2
  154. package/Components/VideoModal/__tests__/PlayerWrapper.test.tsx +13 -10
  155. package/Components/VideoModal/__tests__/__snapshots__/PlayerDetails.test.tsx.snap +2 -40
  156. package/Components/VideoModal/__tests__/__snapshots__/PlayerWrapper.test.tsx.snap +66 -156
  157. package/Components/VideoModal/hooks/__tests__/useDelayedPlayerDetails.test.ts +89 -0
  158. package/Components/VideoModal/hooks/index.ts +7 -0
  159. package/Components/VideoModal/hooks/useDelayedPlayerDetails.ts +49 -0
  160. package/Components/VideoModal/hooks/utils/__tests__/showDetails.test.ts +91 -0
  161. package/Components/VideoModal/hooks/utils/index.ts +33 -0
  162. package/Components/VideoModal/utils.ts +6 -9
  163. package/Components/Viewport/ViewportAware/__tests__/__snapshots__/viewportAware.test.js.snap +24 -36
  164. package/Components/Viewport/ViewportAware/__tests__/viewportAware.test.js +12 -18
  165. package/Components/Viewport/ViewportTracker/__tests__/__snapshots__/viewportTracker.test.js.snap +1 -1
  166. package/Components/Viewport/__tests__/utils.test.js +5 -4
  167. package/Components/ZappUIComponent/Placeholder.tsx +3 -1
  168. package/Components/ZappUIComponent/__tests__/{ZappUIComponent.test.js → ZappUIComponent.test.tsx} +26 -10
  169. package/Components/ZappUIComponent/index.tsx +4 -17
  170. package/Components/default-cell-renderer/__tests__/defaultCellRenderer.test.tsx +20 -17
  171. package/Components/default-cell-renderer/viewTrees/tv/DefaultCell/__tests__/DefaultCell.test.tsx +15 -11
  172. package/Contexts/ComponentsMapOffsetContext/index.tsx +49 -0
  173. package/Contexts/ConfigutaionContext/__tests__/__snapshots__/ConfigurationProvider.test.tsx.snap +1 -1
  174. package/Contexts/FocusableGroupContext/withFocusableContext.tsx +4 -10
  175. package/Contexts/HeaderOffsetContext/index.tsx +4 -6
  176. package/Contexts/ScreenContext/index.tsx +6 -12
  177. package/Contexts/ScreenLayoutContext/index.tsx +5 -3
  178. package/Decorators/Analytics/{index.js → index.tsx} +11 -11
  179. package/Decorators/Navigator/__tests__/navigator.test.js +16 -16
  180. package/Decorators/Navigator/index.tsx +1 -1
  181. package/Decorators/RiverFeedLoader/__tests__/__snapshots__/riverFeedLoader.test.tsx.snap +77 -77
  182. package/Decorators/RiverFeedLoader/__tests__/riverFeedLoader.test.tsx +34 -39
  183. package/Decorators/RiverFeedLoader/__tests__/utils.test.ts +0 -9
  184. package/Decorators/RiverFeedLoader/index.tsx +1 -1
  185. package/Decorators/RiverFeedLoader/utils/getDatasourceUrl.ts +39 -0
  186. package/Decorators/RiverFeedLoader/utils/index.ts +29 -0
  187. package/Decorators/RiverFeedLoader/utils/usePipesContexts.ts +40 -0
  188. package/Decorators/RiverResolver/__tests__/riverResolver.test.tsx +27 -27
  189. package/Decorators/RiverResolver/index.tsx +6 -8
  190. package/Decorators/ZappPipesDataConnector/__tests__/Hero.js +1 -1
  191. package/Decorators/ZappPipesDataConnector/__tests__/zappPipesDataConnector.test.js +29 -22
  192. package/Decorators/ZappPipesDataConnector/index.tsx +7 -3
  193. package/package.json +13 -11
  194. package/tsconfig.json +2 -3
  195. package/.babelrc +0 -8
  196. package/Components/Cell/CellStyles/FallbackCellStyle/index.js +0 -157
  197. package/Components/Cell/CellStyles/Hero/index.js +0 -111
  198. package/Components/Cell/CellStyles/ScreenSelector/index.js +0 -68
  199. package/Components/Cell/CellStyles/cellStylesResolver.ts +0 -19
  200. package/Components/Cell/CellStyles/colors.js +0 -40
  201. package/Components/Cell/CellStyles/index.js +0 -15
  202. package/Components/CellRendererResolver/__tests__/__snapshots__/cellRendererResolver.test.js.snap +0 -53
  203. package/Components/RouteManager/__tests__/__snapshots__/testId.test.js.snap +0 -17
  204. package/Components/ScreenResolver/__tests__/__snapshots__/screenResolver.test.js.snap +0 -17
  205. package/Components/ZappUIComponent/__tests__/__snapshots__/ZappUIComponent.test.js.snap +0 -91
  206. package/Components/default-cell-renderer/__tests__/__snapshots__/defaultCellRenderer.test.tsx.snap +0 -338
  207. package/Decorators/Navigator/__tests__/__snapshots__/navigator.test.js.snap +0 -18
  208. package/Decorators/RiverFeedLoader/utils.ts +0 -100
  209. package/Decorators/RiverResolver/__tests__/__snapshots__/riverResolver.test.tsx.snap +0 -28
@@ -1,17 +1,30 @@
1
1
  import * as React from "react";
2
2
  import { FocusableGroupNative } from "@applicaster/zapp-react-native-ui-components/Components/NativeFocusables";
3
3
  import { BaseFocusable } from "@applicaster/zapp-react-native-ui-components/Components/BaseFocusable";
4
-
5
- function noop() {}
4
+ import { createLogger } from "@applicaster/zapp-react-native-utils/logger";
5
+
6
+ const { log_verbose } = createLogger({
7
+ subsystem: "General",
8
+ category: "FocusableGroup",
9
+ });
10
+
11
+ type FocusableGroupNativeEvent = {
12
+ nativeEvent: {
13
+ focusHeading: FocusManager.Direction;
14
+ groupId: string;
15
+ isActive: boolean;
16
+ isFocusDisabled: boolean;
17
+ isFocusingByUser: boolean;
18
+ itemId: string;
19
+ target: number;
20
+ };
21
+ };
6
22
 
7
23
  type Props = {
8
24
  id: string;
9
25
  children: (arg1: boolean) => React.ComponentType<any>;
10
- onWillUpdateFocus: (nativeEvent: any) => void;
11
- onDidUpdateFocus: (nativeEvent: any) => void;
12
26
  isFocusDisabled: boolean;
13
- initialItemId: string;
14
- resetFocusToInitialValue: boolean;
27
+ isWithMemory: boolean;
15
28
  focusGroupRef: React.Component;
16
29
  shouldUsePreferredFocus: boolean;
17
30
  groupId: string;
@@ -21,86 +34,26 @@ type Props = {
21
34
  };
22
35
 
23
36
  export class FocusableGroup extends BaseFocusable<Props> {
24
- focusableGroupNativeRef: React.Component | null;
25
- constructor(props) {
26
- super(props);
27
- this.focusableGroupNativeRef = null;
28
-
29
- this.state = {
30
- isActive: false,
31
- };
32
-
33
- this.onWillUpdateFocus = this.onWillUpdateFocus.bind(this);
34
- this.onDidUpdateFocus = this.onDidUpdateFocus.bind(this);
35
- this.isGroup = true;
36
-
37
- this.shouldUsePreferredFocus = this.shouldUsePreferredFocus.bind(this);
38
- this.measureView = this.measureView.bind(this);
39
- }
40
-
41
- connectedScreenId() {
42
- const {
43
- screenData: { screenId, parentScreenId },
44
- } = this.props;
45
-
46
- if (screenId) {
47
- return null;
48
- }
49
-
50
- return parentScreenId ? `${parentScreenId}-${screenId}` : screenId;
51
- }
52
-
53
- /**
54
- * tells whether the group should give focus to a preferred item when it gains focus from another
55
- * group
56
- * @returns {boolean}
57
- */
58
- shouldUsePreferredFocus() {
59
- return this.props.shouldUsePreferredFocus || false;
60
- }
61
-
62
- /**
63
- * indicates whether the underlying component should claim preferred focus
64
- * when navigating into the group of this item
65
- * @returns {boolean}
66
- */
67
- isPreferredFocus() {
68
- return this.props.preferredFocus || false;
69
- }
70
-
71
- onWillUpdateFocus({ nativeEvent }) {
72
- const { isActive } = nativeEvent;
73
- this.setState({ isActive });
74
- const { onWillUpdateFocus = noop } = this.props;
75
- onWillUpdateFocus(nativeEvent);
76
- }
77
-
78
- onDidUpdateFocus({ nativeEvent }) {
79
- const { onDidUpdateFocus = noop } = this.props;
80
- onDidUpdateFocus(nativeEvent);
81
- }
82
-
83
- setFocusDisabled(isFocusDisabled) {
84
- if (this.ref) {
85
- this.ref.current.setNativeProps({
86
- isFocusDisabled,
87
- });
88
- }
89
- }
90
-
91
37
  render() {
92
38
  const {
93
39
  children,
94
40
  id,
95
41
  isFocusDisabled,
96
- initialItemId,
97
- resetFocusToInitialValue,
98
- style,
42
+ isWithMemory,
43
+ style = {},
99
44
  groupId,
100
45
  ...otherProps
101
46
  } = this.props;
102
47
 
103
- const focusableStyles = style || {};
48
+ const onGroupFocus = ({ nativeEvent }: FocusableGroupNativeEvent) => {
49
+ log_verbose("FOCUSABLE_GROUP: onGroupFocus", { nativeEvent });
50
+ this.onFocus(this.ref, nativeEvent.focusHeading);
51
+ };
52
+
53
+ const onGroupBlur = ({ nativeEvent }: FocusableGroupNativeEvent) => {
54
+ log_verbose("FOCUSABLE_GROUP: onGroupBlur", { nativeEvent });
55
+ this.onBlur(this.ref, nativeEvent.focusHeading);
56
+ };
104
57
 
105
58
  return (
106
59
  <FocusableGroupNative
@@ -108,16 +61,11 @@ export class FocusableGroup extends BaseFocusable<Props> {
108
61
  itemId={id}
109
62
  ref={this.ref}
110
63
  isFocusDisabled={isFocusDisabled}
111
- initialItemId={initialItemId}
112
- resetFocusToInitialValue={resetFocusToInitialValue}
113
- onLayout={this.measureView}
114
- onViewFocus={this.onFocus}
115
- onViewPress={this.onPress}
116
- onViewBlur={this.onBlur}
117
- style={focusableStyles}
64
+ isWithMemory={isWithMemory}
65
+ onGroupFocus={onGroupFocus}
66
+ onGroupBlur={onGroupBlur}
67
+ style={style}
118
68
  {...otherProps}
119
- onWillUpdateFocus={this.onWillUpdateFocus}
120
- onDidUpdateFocus={this.onDidUpdateFocus}
121
69
  >
122
70
  {children}
123
71
  </FocusableGroupNative>
@@ -16,12 +16,9 @@ type Props = {
16
16
  prioritiseFocusOn?: number;
17
17
  groupId?: string;
18
18
  hasTVPreferredFocus?: boolean;
19
- resetFocusToInitialValue?: boolean;
20
19
  onFocus?: () => void;
21
20
  onBlur?: () => void;
22
- onWillUpdateFocus?: (event?: any) => void;
23
21
  willReceiveFocus?: (event?: any) => void;
24
- onDidUpdateFocus?: (event?: any) => void;
25
22
  hasLostFocus?: any;
26
23
  nextFocusUp?: any;
27
24
  nextFocusDown?: any;
@@ -15,6 +15,7 @@ import { noop } from "@applicaster/zapp-react-native-utils/functionUtils";
15
15
 
16
16
  import { useParentFocus, useCheckItemIdsForUnique } from "./hooks";
17
17
  import { FocusableListItemWrapper } from "./FocusableListItemWrapper";
18
+ import { FocusableScrollView } from "../FocusableScrollView";
18
19
 
19
20
  const mapIndexed = R.addIndex(R.map);
20
21
 
@@ -54,6 +55,7 @@ export type Props<ItemT> = FlatListProps<ItemT> & {
54
55
  disableNextFocusUp?: boolean;
55
56
  disableNextFocusLeft?: boolean;
56
57
  disableNextFocusRight?: boolean;
58
+ useScrollView?: boolean;
57
59
  } & ParentFocus;
58
60
 
59
61
  function FocusableListComponent<ItemT>(props: Props<ItemT>, ref) {
@@ -87,8 +89,8 @@ function FocusableListComponent<ItemT>(props: Props<ItemT>, ref) {
87
89
  initialFocusDirection = "down",
88
90
  data = [],
89
91
  // eslint-disable-next-line unused-imports/no-unused-vars
90
- onAllComponentsLoaded, // TODO: re-implement it
91
92
  omitPropsPropagation = [],
93
+ useScrollView = false,
92
94
  } = props;
93
95
 
94
96
  useCheckItemIdsForUnique({ componentId: props.id, items: data });
@@ -274,6 +276,7 @@ function FocusableListComponent<ItemT>(props: Props<ItemT>, ref) {
274
276
  "initialFocusDirection",
275
277
  "withStateMemory",
276
278
  "useSequentialLoading",
279
+ "useScrollView",
277
280
  ...omitPropsPropagation,
278
281
  ],
279
282
  R.__
@@ -296,15 +299,28 @@ function FocusableListComponent<ItemT>(props: Props<ItemT>, ref) {
296
299
  return (
297
300
  // @ts-ignore
298
301
  <ChildrenFocusDeactivatorView flex={1}>
299
- <FlatList
300
- focusable={false}
301
- scrollEnabled={false}
302
- ref={ref}
303
- {...getFlatListProps(props)}
304
- renderItem={renderItem}
305
- onEndReached={onEndReached}
306
- initialNumToRender={initialNumToRender}
307
- />
302
+ {useScrollView ? (
303
+ <FocusableScrollView
304
+ ref={ref}
305
+ {...getFlatListProps(props)}
306
+ onEndReached={onEndReached}
307
+ initialNumToRender={initialNumToRender}
308
+ renderItem={renderItem}
309
+ focused={focused}
310
+ data={data}
311
+ />
312
+ ) : (
313
+ <FlatList
314
+ testID="focusable-list-flat-list"
315
+ focusable={false}
316
+ scrollEnabled={false}
317
+ ref={ref}
318
+ {...getFlatListProps(props)}
319
+ renderItem={renderItem}
320
+ onEndReached={onEndReached}
321
+ initialNumToRender={initialNumToRender}
322
+ />
323
+ )}
308
324
  </ChildrenFocusDeactivatorView>
309
325
  );
310
326
  }
@@ -11,6 +11,13 @@ import {
11
11
  useInitialFocus,
12
12
  } from "@applicaster/zapp-react-native-utils/focusManager";
13
13
 
14
+ export type FocusableScrollViewRenderItem = (info: {
15
+ item: ZappUIComponent;
16
+ index: number;
17
+ focused: boolean;
18
+ parentFocus: ParentFocus;
19
+ }) => React.ReactElement;
20
+
14
21
  export type Props = ScrollViewProps & {
15
22
  id?: number | string;
16
23
  horizontal?: boolean;
@@ -32,17 +39,27 @@ export type Props = ScrollViewProps & {
32
39
  initialFocusDirection?: FocusManager.Android.FocusNavigationDirections;
33
40
  onAllComponentsLoaded?: () => void;
34
41
  omitPropsPropagation?: Array<keyof FlatListProps<any>>;
35
- renderItem: (info: {
36
- item: ZappUIComponent;
37
- index: number;
38
- focused: boolean;
39
- parentFocus: ParentFocus;
40
- }) => React.ReactElement;
42
+ renderItem: FocusableScrollViewRenderItem;
41
43
  } & ParentFocus;
42
44
 
43
45
  type State = boolean[];
44
46
  type Action = { index?: number; isFocusable: boolean; type?: string };
45
47
 
48
+ const unwrapArray = (maybeArray) =>
49
+ Array.isArray(maybeArray) ? maybeArray[0] : maybeArray;
50
+
51
+ const getEntry = <T extends unknown>(data: T | T[], index: unknown): T => {
52
+ let entry;
53
+
54
+ if (R.isNil(index)) {
55
+ entry = unwrapArray(data);
56
+ } else if (typeof index === "number") {
57
+ entry = unwrapArray(data[index]);
58
+ }
59
+
60
+ return entry;
61
+ };
62
+
46
63
  const focusableStateReducer = (
47
64
  state: State,
48
65
  { index = null, isFocusable, type = null }: Action
@@ -73,7 +90,7 @@ const extendScrollViewRef = (_ref, childCompsMeasurementsMap) => {
73
90
  };
74
91
 
75
92
  _ref.scrollToIndex = (params) => {
76
- const { index, viewOffset } = params;
93
+ const { index, viewOffset = 0 } = params;
77
94
 
78
95
  const itemByIndex = R.find(R.propEq("index", index))(
79
96
  R.values(childCompsMeasurementsMap)
@@ -129,8 +146,11 @@ function FocusableScrollViewComponent(props: Props, ref) {
129
146
  );
130
147
 
131
148
  const getFocusableEntryId = React.useCallback(
132
- (_entry: ZappEntry, index?: number) => {
133
- const entry = R.isNil(index) ? _entry : data[index];
149
+ (_entry: ZappEntry | null, index?: number) => {
150
+ const entry: { id?: string } = getEntry(
151
+ R.isNil(index) ? _entry : data,
152
+ index
153
+ );
134
154
 
135
155
  return entry ? `${props.id}--${entry?.id}` : undefined;
136
156
  },
@@ -273,16 +293,25 @@ function FocusableScrollViewComponent(props: Props, ref) {
273
293
  const renderItem = React.useCallback(
274
294
  (item, index) => {
275
295
  const renderArgs = { item, index };
276
- const id = `${props.id}--${renderArgs?.item?.id}`;
277
- const nextFocus = getNextFocus(renderArgs?.index);
296
+
297
+ const id = getFocusableEntryId(
298
+ Array.isArray(item) ? item[0] : item,
299
+ index
300
+ );
301
+
302
+ const nextFocus = getNextFocus(index);
278
303
 
279
304
  const onItemLayout = (event) => {
280
- childCompsMeasurementsMap.current[item.id] = {
305
+ childCompsMeasurementsMap.current[
306
+ Array.isArray(item) ? index : item.id
307
+ ] = {
281
308
  index,
282
309
  layout: event.nativeEvent.layout,
283
310
  };
284
311
  };
285
312
 
313
+ const onSetIsFocusable = setIsFocusable(renderArgs.index);
314
+
286
315
  return (
287
316
  <View key={id} onLayout={onItemLayout}>
288
317
  <Focusable
@@ -305,6 +334,7 @@ function FocusableScrollViewComponent(props: Props, ref) {
305
334
  id={id}
306
335
  disableFocus={shouldDisableFocus(renderArgs?.index)}
307
336
  blockFocus={!isRendered(renderArgs?.index)}
337
+ onSetIsFocusable={onSetIsFocusable}
308
338
  {...focusableItemProps}
309
339
  >
310
340
  {(focused, parentFocus, parentRef) => (
@@ -319,7 +349,7 @@ function FocusableScrollViewComponent(props: Props, ref) {
319
349
  isReadyToRender={isReadyToRender}
320
350
  onLoadFinished={onLoadFinished(renderArgs.index)}
321
351
  onLoadFailed={onLoadFailed(renderArgs.index)}
322
- setIsFocusable={setIsFocusable(renderArgs.index)}
352
+ setIsFocusable={onSetIsFocusable}
323
353
  />
324
354
  )}
325
355
  </Focusable>
@@ -1,3 +1,4 @@
1
+ import * as React from "react";
1
2
  import { renderHook } from "@testing-library/react-hooks";
2
3
 
3
4
  import {
@@ -9,6 +10,51 @@ import {
9
10
  import * as redux from "react-redux";
10
11
  import * as layoutPresets from "@applicaster/zapp-react-native-redux/hooks/useLayoutPresets";
11
12
  import * as pipesFeeds from "@applicaster/zapp-react-native-redux/hooks/useZappPipesFeeds";
13
+ import { NavigationContext } from "@applicaster/zapp-react-native-ui-components/Contexts/NavigationContext";
14
+ import { PathnameContext } from "@applicaster/zapp-react-native-ui-components/Contexts/PathnameContext";
15
+
16
+ import { Provider } from "react-redux";
17
+ import configureStore from "redux-mock-store";
18
+
19
+ jest.mock(
20
+ "@applicaster/zapp-react-native-utils/reactHooks/navigation/useRoute",
21
+ () => ({
22
+ useRoute: jest.fn().mockReturnValue({
23
+ pathname: "/home",
24
+ }),
25
+ })
26
+ );
27
+
28
+ const homeStack = {
29
+ route: "/home",
30
+ state: {
31
+ screen: { id: "123" },
32
+ entry: { id: "abc" },
33
+ },
34
+ };
35
+
36
+ const mainStackNavigator = {
37
+ getStackForPathname: jest.fn().mockReturnValue(homeStack),
38
+ modalState: {
39
+ screen: {
40
+ id: "modal-1",
41
+ },
42
+ },
43
+ };
44
+
45
+ const store = configureStore()({});
46
+
47
+ const wrapper = ({ children }) => (
48
+ <Provider store={store}>
49
+ <NavigationContext.Provider
50
+ value={{ ...mainStackNavigator, currentRoute: homeStack.route }}
51
+ >
52
+ <PathnameContext.Provider value={homeStack.route}>
53
+ {children}
54
+ </PathnameContext.Provider>
55
+ </NavigationContext.Provider>
56
+ </Provider>
57
+ );
12
58
 
13
59
  describe("getTransformedPreset should return the passed components if smartComponents is empty", () => {
14
60
  describe("getTransformedPreset function", () => {
@@ -94,9 +140,13 @@ describe("getTransformedPreset should return the passed components if smartCompo
94
140
  },
95
141
  };
96
142
 
143
+ const mockUrlsMap = {
144
+ [mockSmartComp.id]: mockSmartComp.data.source,
145
+ };
146
+
97
147
  it("should return the component itself if its component_type is not SMART_COMPONENT_TYPE", () => {
98
148
  expect(
99
- enrichComponent(mockComp, 0, mockFeeds, mockLayoutPresets)
149
+ enrichComponent(mockComp, 0, mockFeeds, mockLayoutPresets, mockUrlsMap)
100
150
  ).toEqual([mockComp]);
101
151
  });
102
152
 
@@ -106,8 +156,18 @@ describe("getTransformedPreset should return the passed components if smartCompo
106
156
  data: { source: "missing_source" },
107
157
  };
108
158
 
159
+ const missing_source_urls_map = {
160
+ [missing_source_comp.id]: missing_source_comp.data.source,
161
+ };
162
+
109
163
  expect(
110
- enrichComponent(missing_source_comp, 0, mockFeeds, mockLayoutPresets)
164
+ enrichComponent(
165
+ missing_source_comp,
166
+ 0,
167
+ mockFeeds,
168
+ mockLayoutPresets,
169
+ missing_source_urls_map
170
+ )
111
171
  ).toEqual(null);
112
172
  });
113
173
 
@@ -116,7 +176,8 @@ describe("getTransformedPreset should return the passed components if smartCompo
116
176
  mockSmartComp,
117
177
  0,
118
178
  mockFeeds,
119
- mockLayoutPresets
179
+ mockLayoutPresets,
180
+ mockUrlsMap
120
181
  );
121
182
 
122
183
  expect(Array.isArray(result)).toBe(true);
@@ -262,7 +323,9 @@ describe("getTransformedPreset should return the passed components if smartCompo
262
323
 
263
324
  mockUseLayoutPresets.mockReturnValue({});
264
325
 
265
- const { result } = renderHook(() => useCurationAPI(mockComponents));
326
+ const { result } = renderHook(() => useCurationAPI(mockComponents), {
327
+ wrapper,
328
+ });
266
329
 
267
330
  // if there are no smart components, it should return the original array
268
331
  expect(result.current).toEqual(mockComponents);
@@ -313,7 +376,9 @@ describe("getTransformedPreset should return the passed components if smartCompo
313
376
 
314
377
  mockUseLayoutPresets.mockReturnValue(mockLayoutPresets);
315
378
 
316
- const { result } = renderHook(() => useCurationAPI(mockComponents));
379
+ const { result } = renderHook(() => useCurationAPI(mockComponents), {
380
+ wrapper,
381
+ });
317
382
 
318
383
  expect(result.current).toEqual(mockTransformedComponents);
319
384
  });
@@ -383,7 +448,9 @@ describe("getTransformedPreset should return the passed components if smartCompo
383
448
 
384
449
  mockUseLayoutPresets.mockReturnValue(mockLayoutPresets);
385
450
 
386
- const { result } = renderHook(() => useCurationAPI(mockComponents));
451
+ const { result } = renderHook(() => useCurationAPI(mockComponents), {
452
+ wrapper,
453
+ });
387
454
 
388
455
  expect(result.current).toEqual(mockTransformedComponents);
389
456
  });
@@ -434,7 +501,9 @@ describe("getTransformedPreset should return the passed components if smartCompo
434
501
  const mockUseLayoutPresets = jest.spyOn(layoutPresets, "useLayoutPresets");
435
502
  mockUseLayoutPresets.mockReturnValue(mockLayoutPresets);
436
503
 
437
- const { result } = renderHook(() => useCurationAPI(mockComponents));
504
+ const { result } = renderHook(() => useCurationAPI(mockComponents), {
505
+ wrapper,
506
+ });
438
507
 
439
508
  expect(result.current).toEqual(mockTransformedComponents);
440
509
  });
@@ -9,6 +9,18 @@ import { loadPipesData } from "@applicaster/zapp-react-native-redux/ZappPipes";
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";
13
+ import {
14
+ ZappPipesEntryContext,
15
+ ZappPipesScreenContext,
16
+ ZappPipesSearchContext,
17
+ } from "@applicaster/zapp-react-native-ui-components/Contexts";
18
+
19
+ import {
20
+ getInflatedDataSourceUrl,
21
+ getSearchContext,
22
+ } from "@applicaster/zapp-react-native-utils/reactHooks/feed/useInflatedUrl";
23
+
12
24
  import { produce } from "immer";
13
25
  // types reference
14
26
 
@@ -20,6 +32,7 @@ type LayoutPresets = PresetsMapping["presets_mappings"];
20
32
 
21
33
  const SMART_COMPONENT_TYPE = "quick-brick-smart-component";
22
34
  const SOURCE_PATH = ["data", "source"];
35
+ const MAPPING_PATH = ["data", "mapping"];
23
36
 
24
37
  const isSmartComponent = (component) =>
25
38
  component.component_type === SMART_COMPONENT_TYPE;
@@ -58,13 +71,14 @@ export const enrichComponent = (
58
71
  comp: ZappUIComponent,
59
72
  index: number,
60
73
  feeds: Feeds,
61
- layoutPresets: LayoutPresets
74
+ layoutPresets: LayoutPresets,
75
+ urlsMap: { [key: string]: string }
62
76
  ): ZappUIComponent[] | null => {
63
77
  if (!isSmartComponent(comp)) {
64
78
  return [comp];
65
79
  }
66
80
 
67
- const presets = prop<string[]>(path(SOURCE_PATH, comp), feeds);
81
+ const presets = prop<string[]>(urlsMap[comp.id], feeds);
68
82
 
69
83
  if (presets && presets.data && presets.data.entry) {
70
84
  return presets.data.entry
@@ -113,11 +127,35 @@ export const useCurationAPI = (
113
127
  [components]
114
128
  );
115
129
 
116
- const urls = useMemo<string[]>(
117
- () =>
118
- smartComponents?.map?.((component) => path(SOURCE_PATH, component)) ?? [],
119
- [smartComponents]
120
- );
130
+ const { pathname } = useRoute();
131
+ const [entryContext] = ZappPipesEntryContext.useZappPipesContext(pathname);
132
+ const [searchContext] = ZappPipesSearchContext.useZappPipesContext();
133
+ const [screenContext] = ZappPipesScreenContext.useZappPipesContext();
134
+
135
+ const urlsMap = useMemo<{ [key: string]: string }>(() => {
136
+ const map = {};
137
+
138
+ smartComponents?.forEach?.((component) => {
139
+ const url = path(SOURCE_PATH, component);
140
+ const mapping = path(MAPPING_PATH, component);
141
+
142
+ map[component.id] = mapping
143
+ ? getInflatedDataSourceUrl({
144
+ source: url,
145
+ contexts: {
146
+ entry: entryContext,
147
+ screen: screenContext,
148
+ search: getSearchContext(searchContext, mapping),
149
+ },
150
+ mapping,
151
+ })
152
+ : url;
153
+ });
154
+
155
+ return map;
156
+ }, [smartComponents, entryContext, screenContext, searchContext]);
157
+
158
+ const urls = useMemo<string[]>(() => Object.values(urlsMap), [urlsMap]);
121
159
 
122
160
  useEffect(() => {
123
161
  urls.forEach((url, index) => {
@@ -138,11 +176,17 @@ export const useCurationAPI = (
138
176
  if (!components) return [];
139
177
 
140
178
  return components.reduce((acc, comp, index) => {
141
- const enrichedComp = enrichComponent(comp, index, feeds, layoutPresets);
179
+ const enrichedComp = enrichComponent(
180
+ comp,
181
+ index,
182
+ feeds,
183
+ layoutPresets,
184
+ urlsMap
185
+ );
142
186
 
143
187
  return enrichedComp ? [...acc, ...enrichedComp] : acc;
144
188
  }, [] as Array<ZappUIComponent>);
145
- }, [components, feeds, layoutPresets]);
189
+ }, [components, feeds, layoutPresets, urlsMap]);
146
190
 
147
191
  return getFinalComponents(
148
192
  enrichedComponents,