@applicaster/zapp-react-native-ui-components 12.0.0-alpha.3788876021 → 12.0.0-alpha.3823240084

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 (99) hide show
  1. package/Components/BaseFocusable/index.tsx +3 -3
  2. package/Components/Cell/Cell.tsx +30 -9
  3. package/Components/Cell/CellWithFocusable.tsx +23 -9
  4. package/Components/Cell/TvOSCellComponent.tsx +3 -7
  5. package/Components/Focusable/Focusable.tsx +6 -1
  6. package/Components/FocusableGroup/index.tsx +11 -2
  7. package/Components/GeneralContentScreen/utils/__tests__/useCurationAPI.test.js +13 -6
  8. package/Components/GeneralContentScreen/utils/useCurationAPI.ts +1 -1
  9. package/Components/HandlePlayable/HandlePlayable.tsx +3 -0
  10. package/Components/Layout/TV/ScreenContainer.tsx +79 -5
  11. package/Components/Layout/TV/ScreenLayoutContextProvider.tsx +2 -2
  12. package/Components/Layout/TV/__tests__/ScreenContainer.test.tsx +38 -28
  13. package/Components/Layout/TV/__tests__/__snapshots__/ScreenContainer.test.tsx.snap +25 -13
  14. package/Components/Layout/TV/__tests__/__snapshots__/index.test.tsx.snap +10 -50
  15. package/Components/Layout/TV/__tests__/index.test.tsx +20 -75
  16. package/Components/Layout/TV/index.tsx +14 -67
  17. package/Components/Layout/TV/index.web.tsx +33 -0
  18. package/Components/Layout/index.tsx +15 -11
  19. package/Components/MasterCell/DefaultComponents/ActionButton.tsx +4 -1
  20. package/Components/MasterCell/DefaultComponents/BorderContainerView/index.tsx +86 -116
  21. package/Components/MasterCell/DefaultComponents/DynamicBadge.tsx +4 -2
  22. package/Components/MasterCell/DefaultComponents/FocusableView/index.tsx +4 -1
  23. package/Components/MasterCell/DefaultComponents/Image/Image.ios.tsx +5 -3
  24. package/Components/MasterCell/DefaultComponents/ImageBorderContainer/index.ts +57 -0
  25. package/Components/MasterCell/DefaultComponents/ImageContainer/index.tsx +5 -1
  26. package/Components/MasterCell/DefaultComponents/LiveImage/index.tsx +34 -1
  27. package/Components/MasterCell/DefaultComponents/Text/index.tsx +14 -2
  28. package/Components/MasterCell/DefaultComponents/__tests__/image.test.js +1 -1
  29. package/Components/MasterCell/DefaultComponents/__tests__/text.test.tsx +24 -9
  30. package/Components/MasterCell/DefaultComponents/index.ts +2 -0
  31. package/Components/MasterCell/DefaultComponents/tv/ButtonContainerView/index.android.tsx +4 -1
  32. package/Components/MasterCell/DefaultComponents/tv/ButtonContainerView/index.tsx +10 -2
  33. package/Components/MasterCell/SharedUI/CollapsibleTextContainer/index.ts +1 -3
  34. package/Components/MasterCell/dataAdapter.ts +21 -7
  35. package/Components/MasterCell/hooks/useAsyncRendering/index.ts +1 -1
  36. package/Components/MasterCell/index.tsx +5 -3
  37. package/Components/MasterCell/utils/__tests__/insertBetween.test.js +9 -0
  38. package/Components/MasterCell/utils/index.ts +17 -30
  39. package/Components/MeasurmentsPortal/BasicMeasurementsPortal.tsx +11 -7
  40. package/Components/MeasurmentsPortal/MeasurementsPortal.tsx +10 -1
  41. package/Components/Navigator/StackNavigator.tsx +57 -0
  42. package/Components/Navigator/index.ts +1 -0
  43. package/Components/PlayerContainer/PlayerContainer.tsx +14 -6
  44. package/Components/River/ComponentsMap/ComponentsMap.tsx +92 -22
  45. package/Components/River/RefreshControl.tsx +55 -1
  46. package/Components/River/TV/River.tsx +0 -23
  47. package/Components/RouteManager/index.tsx +2 -2
  48. package/Components/Screen/TV/hooks/index.ts +3 -0
  49. package/Components/Screen/TV/hooks/useInitialFocus.ts +70 -0
  50. package/Components/Screen/TV/hooks/useRestoreFocus.ts +22 -0
  51. package/Components/Screen/TV/index.web.tsx +165 -0
  52. package/Components/Screen/__tests__/Screen.test.tsx +3 -0
  53. package/Components/Screen/__tests__/__snapshots__/Screen.test.tsx.snap +4 -0
  54. package/Components/Screen/index.tsx +62 -54
  55. package/Components/Screen/navigationHandler.ts +6 -3
  56. package/Components/ScreenResolver/index.tsx +9 -12
  57. package/Components/Transitioner/Scene.tsx +24 -25
  58. package/Components/Transitioner/Transitioner.tsx +38 -43
  59. package/Components/Transitioner/__tests__/__snapshots__/Scene.test.js.snap +12 -4
  60. package/Components/Transitioner/__tests__/__snapshots__/transitioner.test.js.snap +1 -0
  61. package/Components/VideoLive/LiveImageManager.ts +28 -1
  62. package/Components/VideoLive/PlayerLiveImageComponent.tsx +52 -24
  63. package/Components/VideoLive/__tests__/__snapshots__/PlayerLiveImageComponent.test.tsx.snap +25 -28
  64. package/Components/VideoModal/ModalAnimation/AnimatedPlayerModalWrapper.tsx +2 -14
  65. package/Components/VideoModal/ModalAnimation/AnimatedScrollModal.tsx +73 -48
  66. package/Components/VideoModal/ModalAnimation/AnimatedVideoPlayerComponent.tsx +55 -34
  67. package/Components/VideoModal/ModalAnimation/AnimationComponent.tsx +104 -86
  68. package/Components/VideoModal/ModalAnimation/ModalAnimationContext.tsx +44 -5
  69. package/Components/VideoModal/ModalAnimation/utils.ts +7 -4
  70. package/Components/VideoModal/PlayerDetails.tsx +3 -3
  71. package/Components/VideoModal/PlayerWrapper.tsx +67 -60
  72. package/Components/VideoModal/VideoModal.tsx +17 -17
  73. package/Components/VideoModal/__tests__/PlayerWrapper.test.tsx +7 -0
  74. package/Components/VideoModal/__tests__/__snapshots__/PlayerWrapper.test.tsx.snap +80 -14
  75. package/Components/VideoModal/hooks/useModalSize.ts +10 -12
  76. package/Components/VideoModal/utils.ts +5 -2
  77. package/Components/Viewport/ViewportTracker/ViewportTracker.tsx +31 -40
  78. package/Components/Viewport/ViewportTracker/index.tsx +1 -0
  79. package/Components/Viewport/utils.js +1 -1
  80. package/Components/ZappFrameworkComponents/BarView/BarView.tsx +4 -3
  81. package/Components/default-cell-renderer/__tests__/__snapshots__/defaultCellRenderer.test.tsx.snap +4 -4
  82. package/Contexts/FocusableGroupContext/FocusableGroupContext.ts +3 -0
  83. package/Contexts/FocusableGroupContext/FocusableGroupContextProvider.tsx +16 -0
  84. package/Contexts/FocusableGroupContext/__tests__/FocusableGroupContextProvider.test.tsx +22 -0
  85. package/Contexts/FocusableGroupContext/__tests__/withFocusableContext.test.tsx +26 -0
  86. package/Contexts/FocusableGroupContext/index.ts +7 -0
  87. package/Contexts/FocusableGroupContext/withFocusableContext.tsx +17 -0
  88. package/Contexts/MenuToggleContext/{index.js → index.ts} +16 -0
  89. package/Contexts/ScreenContext/__tests__/__snapshots__/index.test.tsx.snap +3 -0
  90. package/Contexts/ScreenContext/__tests__/index.test.tsx +27 -0
  91. package/Contexts/ScreenContext/index.tsx +94 -25
  92. package/Contexts/ScreenDataContext/index.tsx +20 -0
  93. package/Contexts/ZappPipesContext/ZappPipesEntryContext.ts +1 -1
  94. package/events/index.ts +1 -0
  95. package/package.json +5 -5
  96. package/Components/Layout/TV/TransitionOverlay.tsx +0 -64
  97. /package/Components/FocusableGroup/{index.android.js → index.android.ts} +0 -0
  98. /package/Components/FocusableGroup/{index.ios.js → index.ios.ts} +0 -0
  99. /package/Contexts/{index.js → index.ts} +0 -0
@@ -14,12 +14,13 @@ import { PlayerDetails } from "./PlayerDetails";
14
14
  import { playerDimesionsHack } from "./utils";
15
15
  import { PathnameContext } from "../../Contexts/PathnameContext";
16
16
  import { ScreenContextProvider } from "../../Contexts/ScreenContext";
17
+ import { ROUTE_TYPES } from "@applicaster/zapp-react-native-utils/navigationUtils/routeTypes";
17
18
 
18
19
  import {
19
- AnimationComponent,
20
- ComponentAnimationType,
21
20
  AnimatedScrollModal,
22
21
  AnimatedVideoPlayerComponent,
22
+ AnimationComponent,
23
+ ComponentAnimationType,
23
24
  } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation";
24
25
 
25
26
  type DimensionsT = {
@@ -180,65 +181,71 @@ export const PlayerWrapper = (props: Props) => {
180
181
  [containerDimensions, playerDimesionsHack]
181
182
  );
182
183
 
184
+ const pathname = `${ROUTE_TYPES.VIDEO_MODAL}/${entry?.id}`;
185
+
183
186
  return (
184
- <WrapperView
185
- edges={getEdges(isTablet, isInlineModal) as readonly Edge[]}
186
- style={[
187
- safeAreaStyles(configuration, isTablet),
188
- style,
189
- playerDimesionsHack,
190
- ]}
191
- >
192
- <AnimationComponent
193
- animationType={ComponentAnimationType.moveUpComponent}
194
- additionalData={{ saveArea: true }}
195
- style={directionStyles(isTabletLandscape)}
196
- >
197
- <ScreenContextProvider pathname={"videoModal"}>
198
- <PathnameContext.Provider value={"videoModal"}>
199
- <View
200
- testID={`${entry?.id}-player-container`}
201
- style={[
202
- defaultStyles.playerContainer,
203
- containerDimensions,
204
- containerStyle,
205
- playerDimesionsHack,
206
- ]}
207
- >
208
- <AnimationComponent
209
- animationType={ComponentAnimationType.moveUpComponent}
210
- style={isTabletLandscape ? defaultStyles.flex : undefined}
211
- additionalData={{
212
- useLayoutMeasure: isTabletLandscape,
213
- disableAnimatedComponent: !isTabletLandscape,
214
- resetAnimationValue: isTabletLandscape && docked,
215
- }}
216
- >
217
- <AnimatedVideoPlayerComponent>
218
- {children(childrenStyles)}
219
- </AnimatedVideoPlayerComponent>
220
- </AnimationComponent>
221
- </View>
222
- <AnimatedScrollModal>
223
- {isInlineModal ? (
224
- <AnimationComponent
225
- animationType={ComponentAnimationType.componentFade}
226
- style={defaultStyles.flex}
187
+ <PathnameContext.Provider value={pathname}>
188
+ <ScreenContextProvider pathname={pathname}>
189
+ <WrapperView
190
+ edges={getEdges(isTablet, isInlineModal) as readonly Edge[]}
191
+ style={[
192
+ safeAreaStyles(configuration, isTablet),
193
+ style,
194
+ playerDimesionsHack,
195
+ ]}
196
+ >
197
+ <AnimationComponent
198
+ animationType={ComponentAnimationType.moveUpComponent}
199
+ additionalData={{ saveArea: true }}
200
+ style={[directionStyles(isTabletLandscape), defaultStyles.flex]}
201
+ >
202
+ <PathnameContext.Provider value={pathname}>
203
+ <ScreenContextProvider pathname={pathname}>
204
+ <View
205
+ testID={`${entry?.id}-player-container`}
206
+ style={[
207
+ defaultStyles.playerContainer,
208
+ containerDimensions,
209
+ containerStyle,
210
+ playerDimesionsHack,
211
+ ]}
227
212
  >
228
- <PlayerDetails
229
- configuration={configuration}
230
- style={defaultStyles.playerDetails}
231
- entry={entry}
232
- isTabletLandscape={isTabletLandscape}
233
- />
234
- </AnimationComponent>
235
- ) : (
236
- <View style={defaultStyles.playerDetails} />
237
- )}
238
- </AnimatedScrollModal>
239
- </PathnameContext.Provider>
240
- </ScreenContextProvider>
241
- </AnimationComponent>
242
- </WrapperView>
213
+ <AnimationComponent
214
+ animationType={ComponentAnimationType.moveUpComponent}
215
+ style={isTabletLandscape ? defaultStyles.flex : undefined}
216
+ additionalData={{
217
+ useLayoutMeasure: isTabletLandscape,
218
+ disableAnimatedComponent: !isTabletLandscape,
219
+ resetAnimationValue: isTabletLandscape && docked,
220
+ }}
221
+ >
222
+ <AnimatedVideoPlayerComponent>
223
+ {children(childrenStyles)}
224
+ </AnimatedVideoPlayerComponent>
225
+ </AnimationComponent>
226
+ </View>
227
+ <AnimatedScrollModal>
228
+ {isInlineModal && !docked ? (
229
+ <AnimationComponent
230
+ animationType={ComponentAnimationType.componentFade}
231
+ style={defaultStyles.flex}
232
+ >
233
+ <PlayerDetails
234
+ configuration={configuration}
235
+ style={defaultStyles.playerDetails}
236
+ entry={entry}
237
+ isTabletLandscape={isTabletLandscape}
238
+ />
239
+ </AnimationComponent>
240
+ ) : (
241
+ <View style={defaultStyles.playerDetails} />
242
+ )}
243
+ </AnimatedScrollModal>
244
+ </ScreenContextProvider>
245
+ </PathnameContext.Provider>
246
+ </AnimationComponent>
247
+ </WrapperView>
248
+ </ScreenContextProvider>
249
+ </PathnameContext.Provider>
243
250
  );
244
251
  };
@@ -129,17 +129,17 @@ const VideoModalComponent = () => {
129
129
  const pathname = `${ROUTE_TYPES.VIDEO_MODAL}/${item?.id}`;
130
130
 
131
131
  return (
132
- <AnimatedPlayerModalWrapper
133
- style={[
134
- styles.container,
135
- {
136
- backgroundColor,
137
- },
138
- ]}
139
- >
132
+ <PathnameContext.Provider value={pathname}>
140
133
  <ScreenContextProvider pathname={pathname}>
141
- <PathnameContext.Provider value={pathname}>
142
- {itemIdHooksFinished === item?.id ? (
134
+ {itemIdHooksFinished === item?.id ? (
135
+ <AnimatedPlayerModalWrapper
136
+ style={[
137
+ styles.container,
138
+ {
139
+ backgroundColor,
140
+ },
141
+ ]}
142
+ >
143
143
  <HandlePlayable
144
144
  item={item}
145
145
  isModal={mode !== "PIP"}
@@ -147,14 +147,14 @@ const VideoModalComponent = () => {
147
147
  modalWidth={modalSize.width}
148
148
  mode={mode}
149
149
  />
150
- ) : (
151
- <View style={styles.loaderContainer}>
152
- <Spinner />
153
- </View>
154
- )}
155
- </PathnameContext.Provider>
150
+ </AnimatedPlayerModalWrapper>
151
+ ) : (
152
+ <View style={styles.loaderContainer}>
153
+ <Spinner />
154
+ </View>
155
+ )}
156
156
  </ScreenContextProvider>
157
- </AnimatedPlayerModalWrapper>
157
+ </PathnameContext.Provider>
158
158
  );
159
159
  };
160
160
 
@@ -25,6 +25,13 @@ jest.mock("react-native-gesture-handler");
25
25
 
26
26
  jest.mock("../PlayerDetails", () => ({ PlayerDetails: View }));
27
27
 
28
+ jest.mock(
29
+ "@applicaster/zapp-react-native-utils/reactHooks/screen/useScreenContext",
30
+ () => ({
31
+ useScreenContext: jest.fn().mockReturnValue({ screen: {}, entry: {} }),
32
+ })
33
+ );
34
+
28
35
  jest.mock("@applicaster/zapp-react-native-utils/reactHooks/device", () => ({
29
36
  useIsTablet,
30
37
  }));
@@ -42,9 +42,14 @@ exports[`PlayerWrapper renders inline 1`] = `
42
42
  }
43
43
  animationType="moveUpComponent"
44
44
  style={
45
- Object {
46
- "flexDirection": "column",
47
- }
45
+ Array [
46
+ Object {
47
+ "flexDirection": "column",
48
+ },
49
+ Object {
50
+ "flex": 1,
51
+ },
52
+ ]
48
53
  }
49
54
  >
50
55
  <View
@@ -67,12 +72,34 @@ exports[`PlayerWrapper renders inline 1`] = `
67
72
  testID="test-player-container"
68
73
  />
69
74
  <View
75
+ animationType="componentFade"
70
76
  style={
71
77
  Object {
72
78
  "flex": 1,
73
79
  }
74
80
  }
75
- />
81
+ >
82
+ <View
83
+ configuration={
84
+ Object {
85
+ "tablet_landscape_player_container_background_color": "red",
86
+ "tablet_landscape_sidebar_width": "35%",
87
+ }
88
+ }
89
+ entry={
90
+ Object {
91
+ "id": "test",
92
+ }
93
+ }
94
+ isTabletLandscape={false}
95
+ style={
96
+ Object {
97
+ "flex": 1,
98
+ "paddingTop": 20,
99
+ }
100
+ }
101
+ />
102
+ </View>
76
103
  </View>
77
104
  </RNCSafeAreaView>
78
105
  </RNCSafeAreaProvider>
@@ -120,9 +147,14 @@ exports[`PlayerWrapper renders inline and docked 1`] = `
120
147
  }
121
148
  animationType="moveUpComponent"
122
149
  style={
123
- Object {
124
- "flexDirection": "column",
125
- }
150
+ Array [
151
+ Object {
152
+ "flexDirection": "column",
153
+ },
154
+ Object {
155
+ "flex": 1,
156
+ },
157
+ ]
126
158
  }
127
159
  >
128
160
  <View
@@ -148,6 +180,7 @@ exports[`PlayerWrapper renders inline and docked 1`] = `
148
180
  style={
149
181
  Object {
150
182
  "flex": 1,
183
+ "paddingTop": 20,
151
184
  }
152
185
  }
153
186
  />
@@ -198,9 +231,14 @@ exports[`PlayerWrapper renders inline on tablet in landscape orientation 1`] = `
198
231
  }
199
232
  animationType="moveUpComponent"
200
233
  style={
201
- Object {
202
- "flexDirection": "row",
203
- }
234
+ Array [
235
+ Object {
236
+ "flexDirection": "row",
237
+ },
238
+ Object {
239
+ "flex": 1,
240
+ },
241
+ ]
204
242
  }
205
243
  >
206
244
  <View
@@ -239,12 +277,34 @@ exports[`PlayerWrapper renders inline on tablet in landscape orientation 1`] = `
239
277
  />
240
278
  </View>
241
279
  <View
280
+ animationType="componentFade"
242
281
  style={
243
282
  Object {
244
283
  "flex": 1,
245
284
  }
246
285
  }
247
- />
286
+ >
287
+ <View
288
+ configuration={
289
+ Object {
290
+ "tablet_landscape_player_container_background_color": "red",
291
+ "tablet_landscape_sidebar_width": "35%",
292
+ }
293
+ }
294
+ entry={
295
+ Object {
296
+ "id": "test",
297
+ }
298
+ }
299
+ isTabletLandscape={true}
300
+ style={
301
+ Object {
302
+ "flex": 1,
303
+ "paddingTop": 20,
304
+ }
305
+ }
306
+ />
307
+ </View>
248
308
  </View>
249
309
  </RNCSafeAreaView>
250
310
  </RNCSafeAreaProvider>
@@ -292,9 +352,14 @@ exports[`PlayerWrapper renders properly 1`] = `
292
352
  }
293
353
  animationType="moveUpComponent"
294
354
  style={
295
- Object {
296
- "flexDirection": "column",
297
- }
355
+ Array [
356
+ Object {
357
+ "flexDirection": "column",
358
+ },
359
+ Object {
360
+ "flex": 1,
361
+ },
362
+ ]
298
363
  }
299
364
  >
300
365
  <View
@@ -320,6 +385,7 @@ exports[`PlayerWrapper renders properly 1`] = `
320
385
  style={
321
386
  Object {
322
387
  "flex": 1,
388
+ "paddingTop": 20,
323
389
  }
324
390
  }
325
391
  />
@@ -1,5 +1,4 @@
1
1
  import * as React from "react";
2
- import { Dimensions } from "react-native";
3
2
  import { useIsTabletLandscape } from "@applicaster/zapp-react-native-utils/reactHooks/device/useMemoizedIsTablet";
4
3
  import {
5
4
  addOrientationChangeListener,
@@ -9,11 +8,10 @@ import {
9
8
  } from "@applicaster/zapp-react-native-utils/appUtils/orientationHelper";
10
9
 
11
10
  import { getXray } from "@applicaster/zapp-react-native-utils/logger";
11
+ import { useSafeAreaFrame } from "react-native-safe-area-context";
12
12
 
13
13
  const { Logger } = getXray();
14
14
 
15
- const { width: WIDTH, height: HEIGHT } = Dimensions.get("window");
16
-
17
15
  const logger = new Logger(
18
16
  "hooks",
19
17
  "zapp-react-native-ui-components/Components/VideoModal"
@@ -24,20 +22,18 @@ type Size = {
24
22
  height: number | string;
25
23
  };
26
24
 
27
- const MODAL_SIZE_FOR_PORTRAIT: Size = {
28
- width: WIDTH,
29
- height: HEIGHT,
30
- };
31
-
32
25
  const MODAL_SIZE_FOR_LANDSCAPE: Size = {
33
26
  width: "100%",
34
27
  height: "100%",
35
28
  };
36
29
 
37
30
  export const useModalSize = (): Size => {
38
- const [modalSize, setModalSize] = React.useState<Size>(
39
- MODAL_SIZE_FOR_PORTRAIT
40
- );
31
+ const frame = useSafeAreaFrame();
32
+
33
+ const [modalSize, setModalSize] = React.useState<Size>({
34
+ width: frame.width,
35
+ height: frame.height,
36
+ });
41
37
 
42
38
  const setNewModalSize = React.useCallback((newSize, log) => {
43
39
  setModalSize((oldSize) => {
@@ -90,7 +86,9 @@ export const useModalSize = (): Size => {
90
86
  toOrientation === ORIENTATIONS.landscapeSensor;
91
87
 
92
88
  setNewModalSize(
93
- isLandscape ? MODAL_SIZE_FOR_LANDSCAPE : MODAL_SIZE_FOR_PORTRAIT,
89
+ isLandscape
90
+ ? MODAL_SIZE_FOR_LANDSCAPE
91
+ : { width: frame.width, height: frame.height },
94
92
  `useModalSize: set modal size ${
95
93
  isLandscape ? "landscape" : "portrait"
96
94
  } for orientation: ${to}`
@@ -33,8 +33,11 @@ export const useConfiguration = () => {
33
33
  ...pluginConfiguration,
34
34
  });
35
35
 
36
- const { minimised_height, minimised_height_tablet, modal_background_color } =
37
- config;
36
+ const {
37
+ minimised_height = 0,
38
+ minimised_height_tablet = 0,
39
+ modal_background_color,
40
+ } = config;
38
41
 
39
42
  const minimisedHeight = useIsTablet()
40
43
  ? minimised_height_tablet
@@ -6,23 +6,23 @@ import { callOnChildren } from "../utils";
6
6
 
7
7
  export function ViewportTracker(props) {
8
8
  const viewportEvents = useViewportEventsContext();
9
- const { children } = props;
10
- const [width, setWidth] = React.useState(0);
11
- const [height, setHeight] = React.useState(0);
12
- const [offsetX, setOffsetX] = React.useState(0);
13
- const [offsetY, setOffsetY] = React.useState(0);
14
9
  const [nodeHandle, setNodeHandle] = React.useState(null);
15
10
 
16
- const assignRef = React.useCallback(
17
- (ref) => {
18
- callOnChildren(children, "ref", ref);
19
- setNodeHandle(findNodeHandle(ref));
20
- },
21
- [children]
22
- );
11
+ const childrenRef = React.useRef(props.children);
12
+
13
+ const dimensionsRef = React.useRef({ width: 0, height: 0 });
14
+ const offsetRef = React.useRef({ offsetX: 0, offsetY: 0 });
15
+
16
+ const assignRef = React.useCallback((ref) => {
17
+ childrenRef.current?.ref?.(ref);
18
+ setNodeHandle(findNodeHandle(ref));
19
+ }, []);
23
20
 
24
21
  const onViewportChange = React.useCallback(
25
- (event, shouldMeasureLayout = true) => {
22
+ ({
23
+ event = { ...dimensionsRef.current, ...offsetRef.current },
24
+ shouldMeasureLayout = true,
25
+ } = {}) => {
26
26
  if (nodeHandle && event?.width > 0 && event?.height > 0) {
27
27
  viewportEvents?.notify?.({
28
28
  parentHandle: nodeHandle,
@@ -36,54 +36,45 @@ export function ViewportTracker(props) {
36
36
 
37
37
  const onLayout = React.useCallback(
38
38
  (event) => {
39
- callOnChildren(children, "onLayout", event);
40
- setWidth(event?.nativeEvent?.layout?.width);
41
- setHeight(event?.nativeEvent?.layout?.height);
39
+ callOnChildren(childrenRef.current, "onLayout", event);
40
+ dimensionsRef.current = event?.nativeEvent?.layout;
42
41
 
43
- onViewportChange({
44
- width: event?.nativeEvent?.layout?.width,
45
- height: event?.nativeEvent?.layout?.height,
46
- offsetX,
47
- offsetY,
48
- });
42
+ onViewportChange();
49
43
  },
50
- [offsetX, offsetY, children, onViewportChange]
44
+ [onViewportChange]
51
45
  );
52
46
 
53
47
  const onContentSizeChange = React.useCallback(
54
48
  (contentWidth, contentHeight) => {
55
49
  callOnChildren(
56
- children,
50
+ childrenRef.current,
57
51
  "onContentSizeChange",
58
52
  contentWidth,
59
53
  contentHeight
60
54
  );
61
55
 
62
- onViewportChange({ width, height, offsetX, offsetY });
56
+ onViewportChange();
63
57
  },
64
- [onViewportChange, children, width, height, offsetX, offsetY]
58
+ [onViewportChange]
65
59
  );
66
60
 
67
61
  const onScroll = React.useCallback(
68
62
  (event) => {
69
- callOnChildren(children, "onScroll", event);
70
- setOffsetX(event?.nativeEvent?.contentOffset?.x);
71
- setOffsetY(event?.nativeEvent?.contentOffset?.y);
63
+ callOnChildren(childrenRef.current, "onScroll", event);
64
+ offsetRef.current = event?.nativeEvent?.contentOffset;
72
65
 
73
- onViewportChange(
74
- {
75
- width,
76
- height,
77
- offsetX: event?.nativeEvent?.contentOffset?.x,
78
- offsetY: event?.nativeEvent?.contentOffset?.y,
79
- },
80
- false
81
- );
66
+ onViewportChange({
67
+ shouldMeasureLayout: false,
68
+ });
82
69
  },
83
- [onViewportChange, width, height, children]
70
+ [onViewportChange]
84
71
  );
85
72
 
86
- return React.cloneElement(React.Children.only(children), {
73
+ React.useEffect(() => {
74
+ childrenRef.current = props.children;
75
+ }, [props.children]);
76
+
77
+ return React.cloneElement(React.Children.only(props.children), {
87
78
  ref: assignRef,
88
79
  onLayout,
89
80
  onContentSizeChange,
@@ -6,6 +6,7 @@ import { ViewportEventContext, ViewportEvents } from "../ViewportEvents";
6
6
  type Props = {
7
7
  viewportEventsManager?: any;
8
8
  children: React.ReactNode;
9
+ flatListRef?: any; // this ref is used to bind to children component
9
10
  };
10
11
 
11
12
  export function ViewportTracker(props: Props) {
@@ -2,7 +2,7 @@ import * as React from "react";
2
2
 
3
3
  export function callOnChildren(children, method, ...args) {
4
4
  const childMethod = React.Children.only(children).props[method];
5
- childMethod && childMethod(...args);
5
+ typeof childMethod === "function" && childMethod?.(...args);
6
6
  }
7
7
 
8
8
  export function isInViewport(
@@ -1,5 +1,6 @@
1
1
  import React from "react";
2
- import { View, StyleSheet } from "react-native";
2
+ import { StyleSheet } from "react-native";
3
+ import { SafeAreaView } from "react-native-safe-area-context";
3
4
 
4
5
  import { useIsRTL } from "@applicaster/zapp-react-native-utils/localizationUtils";
5
6
  import CloseButton from "./Buttons/CloseButton";
@@ -44,11 +45,11 @@ const BarView = ({ screenStyles, barState = defaultState }: Props) => {
44
45
  );
45
46
 
46
47
  return (
47
- <View style={[style.view, isRTL ? style.rtlStyle : {}]}>
48
+ <SafeAreaView style={[style.view, isRTL ? style.rtlStyle : {}]}>
48
49
  {backButton}
49
50
  <BarTitle title={barState.title} screenStyles={screenStyles} />
50
51
  {closeButton}
51
- </View>
52
+ </SafeAreaView>
52
53
  );
53
54
  };
54
55
 
@@ -16,9 +16,9 @@ exports[`DefaultCellRenderer returns a react component and it renders correctly
16
16
  store={null}
17
17
  style={
18
18
  Object {
19
- "backgroundColor": "#CCC",
19
+ "backgroundColor": "transparent",
20
20
  "margin": 12,
21
- "opacity": 0.6,
21
+ "opacity": 1,
22
22
  "width": 169,
23
23
  }
24
24
  }
@@ -105,7 +105,7 @@ exports[`DefaultCellRenderer returns a react component for LG TVs 1`] = `
105
105
  store={null}
106
106
  style={
107
107
  Object {
108
- "backgroundColor": "rgba(252,70,27,1.0)",
108
+ "backgroundColor": "rgba(47,47,47,1.0)",
109
109
  "borderRadius": 4,
110
110
  "flex": 1,
111
111
  "overflow": "hidden",
@@ -238,7 +238,7 @@ exports[`DefaultCellRenderer returns a react component for Samsung TVs 1`] = `
238
238
  store={null}
239
239
  style={
240
240
  Object {
241
- "backgroundColor": "rgba(252,70,27,1.0)",
241
+ "backgroundColor": "rgba(47,47,47,1.0)",
242
242
  "borderRadius": 4,
243
243
  "flex": 1,
244
244
  "overflow": "hidden",
@@ -0,0 +1,3 @@
1
+ import * as React from "react";
2
+
3
+ export const FocusableGroupContext = React.createContext<string | null>(null);
@@ -0,0 +1,16 @@
1
+ import * as React from "react";
2
+ import { FocusableGroupContext } from "./FocusableGroupContext";
3
+
4
+ type ProviderArgs = {
5
+ id: string;
6
+ children: React.ReactNode;
7
+ };
8
+
9
+ export const FocusableGroupContextProvider = ({
10
+ id,
11
+ children,
12
+ }: ProviderArgs) => (
13
+ <FocusableGroupContext.Provider value={id}>
14
+ {children}
15
+ </FocusableGroupContext.Provider>
16
+ );
@@ -0,0 +1,22 @@
1
+ import React, { useContext } from "react";
2
+ import { Text } from "react-native";
3
+ import { render } from "@testing-library/react-native";
4
+ import { FocusableGroupContextProvider, FocusableGroupContext } from "../";
5
+
6
+ const MockComponent = () => {
7
+ const focusableContext = useContext(FocusableGroupContext) || "default";
8
+
9
+ return <Text testID={focusableContext} />;
10
+ };
11
+
12
+ describe("FocusableGroupContextProvider", () => {
13
+ it("should provide focusable context to the wrapped component", () => {
14
+ const { getByTestId } = render(
15
+ <FocusableGroupContextProvider id="testId">
16
+ <MockComponent />
17
+ </FocusableGroupContextProvider>
18
+ );
19
+
20
+ expect(getByTestId("testId")).toBeTruthy();
21
+ });
22
+ });