@applicaster/zapp-react-native-ui-components 14.0.0-alpha.1661204539 → 14.0.0-alpha.1740013076

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 (157) 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/tv/Artwork.tsx +41 -0
  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} +9 -2
  11. package/Components/AudioPlayer/{Summary.tsx → tv/Summary.tsx} +17 -10
  12. package/Components/AudioPlayer/tv/Title.tsx +46 -0
  13. package/Components/AudioPlayer/{__tests__ → tv/__tests__}/__snapshots__/Runtime.test.js.snap +4 -4
  14. package/Components/AudioPlayer/{__tests__ → tv/__tests__}/__snapshots__/artWork.test.js.snap +9 -4
  15. package/Components/AudioPlayer/tv/__tests__/__snapshots__/audioPlayer.test.js.snap +164 -0
  16. package/Components/AudioPlayer/tv/__tests__/__snapshots__/channel.test.js.snap +19 -0
  17. package/Components/AudioPlayer/{__tests__ → tv/__tests__}/__snapshots__/summary.test.js.snap +2 -3
  18. package/Components/AudioPlayer/{__tests__ → tv/__tests__}/__snapshots__/title.test.js.snap +2 -3
  19. package/Components/AudioPlayer/{__tests__ → tv/__tests__}/audioPlayer.test.js +7 -3
  20. package/Components/AudioPlayer/{helpers.tsx → tv/helpers.tsx} +13 -7
  21. package/Components/AudioPlayer/{AudioPlayer.tsx → tv/index.tsx} +18 -57
  22. package/Components/AudioPlayer/types.ts +40 -0
  23. package/Components/BaseFocusable/index.tsx +23 -12
  24. package/Components/Cell/Cell.tsx +91 -64
  25. package/Components/Cell/CellWithFocusable.tsx +3 -0
  26. package/Components/Cell/__tests__/CellWIthFocusable.test.js +3 -2
  27. package/Components/Cell/index.js +7 -3
  28. package/Components/ComponentResolver/index.ts +1 -1
  29. package/Components/FeedLoader/FeedLoader.tsx +7 -16
  30. package/Components/FeedLoader/FeedLoaderHOC.tsx +21 -0
  31. package/Components/FeedLoader/index.js +2 -8
  32. package/Components/Focusable/Focusable.tsx +12 -3
  33. package/Components/Focusable/FocusableTvOS.tsx +5 -5
  34. package/Components/Focusable/FocusableiOS.tsx +2 -2
  35. package/Components/Focusable/__tests__/index.android.test.tsx +3 -0
  36. package/Components/Focusable/index.android.tsx +12 -8
  37. package/Components/Focusable/index.tsx +1 -1
  38. package/Components/FocusableGroup/FocusableTvOS.tsx +1 -1
  39. package/Components/FocusableList/index.tsx +6 -2
  40. package/Components/FreezeWithCallback/__tests__/index.test.tsx +67 -43
  41. package/Components/GeneralContentScreen/GeneralContentScreen.tsx +0 -2
  42. package/Components/GeneralContentScreen/utils/__tests__/useCurationAPI.test.js +42 -59
  43. package/Components/GeneralContentScreen/utils/useCurationAPI.ts +13 -10
  44. package/Components/HandlePlayable/HandlePlayable.tsx +25 -9
  45. package/Components/Layout/TV/LayoutBackground.tsx +1 -1
  46. package/Components/Layout/TV/__tests__/index.test.tsx +0 -1
  47. package/Components/MasterCell/DefaultComponents/ActionButton.tsx +6 -2
  48. package/Components/MasterCell/DefaultComponents/Button.tsx +1 -1
  49. package/Components/MasterCell/DefaultComponents/FocusableView/index.tsx +4 -39
  50. package/Components/MasterCell/DefaultComponents/Image/hoc/withDimensions.tsx +1 -1
  51. package/Components/MasterCell/DefaultComponents/ImageContainer/index.tsx +1 -1
  52. package/Components/MasterCell/DefaultComponents/Text/index.tsx +27 -6
  53. package/Components/MasterCell/DefaultComponents/__tests__/image.test.js +10 -10
  54. package/Components/MasterCell/DefaultComponents/__tests__/text.test.tsx +18 -18
  55. package/Components/MasterCell/SharedUI/CollapsibleTextContainer/__tests__/index.test.tsx +10 -10
  56. package/Components/MasterCell/elementMapper.tsx +1 -2
  57. package/Components/MasterCell/index.tsx +1 -1
  58. package/Components/MasterCell/utils/behaviorProvider.ts +19 -6
  59. package/Components/MasterCell/utils/index.ts +9 -13
  60. package/Components/OfflineHandler/NotificationView/__tests__/index.test.tsx +13 -18
  61. package/Components/OfflineHandler/__tests__/__snapshots__/index.test.tsx.snap +9 -0
  62. package/Components/OfflineHandler/__tests__/index.test.tsx +26 -35
  63. package/Components/PlayerContainer/ErrorDisplay/index.ts +1 -1
  64. package/Components/PlayerContainer/PlayerContainer.tsx +66 -67
  65. package/Components/PlayerContainer/ProgramInfo/index.tsx +1 -1
  66. package/Components/PlayerContainer/index.ts +1 -1
  67. package/Components/PlayerImageBackground/index.tsx +1 -1
  68. package/Components/River/ComponentsMap/ComponentsMap.tsx +1 -6
  69. package/Components/River/ComponentsMap/hooks/__tests__/useLoadingState.test.ts +378 -0
  70. package/Components/River/ComponentsMap/hooks/useLoadingState.ts +2 -2
  71. package/Components/River/RefreshControl.tsx +11 -17
  72. package/Components/River/RiverItem.tsx +8 -8
  73. package/Components/River/TV/River.tsx +2 -20
  74. package/Components/River/TV/index.tsx +3 -1
  75. package/Components/River/TV/withPipesV1DataLoader.tsx +43 -0
  76. package/Components/River/TV/withRiverDataLoader.tsx +17 -0
  77. package/Components/River/TV/withTVEventHandler.tsx +1 -1
  78. package/Components/River/__tests__/__snapshots__/componentsMap.test.js.snap +2 -6
  79. package/Components/River/__tests__/river.test.js +12 -26
  80. package/Components/River/index.tsx +1 -1
  81. package/Components/Screen/__tests__/Screen.test.tsx +28 -29
  82. package/Components/Screen/__tests__/navigationHandler.test.ts +133 -22
  83. package/Components/Screen/navigationHandler.ts +20 -2
  84. package/Components/ScreenRevealManager/ScreenRevealManager.ts +76 -0
  85. package/Components/ScreenRevealManager/__tests__/ScreenRevealManager.test.ts +107 -0
  86. package/Components/ScreenRevealManager/__tests__/withScreenRevealManager.test.tsx +96 -0
  87. package/Components/ScreenRevealManager/index.ts +1 -0
  88. package/Components/ScreenRevealManager/withScreenRevealManager.tsx +79 -0
  89. package/Components/Tabs/TV/Tabs.android.tsx +1 -3
  90. package/Components/Tabs/Tabs.tsx +2 -3
  91. package/Components/TextInputTv/__tests__/__snapshots__/TextInputTv.test.js.snap +13 -0
  92. package/Components/TextInputTv/index.tsx +11 -0
  93. package/Components/TopMarginApplicator/TopMarginApplicator.tsx +16 -15
  94. package/Components/Touchable/__tests__/__snapshots__/touchable.test.tsx.snap +34 -0
  95. package/Components/Touchable/__tests__/touchable.test.tsx +12 -17
  96. package/Components/Transitioner/__tests__/__snapshots__/Scene.test.js.snap +15 -9
  97. package/Components/VideoLive/animationUtils.ts +3 -3
  98. package/Components/VideoModal/ModalAnimation/AnimatedScrollModal.tsx +3 -9
  99. package/Components/VideoModal/ModalAnimation/AnimatedScrollModal.web.tsx +294 -0
  100. package/Components/VideoModal/ModalAnimation/AnimatedVideoPlayerComponent.web.tsx +93 -0
  101. package/Components/VideoModal/ModalAnimation/ModalAnimationContext.tsx +32 -8
  102. package/Components/VideoModal/PlayerDetails.tsx +24 -2
  103. package/Components/VideoModal/PlayerWrapper.tsx +26 -142
  104. package/Components/VideoModal/VideoModal.tsx +3 -17
  105. package/Components/VideoModal/__tests__/PlayerDetails.test.tsx +5 -5
  106. package/Components/VideoModal/__tests__/PlayerWrapper.test.tsx +1 -7
  107. package/Components/VideoModal/__tests__/__snapshots__/PlayerWrapper.test.tsx.snap +44 -180
  108. package/Components/VideoModal/hooks/__tests__/useDelayedPlayerDetails.test.ts +17 -55
  109. package/Components/VideoModal/hooks/index.ts +0 -2
  110. package/Components/VideoModal/hooks/useDelayedPlayerDetails.ts +15 -26
  111. package/Components/VideoModal/hooks/useModalSize.ts +18 -2
  112. package/Components/VideoModal/utils.ts +6 -0
  113. package/Components/Viewport/ViewportAware/__tests__/viewportAware.test.js +12 -16
  114. package/Components/Viewport/ViewportTracker/__tests__/viewportTracker.test.js +84 -24
  115. package/Components/Viewport/VisibilitySensor/VisibilitySensor.tsx +3 -3
  116. package/Components/default-cell-renderer/viewTrees/tv/DefaultCell/index.ts +3 -3
  117. package/Contexts/CellFocusedStateContext/index.tsx +27 -0
  118. package/Contexts/ConfigutaionContext/__tests__/ConfigurationProvider.test.tsx +3 -3
  119. package/Contexts/ScreenContext/index.tsx +46 -6
  120. package/Decorators/ConfigurationWrapper/__tests__/withConfigurationProvider.test.tsx +3 -3
  121. package/Decorators/ConfigurationWrapper/withConfigurationProvider.tsx +2 -2
  122. package/Decorators/RiverFeedLoader/__tests__/__snapshots__/riverFeedLoader.test.tsx.snap +221 -209
  123. package/Decorators/RiverFeedLoader/__tests__/riverFeedLoader.test.tsx +14 -16
  124. package/Decorators/RiverFeedLoader/__tests__/utils.test.ts +0 -20
  125. package/Decorators/RiverFeedLoader/index.tsx +21 -9
  126. package/Decorators/RiverFeedLoader/utils/index.ts +0 -23
  127. package/Decorators/RiverResolver/__tests__/riverResolver.test.tsx +3 -6
  128. package/Decorators/ZappPipesDataConnector/ResolverSelector.tsx +25 -0
  129. package/Decorators/ZappPipesDataConnector/__tests__/NullFeedResolver.test.tsx +78 -0
  130. package/Decorators/ZappPipesDataConnector/__tests__/ResolverSelector.test.tsx +205 -0
  131. package/Decorators/ZappPipesDataConnector/__tests__/StaticFeedResolver.test.tsx +251 -0
  132. package/Decorators/ZappPipesDataConnector/__tests__/UrlFeedResolver.test.tsx +368 -0
  133. package/Decorators/ZappPipesDataConnector/__tests__/utils.test.ts +39 -0
  134. package/Decorators/ZappPipesDataConnector/index.tsx +27 -308
  135. package/Decorators/ZappPipesDataConnector/resolvers/NullFeedResolver.tsx +25 -0
  136. package/Decorators/ZappPipesDataConnector/resolvers/StaticFeedResolver.tsx +87 -0
  137. package/Decorators/ZappPipesDataConnector/resolvers/UrlFeedResolver.tsx +266 -0
  138. package/Decorators/ZappPipesDataConnector/types.ts +29 -0
  139. package/Decorators/ZappPipesDataConnector/utils/mongoFilter.ts +738 -0
  140. package/Decorators/ZappPipesDataConnector/utils/useFilter.tsx +157 -0
  141. package/events/index.ts +1 -0
  142. package/index.d.ts +0 -1
  143. package/package.json +5 -10
  144. package/Components/AudioPlayer/Artwork.tsx +0 -35
  145. package/Components/AudioPlayer/AudioPlayerLayout.tsx +0 -202
  146. package/Components/AudioPlayer/Title.tsx +0 -39
  147. package/Components/AudioPlayer/__tests__/__snapshots__/audioPlayerLayout.test.js.snap +0 -66
  148. package/Components/AudioPlayer/__tests__/__snapshots__/channel.test.js.snap +0 -28
  149. package/Components/AudioPlayer/__tests__/audioPlayerLayout.test.js +0 -26
  150. package/Components/AudioPlayer/index.ts +0 -1
  151. package/Components/River/__tests__/__snapshots__/river.test.js.snap +0 -27
  152. package/Components/VideoModal/hooks/useBackgroundColor.ts +0 -10
  153. /package/Components/AudioPlayer/{__tests__ → tv/__tests__}/Runtime.test.js +0 -0
  154. /package/Components/AudioPlayer/{__tests__ → tv/__tests__}/artWork.test.js +0 -0
  155. /package/Components/AudioPlayer/{__tests__ → tv/__tests__}/channel.test.js +0 -0
  156. /package/Components/AudioPlayer/{__tests__ → tv/__tests__}/summary.test.js +0 -0
  157. /package/Components/AudioPlayer/{__tests__ → tv/__tests__}/title.test.js +0 -0
@@ -8,6 +8,7 @@ import { getItemType } from "@applicaster/zapp-react-native-utils/navigationUtil
8
8
  import { SCREEN_TYPES } from "@applicaster/zapp-react-native-utils/navigationUtils/itemTypes";
9
9
  import { sendSelectCellEvent } from "@applicaster/zapp-react-native-utils/analyticsUtils";
10
10
  import { noop } from "@applicaster/zapp-react-native-utils/functionUtils";
11
+ import { CellFocusedStateContextProvider } from "@applicaster/zapp-react-native-ui-components/Contexts/CellFocusedStateContext";
11
12
 
12
13
  import { CellWithFocusable } from "./CellWithFocusable";
13
14
  import { BaseFocusable } from "../BaseFocusable";
@@ -15,6 +16,7 @@ import { AccessibilityManager } from "@applicaster/zapp-react-native-utils/appUt
15
16
  import { styles } from "./styles";
16
17
 
17
18
  type Props = {
19
+ dataLength: number;
18
20
  item: ZappEntry;
19
21
  index: number;
20
22
  shouldScrollHorizontally: (arg1: [any]) => boolean | null | undefined;
@@ -67,9 +69,12 @@ type Props = {
67
69
 
68
70
  type State = {
69
71
  hasFocusableInside: boolean;
72
+ cellFocused: boolean;
70
73
  };
71
74
 
72
75
  export class CellComponent extends React.Component<Props, State> {
76
+ accessibilityManager: AccessibilityManager;
77
+
73
78
  constructor(props) {
74
79
  super(props);
75
80
  this.onPress = this.onPress.bind(this);
@@ -79,10 +84,14 @@ export class CellComponent extends React.Component<Props, State> {
79
84
  this.hasReceivedFocus = this.hasReceivedFocus.bind(this);
80
85
  this.scrollVertically = this.scrollVertically.bind(this);
81
86
  this.scrollToIndex = this.scrollToIndex.bind(this);
87
+ this.handleAccessibilityFocus = this.handleAccessibilityFocus.bind(this);
82
88
 
83
89
  this.state = {
84
90
  hasFocusableInside: props.CellRenderer.hasFocusableInside?.(props.item),
91
+ cellFocused: false,
85
92
  };
93
+
94
+ this.accessibilityManager = AccessibilityManager.getInstance();
86
95
  }
87
96
 
88
97
  setScreenLayout(componentAnchorPointY, screenLayout) {
@@ -130,6 +139,8 @@ export class CellComponent extends React.Component<Props, State> {
130
139
  } = this.props;
131
140
 
132
141
  if (isFocusable) {
142
+ this.setState({ cellFocused: true });
143
+
133
144
  if (
134
145
  shouldUpdate &&
135
146
  shouldScrollVertically?.(mouse, focusable, id, title)
@@ -139,7 +150,9 @@ export class CellComponent extends React.Component<Props, State> {
139
150
  }
140
151
  }
141
152
 
142
- onBlur() {}
153
+ onBlur() {
154
+ this.setState({ cellFocused: false });
155
+ }
143
156
 
144
157
  willReceiveFocus() {}
145
158
 
@@ -183,6 +196,25 @@ export class CellComponent extends React.Component<Props, State> {
183
196
  return !isFocusable ? false : focused || focusableFocused;
184
197
  }
185
198
 
199
+ handleAccessibilityFocus(index, dataLength) {
200
+ // For loop scrolling, calculate the correct logical index
201
+ const logicalIndex = dataLength ? index % dataLength : index;
202
+
203
+ const positionLabel = dataLength
204
+ ? `item ${logicalIndex + 1} of ${dataLength}`
205
+ : "";
206
+
207
+ if (this.state.hasFocusableInside) {
208
+ this.accessibilityManager.readText({
209
+ text: " ",
210
+ });
211
+ } else {
212
+ this.accessibilityManager.readText({
213
+ text: `${positionLabel}`,
214
+ });
215
+ }
216
+ }
217
+
186
218
  componentDidUpdate(prevProps: Readonly<Props>) {
187
219
  if (prevProps.item !== this.props.item) {
188
220
  this.setState({
@@ -191,6 +223,8 @@ export class CellComponent extends React.Component<Props, State> {
191
223
  ),
192
224
  });
193
225
  }
226
+
227
+ this.handleAccessibilityFocus(this.props.index, this.props.dataLength);
194
228
  }
195
229
 
196
230
  render() {
@@ -212,7 +246,6 @@ export class CellComponent extends React.Component<Props, State> {
212
246
  } = this.props;
213
247
 
214
248
  const { id } = item;
215
-
216
249
  const focusableId = join("-", [component?.id, id, index]);
217
250
 
218
251
  const handleFocus = (focusable, mouse) => {
@@ -223,73 +256,67 @@ export class CellComponent extends React.Component<Props, State> {
223
256
 
224
257
  if (this.state.hasFocusableInside) {
225
258
  return (
226
- <CellWithFocusable
227
- CellRenderer={CellRenderer}
228
- item={item}
229
- id={focusableId}
230
- groupId={groupId || component?.id}
231
- onFocus={handleFocus}
232
- index={index}
233
- scrollTo={this.scrollToIndex()}
234
- isFocusable={isFocusable}
235
- skipFocusManagerRegistration={skipFocusManagerRegistration}
236
- behavior={behavior}
237
- />
259
+ <CellFocusedStateContextProvider cellFocused={this.state.cellFocused}>
260
+ <CellWithFocusable
261
+ CellRenderer={CellRenderer}
262
+ item={item}
263
+ id={focusableId}
264
+ groupId={groupId || component?.id}
265
+ onFocus={handleFocus}
266
+ onBlur={onBlur || this.onBlur}
267
+ index={index}
268
+ scrollTo={this.scrollToIndex()}
269
+ isFocusable={isFocusable}
270
+ skipFocusManagerRegistration={skipFocusManagerRegistration}
271
+ behavior={behavior}
272
+ />
273
+ </CellFocusedStateContextProvider>
238
274
  );
239
275
  }
240
276
 
241
277
  return (
242
- <View
243
- testID={`${component?.id}-${id}`}
244
- accessible={false}
245
- style={styles.touchableCell}
246
- >
247
- <Focusable
248
- id={focusableId}
249
- groupId={groupId || component?.id}
250
- onFocus={handleFocus}
251
- onBlur={onBlur || this.onBlur}
252
- onPress={this.onPress}
253
- willReceiveFocus={willReceiveFocus || this.willReceiveFocus}
254
- hasReceivedFocus={hasReceivedFocus || this.hasReceivedFocus}
255
- preferredFocus={preferredFocus}
256
- offsetUpdater={offsetUpdater}
257
- style={styles.baseCell}
258
- isFocusable={isFocusable}
259
- skipFocusManagerRegistration={skipFocusManagerRegistration}
278
+ <CellFocusedStateContextProvider cellFocused={this.state.cellFocused}>
279
+ <View
280
+ testID={`${component?.id}-${id}`}
281
+ accessible={false}
282
+ style={styles.touchableCell}
260
283
  >
261
- {(focused, event) => {
262
- const isFocused = this.isCellFocused(focused);
263
-
264
- if (isFocused) {
265
- const accessibilityManager = AccessibilityManager.getInstance();
266
-
267
- const accessibilityTitle =
268
- item?.extensions?.accessibility?.label || item?.title || "";
269
-
270
- const accessibilityHint =
271
- item?.extensions?.accessibility?.hint || "";
272
-
273
- accessibilityManager.readText({
274
- text: `${accessibilityTitle} ${accessibilityHint}`,
275
- });
276
- }
277
-
278
- return (
279
- <FocusableCell
280
- {...{
281
- index,
282
- CellRenderer,
283
- item,
284
- focused: isFocused,
285
- scrollTo: this.scrollToIndex(event),
286
- behavior,
287
- }}
288
- />
289
- );
290
- }}
291
- </Focusable>
292
- </View>
284
+ <Focusable
285
+ id={focusableId}
286
+ groupId={groupId || component?.id}
287
+ onFocus={handleFocus}
288
+ onBlur={onBlur || this.onBlur}
289
+ onPress={this.onPress}
290
+ willReceiveFocus={willReceiveFocus || this.willReceiveFocus}
291
+ hasReceivedFocus={hasReceivedFocus || this.hasReceivedFocus}
292
+ preferredFocus={preferredFocus}
293
+ offsetUpdater={offsetUpdater}
294
+ style={styles.baseCell}
295
+ isFocusable={isFocusable}
296
+ skipFocusManagerRegistration={skipFocusManagerRegistration}
297
+ {...this.accessibilityManager.getButtonAccessibilityProps(
298
+ item?.extensions?.accessibility?.label || item?.title
299
+ )}
300
+ >
301
+ {(focused, event) => {
302
+ const isFocused = this.isCellFocused(focused);
303
+
304
+ return (
305
+ <FocusableCell
306
+ {...{
307
+ index,
308
+ CellRenderer,
309
+ item,
310
+ focused: isFocused,
311
+ scrollTo: this.scrollToIndex(event),
312
+ behavior,
313
+ }}
314
+ />
315
+ );
316
+ }}
317
+ </Focusable>
318
+ </View>
319
+ </CellFocusedStateContextProvider>
293
320
  );
294
321
  }
295
322
  }
@@ -14,6 +14,7 @@ type Props = {
14
14
  id: string;
15
15
  groupId: string;
16
16
  onFocus: Function;
17
+ onBlur?: Function;
17
18
  index: number;
18
19
  scrollTo: Function;
19
20
  preferredFocus?: boolean;
@@ -33,6 +34,7 @@ export function CellWithFocusable(props: Props) {
33
34
  id,
34
35
  groupId,
35
36
  onFocus,
37
+ onBlur = noop,
36
38
  scrollTo = noop,
37
39
  preferredFocus,
38
40
  skipFocusManagerRegistration,
@@ -78,6 +80,7 @@ export function CellWithFocusable(props: Props) {
78
80
  const onGroupBlur = React.useCallback(() => {
79
81
  if (!skipFocusManagerRegistration) {
80
82
  setIsFocused(false);
83
+ onBlur?.();
81
84
  }
82
85
  }, [skipFocusManagerRegistration]);
83
86
 
@@ -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;
@@ -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" />
@@ -43,11 +43,13 @@ export const FocusableContext = React.createContext<
43
43
  // eslint-disable-next-line
44
44
  setIsFocusable: (enableFocus: boolean) => void;
45
45
  ref: FocusManager.FocusableRef;
46
+ parentFocusableId: Option<string>;
46
47
  } & ParentFocus
47
48
  >({
48
49
  focused: false,
49
50
  setIsFocusable: () => {},
50
51
  ref: { current: null },
52
+ parentFocusableId: undefined,
51
53
  });
52
54
 
53
55
  export const useFocusable = () => React.useContext(FocusableContext);
@@ -74,7 +76,7 @@ function FocusableComponent(props: Props, forwardedRef) {
74
76
 
75
77
  const isRTL = useIsRTL();
76
78
  const focusManager = useFocusManager();
77
- const { ref: parentFocusable } = useFocusable();
79
+ const { ref: parentFocusableRef, parentFocusableId } = useFocusable();
78
80
  const touchableRef = React.useRef(null);
79
81
 
80
82
  const [focused, setFocused] = React.useState(() =>
@@ -98,13 +100,14 @@ function FocusableComponent(props: Props, forwardedRef) {
98
100
  }
99
101
  }, [disableFocus]);
100
102
 
101
- React.useEffect(() => {
103
+ React.useLayoutEffect(() => {
102
104
  if (id) {
103
- const unregister = focusManager.registerFocusable(
105
+ const unregister = focusManager.registerFocusable({
104
106
  touchableRef,
105
- parentFocusable,
106
- isFocusableCell
107
- );
107
+ parentFocusableRef,
108
+ isFocusableCell,
109
+ parentFocusableId,
110
+ });
108
111
 
109
112
  onRegister();
110
113
 
@@ -112,7 +115,7 @@ function FocusableComponent(props: Props, forwardedRef) {
112
115
  unregister();
113
116
  };
114
117
  }
115
- }, [id, onRegister, isFocusableCell]);
118
+ }, [id, onRegister, isFocusableCell, parentFocusableId]);
116
119
 
117
120
  if (R.isNil(id)) {
118
121
  // eslint-disable-next-line no-console
@@ -164,8 +167,9 @@ function FocusableComponent(props: Props, forwardedRef) {
164
167
  ...parentFocus,
165
168
  ref: touchableRef,
166
169
  setIsFocusable,
170
+ parentFocusableId: id,
167
171
  };
168
- }, [parentFocus, focused]);
172
+ }, [parentFocus, focused, id]);
169
173
 
170
174
  return (
171
175
  <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;
@@ -20,11 +20,11 @@ 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) =>
@@ -91,6 +91,7 @@ function FocusableListComponent<ItemT>(props: Props<ItemT>, ref) {
91
91
  // eslint-disable-next-line unused-imports/no-unused-vars
92
92
  omitPropsPropagation = [],
93
93
  useScrollView = false,
94
+ onScrollToIndexFailed = noop,
94
95
  } = props;
95
96
 
96
97
  useCheckItemIdsForUnique({ componentId: props.id, items: data });
@@ -277,6 +278,7 @@ function FocusableListComponent<ItemT>(props: Props<ItemT>, ref) {
277
278
  "withStateMemory",
278
279
  "useSequentialLoading",
279
280
  "useScrollView",
281
+ "onScrollToIndexFailed",
280
282
  ...omitPropsPropagation,
281
283
  ],
282
284
  R.__
@@ -305,6 +307,7 @@ function FocusableListComponent<ItemT>(props: Props<ItemT>, ref) {
305
307
  {...getFlatListProps(props)}
306
308
  onEndReached={onEndReached}
307
309
  initialNumToRender={initialNumToRender}
310
+ onScrollToIndexFailed={onScrollToIndexFailed}
308
311
  renderItem={renderItem}
309
312
  focused={focused}
310
313
  data={data}
@@ -319,6 +322,7 @@ function FocusableListComponent<ItemT>(props: Props<ItemT>, ref) {
319
322
  renderItem={renderItem}
320
323
  onEndReached={onEndReached}
321
324
  initialNumToRender={initialNumToRender}
325
+ onScrollToIndexFailed={onScrollToIndexFailed}
322
326
  />
323
327
  )}
324
328
  </ChildrenFocusDeactivatorView>