@applicaster/zapp-react-native-ui-components 14.0.0-rc.9 → 15.0.0-alpha.1001559563

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 (174) hide show
  1. package/Components/AnimatedInOut/index.tsx +5 -3
  2. package/Components/AudioPlayer/index.tsx +15 -0
  3. package/Components/AudioPlayer/mobile/Layout.tsx +66 -0
  4. package/Components/AudioPlayer/{__tests__/__snapshots__/audioPlayer.test.js.snap → mobile/__tests__/__snapshots__/audioPlayerMobileLayout.test.js.snap} +2 -2
  5. package/Components/AudioPlayer/mobile/__tests__/audioPlayerMobileLayout.test.js +18 -0
  6. package/Components/AudioPlayer/mobile/index.tsx +18 -0
  7. package/Components/AudioPlayer/{Artwork.tsx → tv/Artwork.tsx} +3 -2
  8. package/Components/AudioPlayer/{Channel.tsx → tv/Channel.tsx} +7 -7
  9. package/Components/AudioPlayer/tv/Layout.tsx +168 -0
  10. package/Components/AudioPlayer/{Runtime.tsx → tv/Runtime.tsx} +7 -1
  11. package/Components/AudioPlayer/{Summary.tsx → tv/Summary.tsx} +6 -2
  12. package/Components/AudioPlayer/{Title.tsx → tv/Title.tsx} +6 -2
  13. package/Components/AudioPlayer/{__tests__ → tv/__tests__}/__snapshots__/Runtime.test.js.snap +2 -2
  14. package/Components/AudioPlayer/tv/__tests__/__snapshots__/audioPlayer.test.js.snap +164 -0
  15. package/Components/AudioPlayer/tv/__tests__/__snapshots__/channel.test.js.snap +19 -0
  16. package/Components/AudioPlayer/{__tests__ → tv/__tests__}/__snapshots__/summary.test.js.snap +1 -2
  17. package/Components/AudioPlayer/{__tests__ → tv/__tests__}/__snapshots__/title.test.js.snap +1 -2
  18. package/Components/AudioPlayer/{__tests__ → tv/__tests__}/audioPlayer.test.js +7 -3
  19. package/Components/AudioPlayer/{helpers.tsx → tv/helpers.tsx} +11 -5
  20. package/Components/AudioPlayer/{AudioPlayer.tsx → tv/index.tsx} +17 -58
  21. package/Components/AudioPlayer/types.ts +40 -0
  22. package/Components/BaseFocusable/index.tsx +23 -12
  23. package/Components/Cell/Cell.tsx +91 -64
  24. package/Components/Cell/CellWithFocusable.tsx +3 -0
  25. package/Components/Cell/FocusableWrapper.tsx +44 -0
  26. package/Components/Cell/TvOSCellComponent.tsx +80 -14
  27. package/Components/Cell/__tests__/CellWIthFocusable.test.js +3 -2
  28. package/Components/Cell/index.js +7 -3
  29. package/Components/ComponentResolver/index.ts +1 -1
  30. package/Components/FeedLoader/FeedLoader.tsx +7 -16
  31. package/Components/FeedLoader/FeedLoaderHOC.tsx +21 -0
  32. package/Components/FeedLoader/index.js +2 -8
  33. package/Components/Focusable/Focusable.tsx +12 -3
  34. package/Components/Focusable/FocusableTvOS.tsx +5 -5
  35. package/Components/Focusable/FocusableiOS.tsx +2 -2
  36. package/Components/Focusable/Touchable.tsx +5 -3
  37. package/Components/Focusable/__tests__/index.android.test.tsx +3 -0
  38. package/Components/Focusable/index.android.tsx +19 -11
  39. package/Components/Focusable/index.tsx +1 -1
  40. package/Components/FocusableGroup/FocusableTvOS.tsx +1 -1
  41. package/Components/FocusableList/FocusableItem.tsx +4 -3
  42. package/Components/FocusableList/FocusableListItemWrapper.tsx +2 -1
  43. package/Components/FocusableList/hooks/useCellState.android.ts +13 -3
  44. package/Components/FocusableList/index.tsx +20 -9
  45. package/Components/FreezeWithCallback/__tests__/index.test.tsx +67 -43
  46. package/Components/GeneralContentScreen/utils/__tests__/useCurationAPI.test.js +42 -59
  47. package/Components/GeneralContentScreen/utils/useCurationAPI.ts +22 -21
  48. package/Components/HandlePlayable/HandlePlayable.tsx +25 -9
  49. package/Components/HookRenderer/HookRenderer.tsx +5 -1
  50. package/Components/Layout/TV/LayoutBackground.tsx +1 -1
  51. package/Components/Layout/TV/__tests__/index.test.tsx +0 -1
  52. package/Components/MasterCell/DefaultComponents/ActionButton.tsx +6 -2
  53. package/Components/MasterCell/DefaultComponents/Button.tsx +1 -1
  54. package/Components/MasterCell/DefaultComponents/FocusableView/index.tsx +4 -39
  55. package/Components/MasterCell/DefaultComponents/Image/hoc/withDimensions.tsx +1 -1
  56. package/Components/MasterCell/DefaultComponents/ImageContainer/index.tsx +1 -1
  57. package/Components/MasterCell/DefaultComponents/SecondaryImage/Image.tsx +65 -17
  58. package/Components/MasterCell/DefaultComponents/SecondaryImage/__tests__/Image.test.tsx +21 -3
  59. package/Components/MasterCell/DefaultComponents/SecondaryImage/__tests__/__snapshots__/Image.test.tsx.snap +6 -3
  60. package/Components/MasterCell/DefaultComponents/Text/index.tsx +26 -6
  61. package/Components/MasterCell/DefaultComponents/__tests__/image.test.js +10 -10
  62. package/Components/MasterCell/DefaultComponents/__tests__/text.test.tsx +18 -18
  63. package/Components/MasterCell/SharedUI/CollapsibleTextContainer/__tests__/index.test.tsx +10 -10
  64. package/Components/MasterCell/elementMapper.tsx +1 -2
  65. package/Components/MasterCell/index.tsx +1 -1
  66. package/Components/MasterCell/utils/behaviorProvider.ts +82 -14
  67. package/Components/MasterCell/utils/index.ts +11 -5
  68. package/Components/OfflineHandler/NotificationView/__tests__/index.test.tsx +13 -18
  69. package/Components/OfflineHandler/__tests__/__snapshots__/index.test.tsx.snap +9 -0
  70. package/Components/OfflineHandler/__tests__/index.test.tsx +26 -35
  71. package/Components/PlayerContainer/ErrorDisplay/index.ts +1 -1
  72. package/Components/PlayerContainer/PlayerContainer.tsx +46 -33
  73. package/Components/PlayerContainer/ProgramInfo/index.tsx +1 -1
  74. package/Components/PlayerContainer/index.ts +1 -1
  75. package/Components/PlayerImageBackground/index.tsx +1 -1
  76. package/Components/River/ComponentsMap/ComponentsMap.tsx +49 -43
  77. package/Components/River/ComponentsMap/ContextProviders/ComponentsMapHeightContext.ts +8 -0
  78. package/Components/River/ComponentsMap/ContextProviders/ComponentsMapRefContext.ts +8 -0
  79. package/Components/River/ComponentsMap/hooks/__tests__/useLoadingState.test.ts +378 -0
  80. package/Components/River/ComponentsMap/hooks/useLoadingState.ts +2 -2
  81. package/Components/River/RefreshControl.tsx +11 -17
  82. package/Components/River/RiverItem.tsx +3 -0
  83. package/Components/River/TV/River.tsx +2 -17
  84. package/Components/River/TV/index.tsx +3 -1
  85. package/Components/River/TV/withPipesV1DataLoader.tsx +43 -0
  86. package/Components/River/TV/withRiverDataLoader.tsx +17 -0
  87. package/Components/River/TV/withTVEventHandler.tsx +1 -1
  88. package/Components/River/__tests__/__snapshots__/componentsMap.test.js.snap +2 -0
  89. package/Components/River/__tests__/river.test.js +12 -26
  90. package/Components/River/index.tsx +1 -1
  91. package/Components/Screen/TV/hooks/useInitialFocus.ts +14 -4
  92. package/Components/Screen/__tests__/Screen.test.tsx +28 -29
  93. package/Components/Screen/__tests__/__snapshots__/Screen.test.tsx.snap +2 -0
  94. package/Components/Screen/__tests__/navigationHandler.test.ts +133 -22
  95. package/Components/Screen/index.tsx +22 -5
  96. package/Components/Screen/navigationHandler.ts +20 -2
  97. package/Components/ScreenResolver/index.tsx +22 -1
  98. package/Components/ScreenRevealManager/ScreenRevealManager.ts +76 -0
  99. package/Components/ScreenRevealManager/__tests__/ScreenRevealManager.test.ts +107 -0
  100. package/Components/ScreenRevealManager/__tests__/withScreenRevealManager.test.tsx +96 -0
  101. package/Components/ScreenRevealManager/index.ts +1 -0
  102. package/Components/ScreenRevealManager/utils/index.ts +23 -0
  103. package/Components/ScreenRevealManager/withScreenRevealManager.tsx +91 -0
  104. package/Components/Tabs/TV/Tabs.android.tsx +1 -3
  105. package/Components/Tabs/Tabs.tsx +2 -3
  106. package/Components/TextInputTv/__tests__/__snapshots__/TextInputTv.test.js.snap +13 -0
  107. package/Components/TextInputTv/index.tsx +11 -0
  108. package/Components/Touchable/__tests__/__snapshots__/touchable.test.tsx.snap +34 -0
  109. package/Components/Touchable/__tests__/touchable.test.tsx +12 -17
  110. package/Components/Transitioner/__tests__/__snapshots__/Scene.test.js.snap +15 -9
  111. package/Components/VideoLive/animationUtils.ts +3 -3
  112. package/Components/VideoModal/ModalAnimation/AnimatedScrollModal.tsx +6 -10
  113. package/Components/VideoModal/ModalAnimation/AnimatedScrollModal.web.tsx +294 -0
  114. package/Components/VideoModal/ModalAnimation/AnimatedVideoPlayerComponent.web.tsx +93 -0
  115. package/Components/VideoModal/ModalAnimation/ModalAnimationContext.tsx +73 -29
  116. package/Components/VideoModal/PlayerDetails.tsx +29 -7
  117. package/Components/VideoModal/PlayerWrapper.tsx +26 -142
  118. package/Components/VideoModal/VideoModal.tsx +3 -17
  119. package/Components/VideoModal/__tests__/PlayerDetails.test.tsx +5 -5
  120. package/Components/VideoModal/__tests__/PlayerWrapper.test.tsx +1 -7
  121. package/Components/VideoModal/__tests__/__snapshots__/PlayerWrapper.test.tsx.snap +44 -240
  122. package/Components/VideoModal/hooks/__tests__/useDelayedPlayerDetails.test.ts +9 -1
  123. package/Components/VideoModal/hooks/index.ts +0 -2
  124. package/Components/VideoModal/hooks/useDelayedPlayerDetails.ts +40 -15
  125. package/Components/VideoModal/hooks/useModalSize.ts +18 -2
  126. package/Components/VideoModal/hooks/utils/__tests__/showDetails.test.ts +2 -2
  127. package/Components/VideoModal/hooks/utils/index.ts +4 -0
  128. package/Components/VideoModal/utils.ts +6 -0
  129. package/Components/Viewport/ViewportAware/__tests__/viewportAware.test.js +12 -16
  130. package/Components/Viewport/ViewportTracker/__tests__/viewportTracker.test.js +84 -24
  131. package/Components/Viewport/VisibilitySensor/VisibilitySensor.tsx +3 -3
  132. package/Components/ZappFrameworkComponents/BarView/BarView.tsx +4 -6
  133. package/Components/ZappFrameworkComponents/BarView/__tests__/BarView.test.tsx +2 -2
  134. package/Components/default-cell-renderer/viewTrees/tv/DefaultCell/index.ts +3 -3
  135. package/Contexts/CellFocusedStateContext/index.tsx +27 -0
  136. package/Contexts/ConfigutaionContext/__tests__/ConfigurationProvider.test.tsx +3 -3
  137. package/Contexts/ScreenContext/index.tsx +46 -6
  138. package/Decorators/ConfigurationWrapper/__tests__/withConfigurationProvider.test.tsx +3 -3
  139. package/Decorators/ConfigurationWrapper/withConfigurationProvider.tsx +2 -2
  140. package/Decorators/RiverFeedLoader/__tests__/__snapshots__/riverFeedLoader.test.tsx.snap +221 -209
  141. package/Decorators/RiverFeedLoader/__tests__/riverFeedLoader.test.tsx +14 -16
  142. package/Decorators/RiverFeedLoader/__tests__/utils.test.ts +0 -20
  143. package/Decorators/RiverFeedLoader/index.tsx +22 -4
  144. package/Decorators/RiverFeedLoader/utils/getDatasourceUrl.ts +6 -10
  145. package/Decorators/RiverFeedLoader/utils/index.ts +0 -18
  146. package/Decorators/RiverResolver/__tests__/riverResolver.test.tsx +3 -6
  147. package/Decorators/ZappPipesDataConnector/ResolverSelector.tsx +25 -0
  148. package/Decorators/ZappPipesDataConnector/__tests__/NullFeedResolver.test.tsx +78 -0
  149. package/Decorators/ZappPipesDataConnector/__tests__/ResolverSelector.test.tsx +205 -0
  150. package/Decorators/ZappPipesDataConnector/__tests__/StaticFeedResolver.test.tsx +251 -0
  151. package/Decorators/ZappPipesDataConnector/__tests__/UrlFeedResolver.test.tsx +368 -0
  152. package/Decorators/ZappPipesDataConnector/__tests__/utils.test.ts +39 -0
  153. package/Decorators/ZappPipesDataConnector/index.tsx +26 -293
  154. package/Decorators/ZappPipesDataConnector/resolvers/NullFeedResolver.tsx +25 -0
  155. package/Decorators/ZappPipesDataConnector/resolvers/StaticFeedResolver.tsx +87 -0
  156. package/Decorators/ZappPipesDataConnector/resolvers/UrlFeedResolver.tsx +266 -0
  157. package/Decorators/ZappPipesDataConnector/types.ts +29 -0
  158. package/Decorators/ZappPipesDataConnector/utils/mongoFilter.ts +738 -0
  159. package/Decorators/ZappPipesDataConnector/utils/useFilter.tsx +157 -0
  160. package/events/index.ts +3 -0
  161. package/package.json +5 -10
  162. package/Components/AudioPlayer/AudioPlayerLayout.tsx +0 -202
  163. package/Components/AudioPlayer/__tests__/__snapshots__/audioPlayerLayout.test.js.snap +0 -66
  164. package/Components/AudioPlayer/__tests__/__snapshots__/channel.test.js.snap +0 -28
  165. package/Components/AudioPlayer/__tests__/audioPlayerLayout.test.js +0 -26
  166. package/Components/AudioPlayer/index.ts +0 -1
  167. package/Components/River/__tests__/__snapshots__/river.test.js.snap +0 -27
  168. package/Components/VideoModal/hooks/useBackgroundColor.ts +0 -10
  169. /package/Components/AudioPlayer/{__tests__ → tv/__tests__}/Runtime.test.js +0 -0
  170. /package/Components/AudioPlayer/{__tests__ → tv/__tests__}/__snapshots__/artWork.test.js.snap +0 -0
  171. /package/Components/AudioPlayer/{__tests__ → tv/__tests__}/artWork.test.js +0 -0
  172. /package/Components/AudioPlayer/{__tests__ → tv/__tests__}/channel.test.js +0 -0
  173. /package/Components/AudioPlayer/{__tests__ → tv/__tests__}/summary.test.js +0 -0
  174. /package/Components/AudioPlayer/{__tests__ → tv/__tests__}/title.test.js +0 -0
@@ -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,11 @@ 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";
13
20
 
14
21
  type Props = {
15
22
  item: ZappEntry;
@@ -66,6 +73,8 @@ type Props = {
66
73
  shouldUpdate: boolean;
67
74
  behavior: Behavior;
68
75
  componentsMapOffset: number;
76
+ applyFocusableWrapper: boolean;
77
+ hasFocusableInside: boolean;
69
78
  };
70
79
 
71
80
  type State = {
@@ -82,7 +91,7 @@ const baseCellStyles = {
82
91
  flex: 1,
83
92
  } as const;
84
93
 
85
- export class TvOSCellComponent extends React.Component<Props, State> {
94
+ class TvOSCell extends React.Component<Props, State> {
86
95
  cell: any;
87
96
  target: any;
88
97
  layout: any;
@@ -239,6 +248,8 @@ export class TvOSCellComponent extends React.Component<Props, State> {
239
248
  groupId,
240
249
  isFocusable,
241
250
  behavior,
251
+ applyFocusableWrapper,
252
+ hasFocusableInside,
242
253
  } = this.props;
243
254
 
244
255
  const { id } = item;
@@ -254,24 +265,33 @@ export class TvOSCellComponent extends React.Component<Props, State> {
254
265
  this.onFocus(arg1, index);
255
266
  };
256
267
 
257
- const hasFocusableInside = CellRenderer.hasFocusableInside?.(item);
258
-
259
268
  if (hasFocusableInside) {
260
269
  return (
261
270
  <View onLayout={this.onLayout}>
262
- <CellWithFocusable
263
- CellRenderer={CellRenderer}
264
- item={item}
271
+ <FocusableWrapper
265
272
  id={focusableId}
266
- groupId={(groupId || component?.id).toString()}
273
+ groupId={String(groupId || component?.id)}
274
+ isParallaxDisabled={this.layout?.width > 1740}
267
275
  onFocus={handleFocus}
268
- index={index}
269
- scrollTo={this.scrollTo}
270
- preferredFocus={preferredFocus}
271
- focused={this.props.focused}
272
- behavior={behavior}
273
- isFocusable={isFocusable}
274
- />
276
+ onBlur={onBlur || this.onBlur}
277
+ applyWrapper={applyFocusableWrapper}
278
+ >
279
+ {(focused) => (
280
+ <CellWithFocusable
281
+ CellRenderer={CellRenderer}
282
+ item={item}
283
+ id={focusableId}
284
+ groupId={(groupId || component?.id).toString()}
285
+ onFocus={handleFocus}
286
+ index={index}
287
+ scrollTo={this.scrollTo}
288
+ preferredFocus={preferredFocus}
289
+ focused={focused || this.props.focused}
290
+ behavior={behavior}
291
+ isFocusable={isFocusable}
292
+ />
293
+ )}
294
+ </FocusableWrapper>
275
295
  </View>
276
296
  );
277
297
  }
@@ -309,3 +329,49 @@ export class TvOSCellComponent extends React.Component<Props, State> {
309
329
  );
310
330
  }
311
331
  }
332
+
333
+ export function withFocusableWrapperHOC(Component) {
334
+ return function WrappedComponent(props) {
335
+ const [focusableViewIsRendered, setFocusableViewIsRendered] =
336
+ React.useState(false);
337
+
338
+ const { CellRenderer, item, groupId, component } = props;
339
+
340
+ const isFocusable = toBooleanWithDefaultTrue(props?.isFocusable);
341
+
342
+ const focusableGroupId = String(groupId || component?.id);
343
+
344
+ const hasFocusableInside = CellRenderer.hasFocusableInside?.(item);
345
+
346
+ React.useEffect(() => {
347
+ // start waiting any first registration of FocusableButton inside this focusableGroup
348
+ // after it we could get rid of applying focusable-wrapper
349
+ const subscription = focusableButtonsRegistration$(focusableGroupId)
350
+ .pipe(
351
+ filter(() => isFocusable),
352
+ first()
353
+ )
354
+ .subscribe(() => {
355
+ setFocusableViewIsRendered(true);
356
+ });
357
+
358
+ return () => {
359
+ subscription.unsubscribe();
360
+ };
361
+ }, [isFocusable, focusableGroupId]);
362
+
363
+ const applyFocusableWrapper = React.useMemo(() => {
364
+ return isFocusable && hasFocusableInside && !focusableViewIsRendered;
365
+ }, [isFocusable, hasFocusableInside, focusableViewIsRendered]);
366
+
367
+ return (
368
+ <Component
369
+ {...props}
370
+ applyFocusableWrapper={applyFocusableWrapper}
371
+ hasFocusableInside={hasFocusableInside}
372
+ />
373
+ );
374
+ };
375
+ }
376
+
377
+ export const TvOSCellComponent = compose(withFocusableWrapperHOC)(TvOSCell);
@@ -1,12 +1,13 @@
1
1
  import { View } from "react-native";
2
2
  import React from "react";
3
- import { act, render } from "@testing-library/react-native";
3
+ import { act } from "@testing-library/react-native";
4
4
  import { CellWithFocusable } from "../CellWithFocusable.tsx";
5
5
 
6
6
  import { focusManager } from "@applicaster/zapp-react-native-utils/appUtils/focusManager";
7
+ import { renderWithProviders } from "@applicaster/zapp-react-native-utils/testUtils/index.tsx";
7
8
 
8
9
  const renderWith = (props) => {
9
- return render(<CellWithFocusable {...props} />);
10
+ return renderWithProviders(<CellWithFocusable {...props} />);
10
11
  };
11
12
 
12
13
  describe("CellWithFocusable", () => {
@@ -1,13 +1,17 @@
1
1
  import * as R from "ramda";
2
2
 
3
- import { connectToStore } from "@applicaster/zapp-react-native-redux";
3
+ import { connectToStore } from "@applicaster/zapp-react-native-redux/utils/connectToStore";
4
4
  import { platformSelect } from "@applicaster/zapp-react-native-utils/reactUtils";
5
5
 
6
- import { HorizontalScrollContext, RiverOffsetContext } from "../../Contexts";
6
+ import {
7
+ HorizontalScrollContext,
8
+ RiverOffsetContext,
9
+ ScreenScrollingContext,
10
+ } from "../../Contexts";
11
+
7
12
  import { CellComponent } from "./Cell";
8
13
  import { TvOSCellComponent } from "./TvOSCellComponent";
9
14
  import { withConsumer } from "../../Contexts/HeaderOffsetContext";
10
- import { ScreenScrollingContext } from "../../Contexts/ScreenScrollingContext";
11
15
 
12
16
  import { ScreenLayoutContextConsumer } from "../../Contexts/ScreenLayoutContext";
13
17
  import { createContext } from "@applicaster/zapp-react-native-utils/reactUtils/createContext";
@@ -1,6 +1,6 @@
1
1
  import * as R from "ramda";
2
2
 
3
- import { connectToStore } from "@applicaster/zapp-react-native-redux";
3
+ import { connectToStore } from "@applicaster/zapp-react-native-redux/utils/connectToStore";
4
4
 
5
5
  import { ComponentResolverComponent } from "./ComponentResolver";
6
6
 
@@ -1,25 +1,16 @@
1
1
  import React from "react";
2
2
  import * as R from "ramda";
3
+ import { selectZappPipes } from "@applicaster/zapp-react-native-redux";
3
4
 
4
5
  type Props = {
5
- zappPipes: ZappPipesData;
6
- loadPipesData: (
7
- feed: string,
8
- options?: Partial<{
9
- clearCache: boolean;
10
- meta: any;
11
- loadLocalFavorites: boolean;
12
- silentRefresh: boolean;
13
- parentFeed: ZappFeed;
14
- callback: () => void;
15
- bodyParams: any;
16
- riverId: string;
17
- }>
18
- ) => void;
6
+ zappPipes: ReturnType<typeof selectZappPipes>;
7
+ loadPipesData: ReturnType<
8
+ typeof import("@applicaster/zapp-react-native-utils/reactHooks/feed").useLoadPipesDataDispatch
9
+ >;
19
10
  feedUrl: string;
20
- children: (feed: ZappFeed) => React.ComponentType<any>;
11
+ children: (feed: ZappFeed) => React.ReactNode;
21
12
  onFeedLoaded: (feed: ZappFeed) => {};
22
- onError: (feed: ZappFeed) => {};
13
+ onError: (error: ZappPipesData["error"]) => {};
23
14
  refreshing: boolean;
24
15
  refreshCallback: () => void;
25
16
  };
@@ -0,0 +1,21 @@
1
+ import React from "react";
2
+ import {
3
+ selectZappPipes,
4
+ useAppSelector,
5
+ } from "@applicaster/zapp-react-native-redux";
6
+ import { useLoadPipesDataDispatch } from "@applicaster/zapp-react-native-utils/reactHooks/feed";
7
+
8
+ export const FeedLoaderHOC = (_Component: any) => {
9
+ return function FeedLoaderHOC(props: any) {
10
+ const zappPipes = useAppSelector(selectZappPipes);
11
+ const loadPipesData = useLoadPipesDataDispatch();
12
+
13
+ return (
14
+ <_Component
15
+ {...props}
16
+ zappPipes={zappPipes}
17
+ loadPipesData={loadPipesData}
18
+ />
19
+ );
20
+ };
21
+ };
@@ -1,10 +1,4 @@
1
- import * as R from "ramda";
2
-
3
- import { connectToStore } from "@applicaster/zapp-react-native-redux";
4
- import { loadPipesData } from "@applicaster/zapp-react-native-redux/ZappPipes";
5
-
6
1
  import { FeedLoaderComponent } from "./FeedLoader";
2
+ import { FeedLoaderHOC } from "./FeedLoaderHOC";
7
3
 
8
- export const FeedLoader = connectToStore(R.pick(["zappPipes"]), {
9
- loadPipesData,
10
- })(FeedLoaderComponent);
4
+ export const FeedLoader = FeedLoaderHOC(FeedLoaderComponent);
@@ -5,6 +5,8 @@ import { BaseFocusable } from "../BaseFocusable";
5
5
  import { focusManager } from "@applicaster/zapp-react-native-utils/appUtils/focusManager";
6
6
  import { LONG_KEY_PRESS_TIMEOUT } from "@applicaster/quick-brick-core/const";
7
7
  import { withFocusableContext } from "../../Contexts/FocusableGroupContext/withFocusableContext";
8
+ import { StyleSheet, ViewStyle } from "react-native";
9
+ import { AccessibilityManager } from "@applicaster/zapp-react-native-utils/appUtils/accessibilityManager";
8
10
 
9
11
  type Props = {
10
12
  initialFocus?: boolean;
@@ -19,15 +21,16 @@ type Props = {
19
21
  onPressOut?: () => void;
20
22
  onLongPress?: () => void;
21
23
  handleFocus?: ({ mouse }: { mouse: boolean }) => void;
22
- children: (boolean, string) => React.ComponentType<any>;
24
+ children: (boolean, string) => React.ReactNode;
23
25
  selected?: boolean;
24
- style?: React.CSSProperties;
26
+ style?: ViewStyle[] | ViewStyle;
25
27
  };
26
28
 
27
29
  class Focusable extends BaseFocusable<Props> {
28
30
  isGroup: boolean;
29
31
  mouse: boolean;
30
32
  longPressTimeout = null;
33
+ accessibilityManager: AccessibilityManager;
31
34
 
32
35
  constructor(props) {
33
36
  super(props);
@@ -42,6 +45,8 @@ class Focusable extends BaseFocusable<Props> {
42
45
  this.resetLongPressTimeout = this.resetLongPressTimeout.bind(this);
43
46
  this.longPress = this.longPress.bind(this);
44
47
  this.press = this.press.bind(this);
48
+
49
+ this.accessibilityManager = AccessibilityManager.getInstance();
45
50
  }
46
51
 
47
52
  /**
@@ -128,6 +133,9 @@ class Focusable extends BaseFocusable<Props> {
128
133
  const id = this.getId();
129
134
  const focusableId = `focusable-${id}`;
130
135
 
136
+ const accessibilityProps =
137
+ this.accessibilityManager.getWebAccessibilityProps(this.props);
138
+
131
139
  return (
132
140
  <div
133
141
  id={focusableId}
@@ -139,7 +147,8 @@ class Focusable extends BaseFocusable<Props> {
139
147
  onMouseUp={this.pressOut}
140
148
  data-testid={focusableId}
141
149
  focused-teststate={focused ? "focused" : "default"}
142
- style={style}
150
+ style={StyleSheet.flatten(style) as any as React.CSSProperties}
151
+ {...accessibilityProps}
143
152
  >
144
153
  {children(focused, { mouse: this.mouse })}
145
154
  </div>
@@ -16,10 +16,10 @@ function noop() {}
16
16
  type Props = {
17
17
  id: string;
18
18
  groupId: string;
19
- onPress?: (nativeEvent: React.SyntheticEvent) => void;
20
- onFocus?: (nativeEvent: React.SyntheticEvent) => void;
21
- onBlur?: (nativeEvent: React.SyntheticEvent) => void;
22
- children: (focused?: boolean) => React.ReactNode;
19
+ onPress?: (nativeEvent: any) => void;
20
+ onFocus?: (nativeEvent: any) => void;
21
+ onBlur?: (nativeEvent: any) => void;
22
+ children: ((focused?: boolean) => React.ReactNode) | React.ReactNode;
23
23
  isParallaxDisabled: boolean;
24
24
  preferredFocus?: boolean;
25
25
  selected?: boolean;
@@ -204,7 +204,7 @@ export class Focusable extends BaseFocusable<Props> {
204
204
  {...this.nextFocusableReactTags}
205
205
  {...otherProps}
206
206
  >
207
- {R.is(Function, children) ? children(focused) : children}
207
+ {typeof children === "function" ? children(focused) : children}
208
208
  </FocusableItemNative>
209
209
  );
210
210
  }
@@ -2,7 +2,7 @@ import React from "react";
2
2
 
3
3
  type Props = {
4
4
  children: () => React.ReactNode;
5
- };
5
+ } & Record<string, any>;
6
6
 
7
7
  function FocusableiOSComponent({ children }: Props) {
8
8
  if (typeof children === "function") {
@@ -12,4 +12,4 @@ function FocusableiOSComponent({ children }: Props) {
12
12
  return children;
13
13
  }
14
14
 
15
- export const FocusableiOS = React.forwardRef(FocusableiOSComponent);
15
+ export const FocusableiOS = FocusableiOSComponent;
@@ -9,7 +9,8 @@ type Props = {
9
9
  onLongPress?: (ref: FocusManager.TouchableRef) => void;
10
10
  onFocus?: (
11
11
  ref: FocusManager.TouchableRef,
12
- options: FocusManager.Android.CallbackOptions
12
+ options: FocusManager.Android.CallbackOptions,
13
+ context: Option<FocusManager.FocusContext>
13
14
  ) => void;
14
15
  onBlur?: (
15
16
  ref: FocusManager.TouchableRef,
@@ -39,9 +40,10 @@ export class Touchable extends React.Component<Props> {
39
40
 
40
41
  onFocus(
41
42
  focusableRef: FocusManager.TouchableRef,
42
- options: FocusManager.Android.CallbackOptions
43
+ options: FocusManager.Android.CallbackOptions,
44
+ context: Option<FocusManager.FocusContext>
43
45
  ): void {
44
- this.props?.onFocus?.(focusableRef, options);
46
+ this.props?.onFocus?.(focusableRef, options, context);
45
47
  }
46
48
 
47
49
  onBlur(
@@ -38,6 +38,9 @@ describe("Focusable", () => {
38
38
  });
39
39
 
40
40
  it("updates disableFocus state when disableFocus prop changes", () => {
41
+ const unregister = jest.fn();
42
+ mockFocusManager.registerFocusable.mockReturnValue(unregister);
43
+
41
44
  const { rerender } = render(
42
45
  <Focusable id="test-id" disableFocus={false}>
43
46
  <Touchable testID="touchable" />
@@ -22,7 +22,8 @@ type Props = {
22
22
  onPress?: (ref: FocusManager.FocusableRef) => void;
23
23
  onFocus?: (
24
24
  ref: FocusManager.FocusableRef,
25
- options: FocusManager.Android.CallbackOptions
25
+ options: FocusManager.Android.CallbackOptions,
26
+ context?: FocusManager.FocusContext
26
27
  ) => void;
27
28
  onBlur?: (
28
29
  ref: FocusManager.FocusableRef,
@@ -32,6 +33,7 @@ type Props = {
32
33
  onPressOut?: (ref: FocusManager.FocusableRef) => void;
33
34
  onLongPress?: (ref: FocusManager.FocusableRef) => void;
34
35
  onRegister?: () => void;
36
+ onUnregister?: () => void;
35
37
  isFocusableCell?: boolean;
36
38
  /** only for FocusableScrollView */
37
39
  onSetIsFocusable?: (isFocusable: boolean) => void;
@@ -43,11 +45,13 @@ export const FocusableContext = React.createContext<
43
45
  // eslint-disable-next-line
44
46
  setIsFocusable: (enableFocus: boolean) => void;
45
47
  ref: FocusManager.FocusableRef;
48
+ parentFocusableId: Option<string>;
46
49
  } & ParentFocus
47
50
  >({
48
51
  focused: false,
49
52
  setIsFocusable: () => {},
50
53
  ref: { current: null },
54
+ parentFocusableId: undefined,
51
55
  });
52
56
 
53
57
  export const useFocusable = () => React.useContext(FocusableContext);
@@ -68,13 +72,14 @@ function FocusableComponent(props: Props, forwardedRef) {
68
72
  onPressOut,
69
73
  onLongPress,
70
74
  onRegister = noop,
75
+ onUnregister = noop,
71
76
  isFocusableCell = true,
72
77
  onSetIsFocusable,
73
78
  } = props;
74
79
 
75
80
  const isRTL = useIsRTL();
76
81
  const focusManager = useFocusManager();
77
- const { ref: parentFocusable } = useFocusable();
82
+ const { ref: parentFocusableRef, parentFocusableId } = useFocusable();
78
83
  const touchableRef = React.useRef(null);
79
84
 
80
85
  const [focused, setFocused] = React.useState(() =>
@@ -98,21 +103,23 @@ function FocusableComponent(props: Props, forwardedRef) {
98
103
  }
99
104
  }, [disableFocus]);
100
105
 
101
- React.useEffect(() => {
106
+ React.useLayoutEffect(() => {
102
107
  if (id) {
103
- const unregister = focusManager.registerFocusable(
108
+ const unregister = focusManager.registerFocusable({
104
109
  touchableRef,
105
- parentFocusable,
106
- isFocusableCell
107
- );
110
+ parentFocusableRef,
111
+ isFocusableCell,
112
+ parentFocusableId,
113
+ });
108
114
 
109
115
  onRegister();
110
116
 
111
117
  return () => {
112
118
  unregister();
119
+ onUnregister();
113
120
  };
114
121
  }
115
- }, [id, onRegister, isFocusableCell]);
122
+ }, [id, onRegister, onUnregister, isFocusableCell, parentFocusableId]);
116
123
 
117
124
  if (R.isNil(id)) {
118
125
  // eslint-disable-next-line no-console
@@ -122,9 +129,9 @@ function FocusableComponent(props: Props, forwardedRef) {
122
129
  }
123
130
 
124
131
  const _onFocus = React.useCallback(
125
- (ref, options) => {
132
+ (ref, options, context) => {
126
133
  setFocused(true);
127
- onFocus?.(ref, options);
134
+ onFocus?.(ref, options, context);
128
135
  },
129
136
  [onFocus]
130
137
  );
@@ -164,8 +171,9 @@ function FocusableComponent(props: Props, forwardedRef) {
164
171
  ...parentFocus,
165
172
  ref: touchableRef,
166
173
  setIsFocusable,
174
+ parentFocusableId: id,
167
175
  };
168
- }, [parentFocus, focused]);
176
+ }, [parentFocus, focused, id]);
169
177
 
170
178
  return (
171
179
  <Touchable
@@ -4,7 +4,7 @@ import { FocusableiOS } from "./FocusableiOS";
4
4
 
5
5
  import { platformSelect } from "@applicaster/zapp-react-native-utils/reactUtils";
6
6
 
7
- export const Focusable = platformSelect({
7
+ export const Focusable: React.ComponentType<any> = platformSelect({
8
8
  tvos: FocusableTvOS,
9
9
  ios: FocusableiOS,
10
10
  default: FocusableDefault,
@@ -22,7 +22,7 @@ type FocusableGroupNativeEvent = {
22
22
 
23
23
  type Props = {
24
24
  id: string;
25
- children: (arg1: boolean) => React.ComponentType<any>;
25
+ children: React.ReactNode;
26
26
  isFocusDisabled: boolean;
27
27
  isWithMemory: boolean;
28
28
  focusGroupRef: React.Component;
@@ -10,7 +10,8 @@ type FocusableItemComponentProps = {
10
10
  onFocus: (
11
11
  element: FocusManager.FocusableRef,
12
12
  renderArgs: { item: FocusableItemComponentProps["item"]; index: number },
13
- direction: FocusManager.Android.FocusNavigationDirections
13
+ options: FocusManager.Android.CallbackOptions,
14
+ context: Option<FocusManager.FocusContext>
14
15
  ) => void;
15
16
  onListElementFocus?: (any, RenderItemProps, Direction) => void;
16
17
  onListElementBlur?: (any, RenderItemProps, Direction) => void;
@@ -45,8 +46,8 @@ const FocusableItemComponent = ({
45
46
  const renderArgs = { item, index };
46
47
 
47
48
  const onFocusHandler = React.useCallback(
48
- (element, direction) => {
49
- onFocus?.(element, renderArgs, direction);
49
+ (element, options, context) => {
50
+ onFocus?.(element, renderArgs, options, context);
50
51
  },
51
52
  [item, onFocus]
52
53
  );
@@ -17,7 +17,8 @@ type Props = {
17
17
  onFocus: (
18
18
  element: FocusManager.FocusableRef,
19
19
  renderArgs: { item: Item; index: number },
20
- direction: FocusManager.Android.FocusNavigationDirections
20
+ options: FocusManager.Android.CallbackOptions,
21
+ context: FocusManager.FocusContext
21
22
  ) => void;
22
23
  onListElementBlur?: (any, RenderItemProps, Direction) => void;
23
24
  onListElementPress?: (any, RenderItemProps) => void;
@@ -10,15 +10,25 @@ export const useCellState = (id: string) => {
10
10
  );
11
11
 
12
12
  React.useEffect(() => {
13
- const handler = (focusable) => {
13
+ const focusHandler = (focusable) => {
14
14
  const isChildren = focusManager.isFocusableChildOf(focusable, id);
15
+
15
16
  setCurrentCellFocused(isChildren);
16
17
  };
17
18
 
18
- focusManager.on(FOCUS_EVENTS.FOCUS, handler);
19
+ focusManager.on(FOCUS_EVENTS.FOCUS, focusHandler);
20
+
21
+ const resetHandler = ({ focusedId }) => {
22
+ if (id === focusedId) {
23
+ setCurrentCellFocused(false);
24
+ }
25
+ };
26
+
27
+ focusManager.on(FOCUS_EVENTS.RESET, resetHandler);
19
28
 
20
29
  return () => {
21
- focusManager.removeHandler(FOCUS_EVENTS.FOCUS, handler);
30
+ focusManager.removeHandler(FOCUS_EVENTS.FOCUS, focusHandler);
31
+ focusManager.removeHandler(FOCUS_EVENTS.RESET, resetHandler);
22
32
  };
23
33
  }, [id]);
24
34
 
@@ -20,27 +20,34 @@ import { FocusableScrollView } from "../FocusableScrollView";
20
20
  const mapIndexed = R.addIndex(R.map);
21
21
 
22
22
  export type IListRenderItem<ItemT> = (
23
- info: IListRenderItemInfo<ItemT> & {
23
+ info: {
24
24
  focused: boolean;
25
25
  onLoadFinished: () => void;
26
26
  onLoadFailed: () => void;
27
- }
27
+ } & IListRenderItemInfo<ItemT>
28
28
  ) => React.ReactElement | null;
29
29
 
30
30
  export const getFocusableId = (parentId, index) =>
31
31
  `${parentId}___index:${index}`;
32
32
 
33
+ type Item = ZappEntry | ZappUIComponent | any;
34
+
33
35
  export type Props<ItemT> = FlatListProps<ItemT> & {
34
36
  id?: number | string;
35
37
  horizontal?: boolean;
36
38
  loop?: boolean;
37
39
  numColumns?: number;
38
40
  data: ZappEntry[] | ZappUIComponent[] | any[];
39
- onListElementFocus?: (any, RenderItemProps, Direction) => void;
40
- onListElementBlur?: (any, RenderItemProps, Direction) => void;
41
- onListElementPress?: (any, RenderItemProps) => void;
42
- onListElementPressOut?: (any, RenderItemProps) => void;
43
- onListElementLongPress?: (any, RenderItemProps) => void;
41
+ onListElementFocus?: (
42
+ element: FocusManager.FocusableRef,
43
+ renderItemProps: { item: Item; index: number },
44
+ options: FocusManager.Android.CallbackOptions,
45
+ context: FocusManager.FocusContext
46
+ ) => void;
47
+ onListElementBlur?: (element, renderItemProps, direction) => void;
48
+ onListElementPress?: (element, renderItemProps) => void;
49
+ onListElementPressOut?: (element, renderItemProps) => void;
50
+ onListElementLongPress?: (element, renderItemProps) => void;
44
51
  focusableItemProps?: any;
45
52
  focused?: boolean;
46
53
  initialScrollIndex?: number;
@@ -91,6 +98,7 @@ function FocusableListComponent<ItemT>(props: Props<ItemT>, ref) {
91
98
  // eslint-disable-next-line unused-imports/no-unused-vars
92
99
  omitPropsPropagation = [],
93
100
  useScrollView = false,
101
+ onScrollToIndexFailed = noop,
94
102
  } = props;
95
103
 
96
104
  useCheckItemIdsForUnique({ componentId: props.id, items: data });
@@ -137,11 +145,11 @@ function FocusableListComponent<ItemT>(props: Props<ItemT>, ref) {
137
145
  );
138
146
 
139
147
  const onFocus = React.useCallback(
140
- (element, renderArgs, direction) => {
148
+ (element, renderArgs, options, context) => {
141
149
  const { index } = renderArgs;
142
150
 
143
151
  updateFocusedIndex?.(index);
144
- onListElementFocus?.(element, renderArgs, direction);
152
+ onListElementFocus?.(element, renderArgs, options, context);
145
153
  },
146
154
  [onListElementFocus, updateFocusedIndex]
147
155
  );
@@ -277,6 +285,7 @@ function FocusableListComponent<ItemT>(props: Props<ItemT>, ref) {
277
285
  "withStateMemory",
278
286
  "useSequentialLoading",
279
287
  "useScrollView",
288
+ "onScrollToIndexFailed",
280
289
  ...omitPropsPropagation,
281
290
  ],
282
291
  R.__
@@ -305,6 +314,7 @@ function FocusableListComponent<ItemT>(props: Props<ItemT>, ref) {
305
314
  {...getFlatListProps(props)}
306
315
  onEndReached={onEndReached}
307
316
  initialNumToRender={initialNumToRender}
317
+ onScrollToIndexFailed={onScrollToIndexFailed}
308
318
  renderItem={renderItem}
309
319
  focused={focused}
310
320
  data={data}
@@ -319,6 +329,7 @@ function FocusableListComponent<ItemT>(props: Props<ItemT>, ref) {
319
329
  renderItem={renderItem}
320
330
  onEndReached={onEndReached}
321
331
  initialNumToRender={initialNumToRender}
332
+ onScrollToIndexFailed={onScrollToIndexFailed}
322
333
  />
323
334
  )}
324
335
  </ChildrenFocusDeactivatorView>