@applicaster/zapp-react-native-ui-components 12.0.0-alpha.4081044014 → 12.0.0-alpha.4102526423

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 (23) hide show
  1. package/Components/Cell/Cell.tsx +1 -8
  2. package/Components/Focusable/index.android.tsx +9 -15
  3. package/Components/FocusableList/FocusableChild.ts +2 -2
  4. package/Components/FocusableList/index.tsx +12 -11
  5. package/Components/FocusableScrollView/index.tsx +1 -1
  6. package/Components/Image/Image.android.tsx +1 -1
  7. package/Components/MasterCell/DefaultComponents/ActionButton.tsx +7 -11
  8. package/Components/MasterCell/DefaultComponents/CellBadge/index.tsx +1 -6
  9. package/Components/MasterCell/utils/index.ts +4 -3
  10. package/Components/PlayerContainer/PlayerContainer.tsx +13 -11
  11. package/Components/VideoModal/ModalAnimation/AnimatedPlayerModalWrapper.tsx +9 -3
  12. package/Components/VideoModal/ModalAnimation/AnimatedScrollModal.tsx +44 -68
  13. package/Components/VideoModal/ModalAnimation/AnimatedVideoPlayerComponent.tsx +8 -15
  14. package/Components/VideoModal/ModalAnimation/AnimationComponent.tsx +24 -19
  15. package/Components/ZappFrameworkComponents/BarView/BarView.tsx +1 -4
  16. package/Components/ZappFrameworkComponents/BarView/Buttons/BackButton.tsx +2 -7
  17. package/Components/ZappFrameworkComponents/BarView/Buttons/CloseButton.tsx +2 -7
  18. package/Components/ZappFrameworkComponents/Buttons/ActionButton.tsx +4 -9
  19. package/Contexts/CachedDimensionsContext/index.ts +9 -13
  20. package/Contexts/ScreenContext/index.tsx +1 -6
  21. package/package.json +5 -5
  22. package/Components/Focusable/__tests__/index.android.test.tsx +0 -72
  23. package/Components/ZappFrameworkComponents/BarView/__tests__/BarView.test.tsx +0 -87
@@ -276,20 +276,13 @@ export class CellComponent extends React.Component<Props, State> {
276
276
  skipFocusManagerRegistration={skipFocusManagerRegistration}
277
277
  >
278
278
  {(focused, event) => {
279
- const isFocused = this.isCellFocused(focused);
280
-
281
- if (isFocused) {
282
- const accessibilityManager = AccessibilityManager.getInstance();
283
- accessibilityManager.readText({ text: item.title });
284
- }
285
-
286
279
  return (
287
280
  <FocusableCell
288
281
  {...{
289
282
  index,
290
283
  CellRenderer,
291
284
  item,
292
- focused: isFocused,
285
+ focused: this.isCellFocused(focused),
293
286
  scrollTo: this.scrollToIndex(event),
294
287
  behavior,
295
288
  }}
@@ -128,10 +128,7 @@ function FocusableComponent(props: Props, forwardedRef) {
128
128
 
129
129
  const _onBlur = React.useCallback(
130
130
  (ref, options = {}) => {
131
- if (ref.props.id !== focusManager.focusedId) {
132
- setFocused(false);
133
- }
134
-
131
+ setFocused(false);
135
132
  onBlur?.(ref, options);
136
133
  },
137
134
  [onBlur]
@@ -151,14 +148,15 @@ function FocusableComponent(props: Props, forwardedRef) {
151
148
  [isRTL, nextFocusDown, nextFocusUp, nextFocusLeft, nextFocusRight]
152
149
  );
153
150
 
154
- const contextState = React.useMemo(() => {
155
- return {
151
+ const contextState = React.useMemo(
152
+ () => ({
156
153
  focused,
157
154
  ...parentFocus,
158
155
  ref: touchableRef,
159
156
  setIsFocusable,
160
- };
161
- }, [parentFocus, focused]);
157
+ }),
158
+ [parentFocus, focused]
159
+ );
162
160
 
163
161
  return (
164
162
  <Touchable
@@ -175,13 +173,9 @@ function FocusableComponent(props: Props, forwardedRef) {
175
173
  {...parentFocus}
176
174
  >
177
175
  <FocusableContext.Provider value={contextState}>
178
- {React.useMemo(
179
- () =>
180
- typeof children === "function"
181
- ? children(focused, parentFocus, touchableRef)
182
- : children,
183
- [children, focused, parentFocus]
184
- )}
176
+ {typeof children === "function"
177
+ ? children(focused, parentFocus, touchableRef)
178
+ : children}
185
179
  </FocusableContext.Provider>
186
180
  </Touchable>
187
181
  );
@@ -31,14 +31,14 @@ const useParentFocus = (
31
31
 
32
32
  function FocusableChildComponent(props) {
33
33
  const { setIsFocusable, ...focusableContext } = useFocusable();
34
- const focused = useCellState(props.id);
35
-
36
34
  const parentFocus = useParentFocus(props, focusableContext);
37
35
 
38
36
  const onLoadFailed = React.useCallback(() => {
39
37
  setIsFocusable(false);
40
38
  }, []);
41
39
 
40
+ const focused = useCellState(props.id);
41
+
42
42
  return props.renderItem({
43
43
  ...props,
44
44
  focused,
@@ -88,7 +88,6 @@ function FocusableListComponent<ItemT>(props: Props<ItemT>, ref) {
88
88
  data = [],
89
89
  // eslint-disable-next-line unused-imports/no-unused-vars
90
90
  onAllComponentsLoaded, // TODO: re-implement it
91
- omitPropsPropagation = [],
92
91
  } = props;
93
92
 
94
93
  useCheckItemIdsForUnique({ componentId: props.id, items: data });
@@ -253,9 +252,9 @@ function FocusableListComponent<ItemT>(props: Props<ItemT>, ref) {
253
252
  ]
254
253
  );
255
254
 
256
- const getFlatListProps = React.useCallback(
257
- R.omit(
258
- [
255
+ const flatListProps = React.useMemo(
256
+ () =>
257
+ R.omit([
259
258
  "onListElementFocus",
260
259
  "onListElementPress",
261
260
  "onListElementPressOut",
@@ -268,17 +267,17 @@ function FocusableListComponent<ItemT>(props: Props<ItemT>, ref) {
268
267
  "focusableItemProps",
269
268
  "renderItem",
270
269
  "extraChildrenData",
270
+ "extraData",
271
+ "keyExtractor",
271
272
  "onAllComponentsLoaded",
272
273
  "focused",
273
274
  "id",
274
275
  "initialFocusDirection",
275
276
  "withStateMemory",
276
277
  "useSequentialLoading",
277
- ...omitPropsPropagation,
278
- ],
279
- R.__
280
- ),
281
- [omitPropsPropagation]
278
+ ...(props.omitPropsPropagation || []),
279
+ ])(props),
280
+ [props]
282
281
  );
283
282
 
284
283
  const onEndReached = React.useCallback(
@@ -290,7 +289,7 @@ function FocusableListComponent<ItemT>(props: Props<ItemT>, ref) {
290
289
 
291
290
  const initialNumToRender = toFiniteNumberWithDefault(
292
291
  10,
293
- props.initialNumToRender
292
+ flatListProps.initialNumToRender
294
293
  );
295
294
 
296
295
  return (
@@ -299,10 +298,12 @@ function FocusableListComponent<ItemT>(props: Props<ItemT>, ref) {
299
298
  <FlatList
300
299
  focusable={false}
301
300
  scrollEnabled={false}
301
+ extraData={props.extraData}
302
302
  ref={ref}
303
- {...getFlatListProps(props)}
303
+ {...flatListProps}
304
304
  renderItem={renderItem}
305
305
  onEndReached={onEndReached}
306
+ keyExtractor={props.keyExtractor}
306
307
  initialNumToRender={initialNumToRender}
307
308
  />
308
309
  </ChildrenFocusDeactivatorView>
@@ -284,7 +284,7 @@ function FocusableScrollViewComponent(props: Props, ref) {
284
284
  };
285
285
 
286
286
  return (
287
- <View key={id} onLayout={onItemLayout}>
287
+ <View onLayout={onItemLayout}>
288
288
  <Focusable
289
289
  {...nextFocus}
290
290
  onFocus={(element, direction) =>
@@ -8,5 +8,5 @@ import { useImageSource } from "./utils";
8
8
  export const QBImage = (props: FastImageProps) => {
9
9
  const source = useImageSource(props.source);
10
10
 
11
- return <FastImage useLastImageAsDefaultSource {...props} source={source} />;
11
+ return <FastImage {...props} source={source} />;
12
12
  };
@@ -66,24 +66,20 @@ export function ActionButton(props: Props) {
66
66
  );
67
67
 
68
68
  useEffect(() => {
69
- if (!((actionDisabled || !actionContext) && actionState !== null)) {
70
- setActionState(actionContext.initialEntryState(item));
71
- }
72
- }, [actionDisabled, item?.id, actionContext, action]);
69
+ if (actionDisabled || !actionContext) return;
70
+
71
+ setActionState(actionContext.initialEntryState(item));
72
+ }, [actionDisabled, item?.id, actionContext]);
73
73
 
74
74
  const onPress = useCallback(() => {
75
75
  actionContext.invokeAction(item, {
76
- updateState: (state) => {
77
- setActionState(state);
78
- },
76
+ updateState: setActionState,
79
77
  });
80
- }, [actionState, actionContext?.state, item?.id]);
78
+ }, [actionState, actionContext?.state, setActionState, item?.id]);
81
79
 
82
80
  useEffect(() => {
83
81
  if (typeof actionContext?.addListener === "function") {
84
- return actionContext?.addListener(String(item.id), (state) => {
85
- setActionState(state);
86
- });
82
+ return actionContext?.addListener(item.id as string, setActionState);
87
83
  }
88
84
  }, [item?.id]);
89
85
 
@@ -3,7 +3,6 @@ import {
3
3
  ifElseFocusedSelected,
4
4
  ifElseSelected,
5
5
  } from "@applicaster/zapp-react-native-utils/cellUtils";
6
- import { platformSelect } from "@applicaster/zapp-react-native-utils/reactUtils";
7
6
 
8
7
  import { getPositionStyles } from "./utils";
9
8
 
@@ -32,11 +31,7 @@ export const CellBadge = ({
32
31
  return {
33
32
  type: View, // Cell badge view
34
33
  style: {
35
- flex: platformSelect({
36
- tvos: 0,
37
- android_tv: 0,
38
- default: 1,
39
- }),
34
+ flex: 1,
40
35
  position: "absolute",
41
36
  ...getPositionStyles(position, {
42
37
  width: value("cell_badge_width"),
@@ -53,9 +53,10 @@ function resolveColorForProp(entry, style, colorProp) {
53
53
  const colorFromProp = style[colorProp];
54
54
  const nestedEntryValue = R.path(colorFromProp.split("."), entry);
55
55
 
56
- const color = colorFromProp.replace(".00", "").replace(".0", ""); // https://github.com/dreamyguy/validate-color/issues/44
57
-
58
- if (nestedEntryValue === undefined && !validateColor(color)) {
56
+ if (
57
+ nestedEntryValue === undefined &&
58
+ !validateColor(colorFromProp.replace(".00", "")) // https://github.com/dreamyguy/validate-color/issues/44
59
+ ) {
59
60
  logWarning(colorFromProp, style, entry, nestedEntryValue);
60
61
  }
61
62
 
@@ -362,15 +362,21 @@ const PlayerContainerComponent = (props: Props) => {
362
362
  const toggleFullscreen = (event) => {
363
363
  const { fullscreen = false } = event || {};
364
364
 
365
- setTimeout(() => {
366
- if (fullscreen) {
367
- navigator.fullscreenVideoModal();
365
+ if (fullscreen) {
366
+ // in order to avoid UI glitches with player we have to start re-render ealier and then start real rotation
367
+ navigator.fullscreenVideoModal();
368
+
369
+ setTimeout(() => {
368
370
  playerEvent("onFullscreenPlayerWillPresent");
369
- } else {
370
- navigator.maximiseVideoModal();
371
+ });
372
+ } else {
373
+ // in order to avoid UI glitches with player we have to start re-render ealier and then start real rotation
374
+ navigator.maximiseVideoModal();
375
+
376
+ setTimeout(() => {
371
377
  playerEvent("onFullscreenPlayerWillDismiss");
372
- }
373
- });
378
+ });
379
+ }
374
380
  };
375
381
 
376
382
  const onCellTap = (entry) => {
@@ -465,10 +471,6 @@ const PlayerContainerComponent = (props: Props) => {
465
471
 
466
472
  if (mode === VideoModalMode.FULLSCREEN) {
467
473
  toggleFullscreen({ fullscreen: false });
468
-
469
- if (!isModal) {
470
- playerManager.closeNativePlayer();
471
- }
472
474
  }
473
475
 
474
476
  return !!(
@@ -45,9 +45,15 @@ export const AnimatedPlayerModalWrapper = (props: Props) => {
45
45
  }
46
46
 
47
47
  React.useEffect(() => {
48
- (playerAnimationState === PlayerAnimationStateEnum.minimize ||
49
- playerAnimationState === PlayerAnimationStateEnum.maximaze) &&
50
- setStartComponentsAnimation(true);
48
+ const translateYListener = translateY.addListener(() => {
49
+ (playerAnimationState === PlayerAnimationStateEnum.minimize ||
50
+ playerAnimationState === PlayerAnimationStateEnum.maximaze) &&
51
+ setStartComponentsAnimation(true);
52
+ });
53
+
54
+ return () => {
55
+ translateYListener && translateY.removeListener(translateYListener);
56
+ };
51
57
  }, [playerAnimationState]);
52
58
 
53
59
  return (
@@ -61,32 +61,29 @@ export const AnimatedScrollModalComponent = ({ children }: Props) => {
61
61
  setStartComponentsAnimation,
62
62
  } = useModalAnimationContext();
63
63
 
64
- const [enableGesture, setIEnableGesture] = React.useState<boolean>(true);
65
64
  const { isLanguageOverlayVisible } = React.useContext(PlayerContainerContext);
66
65
 
67
66
  const { maximiseVideoModal, minimiseVideoModal, videoModalState } =
68
67
  useNavigation();
69
68
 
70
- const { mode: videoModalMode, item: videoModalItem } = videoModalState;
71
- const isMaximazedModal = videoModalMode === "MAXIMIZED";
72
- const isMinimizedModal = videoModalMode === "MINIMIZED";
73
- const previousItemId = usePrevious(videoModalItem?.id);
69
+ const isMaximazedModal = videoModalState.mode === "MAXIMIZED";
70
+ const isMinimizedModal = videoModalState.mode === "MINIMIZED";
71
+ const previousItemId = usePrevious(videoModalState.item?.id);
74
72
 
75
73
  const isNotMinimizeMaximazeAnimation =
76
74
  playerAnimationState !== PlayerAnimationStateEnum.minimize &&
77
75
  playerAnimationState !== PlayerAnimationStateEnum.maximaze;
78
76
 
79
77
  const isEnablePanGesture =
80
- enableGesture &&
81
78
  !isLanguageOverlayVisible &&
82
79
  isNotMinimizeMaximazeAnimation &&
83
80
  (isMaximazedModal || isMinimizedModal);
84
81
 
85
82
  const isAudioItem = React.useMemo(
86
83
  () =>
87
- videoModalItem?.content?.type?.includes?.("audio") ||
88
- videoModalItem?.type?.value === "audio",
89
- [videoModalItem]
84
+ videoModalState.item?.content?.type?.includes?.("audio") ||
85
+ videoModalState.item?.type?.value === "audio",
86
+ [videoModalState.item]
90
87
  );
91
88
 
92
89
  // Refs for components
@@ -117,7 +114,7 @@ export const AnimatedScrollModalComponent = ({ children }: Props) => {
117
114
  const preparedTranslationY =
118
115
  Math.abs(translationY) - lastScrollYValue.current;
119
116
 
120
- if (videoModalMode === "MAXIMIZED") {
117
+ if (videoModalState.mode === "MAXIMIZED") {
121
118
  const endOffsetY =
122
119
  lastSnap + preparedTranslationY + dragToss * velocityY + 150;
123
120
 
@@ -164,38 +161,22 @@ export const AnimatedScrollModalComponent = ({ children }: Props) => {
164
161
  resetPlayerAnimationState();
165
162
  }
166
163
  },
167
- [lastSnap, modalSnapPoints, playerAnimationState, videoModalMode]
164
+ [lastSnap, modalSnapPoints, playerAnimationState, videoModalState.mode]
168
165
  );
169
166
 
170
167
  const onScroll = React.useCallback(({ nativeEvent }) => {
171
168
  scrollPosition.current = nativeEvent.contentOffset.y;
172
169
  }, []);
173
170
 
174
- // Workaround for onMomentumScrollEnd issue
175
- // https://github.com/facebook/react-native/issues/32696#issuecomment-1104217223
176
- const canMomentum = React.useRef(false);
177
-
178
- const onMomentumScrollBegin = React.useCallback(() => {
179
- canMomentum.current = true;
180
- }, []);
181
-
182
171
  const onMomentumScrollEnd = React.useCallback(
183
172
  ({ nativeEvent }) => {
184
- if (canMomentum.current && !isActiveGesture) {
185
- if (nativeEvent.contentOffset.y === 0) {
186
- resetScrollAnimatedValues(
187
- lastScrollY,
188
- lastScrollYValue,
189
- dragScrollY,
190
- dragVideoPlayerY
191
- );
192
-
193
- setIEnableGesture(true);
194
- } else {
195
- setIEnableGesture(false);
196
- }
197
-
198
- canMomentum.current = false;
173
+ if (nativeEvent.contentOffset.y === 0 && !isActiveGesture) {
174
+ resetScrollAnimatedValues(
175
+ lastScrollY,
176
+ lastScrollYValue,
177
+ dragScrollY,
178
+ dragVideoPlayerY
179
+ );
199
180
  }
200
181
  },
201
182
  [isActiveGesture]
@@ -215,17 +196,10 @@ export const AnimatedScrollModalComponent = ({ children }: Props) => {
215
196
  }, []);
216
197
 
217
198
  React.useEffect(() => {
218
- const { mode, previousMode, item } = videoModalState;
219
-
220
199
  if (
221
- mode === "MAXIMIZED" &&
222
- !enableGesture &&
223
- scrollPosition.current === 0
200
+ videoModalState.mode === "MINIMIZED" &&
201
+ videoModalState.previousMode === "MAXIMIZED"
224
202
  ) {
225
- setIEnableGesture(true);
226
- }
227
-
228
- if (mode === "MINIMIZED" && previousMode === "MAXIMIZED") {
229
203
  // set animation to the minimize values if moving from the player to another screen
230
204
  if (playerAnimationState === null) {
231
205
  setScrollModalAnimatedValue(
@@ -240,17 +214,22 @@ export const AnimatedScrollModalComponent = ({ children }: Props) => {
240
214
  dragScrollY,
241
215
  dragVideoPlayerY
242
216
  );
217
+ } else {
218
+ resetPlayerAnimationState();
243
219
  }
244
- } else if (
245
- playerAnimationState === null &&
246
- ((previousItemId === item?.id &&
247
- mode === "MAXIMIZED" &&
248
- (previousMode === "MINIMIZED" || previousMode === "MAXIMIZED")) ||
249
- (previousItemId !== item?.id && mode !== "FULLSCREEN"))
220
+ }
221
+
222
+ if (
223
+ (videoModalState.mode === "MAXIMIZED" &&
224
+ videoModalState.previousMode === "MINIMIZED" &&
225
+ previousItemId === videoModalState.item?.id) ||
226
+ (previousItemId !== videoModalState.item?.id &&
227
+ videoModalState.mode !== "FULLSCREEN")
250
228
  ) {
251
229
  setPlayerAnimationState(PlayerAnimationStateEnum.maximaze);
230
+ setTimeout(() => resetPlayerAnimationState());
252
231
  }
253
- }, [videoModalState]);
232
+ }, [videoModalState, previousItemId]);
254
233
 
255
234
  React.useEffect(() => {
256
235
  if (playerAnimationState === PlayerAnimationStateEnum.minimize) {
@@ -275,22 +254,22 @@ export const AnimatedScrollModalComponent = ({ children }: Props) => {
275
254
  translateYOffset,
276
255
  getAnimatedConfig(modalSnapPoints[1])
277
256
  ).start(() => {
278
- minimiseVideoModal();
279
-
280
- setScrollModalAnimatedValue(
281
- translateYOffset,
282
- modalSnapPoints[1],
283
- setLastSnap
284
- );
257
+ setTimeout(() => {
258
+ minimiseVideoModal();
285
259
 
286
- resetScrollAnimatedValues(
287
- lastScrollY,
288
- lastScrollYValue,
289
- dragScrollY,
290
- dragVideoPlayerY
291
- );
260
+ setScrollModalAnimatedValue(
261
+ translateYOffset,
262
+ modalSnapPoints[1],
263
+ setLastSnap
264
+ );
292
265
 
293
- resetPlayerAnimationState();
266
+ resetScrollAnimatedValues(
267
+ lastScrollY,
268
+ lastScrollYValue,
269
+ dragScrollY,
270
+ dragVideoPlayerY
271
+ );
272
+ }, 150);
294
273
  });
295
274
  } else if (playerAnimationState === PlayerAnimationStateEnum.maximaze) {
296
275
  Animated.timing(translateYOffset, getAnimatedConfig(0)).start(() => {
@@ -307,9 +286,7 @@ export const AnimatedScrollModalComponent = ({ children }: Props) => {
307
286
  resetPlayerAnimationState();
308
287
  });
309
288
  }
310
- }, [playerAnimationState]);
311
289
 
312
- React.useEffect(() => {
313
290
  const lastScrollYListenerId = lastScrollY.addListener(({ value }) => {
314
291
  lastScrollYValue.current = value;
315
292
  });
@@ -335,7 +312,7 @@ export const AnimatedScrollModalComponent = ({ children }: Props) => {
335
312
  lastScrollY.removeListener(lastScrollYListenerId);
336
313
  dragScrollY.removeListener(dragListenerId);
337
314
  };
338
- }, [playerAnimationState, isAudioItem, isMinimizedModal]);
315
+ }, [playerAnimationState, isAudioItem, modalSnapPoints, isMinimizedModal]);
339
316
 
340
317
  const Wrapper = React.useMemo(
341
318
  () => (Platform.OS === "android" ? GestureHandlerRootView : View),
@@ -373,7 +350,6 @@ export const AnimatedScrollModalComponent = ({ children }: Props) => {
373
350
  bounces={false}
374
351
  onScrollBeginDrag={onRegisterLastScroll}
375
352
  onScroll={onScroll}
376
- onMomentumScrollBegin={onMomentumScrollBegin}
377
353
  onMomentumScrollEnd={onMomentumScrollEnd}
378
354
  scrollEventThrottle={1}
379
355
  showsVerticalScrollIndicator={false}
@@ -37,22 +37,14 @@ export const AnimatedVideoPlayer = ({ children }: Props) => {
37
37
  setStartComponentsAnimation,
38
38
  } = useModalAnimationContext();
39
39
 
40
- const {
41
- videoModalState: { mode: videoModalMode },
42
- } = useNavigation();
43
-
40
+ const { videoModalState } = useNavigation();
44
41
  const { isLanguageOverlayVisible } = React.useContext(PlayerContainerContext);
45
- const isMaximazedModal = videoModalMode === "MAXIMIZED";
46
- const isMinimizedModal = videoModalMode === "MINIMIZED";
47
42
 
48
- const isNotMinimizeMaximazeAnimation =
49
- playerAnimationState !== PlayerAnimationStateEnum.minimize &&
50
- playerAnimationState !== PlayerAnimationStateEnum.maximaze;
43
+ const isMaximazedModal = videoModalState.mode === "MAXIMIZED";
44
+ const isMinimizedModal = videoModalState.mode === "MINIMIZED";
51
45
 
52
46
  const isEnablePanGesture =
53
- !isLanguageOverlayVisible &&
54
- isNotMinimizeMaximazeAnimation &&
55
- (isMaximazedModal || isMinimizedModal);
47
+ !isLanguageOverlayVisible && (isMaximazedModal || isMinimizedModal);
56
48
 
57
49
  const onGestureEvent = Animated.event(
58
50
  [{ nativeEvent: { translationY: dragVideoPlayerY } }],
@@ -67,7 +59,7 @@ export const AnimatedVideoPlayer = ({ children }: Props) => {
67
59
  const preparedTranslationY = Math.abs(translationY);
68
60
  const dragToss = 0.05;
69
61
 
70
- if (videoModalMode === "MAXIMIZED") {
62
+ if (videoModalState.mode === "MAXIMIZED") {
71
63
  if (translationY > 0) {
72
64
  const endOffsetY =
73
65
  lastSnap + preparedTranslationY + dragToss * velocityY + 200;
@@ -92,7 +84,7 @@ export const AnimatedVideoPlayer = ({ children }: Props) => {
92
84
  setPlayerAnimationState(PlayerAnimationStateEnum.minimize);
93
85
  }
94
86
  }
95
- } else if (videoModalMode === "MINIMIZED") {
87
+ } else if (videoModalState.mode === "MINIMIZED") {
96
88
  if (translationY < 0) {
97
89
  // from mini to full
98
90
  setLastSnap(modalSnapPoints[0]);
@@ -108,7 +100,7 @@ export const AnimatedVideoPlayer = ({ children }: Props) => {
108
100
  }
109
101
  }
110
102
  },
111
- [lastSnap, modalSnapPoints, videoModalMode]
103
+ [lastSnap, modalSnapPoints, videoModalState.mode]
112
104
  );
113
105
 
114
106
  React.useEffect(() => {
@@ -153,6 +145,7 @@ export const AnimatedVideoPlayer = ({ children }: Props) => {
153
145
  return (
154
146
  <PanGestureHandler
155
147
  enabled={isEnablePanGesture}
148
+ shouldCancelWhenOutside={isMaximazedModal}
156
149
  onGestureEvent={onGestureEvent}
157
150
  onHandlerStateChange={onHandlerStateChange}
158
151
  >
@@ -62,12 +62,9 @@ export const AnimationView = ({
62
62
  deviceInfo: { isTablet, isTabletLandscape },
63
63
  } = useDimensions("window", {
64
64
  deviceInfo: true,
65
- updateForInactiveScreens: true,
66
65
  });
67
66
 
68
67
  const { videoModalState } = useNavigation();
69
- const { mode: videoModalMode, item: videoModalItem } = videoModalState;
70
-
71
68
  const insets = useSafeAreaInsets();
72
69
  const bottomTabBarHeight = useGetBottomTabBarHeight() + (insets.bottom || 0);
73
70
  const minimisedWidth = defaultAspectRatioWidth(minimisedHeight);
@@ -90,9 +87,9 @@ export const AnimationView = ({
90
87
 
91
88
  const isAudioItem = React.useMemo(
92
89
  () =>
93
- videoModalItem?.content?.type?.includes?.("audio") ||
94
- videoModalItem?.type?.value === "audio",
95
- [videoModalItem]
90
+ videoModalState.item?.content?.type?.includes?.("audio") ||
91
+ videoModalState.item?.type?.value === "audio",
92
+ [videoModalState.item]
96
93
  );
97
94
 
98
95
  const inlineAudioPlayer = additionalData.inlineAudioPlayer;
@@ -231,8 +228,10 @@ export const AnimationView = ({
231
228
  );
232
229
 
233
230
  const getInitialValue = React.useCallback(() => {
234
- const { mode: videoModalMode, previousMode } = videoModalState;
235
- const mode = videoModalMode === "PIP" ? previousMode : videoModalMode;
231
+ const mode =
232
+ videoModalState.mode === "PIP"
233
+ ? videoModalState.previousMode
234
+ : videoModalState.mode;
236
235
 
237
236
  switch (mode) {
238
237
  case "MINIMIZED":
@@ -266,7 +265,7 @@ export const AnimationView = ({
266
265
  isTablet,
267
266
  isTabletLandscape,
268
267
  isRTL,
269
- fromMiniPlayer: videoModalMode === "MINIMIZED",
268
+ fromMiniPlayer: videoModalState.mode === "MINIMIZED",
270
269
  inlineAudioPlayer,
271
270
  }),
272
271
  [
@@ -276,7 +275,7 @@ export const AnimationView = ({
276
275
  defaultValue,
277
276
  moveUpValue,
278
277
  moveComponentHorizontalValue,
279
- videoModalMode,
278
+ videoModalState.mode,
280
279
  ]
281
280
  );
282
281
 
@@ -305,7 +304,7 @@ export const AnimationView = ({
305
304
  }
306
305
 
307
306
  if (
308
- videoModalMode === "MAXIMIZED" &&
307
+ videoModalState.mode === "MAXIMIZED" &&
309
308
  defaultValue.x !== screenWidth &&
310
309
  width &&
311
310
  height
@@ -318,9 +317,10 @@ export const AnimationView = ({
318
317
  }, [screenWidth]);
319
318
 
320
319
  React.useEffect(() => {
321
- const { mode, previousMode } = videoModalState;
322
-
323
- if (mode === "MINIMIZED" && previousMode === "MAXIMIZED") {
320
+ if (
321
+ videoModalState.mode === "MINIMIZED" &&
322
+ videoModalState.previousMode === "MAXIMIZED"
323
+ ) {
324
324
  // set animation to the minimize values if moving from the player to another screen
325
325
  if (playerAnimationState === null) {
326
326
  const value = getAnimationValue(
@@ -337,7 +337,7 @@ export const AnimationView = ({
337
337
  if (
338
338
  playerAnimationState === PlayerAnimationStateEnum.minimize &&
339
339
  startComponentsAnimation &&
340
- videoModalMode === "MAXIMIZED"
340
+ videoModalState.mode === "MAXIMIZED"
341
341
  ) {
342
342
  Animated.timing(
343
343
  animatedValue,
@@ -346,7 +346,12 @@ export const AnimationView = ({
346
346
  } else if (playerAnimationState === PlayerAnimationStateEnum.maximaze) {
347
347
  animatedValue.setValue(defaultValue);
348
348
  }
349
- }, [playerAnimationState, startComponentsAnimation, defaultValue]);
349
+ }, [
350
+ playerAnimationState,
351
+ startComponentsAnimation,
352
+ videoModalState.mode,
353
+ defaultValue,
354
+ ]);
350
355
 
351
356
  React.useEffect(() => {
352
357
  const dragVideoPlayerYListenerId = dragVideoPlayerY.addListener(
@@ -408,9 +413,9 @@ export const AnimationView = ({
408
413
  ref={animationComponentRef}
409
414
  style={[
410
415
  ...preparedStyles,
411
- (videoModalMode === "MAXIMIZED" ||
412
- videoModalMode === "MINIMIZED" ||
413
- (videoModalMode === "PIP" && isAppActive)) &&
416
+ (videoModalState.mode === "MAXIMIZED" ||
417
+ videoModalState.mode === "MINIMIZED" ||
418
+ (videoModalState.mode === "PIP" && isAppActive)) &&
414
419
  getAnimationStyle(animationType, animatedValue),
415
420
  ]}
416
421
  >
@@ -45,10 +45,7 @@ const BarView = ({ screenStyles, barState = defaultState }: Props) => {
45
45
  );
46
46
 
47
47
  return (
48
- <SafeAreaView
49
- style={[style.view, isRTL ? style.rtlStyle : {}]}
50
- testID="BarView-safeAreaView"
51
- >
48
+ <SafeAreaView style={[style.view, isRTL ? style.rtlStyle : {}]}>
52
49
  {backButton}
53
50
  <BarTitle title={barState.title} screenStyles={screenStyles} />
54
51
  {closeButton}
@@ -11,16 +11,12 @@ const renderEmptyView = () => {
11
11
  return <View style={emptyViewStyle} />;
12
12
  };
13
13
 
14
- type FloatingButtonProps = Testable & {
14
+ type FloatingButtonProps = {
15
15
  onPress: () => void;
16
16
  screenStyles: any;
17
17
  };
18
18
 
19
- const BackButton = ({
20
- onPress,
21
- screenStyles,
22
- testID = "backButton",
23
- }: FloatingButtonProps) => {
19
+ const BackButton = ({ onPress, screenStyles }: FloatingButtonProps) => {
24
20
  const containerStyle: any = {};
25
21
 
26
22
  if (!onPress) {
@@ -29,7 +25,6 @@ const BackButton = ({
29
25
 
30
26
  return (
31
27
  <ActionButton
32
- testID={`${testID}-actionButton`}
33
28
  onPress={onPress}
34
29
  buttonStyles={containerStyle}
35
30
  imageUrl={screenStyles.back_button_image}
@@ -11,16 +11,12 @@ const renderEmptyView = () => {
11
11
  return <View style={emptyViewStyle} />;
12
12
  };
13
13
 
14
- type CloseButtonProps = Testable & {
14
+ type CloseButtonProps = {
15
15
  onPress: () => void;
16
16
  screenStyles?: any;
17
17
  };
18
18
 
19
- const CloseButton = ({
20
- onPress,
21
- screenStyles,
22
- testID = "closeButton",
23
- }: CloseButtonProps) => {
19
+ const CloseButton = ({ onPress, screenStyles }: CloseButtonProps) => {
24
20
  const containerStyle: any = {};
25
21
 
26
22
  if (!onPress) {
@@ -29,7 +25,6 @@ const CloseButton = ({
29
25
 
30
26
  return (
31
27
  <ActionButton
32
- testID={`${testID}-actionButton`}
33
28
  onPress={onPress}
34
29
  buttonStyles={containerStyle}
35
30
  imageUrl={screenStyles.close_button_image}
@@ -28,7 +28,7 @@ styles: {
28
28
  }
29
29
  */
30
30
 
31
- type ActionButtonProps = Testable & {
31
+ type ActionButtonProps = {
32
32
  onPress: () => void;
33
33
  buttonStyles: any;
34
34
  imageUrl: string;
@@ -46,16 +46,11 @@ const ActionButton = ({
46
46
  buttonStyles,
47
47
  imageUrl,
48
48
  imageStyle = closeButtonStyle,
49
- testID,
50
49
  }: ActionButtonProps) => {
51
50
  return (
52
- <View style={buttonStyles} testID={testID}>
53
- <TouchableOpacity onPress={onPress} testID={`${testID}-touchable`}>
54
- <Image
55
- source={{ uri: imageUrl }}
56
- style={imageStyle}
57
- testID={`${testID}-image`}
58
- />
51
+ <View style={buttonStyles}>
52
+ <TouchableOpacity onPress={onPress}>
53
+ <Image source={{ uri: imageUrl }} style={imageStyle} />
59
54
  </TouchableOpacity>
60
55
  </View>
61
56
  );
@@ -1,6 +1,5 @@
1
1
  import { create, useStore } from "zustand";
2
2
  import { produce } from "immer";
3
- import { useCallback, useMemo } from "react";
4
3
 
5
4
  type Dimensions = {
6
5
  width: Option<number>;
@@ -32,19 +31,16 @@ export const useCachedDimensions = (id: string) => {
32
31
  dimensionsStore
33
32
  ) as DimensionsState;
34
33
 
35
- const getCachedDimensions = useCallback(() => {
34
+ const getCachedDimensions = () => {
36
35
  return dimensions[id] || initialDimensions();
37
- }, [dimensions?.[id], id]);
36
+ };
38
37
 
39
- const handleSetCachedDimensions = useCallback((newDimensions) => {
38
+ const handleSetCachedDimensions = (newDimensions) => {
40
39
  setCachedDimensions(id, newDimensions);
41
- }, []);
42
-
43
- return useMemo(
44
- () => ({
45
- getCachedDimensions,
46
- setCachedDimensions: handleSetCachedDimensions,
47
- }),
48
- [getCachedDimensions, handleSetCachedDimensions]
49
- );
40
+ };
41
+
42
+ return {
43
+ getCachedDimensions,
44
+ setCachedDimensions: handleSetCachedDimensions,
45
+ };
50
46
  };
@@ -177,12 +177,7 @@ export function withScreenContext(Component: React.ComponentType<any>) {
177
177
  return function WithScreenContextWrapper(props) {
178
178
  return (
179
179
  <ScreenContext.Consumer>
180
- {useCallback(
181
- (value) => (
182
- <Component {...props} screenContext={value} />
183
- ),
184
- [Component, props]
185
- )}
180
+ {(value) => <Component {...props} screenContext={value} />}
186
181
  </ScreenContext.Consumer>
187
182
  );
188
183
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@applicaster/zapp-react-native-ui-components",
3
- "version": "12.0.0-alpha.4081044014",
3
+ "version": "12.0.0-alpha.4102526423",
4
4
  "description": "Applicaster Zapp React Native ui components for the Quick Brick App",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -34,10 +34,10 @@
34
34
  "redux-mock-store": "^1.5.3"
35
35
  },
36
36
  "dependencies": {
37
- "@applicaster/applicaster-types": "12.0.0-alpha.4081044014",
38
- "@applicaster/zapp-react-native-bridge": "12.0.0-alpha.4081044014",
39
- "@applicaster/zapp-react-native-redux": "12.0.0-alpha.4081044014",
40
- "@applicaster/zapp-react-native-utils": "12.0.0-alpha.4081044014",
37
+ "@applicaster/applicaster-types": "12.0.0-alpha.4102526423",
38
+ "@applicaster/zapp-react-native-bridge": "12.0.0-alpha.4102526423",
39
+ "@applicaster/zapp-react-native-redux": "12.0.0-alpha.4102526423",
40
+ "@applicaster/zapp-react-native-utils": "12.0.0-alpha.4102526423",
41
41
  "promise": "^8.3.0",
42
42
  "react-router-native": "^5.1.2",
43
43
  "url": "^0.11.0",
@@ -1,72 +0,0 @@
1
- import React from "react";
2
- import { render, act } from "@testing-library/react-native";
3
- import { Touchable } from "../../Touchable";
4
-
5
- const mockUseIsRTL = jest.fn();
6
-
7
- jest.mock("@applicaster/zapp-react-native-utils/localizationUtils", () => ({
8
- useIsRTL: mockUseIsRTL,
9
- }));
10
-
11
- const mockUseFocusManager = jest.fn();
12
-
13
- jest.mock("@applicaster/zapp-react-native-utils/focusManager", () => ({
14
- useFocusManager: mockUseFocusManager,
15
- }));
16
-
17
- const mockUsePrevious = jest.fn();
18
-
19
- jest.mock("@applicaster/zapp-react-native-utils/reactHooks/utils", () => ({
20
- usePrevious: mockUsePrevious,
21
- }));
22
-
23
- const { Focusable } = require("../index.android");
24
-
25
- describe("Focusable", () => {
26
- const mockFocusManager = {
27
- isFocused: jest.fn(),
28
- onDisableFocusChange: jest.fn(),
29
- registerFocusable: jest.fn(),
30
- focusedId: "test-id",
31
- };
32
-
33
- beforeEach(() => {
34
- jest.clearAllMocks();
35
- mockUseIsRTL.mockReturnValue(false);
36
- mockUseFocusManager.mockReturnValue(mockFocusManager);
37
- mockUsePrevious.mockReturnValue(false);
38
- });
39
-
40
- it("updates disableFocus state when disableFocus prop changes", () => {
41
- const { rerender } = render(
42
- <Focusable id="test-id" disableFocus={false}>
43
- <Touchable testID="touchable" />
44
- </Focusable>
45
- );
46
-
47
- rerender(
48
- <Focusable id="test-id" disableFocus={true}>
49
- <Touchable testID="touchable" />
50
- </Focusable>
51
- );
52
-
53
- expect(mockFocusManager.onDisableFocusChange).toHaveBeenCalledWith(
54
- "test-id"
55
- );
56
- });
57
-
58
- it("calls focusManager.registerFocusable on mount and unregisters on unmount", () => {
59
- const unregister = jest.fn();
60
- mockFocusManager.registerFocusable.mockReturnValue(unregister);
61
-
62
- const { unmount } = render(
63
- <Focusable id="test-id">
64
- <Touchable testID="touchable" />
65
- </Focusable>
66
- );
67
-
68
- expect(mockFocusManager.registerFocusable).toHaveBeenCalled();
69
- act(() => unmount());
70
- expect(unregister).toHaveBeenCalled();
71
- });
72
- });
@@ -1,87 +0,0 @@
1
- import React from "react";
2
- import { renderWithProviders } from "@applicaster/zapp-react-native-utils/testUtils";
3
- import { fireEvent } from "@testing-library/react-native";
4
-
5
- const mockUseIsRTL = jest.fn(() => true);
6
-
7
- jest.mock("@applicaster/zapp-react-native-utils/localizationUtils", () => ({
8
- useIsRTL: mockUseIsRTL,
9
- }));
10
-
11
- const BarView = require("../BarView").default;
12
-
13
- describe("BarView", () => {
14
- const screenStyles = {
15
- title_font_color: "#000",
16
- title_font_android: "Roboto",
17
- title_font_ios: "San Francisco",
18
- title_font_size: "16",
19
- background_color: "#fff",
20
- };
21
-
22
- const barState = {
23
- backHandler: jest.fn(),
24
- closeHandler: jest.fn(),
25
- title: "Test Title",
26
- };
27
-
28
- beforeEach(() => {
29
- jest.clearAllMocks();
30
- });
31
-
32
- it("renders without crashing", () => {
33
- mockUseIsRTL.mockReturnValue(false);
34
-
35
- const { getByText } = renderWithProviders(
36
- <BarView screenStyles={screenStyles} barState={barState} />
37
- );
38
-
39
- expect(getByText("Test Title")).toBeTruthy();
40
- });
41
-
42
- it("applies RTL styles when isRTL is true", () => {
43
- mockUseIsRTL.mockReturnValue(true);
44
-
45
- const { getByTestId } = renderWithProviders(
46
- <BarView screenStyles={screenStyles} barState={barState} />
47
- );
48
-
49
- expect(getByTestId("BarView-safeAreaView").props.style).toContainEqual({
50
- transform: [{ scaleX: -1 }],
51
- });
52
- });
53
-
54
- it("does not apply RTL styles when isRTL is false", () => {
55
- mockUseIsRTL.mockReturnValue(false);
56
-
57
- const { getByTestId } = renderWithProviders(
58
- <BarView screenStyles={screenStyles} barState={barState} />
59
- );
60
-
61
- expect(getByTestId("BarView-safeAreaView").props.style).not.toContainEqual({
62
- transform: [{ scaleX: -1 }],
63
- });
64
- });
65
-
66
- it("calls closeHandler when CloseButton is pressed", () => {
67
- mockUseIsRTL.mockReturnValue(false);
68
-
69
- const { getByTestId } = renderWithProviders(
70
- <BarView screenStyles={screenStyles} barState={barState} />
71
- );
72
-
73
- fireEvent.press(getByTestId("closeButton-actionButton-touchable"));
74
- expect(barState.closeHandler).toHaveBeenCalled();
75
- });
76
-
77
- it("calls backHandler when BackButton is pressed", () => {
78
- mockUseIsRTL.mockReturnValue(false);
79
-
80
- const { getByTestId } = renderWithProviders(
81
- <BarView screenStyles={screenStyles} barState={barState} />
82
- );
83
-
84
- fireEvent.press(getByTestId("backButton-actionButton-touchable"));
85
- expect(barState.backHandler).toHaveBeenCalled();
86
- });
87
- });