@applicaster/zapp-react-native-ui-components 15.0.0-alpha.4515904047 → 15.0.0-alpha.4586051410

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 (236) 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 +105 -20
  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/GeneralContentScreen.tsx +39 -28
  12. package/Components/GeneralContentScreen/__tests__/GeneralContentScreen.test.tsx +104 -0
  13. package/Components/GeneralContentScreen/utils/__tests__/getScreenDataSource.test.ts +19 -0
  14. package/Components/GeneralContentScreen/utils/__tests__/useCurationAPI.test.js +1 -1
  15. package/Components/GeneralContentScreen/utils/getScreenDataSource.ts +9 -0
  16. package/Components/GeneralContentScreen/utils/useCurationAPI.ts +31 -17
  17. package/Components/HandlePlayable/HandlePlayable.tsx +33 -94
  18. package/Components/HandlePlayable/const.ts +3 -0
  19. package/Components/HandlePlayable/utils.ts +105 -0
  20. package/Components/HookRenderer/HookRenderer.tsx +40 -10
  21. package/Components/HookRenderer/__tests__/HookRenderer.test.tsx +60 -0
  22. package/Components/Layout/TV/LayoutBackground.tsx +5 -2
  23. package/Components/Layout/TV/NavBarContainer.tsx +1 -10
  24. package/Components/Layout/TV/ScreenContainer.tsx +2 -6
  25. package/Components/Layout/TV/__tests__/__snapshots__/NavBarContainer.test.tsx.snap +7 -12
  26. package/Components/Layout/TV/__tests__/__snapshots__/ScreenContainer.test.tsx.snap +7 -12
  27. package/Components/Layout/TV/__tests__/__snapshots__/index.test.tsx.snap +5 -0
  28. package/Components/Layout/TV/index.tsx +3 -4
  29. package/Components/Layout/TV/index.web.tsx +3 -4
  30. package/Components/LinkHandler/LinkHandler.tsx +2 -2
  31. package/Components/MasterCell/CONFIG_BUILDER_TO_REACT_COMPONENT.md +144 -0
  32. package/Components/MasterCell/DefaultComponents/ActionButtonsCore/__tests__/model.test.ts +80 -0
  33. package/Components/MasterCell/DefaultComponents/ActionButtonsCore/__tests__/placement.test.ts +187 -0
  34. package/Components/MasterCell/DefaultComponents/ActionButtonsCore/__tests__/selectors.test.ts +45 -0
  35. package/Components/MasterCell/DefaultComponents/ActionButtonsCore/__tests__/style.test.ts +49 -0
  36. package/Components/MasterCell/DefaultComponents/ActionButtonsCore/components/ActionButtonController.tsx +165 -0
  37. package/Components/MasterCell/DefaultComponents/ActionButtonsCore/components/__tests__/ActionButtonController.test.tsx +405 -0
  38. package/Components/MasterCell/DefaultComponents/ActionButtonsCore/components/index.ts +1 -0
  39. package/Components/MasterCell/DefaultComponents/ActionButtonsCore/model.ts +47 -0
  40. package/Components/MasterCell/DefaultComponents/ActionButtonsCore/placement.ts +170 -0
  41. package/Components/MasterCell/DefaultComponents/ActionButtonsCore/selectors.ts +26 -0
  42. package/Components/MasterCell/DefaultComponents/ActionButtonsCore/style.ts +29 -0
  43. package/Components/MasterCell/DefaultComponents/ActionButtonsCore/types.ts +37 -0
  44. package/Components/MasterCell/DefaultComponents/BorderContainerView/__tests__/index.test.tsx +16 -1
  45. package/Components/MasterCell/DefaultComponents/BorderContainerView/index.tsx +30 -2
  46. package/Components/MasterCell/DefaultComponents/Button.tsx +0 -15
  47. package/Components/MasterCell/DefaultComponents/ButtonContainerView/components/HorizontalSeparator.tsx +8 -0
  48. package/Components/MasterCell/DefaultComponents/ButtonContainerView/index.tsx +15 -0
  49. package/Components/MasterCell/DefaultComponents/ButtonContainerView/index.tv.android.tsx +58 -0
  50. package/Components/MasterCell/DefaultComponents/{tv/ButtonContainerView/index.tsx → ButtonContainerView/index.tv.tsx} +3 -11
  51. package/Components/MasterCell/DefaultComponents/ButtonContainerView/index.web.ts +1 -0
  52. package/Components/MasterCell/DefaultComponents/ButtonContainerView/types.ts +40 -0
  53. package/Components/MasterCell/DefaultComponents/DataProvider/index.tsx +163 -0
  54. package/Components/MasterCell/DefaultComponents/FocusableView/index.android.tsx +2 -23
  55. package/Components/MasterCell/DefaultComponents/FocusableView/index.tsx +4 -22
  56. package/Components/MasterCell/DefaultComponents/Image/Image.android.tsx +5 -1
  57. package/Components/MasterCell/DefaultComponents/Image/Image.ios.tsx +11 -3
  58. package/Components/MasterCell/DefaultComponents/Image/Image.web.tsx +9 -1
  59. package/Components/MasterCell/DefaultComponents/Image/hooks/useImage.ts +15 -14
  60. package/Components/MasterCell/DefaultComponents/LiveImage/__tests__/prepareEntry.test.ts +352 -0
  61. package/Components/MasterCell/DefaultComponents/LiveImage/executePreloadHooks.ts +136 -0
  62. package/Components/MasterCell/DefaultComponents/LiveImage/index.tsx +43 -22
  63. package/Components/MasterCell/DefaultComponents/PressableView.tsx +34 -0
  64. package/Components/MasterCell/DefaultComponents/SecondaryImage/Image.tsx +40 -39
  65. package/Components/MasterCell/DefaultComponents/SecondaryImage/__tests__/Image.test.tsx +95 -0
  66. package/Components/MasterCell/DefaultComponents/SecondaryImage/__tests__/__snapshots__/Image.test.tsx.snap +86 -0
  67. package/Components/MasterCell/DefaultComponents/SecondaryImage/__tests__/index.test.ts +141 -0
  68. package/Components/MasterCell/DefaultComponents/SecondaryImage/hooks/__tests__/useGetImageDimensions.test.ts +7 -6
  69. package/Components/MasterCell/DefaultComponents/SecondaryImage/index.ts +1 -1
  70. package/Components/MasterCell/DefaultComponents/Text/hooks/useText.ts +11 -0
  71. package/Components/MasterCell/DefaultComponents/Text/index.tsx +10 -14
  72. package/Components/MasterCell/DefaultComponents/__tests__/DataProvider.test.tsx +141 -0
  73. package/Components/MasterCell/DefaultComponents/index.ts +9 -3
  74. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/ActionButton.tsx +135 -0
  75. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/Asset.ts +33 -0
  76. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/AssetComponent.tsx +22 -0
  77. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/Button.ts +125 -0
  78. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/Spacer.ts +16 -0
  79. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/TextLabel.ts +67 -0
  80. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/TextLabelsContainer.ts +37 -0
  81. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/__tests__/PressableView.test.tsx +393 -0
  82. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/__tests__/builders.test.ts +141 -0
  83. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/__tests__/index.test.ts +343 -0
  84. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/helpers.ts +105 -0
  85. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/index.ts +122 -0
  86. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/utils/__tests__/insertButtons.test.ts +118 -0
  87. package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/utils/index.ts +238 -0
  88. package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/Asset.ts +4 -18
  89. package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/Button.ts +24 -73
  90. package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/TextLabelsContainer.ts +37 -18
  91. package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/TvActionButton.tsx +27 -0
  92. package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/__tests__/index.test.ts +89 -0
  93. package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/__tests__/renderedTree.test.tsx +231 -0
  94. package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/index.ts +47 -48
  95. package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/utils/__tests__/getPluginIdentifier.test.ts +115 -29
  96. package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/utils/index.ts +101 -144
  97. package/Components/MasterCell/MappingFunctions/index.js +3 -2
  98. package/Components/MasterCell/README.md +4 -0
  99. package/Components/MasterCell/__tests__/__snapshots__/dataAdapter.test.js.snap +24 -0
  100. package/Components/MasterCell/__tests__/configInflater.test.js +1 -0
  101. package/Components/MasterCell/__tests__/elementMapper.test.js +46 -0
  102. package/Components/MasterCell/dataAdapter.ts +4 -1
  103. package/Components/MasterCell/elementMapper.tsx +52 -7
  104. package/Components/MasterCell/hoc/__tests__/withAsyncRender.test.tsx +219 -0
  105. package/Components/MasterCell/hoc/withAsyncRender.tsx +9 -7
  106. package/Components/MasterCell/index.tsx +2 -0
  107. package/Components/MasterCell/utils/__tests__/cloneChildrenWithIds.test.tsx +43 -0
  108. package/Components/MasterCell/utils/__tests__/resolveColor.test.js +82 -3
  109. package/Components/MasterCell/utils/__tests__/useFilterChildren.test.tsx +80 -0
  110. package/Components/MasterCell/utils/index.ts +146 -46
  111. package/Components/MeasurmentsPortal/MeasurementsPortal.tsx +102 -87
  112. package/Components/MeasurmentsPortal/__tests__/MeasurementsPortal.test.tsx +355 -0
  113. package/Components/Navigator/StackNavigator.tsx +6 -0
  114. package/Components/OfflineHandler/NotificationView/NotificationView.lg.tsx +17 -9
  115. package/Components/OfflineHandler/NotificationView/NotificationView.samsung.tsx +16 -8
  116. package/Components/OfflineHandler/NotificationView/NotificationView.tsx +2 -2
  117. package/Components/OfflineHandler/NotificationView/__tests__/index.test.tsx +17 -18
  118. package/Components/OfflineHandler/NotificationView/utils.ts +34 -0
  119. package/Components/OfflineHandler/__tests__/index.test.tsx +27 -18
  120. package/Components/PlayerContainer/PlayerContainer.tsx +44 -65
  121. package/Components/PlayerImageBackground/index.tsx +3 -22
  122. package/Components/PreloaderWrapper/__tests__/index.test.tsx +26 -0
  123. package/Components/PreloaderWrapper/index.tsx +15 -0
  124. package/Components/River/ComponentsMap/ComponentsMap.tsx +18 -16
  125. package/Components/River/ComponentsMap/hooks/__tests__/useLoadingState.test.ts +1 -1
  126. package/Components/River/RefreshControl.tsx +19 -82
  127. package/Components/River/River.tsx +9 -82
  128. package/Components/River/RiverItem.tsx +26 -20
  129. package/Components/River/TV/River.tsx +31 -14
  130. package/Components/River/TV/index.tsx +8 -4
  131. package/Components/River/TV/utils/__tests__/toStringOrEmpty.test.ts +30 -0
  132. package/Components/River/TV/utils/index.ts +4 -0
  133. package/Components/River/TV/withFocusableGroupForContent.tsx +71 -0
  134. package/Components/River/__tests__/__snapshots__/componentsMap.test.js.snap +2 -0
  135. package/Components/River/__tests__/componentsMap.test.js +38 -0
  136. package/Components/River/hooks/__tests__/usePullToRefresh.test.ts +132 -0
  137. package/Components/River/hooks/index.ts +1 -0
  138. package/Components/River/hooks/usePullToRefresh.ts +51 -0
  139. package/Components/Screen/TV/hooks/useInitialFocus.ts +14 -4
  140. package/Components/Screen/TV/index.web.tsx +4 -2
  141. package/Components/Screen/__tests__/Screen.test.tsx +66 -42
  142. package/Components/Screen/__tests__/__snapshots__/Screen.test.tsx.snap +68 -42
  143. package/Components/Screen/hooks.ts +75 -6
  144. package/Components/Screen/index.tsx +31 -9
  145. package/Components/Screen/navigationHandler.ts +49 -24
  146. package/Components/Screen/orientationHandler.ts +10 -13
  147. package/Components/ScreenFeedLoader/ScreenFeedLoader.tsx +46 -0
  148. package/Components/ScreenFeedLoader/__tests__/ScreenFeedLoader.test.tsx +94 -0
  149. package/Components/ScreenFeedLoader/index.ts +1 -0
  150. package/Components/ScreenResolver/__tests__/screenResolver.test.js +24 -0
  151. package/Components/ScreenResolver/hooks/index.ts +3 -0
  152. package/Components/ScreenResolver/hooks/useGetComponent.ts +15 -0
  153. package/Components/ScreenResolver/hooks/useScreenComponentResolver.tsx +90 -0
  154. package/Components/ScreenResolver/index.tsx +17 -107
  155. package/Components/ScreenResolver/utils/__tests__/getScreenTypeProps.test.ts +45 -0
  156. package/Components/ScreenResolver/utils/getScreenTypeProps.ts +43 -0
  157. package/Components/ScreenResolver/utils/index.ts +1 -0
  158. package/Components/ScreenResolver/withDefaultScreenContext.tsx +16 -0
  159. package/Components/ScreenResolverFeedProvider/ScreenResolverFeedProvider.tsx +25 -0
  160. package/Components/ScreenResolverFeedProvider/__tests__/ScreenResolverFeedProvider.test.tsx +44 -0
  161. package/Components/ScreenResolverFeedProvider/index.ts +1 -0
  162. package/Components/ScreenRevealManager/ScreenRevealManager.ts +40 -8
  163. package/Components/ScreenRevealManager/__tests__/ScreenRevealManager.test.ts +86 -69
  164. package/Components/ScreenRevealManager/utils/index.ts +23 -0
  165. package/Components/ScreenRevealManager/withScreenRevealManager.tsx +57 -24
  166. package/Components/Tabs/TV/Tabs.tsx +20 -3
  167. package/Components/Tabs/TabContent.tsx +7 -4
  168. package/Components/TopCutoffOverlay/__tests__/TopCutoffOverlay.test.tsx +201 -0
  169. package/Components/TopCutoffOverlay/hooks/__tests__/useMarginTop.test.ts +130 -0
  170. package/Components/TopCutoffOverlay/hooks/index.ts +1 -0
  171. package/Components/TopCutoffOverlay/hooks/useMarginTop.ts +59 -0
  172. package/Components/TopCutoffOverlay/index.tsx +55 -0
  173. package/Components/Transitioner/Scene.tsx +10 -3
  174. package/Components/Transitioner/index.js +3 -3
  175. package/Components/VideoLive/LiveImageManager.ts +199 -54
  176. package/Components/VideoLive/PlayerLiveImageComponent.tsx +31 -33
  177. package/Components/VideoLive/__tests__/PlayerLiveImageComponent.test.tsx +2 -17
  178. package/Components/VideoLive/__tests__/__snapshots__/PlayerLiveImageComponent.test.tsx.snap +1 -0
  179. package/Components/VideoModal/ModalAnimation/ModalAnimationContext.tsx +118 -171
  180. package/Components/VideoModal/ModalAnimation/index.ts +2 -13
  181. package/Components/VideoModal/ModalAnimation/utils.ts +1 -327
  182. package/Components/VideoModal/PlayerWrapper.tsx +14 -88
  183. package/Components/VideoModal/VideoModal.tsx +1 -5
  184. package/Components/VideoModal/__tests__/PlayerWrapper.test.tsx +1 -0
  185. package/Components/VideoModal/hooks/__tests__/useDelayedPlayerDetails.test.ts +15 -7
  186. package/Components/VideoModal/hooks/useModalSize.ts +10 -5
  187. package/Components/VideoModal/playerWrapperStyle.ts +70 -0
  188. package/Components/VideoModal/playerWrapperUtils.ts +91 -0
  189. package/Components/VideoModal/utils.ts +19 -9
  190. package/Components/Viewport/ViewportAware/__tests__/viewportAware.test.js +0 -2
  191. package/Components/Viewport/ViewportAware/index.tsx +16 -7
  192. package/Components/Viewport/ViewportEvents/__tests__/viewportEvents.test.js +1 -1
  193. package/Components/ZappFrameworkComponents/BarView/BarView.tsx +4 -6
  194. package/Components/ZappFrameworkComponents/BarView/__tests__/BarView.test.tsx +2 -2
  195. package/Components/ZappUIComponent/index.tsx +12 -6
  196. package/Components/default-cell-renderer/viewTrees/mobile/index.ts +0 -3
  197. package/Components/index.js +1 -1
  198. package/Contexts/ScreenContext/__tests__/index.test.tsx +57 -0
  199. package/Contexts/ScreenContext/index.tsx +71 -19
  200. package/Contexts/ScreenTrackedViewPositionsContext/__tests__/index.test.tsx +1 -1
  201. package/Contexts/ZappHookModalContext/index.tsx +37 -61
  202. package/Contexts/ZappPipesContext/ZappPipesContextFactory.tsx +18 -7
  203. package/Contexts/index.ts +0 -2
  204. package/Decorators/Analytics/index.tsx +6 -5
  205. package/Decorators/ConfigurationWrapper/__tests__/__snapshots__/withConfigurationProvider.test.tsx.snap +1 -0
  206. package/Decorators/ConfigurationWrapper/const.ts +1 -0
  207. package/Decorators/RiverFeedLoader/utils/getDatasourceUrl.ts +6 -10
  208. package/Decorators/ZappPipesDataConnector/ResolverSelector.tsx +25 -7
  209. package/Decorators/ZappPipesDataConnector/__tests__/ResolverSelector.test.tsx +212 -5
  210. package/Decorators/ZappPipesDataConnector/__tests__/UrlFeedResolver.test.tsx +39 -21
  211. package/Decorators/ZappPipesDataConnector/__tests__/zappPipesDataConnector.test.js +1 -1
  212. package/Decorators/ZappPipesDataConnector/index.tsx +2 -2
  213. package/Decorators/ZappPipesDataConnector/resolvers/StaticFeedResolver.tsx +1 -1
  214. package/Decorators/ZappPipesDataConnector/resolvers/UrlFeedResolver.tsx +18 -7
  215. package/Helpers/DataSourceHelper/__tests__/itemLimitForData.test.ts +80 -0
  216. package/Helpers/DataSourceHelper/index.ts +19 -0
  217. package/events/index.ts +3 -0
  218. package/events/scrollEndReached.ts +15 -0
  219. package/index.d.ts +7 -0
  220. package/package.json +6 -5
  221. package/Components/MasterCell/DefaultComponents/Text/utils/__tests__/withAdjustedLineHeight.test.ts +0 -46
  222. package/Components/MasterCell/DefaultComponents/Text/utils/index.ts +0 -21
  223. package/Components/MasterCell/DefaultComponents/tv/ButtonContainerView/index.android.tsx +0 -135
  224. package/Components/MasterCell/DefaultComponents/tv/ButtonContainerView/types.ts +0 -25
  225. package/Components/PlayerContainer/ErrorDisplay/ErrorDisplay.tsx +0 -57
  226. package/Components/PlayerContainer/ErrorDisplay/index.ts +0 -9
  227. package/Components/River/TV/withTVEventHandler.tsx +0 -27
  228. package/Components/VideoModal/ModalAnimation/AnimatedPlayerModalWrapper.tsx +0 -60
  229. package/Components/VideoModal/ModalAnimation/AnimatedScrollModal.tsx +0 -417
  230. package/Components/VideoModal/ModalAnimation/AnimatedScrollModal.web.tsx +0 -294
  231. package/Components/VideoModal/ModalAnimation/AnimatedVideoPlayerComponent.tsx +0 -176
  232. package/Components/VideoModal/ModalAnimation/AnimatedVideoPlayerComponent.web.tsx +0 -93
  233. package/Components/VideoModal/ModalAnimation/AnimationComponent.tsx +0 -500
  234. package/Components/VideoModal/ModalAnimation/__tests__/getMoveUpValue.test.ts +0 -108
  235. package/Helpers/DataSourceHelper/index.js +0 -19
  236. /package/Components/HookRenderer/{index.tsx → index.ts} +0 -0
@@ -6,10 +6,6 @@ import { noop } from "@applicaster/zapp-react-native-utils/functionUtils";
6
6
 
7
7
  type AnimatedInterpolatedStyle = any;
8
8
 
9
- // type AnimatedInterpolatedStyle =
10
- // | Animated.AnimatedInterpolation
11
- // | [{ [Key: string]: Animated.AnimatedInterpolation }];
12
-
13
9
  type AnimationConfig = {
14
10
  duration: number;
15
11
  easing: EasingFunction;
@@ -45,32 +41,57 @@ export function AnimatedInOut({
45
41
  children,
46
42
  }: Props) {
47
43
  const [animatedValue] = React.useState(new Animated.Value(visible ? 1 : 0));
48
- const [animating, setAnimating] = React.useState(undefined);
44
+ const animationRef = React.useRef<Animated.CompositeAnimation | null>(null);
45
+ const delayTimerRef = React.useRef<NodeJS.Timeout | null>(null);
49
46
 
50
47
  const previousVisible = usePrevious(toBooleanWithDefaultFalse(visible));
51
48
 
52
- function startAnimation(toValue, config) {
53
- if (animating) {
54
- animating.reset();
55
- }
56
-
57
- const { duration, easing, delay = 0, onAnimationEnd = noop } = config;
49
+ const startAnimation = React.useCallback(
50
+ (toValue: number, config: AnimationConfig) => {
51
+ if (delayTimerRef.current) {
52
+ clearTimeout(delayTimerRef.current);
53
+ delayTimerRef.current = null;
54
+ }
55
+
56
+ if (animationRef.current) {
57
+ animationRef.current.stop();
58
+ animationRef.current = null;
59
+ }
60
+
61
+ const { duration, easing, delay = 0, onAnimationEnd = noop } = config;
62
+
63
+ const runAnimation = () => {
64
+ animationRef.current = Animated.timing(animatedValue, {
65
+ duration,
66
+ toValue,
67
+ easing,
68
+ useNativeDriver: true,
69
+ });
70
+
71
+ animationRef.current.start(({ finished }) => {
72
+ if (finished) {
73
+ animationRef.current = null;
74
+ onAnimationEnd();
75
+ }
76
+ });
77
+ };
78
+
79
+ if (delay > 0) {
80
+ delayTimerRef.current = setTimeout(runAnimation, delay);
81
+ } else {
82
+ runAnimation();
83
+ }
84
+ },
85
+ [animatedValue]
86
+ );
58
87
 
59
- const compositeAnimation = Animated.timing(animatedValue, {
60
- duration,
61
- toValue,
62
- easing,
63
- delay,
64
- useNativeDriver: true,
65
- }).start(() => {
66
- setAnimating(undefined);
67
- onAnimationEnd();
68
- });
88
+ React.useEffect(() => {
89
+ if (previousVisible === undefined) {
90
+ animatedValue.setValue(visible ? 1 : 0);
69
91
 
70
- setAnimating(compositeAnimation);
71
- }
92
+ return;
93
+ }
72
94
 
73
- React.useEffect(() => {
74
95
  if (!previousVisible && visible) {
75
96
  startAnimation(1.0, getAnimation(animationConfig, "in"));
76
97
  }
@@ -78,7 +99,29 @@ export function AnimatedInOut({
78
99
  if (previousVisible && !visible) {
79
100
  startAnimation(0.0, getAnimation(animationConfig, "out"));
80
101
  }
81
- }, [visible, previousVisible]);
102
+ }, [
103
+ visible,
104
+ previousVisible,
105
+ animatedValue,
106
+ startAnimation,
107
+ animationConfig,
108
+ ]);
109
+
110
+ React.useEffect(() => {
111
+ return () => {
112
+ if (delayTimerRef.current) {
113
+ clearTimeout(delayTimerRef.current);
114
+ delayTimerRef.current = null;
115
+ }
116
+
117
+ if (animationRef.current) {
118
+ animationRef.current.stop();
119
+ animationRef.current = null;
120
+ }
121
+
122
+ animatedValue.stopAnimation();
123
+ };
124
+ }, [animatedValue]);
82
125
 
83
126
  const styles = visible
84
127
  ? getAnimation(animationConfig, "in").styles
@@ -86,7 +129,7 @@ export function AnimatedInOut({
86
129
 
87
130
  return (
88
131
  <Animated.View
89
- renderToHardwareTextureAndroid={animating}
132
+ renderToHardwareTextureAndroid={!!animationRef.current}
90
133
  style={[styles(animatedValue), staticStyles]}
91
134
  >
92
135
  {children}
@@ -22,6 +22,7 @@ type Props = {
22
22
  onFocus?: FocusManager.FocusEventCB;
23
23
  onBlur?: FocusManager.FocusEventCB;
24
24
  selected?: boolean;
25
+ skipFocusManagerRegistration?: boolean;
25
26
  };
26
27
 
27
28
  export class BaseFocusable<
@@ -61,10 +62,14 @@ export class BaseFocusable<
61
62
  }
62
63
 
63
64
  componentDidMount() {
64
- const { id } = this.props;
65
+ const { id, skipFocusManagerRegistration } = this.props;
65
66
  const component = this;
66
67
  this.node = this.ref.current;
67
68
 
69
+ if (skipFocusManagerRegistration) {
70
+ return;
71
+ }
72
+
68
73
  focusManager.register({
69
74
  id,
70
75
  component: component,
@@ -118,7 +123,12 @@ export class BaseFocusable<
118
123
 
119
124
  componentWillUnmount() {
120
125
  this._isMounted = false;
121
- const { id } = this.props;
126
+ const { id, skipFocusManagerRegistration } = this.props;
127
+
128
+ if (skipFocusManagerRegistration) {
129
+ return;
130
+ }
131
+
122
132
  focusManager.unregister(id, { group: this.isGroup || false });
123
133
  }
124
134
 
@@ -26,11 +26,15 @@ type Props = {
26
26
  componentAnchorPointY: number;
27
27
  headerOffset?: number;
28
28
  extraAnchorPointYOffset?: number;
29
+ componentPaddingTop?: number;
29
30
  }) => void;
30
31
  offsetUpdater: (arg1: string, arg2: number, arg3: number) => number;
31
32
  componentId: string;
32
33
  component: {
33
34
  id: string;
35
+ styles?: {
36
+ component_padding_top?: number;
37
+ };
34
38
  };
35
39
  selected?: boolean;
36
40
  CellRenderer: React.FunctionComponent<any> & {
@@ -178,6 +182,8 @@ export class CellComponent extends React.Component<Props, State> {
178
182
  componentAnchorPointY,
179
183
  headerOffset,
180
184
  extraAnchorPointYOffset,
185
+ componentPaddingTop:
186
+ this.props?.component?.styles?.component_padding_top,
181
187
  });
182
188
  }
183
189
  }
@@ -208,14 +214,14 @@ export class CellComponent extends React.Component<Props, State> {
208
214
  this.accessibilityManager.readText({
209
215
  text: " ",
210
216
  });
211
- } else {
217
+ } else if (this.state.cellFocused) {
212
218
  this.accessibilityManager.readText({
213
219
  text: `${positionLabel}`,
214
220
  });
215
221
  }
216
222
  }
217
223
 
218
- componentDidUpdate(prevProps: Readonly<Props>) {
224
+ componentDidUpdate(prevProps: Readonly<Props>, prevState: Readonly<State>) {
219
225
  if (prevProps.item !== this.props.item) {
220
226
  this.setState({
221
227
  hasFocusableInside: this.props.CellRenderer.hasFocusableInside?.(
@@ -224,7 +230,12 @@ export class CellComponent extends React.Component<Props, State> {
224
230
  });
225
231
  }
226
232
 
227
- this.handleAccessibilityFocus(this.props.index, this.props.dataLength);
233
+ if (
234
+ prevState.cellFocused !== this.state.cellFocused ||
235
+ this.state.hasFocusableInside
236
+ ) {
237
+ this.handleAccessibilityFocus(this.props.index, this.props.dataLength);
238
+ }
228
239
  }
229
240
 
230
241
  render() {
@@ -2,6 +2,7 @@ import * as React from "react";
2
2
 
3
3
  import { noop } from "@applicaster/zapp-react-native-utils/functionUtils";
4
4
  import { toBooleanWithDefaultFalse } from "@applicaster/zapp-react-native-utils/booleanUtils";
5
+ import { platformSelect } from "@applicaster/zapp-react-native-utils/reactUtils";
5
6
 
6
7
  import { useCellState } from "../MasterCell/utils";
7
8
  import { FocusableGroup } from "../FocusableGroup";
@@ -26,6 +27,13 @@ type Props = {
26
27
 
27
28
  const addPrefix = (id: string) => `focusable-cell-wrapper-${id}`;
28
29
 
30
+ const wrapperStyles = {
31
+ flex: platformSelect({
32
+ tvos: 1,
33
+ default: undefined,
34
+ }),
35
+ };
36
+
29
37
  export function CellWithFocusable(props: Props) {
30
38
  const {
31
39
  index,
@@ -94,6 +102,7 @@ export function CellWithFocusable(props: Props) {
94
102
  onFocus={onGroupFocus}
95
103
  onBlur={onGroupBlur}
96
104
  skipFocusManagerRegistration={skipFocusManagerRegistration}
105
+ style={wrapperStyles}
97
106
  >
98
107
  <CellWrapper style={styles.cellWrapper}>
99
108
  <CellRenderer
@@ -0,0 +1,47 @@
1
+ import * as React from "react";
2
+ import { Focusable } from "@applicaster/zapp-react-native-ui-components/Components/Focusable/FocusableTvOS";
3
+ import { noop } from "@applicaster/zapp-react-native-utils/functionUtils";
4
+
5
+ type Props = {
6
+ id: string;
7
+ groupId: string;
8
+ isParallaxDisabled: boolean;
9
+ applyWrapper: boolean;
10
+ children: (focused: boolean) => React.ReactNode;
11
+ onFocus: (arg1: any, index?: number) => void;
12
+ onBlur: Callback;
13
+ skipFocusManagerRegistration?: boolean;
14
+ };
15
+
16
+ export const FocusableWrapper = ({
17
+ id,
18
+ groupId,
19
+ isParallaxDisabled,
20
+ children,
21
+ applyWrapper,
22
+ onFocus,
23
+ onBlur,
24
+ skipFocusManagerRegistration,
25
+ }: Props) => {
26
+ if (applyWrapper) {
27
+ return (
28
+ <Focusable
29
+ id={id}
30
+ groupId={groupId}
31
+ isParallaxDisabled={isParallaxDisabled}
32
+ onFocus={onFocus}
33
+ onBlur={onBlur}
34
+ willReceiveFocus={noop}
35
+ hasReceivedFocus={noop}
36
+ // @ts-ignore
37
+ offsetUpdater={noop}
38
+ isFocusable
39
+ skipFocusManagerRegistration={skipFocusManagerRegistration}
40
+ >
41
+ {(focused) => children(focused)}
42
+ </Focusable>
43
+ );
44
+ }
45
+
46
+ return <>{children(false)}</>;
47
+ };
@@ -1,6 +1,9 @@
1
1
  import * as React from "react";
2
2
  import * as R from "ramda";
3
3
  import { View, StyleSheet } from "react-native";
4
+ import { first, filter } from "rxjs/operators";
5
+
6
+ import { compose } from "@applicaster/zapp-react-native-utils/utils";
4
7
 
5
8
  import { Focusable } from "@applicaster/zapp-react-native-ui-components/Components/Focusable/FocusableTvOS";
6
9
  import { FocusableCell } from "@applicaster/zapp-react-native-ui-components/Components/FocusableCell";
@@ -9,7 +12,12 @@ import { SCREEN_TYPES } from "@applicaster/zapp-react-native-utils/navigationUti
9
12
  import { focusManager } from "@applicaster/zapp-react-native-utils/appUtils/focusManager";
10
13
  import { sendSelectCellEvent } from "@applicaster/zapp-react-native-utils/analyticsUtils";
11
14
  import { noop } from "@applicaster/zapp-react-native-utils/functionUtils";
15
+ import { toBooleanWithDefaultTrue } from "@applicaster/zapp-react-native-utils/booleanUtils";
12
16
  import { CellWithFocusable } from "./CellWithFocusable";
17
+ import { FocusableWrapper } from "./FocusableWrapper";
18
+
19
+ import { focusableButtonsRegistration$ } from "@applicaster/zapp-react-native-utils/appUtils/focusManagerAux/utils/utils.ios";
20
+ import { toNumberWithDefaultZero } from "@applicaster/zapp-react-native-utils/numberUtils";
13
21
 
14
22
  type Props = {
15
23
  item: ZappEntry;
@@ -30,6 +38,10 @@ type Props = {
30
38
  component: {
31
39
  id: number | string;
32
40
  component_type: string;
41
+ styles?: {
42
+ component_margin_top?: number;
43
+ component_padding_top?: number;
44
+ };
33
45
  };
34
46
  selected: boolean;
35
47
  CellRenderer: React.FunctionComponent<any> & {
@@ -66,6 +78,9 @@ type Props = {
66
78
  shouldUpdate: boolean;
67
79
  behavior: Behavior;
68
80
  componentsMapOffset: number;
81
+ applyFocusableWrapper: boolean;
82
+ hasFocusableInside: boolean;
83
+ skipFocusManagerRegistration?: boolean;
69
84
  };
70
85
 
71
86
  type State = {
@@ -82,7 +97,7 @@ const baseCellStyles = {
82
97
  flex: 1,
83
98
  } as const;
84
99
 
85
- export class TvOSCellComponent extends React.Component<Props, State> {
100
+ class TvOSCell extends React.Component<Props, State> {
86
101
  cell: any;
87
102
  target: any;
88
103
  layout: any;
@@ -180,7 +195,6 @@ export class TvOSCellComponent extends React.Component<Props, State> {
180
195
  groupId,
181
196
  component,
182
197
  index,
183
- componentsMapOffset,
184
198
  } = this.props;
185
199
 
186
200
  this.setScreenLayout(componentAnchorPointY, screenLayout);
@@ -192,14 +206,24 @@ export class TvOSCellComponent extends React.Component<Props, State> {
192
206
  ) {
193
207
  const { headerOffset } = getHeaderOffset();
194
208
 
195
- const extraAnchorPointYOffset =
196
- screenLayout?.extraAnchorPointYOffset || 0;
209
+ const extraAnchorPointYOffset = toNumberWithDefaultZero(
210
+ screenLayout?.extraAnchorPointYOffset
211
+ );
212
+
213
+ const componentMarginTop = toNumberWithDefaultZero(
214
+ component?.styles?.component_margin_top
215
+ );
216
+
217
+ const componentPaddingTop = toNumberWithDefaultZero(
218
+ component?.styles?.component_padding_top
219
+ );
197
220
 
198
221
  const totalOffset =
199
222
  headerOffset +
200
- (componentAnchorPointY || 0) +
201
- extraAnchorPointYOffset -
202
- componentsMapOffset || 0;
223
+ toNumberWithDefaultZero(componentAnchorPointY) +
224
+ extraAnchorPointYOffset +
225
+ componentMarginTop +
226
+ componentPaddingTop;
203
227
 
204
228
  mainOffsetUpdater?.(
205
229
  { tag: this.target },
@@ -239,6 +263,9 @@ export class TvOSCellComponent extends React.Component<Props, State> {
239
263
  groupId,
240
264
  isFocusable,
241
265
  behavior,
266
+ applyFocusableWrapper,
267
+ hasFocusableInside,
268
+ skipFocusManagerRegistration,
242
269
  } = this.props;
243
270
 
244
271
  const { id } = item;
@@ -254,24 +281,35 @@ export class TvOSCellComponent extends React.Component<Props, State> {
254
281
  this.onFocus(arg1, index);
255
282
  };
256
283
 
257
- const hasFocusableInside = CellRenderer.hasFocusableInside?.(item);
258
-
259
284
  if (hasFocusableInside) {
260
285
  return (
261
286
  <View onLayout={this.onLayout}>
262
- <CellWithFocusable
263
- CellRenderer={CellRenderer}
264
- item={item}
287
+ <FocusableWrapper
265
288
  id={focusableId}
266
- groupId={(groupId || component?.id).toString()}
289
+ groupId={String(groupId || component?.id)}
290
+ isParallaxDisabled={this.layout?.width > 1740}
267
291
  onFocus={handleFocus}
268
- index={index}
269
- scrollTo={this.scrollTo}
270
- preferredFocus={preferredFocus}
271
- focused={this.props.focused}
272
- behavior={behavior}
273
- isFocusable={isFocusable}
274
- />
292
+ onBlur={onBlur || this.onBlur}
293
+ applyWrapper={applyFocusableWrapper}
294
+ skipFocusManagerRegistration={skipFocusManagerRegistration}
295
+ >
296
+ {(focused) => (
297
+ <CellWithFocusable
298
+ CellRenderer={CellRenderer}
299
+ item={item}
300
+ id={focusableId}
301
+ groupId={(groupId || component?.id).toString()}
302
+ onFocus={handleFocus}
303
+ index={index}
304
+ scrollTo={this.scrollTo}
305
+ preferredFocus={preferredFocus}
306
+ focused={focused || this.props.focused}
307
+ behavior={behavior}
308
+ isFocusable={isFocusable}
309
+ skipFocusManagerRegistration={skipFocusManagerRegistration}
310
+ />
311
+ )}
312
+ </FocusableWrapper>
275
313
  </View>
276
314
  );
277
315
  }
@@ -291,6 +329,7 @@ export class TvOSCellComponent extends React.Component<Props, State> {
291
329
  offsetUpdater={offsetUpdater}
292
330
  style={baseCellStyles}
293
331
  isFocusable={isFocusable}
332
+ skipFocusManagerRegistration={skipFocusManagerRegistration}
294
333
  >
295
334
  {(focused) => (
296
335
  <FocusableCell
@@ -309,3 +348,49 @@ export class TvOSCellComponent extends React.Component<Props, State> {
309
348
  );
310
349
  }
311
350
  }
351
+
352
+ export function withFocusableWrapperHOC(Component) {
353
+ return function WrappedComponent(props) {
354
+ const [focusableViewIsRendered, setFocusableViewIsRendered] =
355
+ React.useState(false);
356
+
357
+ const { CellRenderer, item, groupId, component } = props;
358
+
359
+ const isFocusable = toBooleanWithDefaultTrue(props?.isFocusable);
360
+
361
+ const focusableGroupId = String(groupId || component?.id);
362
+
363
+ const hasFocusableInside = CellRenderer.hasFocusableInside?.(item);
364
+
365
+ React.useEffect(() => {
366
+ // start waiting any first registration of FocusableButton inside this focusableGroup
367
+ // after it we could get rid of applying focusable-wrapper
368
+ const subscription = focusableButtonsRegistration$(focusableGroupId)
369
+ .pipe(
370
+ filter(() => isFocusable),
371
+ first()
372
+ )
373
+ .subscribe(() => {
374
+ setFocusableViewIsRendered(true);
375
+ });
376
+
377
+ return () => {
378
+ subscription.unsubscribe();
379
+ };
380
+ }, [isFocusable, focusableGroupId]);
381
+
382
+ const applyFocusableWrapper = React.useMemo(() => {
383
+ return isFocusable && hasFocusableInside && !focusableViewIsRendered;
384
+ }, [isFocusable, hasFocusableInside, focusableViewIsRendered]);
385
+
386
+ return (
387
+ <Component
388
+ {...props}
389
+ applyFocusableWrapper={applyFocusableWrapper}
390
+ hasFocusableInside={hasFocusableInside}
391
+ />
392
+ );
393
+ };
394
+ }
395
+
396
+ export const TvOSCellComponent = compose(withFocusableWrapperHOC)(TvOSCell);
@@ -8,6 +8,8 @@ import { withFocusableContext } from "../../Contexts/FocusableGroupContext/withF
8
8
  import { StyleSheet, ViewStyle } from "react-native";
9
9
  import { AccessibilityManager } from "@applicaster/zapp-react-native-utils/appUtils/accessibilityManager";
10
10
 
11
+ import { isSearchInputId } from "@applicaster/zapp-react-native-utils/searchUtils";
12
+
11
13
  type Props = {
12
14
  initialFocus?: boolean;
13
15
  id: string;
@@ -106,7 +108,7 @@ class Focusable extends BaseFocusable<Props> {
106
108
  onMouseEnter() {
107
109
  const { id } = this.props;
108
110
 
109
- if (id !== "search_input_group_id") {
111
+ if (!isSearchInputId(id)) {
110
112
  this.mouse = true;
111
113
  this.props?.handleFocus?.({ mouse: true });
112
114
 
@@ -120,7 +122,7 @@ class Focusable extends BaseFocusable<Props> {
120
122
  onMouseLeave() {
121
123
  const { id } = this.props;
122
124
 
123
- if (id !== "search_input_group_id") {
125
+ if (!isSearchInputId(id)) {
124
126
  this.mouse = false;
125
127
  this.blur(null);
126
128
  }
@@ -10,8 +10,12 @@ import {
10
10
  forceFocusableFocus,
11
11
  } from "@applicaster/zapp-react-native-utils/appUtils/focusManager/index.ios";
12
12
  import { findNodeHandle, ViewStyle } from "react-native";
13
+ import { noop } from "@applicaster/zapp-react-native-utils/functionUtils";
13
14
 
14
- function noop() {}
15
+ import {
16
+ emitFocused,
17
+ emitNativeRegistered,
18
+ } from "@applicaster/zapp-react-native-utils/appUtils/focusManagerAux/utils/utils.ios";
15
19
 
16
20
  type Props = {
17
21
  id: string;
@@ -39,6 +43,7 @@ type Props = {
39
43
  hasReceivedFocus: () => void;
40
44
  offsetUpdater: (arg1: string, arg2: number) => number;
41
45
  style: ViewStyle;
46
+ skipFocusManagerRegistration?: boolean;
42
47
  };
43
48
 
44
49
  export class Focusable extends BaseFocusable<Props> {
@@ -53,6 +58,7 @@ export class Focusable extends BaseFocusable<Props> {
53
58
  this.nextFocusableReactTags = {};
54
59
  this.preferredFocus = this.preferredFocus.bind(this);
55
60
  this.measureView = this.measureView.bind(this);
61
+ this.onRegistered = this.onRegistered.bind(this);
56
62
  }
57
63
 
58
64
  /**
@@ -84,6 +90,9 @@ export class Focusable extends BaseFocusable<Props> {
84
90
  });
85
91
  }
86
92
 
93
+ const id: string = nativeEvent.itemID;
94
+ emitFocused(id);
95
+
87
96
  onFocus(nativeEvent);
88
97
  }
89
98
 
@@ -169,6 +178,13 @@ export class Focusable extends BaseFocusable<Props> {
169
178
  });
170
179
  }
171
180
 
181
+ onRegistered({ nativeEvent }) {
182
+ const groupId = nativeEvent?.groupId;
183
+ const id = nativeEvent?.itemId;
184
+
185
+ emitNativeRegistered({ id, groupId, isGroup: false });
186
+ }
187
+
172
188
  render() {
173
189
  const {
174
190
  children,
@@ -203,6 +219,7 @@ export class Focusable extends BaseFocusable<Props> {
203
219
  focusable={isFocusable}
204
220
  {...this.nextFocusableReactTags}
205
221
  {...otherProps}
222
+ onRegistered={this.onRegistered}
206
223
  >
207
224
  {typeof children === "function" ? children(focused) : children}
208
225
  </FocusableItemNative>
@@ -5,6 +5,7 @@ exports[`FocusableTvOS should render correctly 1`] = `
5
5
  groupId={null}
6
6
  itemId={null}
7
7
  onLayout={[Function]}
8
+ onRegistered={[Function]}
8
9
  onViewBlur={[Function]}
9
10
  onViewFocus={[Function]}
10
11
  onViewPress={[Function]}
@@ -2,6 +2,10 @@ 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
4
  import { createLogger } from "@applicaster/zapp-react-native-utils/logger";
5
+ import { LayoutContext } from "@applicaster/zapp-react-native-tvos-app/Context/LayoutContext";
6
+ import { useRoute } from "@applicaster/zapp-react-native-utils/reactHooks/navigation/useRoute";
7
+ import { isScreenPlayable } from "@applicaster/zapp-react-native-utils/navigationUtils/itemTypes";
8
+ import { emitNativeRegistered } from "@applicaster/zapp-react-native-utils/appUtils/focusManagerAux/utils/utils.ios";
5
9
 
6
10
  const { log_verbose } = createLogger({
7
11
  subsystem: "General",
@@ -33,7 +37,16 @@ type Props = {
33
37
  screenData: { screenId: string; parentScreenId: string };
34
38
  };
35
39
 
36
- export class FocusableGroup extends BaseFocusable<Props> {
40
+ class FocusableGroupComponent extends BaseFocusable<Props> {
41
+ public readonly isGroup: boolean = true;
42
+
43
+ onRegistered = ({ nativeEvent }) => {
44
+ const groupId = nativeEvent?.groupId;
45
+ const id = nativeEvent?.itemId;
46
+
47
+ emitNativeRegistered({ id, groupId, isGroup: true });
48
+ };
49
+
37
50
  render() {
38
51
  const {
39
52
  children,
@@ -66,9 +79,27 @@ export class FocusableGroup extends BaseFocusable<Props> {
66
79
  onGroupBlur={onGroupBlur}
67
80
  style={style}
68
81
  {...otherProps}
82
+ onRegistered={this.onRegistered}
69
83
  >
70
84
  {children}
71
85
  </FocusableGroupNative>
72
86
  );
73
87
  }
74
88
  }
89
+
90
+ export const withFocusDisabled = (Component) => {
91
+ return function WithFocusDisabled(props) {
92
+ // @ts-ignore
93
+ const { screenFocusBlocked } = React.useContext(LayoutContext.ReactContext);
94
+
95
+ const { pathname } = useRoute();
96
+
97
+ const isPlayerPresented = isScreenPlayable(pathname);
98
+
99
+ const blockScreenFocus = isPlayerPresented === false && screenFocusBlocked;
100
+
101
+ return <Component {...props} isFocusDisabled={blockScreenFocus} />;
102
+ };
103
+ };
104
+
105
+ export const FocusableGroup = withFocusDisabled(FocusableGroupComponent);