@react-navigation/stack 8.0.0-alpha.35 → 8.0.0-alpha.37

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 (95) hide show
  1. package/lib/module/index.js +2 -2
  2. package/lib/module/index.js.map +1 -1
  3. package/lib/module/utils/GestureHandlerContext.js +5 -0
  4. package/lib/module/utils/GestureHandlerContext.js.map +1 -0
  5. package/lib/module/utils/gestureActivationCriteria.js +10 -8
  6. package/lib/module/utils/gestureActivationCriteria.js.map +1 -1
  7. package/lib/module/utils/useGestureHandler.js +9 -0
  8. package/lib/module/utils/useGestureHandler.js.map +1 -0
  9. package/lib/module/views/GestureHandler.js +15 -14
  10. package/lib/module/views/GestureHandler.js.map +1 -1
  11. package/lib/module/views/GestureHandlerNative.js +16 -10
  12. package/lib/module/views/GestureHandlerNative.js.map +1 -1
  13. package/lib/module/views/Stack/Card.js +74 -76
  14. package/lib/module/views/Stack/Card.js.map +1 -1
  15. package/lib/module/views/Stack/CardStack.js +33 -11
  16. package/lib/module/views/Stack/CardStack.js.map +1 -1
  17. package/lib/module/views/Stack/StackView.js +24 -7
  18. package/lib/module/views/Stack/StackView.js.map +1 -1
  19. package/lib/typescript/src/TransitionConfigs/CardStyleInterpolators.d.ts +1 -1
  20. package/lib/typescript/src/TransitionConfigs/CardStyleInterpolators.d.ts.map +1 -1
  21. package/lib/typescript/src/TransitionConfigs/HeaderStyleInterpolators.d.ts +1 -1
  22. package/lib/typescript/src/TransitionConfigs/HeaderStyleInterpolators.d.ts.map +1 -1
  23. package/lib/typescript/src/TransitionConfigs/TransitionPresets.d.ts +1 -1
  24. package/lib/typescript/src/TransitionConfigs/TransitionPresets.d.ts.map +1 -1
  25. package/lib/typescript/src/TransitionConfigs/TransitionSpecs.d.ts +1 -1
  26. package/lib/typescript/src/TransitionConfigs/TransitionSpecs.d.ts.map +1 -1
  27. package/lib/typescript/src/index.d.ts +12 -12
  28. package/lib/typescript/src/index.d.ts.map +1 -1
  29. package/lib/typescript/src/navigators/createStackNavigator.d.ts +3 -2
  30. package/lib/typescript/src/navigators/createStackNavigator.d.ts.map +1 -1
  31. package/lib/typescript/src/utils/CardAnimationContext.d.ts +1 -1
  32. package/lib/typescript/src/utils/CardAnimationContext.d.ts.map +1 -1
  33. package/lib/typescript/src/utils/GestureHandlerContext.d.ts +3 -0
  34. package/lib/typescript/src/utils/GestureHandlerContext.d.ts.map +1 -0
  35. package/lib/typescript/src/utils/gestureActivationCriteria.d.ts +3 -50
  36. package/lib/typescript/src/utils/gestureActivationCriteria.d.ts.map +1 -1
  37. package/lib/typescript/src/utils/getDistanceForDirection.d.ts +1 -1
  38. package/lib/typescript/src/utils/getDistanceForDirection.d.ts.map +1 -1
  39. package/lib/typescript/src/utils/getInvertedMultiplier.d.ts +1 -1
  40. package/lib/typescript/src/utils/getInvertedMultiplier.d.ts.map +1 -1
  41. package/lib/typescript/src/utils/getModalRoutesKeys.d.ts +1 -1
  42. package/lib/typescript/src/utils/getModalRoutesKeys.d.ts.map +1 -1
  43. package/lib/typescript/src/utils/useCardAnimation.d.ts +1 -1
  44. package/lib/typescript/src/utils/useCardAnimation.d.ts.map +1 -1
  45. package/lib/typescript/src/utils/useGestureHandler.d.ts +2 -0
  46. package/lib/typescript/src/utils/useGestureHandler.d.ts.map +1 -0
  47. package/lib/typescript/src/views/GestureHandler.android.d.ts +1 -1
  48. package/lib/typescript/src/views/GestureHandler.android.d.ts.map +1 -1
  49. package/lib/typescript/src/views/GestureHandler.d.ts +7 -11
  50. package/lib/typescript/src/views/GestureHandler.d.ts.map +1 -1
  51. package/lib/typescript/src/views/GestureHandler.ios.d.ts +1 -1
  52. package/lib/typescript/src/views/GestureHandler.ios.d.ts.map +1 -1
  53. package/lib/typescript/src/views/GestureHandlerNative.d.ts +9 -4
  54. package/lib/typescript/src/views/GestureHandlerNative.d.ts.map +1 -1
  55. package/lib/typescript/src/views/Header/Header.d.ts +2 -2
  56. package/lib/typescript/src/views/Header/Header.d.ts.map +1 -1
  57. package/lib/typescript/src/views/Header/HeaderContainer.d.ts +3 -2
  58. package/lib/typescript/src/views/Header/HeaderContainer.d.ts.map +1 -1
  59. package/lib/typescript/src/views/Header/HeaderSegment.d.ts +3 -2
  60. package/lib/typescript/src/views/Header/HeaderSegment.d.ts.map +1 -1
  61. package/lib/typescript/src/views/Stack/Card.d.ts +2 -2
  62. package/lib/typescript/src/views/Stack/Card.d.ts.map +1 -1
  63. package/lib/typescript/src/views/Stack/CardContainer.d.ts +3 -3
  64. package/lib/typescript/src/views/Stack/CardContainer.d.ts.map +1 -1
  65. package/lib/typescript/src/views/Stack/CardContent.d.ts +1 -1
  66. package/lib/typescript/src/views/Stack/CardContent.d.ts.map +1 -1
  67. package/lib/typescript/src/views/Stack/CardStack.d.ts +3 -3
  68. package/lib/typescript/src/views/Stack/CardStack.d.ts.map +1 -1
  69. package/lib/typescript/src/views/Stack/StackView.d.ts +4 -4
  70. package/lib/typescript/src/views/Stack/StackView.d.ts.map +1 -1
  71. package/package.json +16 -16
  72. package/src/index.tsx +2 -2
  73. package/src/utils/GestureHandlerContext.tsx +5 -0
  74. package/src/utils/gestureActivationCriteria.tsx +13 -9
  75. package/src/utils/useGestureHandler.tsx +9 -0
  76. package/src/views/GestureHandler.tsx +27 -16
  77. package/src/views/GestureHandlerNative.tsx +26 -12
  78. package/src/views/Stack/Card.tsx +111 -101
  79. package/src/views/Stack/CardStack.tsx +62 -28
  80. package/src/views/Stack/StackView.tsx +41 -11
  81. package/lib/module/utils/GestureHandlerRefContext.js +0 -5
  82. package/lib/module/utils/GestureHandlerRefContext.js.map +0 -1
  83. package/lib/module/utils/findLastIndex.js +0 -11
  84. package/lib/module/utils/findLastIndex.js.map +0 -1
  85. package/lib/module/utils/useGestureHandlerRef.js +0 -12
  86. package/lib/module/utils/useGestureHandlerRef.js.map +0 -1
  87. package/lib/typescript/src/utils/GestureHandlerRefContext.d.ts +0 -3
  88. package/lib/typescript/src/utils/GestureHandlerRefContext.d.ts.map +0 -1
  89. package/lib/typescript/src/utils/findLastIndex.d.ts +0 -2
  90. package/lib/typescript/src/utils/findLastIndex.d.ts.map +0 -1
  91. package/lib/typescript/src/utils/useGestureHandlerRef.d.ts +0 -3
  92. package/lib/typescript/src/utils/useGestureHandlerRef.d.ts.map +0 -1
  93. package/src/utils/GestureHandlerRefContext.tsx +0 -5
  94. package/src/utils/findLastIndex.tsx +0 -9
  95. package/src/utils/useGestureHandlerRef.tsx +0 -15
@@ -9,6 +9,7 @@ import {
9
9
  View,
10
10
  type ViewStyle,
11
11
  } from 'react-native';
12
+ import type { PanGestureConfig } from 'react-native-gesture-handler';
12
13
  import type { EdgeInsets } from 'react-native-safe-area-context';
13
14
  import useLatestCallback from 'use-latest-callback';
14
15
 
@@ -23,11 +24,7 @@ import { gestureActivationCriteria } from '../../utils/gestureActivationCriteria
23
24
  import { getDistanceForDirection } from '../../utils/getDistanceForDirection';
24
25
  import { getInvertedMultiplier } from '../../utils/getInvertedMultiplier';
25
26
  import { getShadowStyle } from '../../utils/getShadowStyle';
26
- import {
27
- GestureState,
28
- PanGestureHandler,
29
- type PanGestureHandlerGestureEvent,
30
- } from '../GestureHandler';
27
+ import { GestureDetector, usePanGesture } from '../GestureHandler';
31
28
  import { CardContent } from './CardContent';
32
29
 
33
30
  type Props = {
@@ -243,84 +240,6 @@ function Card({
243
240
  }
244
241
  );
245
242
 
246
- const onGestureStateChange = useLatestCallback(
247
- ({ nativeEvent }: PanGestureHandlerGestureEvent) => {
248
- switch (nativeEvent.state) {
249
- case GestureState.ACTIVE:
250
- clearTimeout(pendingGestureCallbackRef.current);
251
- clearTimeout(pendingOnCloseCallbackRef.current);
252
- isSwiping.setValue(TRUE);
253
- onGestureBegin?.();
254
- break;
255
- case GestureState.CANCELLED:
256
- case GestureState.FAILED: {
257
- isSwiping.setValue(FALSE);
258
-
259
- const velocity =
260
- gestureDirection === 'vertical' ||
261
- gestureDirection === 'vertical-inverted'
262
- ? nativeEvent.velocityY
263
- : nativeEvent.velocityX;
264
-
265
- animate({
266
- closing,
267
- velocity,
268
- });
269
-
270
- onGestureCanceled?.();
271
- break;
272
- }
273
- case GestureState.END: {
274
- isSwiping.setValue(FALSE);
275
-
276
- let distance;
277
- let translation;
278
- let velocity;
279
-
280
- if (
281
- gestureDirection === 'vertical' ||
282
- gestureDirection === 'vertical-inverted'
283
- ) {
284
- distance = layout.height;
285
- translation = nativeEvent.translationY;
286
- velocity = nativeEvent.velocityY;
287
- } else {
288
- distance = layout.width;
289
- translation = nativeEvent.translationX;
290
- velocity = nativeEvent.velocityX;
291
- }
292
-
293
- const shouldClose =
294
- (translation + velocity * gestureVelocityImpact) *
295
- getInvertedMultiplier(gestureDirection, direction === 'rtl') >
296
- distance / 2
297
- ? velocity !== 0 || translation !== 0
298
- : closing;
299
-
300
- animate({ closing: shouldClose, velocity });
301
-
302
- if (shouldClose) {
303
- // We call onClose with a delay to make sure that the animation has already started
304
- // This will make sure that the state update caused by this doesn't affect start of animation
305
- pendingGestureCallbackRef.current = setTimeout(() => {
306
- onClose();
307
-
308
- // Check if the screen is still closing with a delay
309
- // So state update from onClose has a chance to go through
310
- // If route wasn't removed after onClose, re-open it
311
- pendingOnCloseCallbackRef.current = setTimeout(() => {
312
- maybeAnimate();
313
- }, 32);
314
- }, 16);
315
- }
316
-
317
- onGestureEnd?.();
318
- break;
319
- }
320
- }
321
- }
322
- );
323
-
324
243
  React.useLayoutEffect(() => {
325
244
  layoutAnim.width.setValue(layout.width);
326
245
  layoutAnim.height.setValue(layout.height);
@@ -478,17 +397,89 @@ function Card({
478
397
  [styleInterpolator, interpolationProps]
479
398
  );
480
399
 
481
- const onGestureEvent = React.useMemo(
400
+ const onGestureActivate: PanGestureConfig['onActivate'] = useLatestCallback(
401
+ () => {
402
+ clearTimeout(pendingGestureCallbackRef.current);
403
+ clearTimeout(pendingOnCloseCallbackRef.current);
404
+ isSwiping.setValue(TRUE);
405
+ onGestureBegin?.();
406
+ }
407
+ );
408
+
409
+ const onGestureDeactivate: PanGestureConfig['onDeactivate'] =
410
+ useLatestCallback((event) => {
411
+ isSwiping.setValue(FALSE);
412
+
413
+ let distance;
414
+ let translation;
415
+ let velocity;
416
+
417
+ if (
418
+ gestureDirection === 'vertical' ||
419
+ gestureDirection === 'vertical-inverted'
420
+ ) {
421
+ distance = layout.height;
422
+ translation = event.translationY;
423
+ velocity = event.velocityY;
424
+ } else {
425
+ distance = layout.width;
426
+ translation = event.translationX;
427
+ velocity = event.velocityX;
428
+ }
429
+
430
+ gesture.setValue(translation);
431
+
432
+ if (event.canceled) {
433
+ animate({
434
+ closing,
435
+ velocity,
436
+ });
437
+
438
+ onGestureCanceled?.();
439
+
440
+ return;
441
+ }
442
+
443
+ const shouldClose =
444
+ (translation + velocity * gestureVelocityImpact) *
445
+ getInvertedMultiplier(gestureDirection, direction === 'rtl') >
446
+ distance / 2
447
+ ? velocity !== 0 || translation !== 0
448
+ : closing;
449
+
450
+ animate({ closing: shouldClose, velocity });
451
+
452
+ if (shouldClose) {
453
+ // We call onClose with a delay to make sure that the animation has already started
454
+ // This will make sure that the state update caused by this doesn't affect start of animation
455
+ pendingGestureCallbackRef.current = setTimeout(() => {
456
+ onClose();
457
+
458
+ // Check if the screen is still closing with a delay
459
+ // So state update from onClose has a chance to go through
460
+ // If route wasn't removed after onClose, re-open it
461
+ pendingOnCloseCallbackRef.current = setTimeout(() => {
462
+ maybeAnimate();
463
+ }, 32);
464
+ }, 16);
465
+ }
466
+
467
+ onGestureEnd?.();
468
+ });
469
+
470
+ const onGestureEvent: PanGestureConfig['onUpdate'] = React.useMemo(
482
471
  () =>
483
472
  gestureEnabled
484
473
  ? Animated.event(
485
474
  [
486
475
  {
487
- nativeEvent:
488
- gestureDirection === 'vertical' ||
489
- gestureDirection === 'vertical-inverted'
490
- ? { translationY: gesture }
491
- : { translationX: gesture },
476
+ nativeEvent: {
477
+ handlerData:
478
+ gestureDirection === 'vertical' ||
479
+ gestureDirection === 'vertical-inverted'
480
+ ? { translationY: gesture }
481
+ : { translationX: gesture },
482
+ },
492
483
  },
493
484
  ],
494
485
  { useNativeDriver }
@@ -497,6 +488,35 @@ function Card({
497
488
  [gesture, gestureDirection, gestureEnabled]
498
489
  );
499
490
 
491
+ const panGestureConfig = React.useMemo(
492
+ (): PanGestureConfig => ({
493
+ enabled: layout.width !== 0 && gestureEnabled,
494
+ onActivate: onGestureActivate,
495
+ onDeactivate: onGestureDeactivate,
496
+ onUpdate: onGestureEvent,
497
+ disableReanimated: true,
498
+ useAnimated: true,
499
+ ...gestureActivationCriteria({
500
+ layout,
501
+ direction,
502
+ gestureDirection,
503
+ gestureResponseDistance,
504
+ }),
505
+ }),
506
+ [
507
+ direction,
508
+ gestureDirection,
509
+ gestureEnabled,
510
+ gestureResponseDistance,
511
+ layout,
512
+ onGestureActivate,
513
+ onGestureDeactivate,
514
+ onGestureEvent,
515
+ ]
516
+ );
517
+
518
+ const panGesture = usePanGesture(panGestureConfig);
519
+
500
520
  const { backgroundColor } = StyleSheet.flatten(contentStyle || {});
501
521
 
502
522
  const isTransparent =
@@ -528,17 +548,7 @@ function Card({
528
548
  <Animated.View
529
549
  style={[styles.container, containerStyle, customContainerStyle]}
530
550
  >
531
- <PanGestureHandler
532
- enabled={layout.width !== 0 && gestureEnabled}
533
- onGestureEvent={onGestureEvent}
534
- onHandlerStateChange={onGestureStateChange}
535
- {...gestureActivationCriteria({
536
- layout,
537
- direction,
538
- gestureDirection,
539
- gestureResponseDistance,
540
- })}
541
- >
551
+ <GestureDetector gesture={panGesture}>
542
552
  <Animated.View
543
553
  needsOffscreenAlphaCompositing={hasOpacityStyle(cardStyle)}
544
554
  style={[styles.container, cardStyle]}
@@ -567,7 +577,7 @@ function Card({
567
577
  {children}
568
578
  </CardContent>
569
579
  </Animated.View>
570
- </PanGestureHandler>
580
+ </GestureDetector>
571
581
  </Animated.View>
572
582
  </CardAnimationContext.Provider>
573
583
  );
@@ -113,12 +113,16 @@ const NAMED_TRANSITIONS_PRESETS = {
113
113
  }),
114
114
  } as const satisfies Record<StackAnimationName, TransitionPreset>;
115
115
 
116
- const FALLBACK_DESCRIPTOR = Object.freeze({ options: {} });
117
-
118
116
  const HIDDEN_HEADER_HEIGHT = { measured: false, value: 0 };
119
117
 
120
118
  const getInterpolationIndex = (scenes: Scene[], index: number) => {
121
- const { cardStyleInterpolator } = scenes[index].descriptor.options;
119
+ const scene = scenes[index];
120
+
121
+ if (scene == null) {
122
+ throw new Error(`Couldn't find a scene at index ${index}.`);
123
+ }
124
+
125
+ const { cardStyleInterpolator } = scene.descriptor.options;
122
126
 
123
127
  // Start from current card and count backwards the number of cards with same interpolation
124
128
  let interpolationIndex = 0;
@@ -347,27 +351,36 @@ export class CardStack extends React.Component<Props, State> {
347
351
  const oldScene = state.scenes[index];
348
352
 
349
353
  const currentGesture = gestures[route.key];
354
+
355
+ if (currentGesture == null) {
356
+ throw new Error(`Couldn't find a gesture for route '${route.key}'.`);
357
+ }
358
+
350
359
  const previousGesture = previousRoute
351
360
  ? gestures[previousRoute.key]
352
361
  : undefined;
353
362
  const nextGesture = nextRoute ? gestures[nextRoute.key] : undefined;
354
363
 
355
364
  const descriptor =
356
- props.descriptors[route.key] ||
357
- state.descriptors[route.key] ||
358
- (oldScene ? oldScene.descriptor : FALLBACK_DESCRIPTOR);
359
-
360
- const nextOptions =
361
- nextRoute &&
362
- (props.descriptors[nextRoute?.key] || state.descriptors[nextRoute?.key])
363
- ?.options;
364
-
365
- const previousOptions =
366
- previousRoute &&
367
- (
368
- props.descriptors[previousRoute?.key] ||
369
- state.descriptors[previousRoute?.key]
370
- )?.options;
365
+ props.descriptors[route.key] ??
366
+ state.descriptors[route.key] ??
367
+ oldScene?.descriptor;
368
+
369
+ if (descriptor == null) {
370
+ throw new Error(`Couldn't find a descriptor for route '${route.key}'.`);
371
+ }
372
+
373
+ const nextOptions = nextRoute
374
+ ? (props.descriptors[nextRoute.key] ?? state.descriptors[nextRoute.key])
375
+ ?.options
376
+ : undefined;
377
+
378
+ const previousOptions = previousRoute
379
+ ? (
380
+ props.descriptors[previousRoute.key] ??
381
+ state.descriptors[previousRoute.key]
382
+ )?.options
383
+ : undefined;
371
384
 
372
385
  // When a screen is not the last, it should use next screen's transition config
373
386
  // Many transitions also animate the previous screen, so using 2 different transitions doesn't look right
@@ -582,7 +595,13 @@ export class CardStack extends React.Component<Props, State> {
582
595
  private getFocusedRoute = () => {
583
596
  const { state } = this.props;
584
597
 
585
- return state.routes[state.index];
598
+ const route = state.routes[state.index];
599
+
600
+ if (route == null) {
601
+ throw new Error(`Couldn't find a route at index ${state.index}.`);
602
+ }
603
+
604
+ return route;
586
605
  };
587
606
 
588
607
  private getPreviousScene = ({ route }: { route: Route<string> }) => {
@@ -628,6 +647,10 @@ export class CardStack extends React.Component<Props, State> {
628
647
 
629
648
  const focusedRoute = state.routes[state.index];
630
649
 
650
+ if (focusedRoute == null) {
651
+ throw new Error(`Couldn't find a route at index ${state.index}.`);
652
+ }
653
+
631
654
  // Render only two top-most active headers as a workaround for
632
655
  // https://github.com/react-navigation/react-navigation/issues/12456.
633
656
  // If the header is persisted, it might be placed incorrectly when navigating back
@@ -682,6 +705,19 @@ export class CardStack extends React.Component<Props, State> {
682
705
  const gesture = gestures[route.key];
683
706
  const scene = scenes[index];
684
707
 
708
+ if (gesture == null) {
709
+ throw new Error(
710
+ `Couldn't find a gesture for route '${route.key}'.`
711
+ );
712
+ }
713
+
714
+ if (scene == null) {
715
+ throw new Error(`Couldn't find a scene at index ${index}.`);
716
+ }
717
+
718
+ const nextScene = scenes[index + 1];
719
+ const nextRoute = self[index + 1];
720
+
685
721
  const {
686
722
  inactiveBehavior = 'pause',
687
723
  animation,
@@ -712,15 +748,12 @@ export class CardStack extends React.Component<Props, State> {
712
748
  getAnimationEnabled(animation) ||
713
749
  // Also check next screen's animation,
714
750
  // As it will result in both screens being visible
715
- (scenes[index + 1]
716
- ? getAnimationEnabled(
717
- scenes[index + 1].descriptor.options.animation
718
- )
751
+ (nextScene
752
+ ? getAnimationEnabled(nextScene.descriptor.options.animation)
719
753
  : false);
720
754
 
721
755
  const isNextScreenTransparent =
722
- scenes[index + 1]?.descriptor.options.presentation ===
723
- 'transparentModal';
756
+ nextScene?.descriptor.options.presentation === 'transparentModal';
724
757
 
725
758
  const isRemoving =
726
759
  replacingRouteKeys.includes(route.key) ||
@@ -728,9 +761,10 @@ export class CardStack extends React.Component<Props, State> {
728
761
 
729
762
  const isFocusing =
730
763
  openingRouteKeys.includes(route.key) ||
731
- [...closingRouteKeys, ...replacingRouteKeys].includes(
732
- self[index + 1]?.key
733
- );
764
+ (nextRoute != null &&
765
+ [...closingRouteKeys, ...replacingRouteKeys].includes(
766
+ nextRoute.key
767
+ ));
734
768
 
735
769
  const isInactive = isInactiveRoute(route, this.props.routes);
736
770
  const isRetained = state.retainedRouteKeys?.includes(route.key);
@@ -64,10 +64,20 @@ export class StackView extends React.Component<Props, State> {
64
64
  ) {
65
65
  const allRoutes = props.state.routes;
66
66
  const previousRoutes = state.previousState?.routes ?? [];
67
- const previousFocusedRoute = state.previousState
68
- ? state.previousState.routes[state.previousState.index]
69
- : undefined;
67
+ const previousFocusedRoute =
68
+ state.previousState?.routes[state.previousState.index];
70
69
  const nextFocusedRouteFromState = props.state.routes[props.state.index];
70
+
71
+ if (state.previousState && previousFocusedRoute == null) {
72
+ throw new Error(
73
+ `Couldn't find a route at index ${state.previousState.index}.`
74
+ );
75
+ }
76
+
77
+ if (nextFocusedRouteFromState == null) {
78
+ throw new Error(`Couldn't find a route at index ${props.state.index}.`);
79
+ }
80
+
71
81
  const activeRoutes = props.state.routes.slice(0, props.state.index + 1);
72
82
 
73
83
  // If there was no change in routes, we don't need to compute anything
@@ -118,7 +128,7 @@ export class StackView extends React.Component<Props, State> {
118
128
  {}
119
129
  );
120
130
 
121
- routes = routes.map((route) => map[route.key] || route);
131
+ routes = routes.map((route) => map[route.key] ?? route);
122
132
  }
123
133
 
124
134
  const routeKeys = new Set(routes.map((route) => route.key));
@@ -126,8 +136,16 @@ export class StackView extends React.Component<Props, State> {
126
136
  ...routes,
127
137
  ...props.state.routes.filter((route) => !routeKeys.has(route.key)),
128
138
  ].reduce<StackDescriptorMap>((acc, route) => {
129
- acc[route.key] =
130
- props.descriptors[route.key] || state.descriptors[route.key];
139
+ const descriptor =
140
+ props.descriptors[route.key] ?? state.descriptors[route.key];
141
+
142
+ if (descriptor == null) {
143
+ throw new Error(
144
+ `Couldn't find a descriptor for route '${route.key}'.`
145
+ );
146
+ }
147
+
148
+ acc[route.key] = descriptor;
131
149
 
132
150
  return acc;
133
151
  }, {});
@@ -157,16 +175,22 @@ export class StackView extends React.Component<Props, State> {
157
175
  // Get previous focused route from previous active routes
158
176
  const nextFocusedRoute = activeRoutes[activeRoutes.length - 1];
159
177
 
178
+ if (nextFocusedRoute == null) {
179
+ throw new Error(
180
+ `Couldn't find a route at index ${activeRoutes.length - 1}.`
181
+ );
182
+ }
183
+
160
184
  const isAnimationEnabled = (key: string) => {
161
- const descriptor = props.descriptors[key] || state.descriptors[key];
185
+ const descriptor = props.descriptors[key] ?? state.descriptors[key];
162
186
 
163
187
  return getAnimationEnabled(descriptor?.options.animation);
164
188
  };
165
189
 
166
190
  const getAnimationTypeForReplace = (key: string) => {
167
- const descriptor = props.descriptors[key] || state.descriptors[key];
191
+ const descriptor = props.descriptors[key] ?? state.descriptors[key];
168
192
 
169
- return descriptor.options.animationTypeForReplace ?? 'push';
193
+ return descriptor?.options.animationTypeForReplace ?? 'push';
170
194
  };
171
195
 
172
196
  let routes = activeRoutes;
@@ -301,8 +325,14 @@ export class StackView extends React.Component<Props, State> {
301
325
  ...routes,
302
326
  ...props.state.routes.filter((route) => !routeKeys.has(route.key)),
303
327
  ].reduce<StackDescriptorMap>((acc, route) => {
304
- acc[route.key] =
305
- props.descriptors[route.key] || state.descriptors[route.key];
328
+ const descriptor =
329
+ props.descriptors[route.key] ?? state.descriptors[route.key];
330
+
331
+ if (descriptor == null) {
332
+ throw new Error(`Couldn't find a descriptor for route '${route.key}'.`);
333
+ }
334
+
335
+ acc[route.key] = descriptor;
306
336
 
307
337
  return acc;
308
338
  }, {});
@@ -1,5 +0,0 @@
1
- "use strict";
2
-
3
- import * as React from 'react';
4
- export const GestureHandlerRefContext = /*#__PURE__*/React.createContext(null);
5
- //# sourceMappingURL=GestureHandlerRefContext.js.map
@@ -1 +0,0 @@
1
- {"version":3,"names":["React","GestureHandlerRefContext","createContext"],"sourceRoot":"../../../src","sources":["utils/GestureHandlerRefContext.tsx"],"mappings":";;AAAA,OAAO,KAAKA,KAAK,MAAM,OAAO;AAE9B,OAAO,MAAMC,wBAAwB,gBAAGD,KAAK,CAACE,aAAa,CAEjD,IAAI,CAAC","ignoreList":[]}
@@ -1,11 +0,0 @@
1
- "use strict";
2
-
3
- export function findLastIndex(array, callback) {
4
- for (let i = array.length - 1; i >= 0; i--) {
5
- if (callback(array[i])) {
6
- return i;
7
- }
8
- }
9
- return -1;
10
- }
11
- //# sourceMappingURL=findLastIndex.js.map
@@ -1 +0,0 @@
1
- {"version":3,"names":["findLastIndex","array","callback","i","length"],"sourceRoot":"../../../src","sources":["utils/findLastIndex.tsx"],"mappings":";;AAAA,OAAO,SAASA,aAAaA,CAAIC,KAAU,EAAEC,QAA+B,EAAE;EAC5E,KAAK,IAAIC,CAAC,GAAGF,KAAK,CAACG,MAAM,GAAG,CAAC,EAAED,CAAC,IAAI,CAAC,EAAEA,CAAC,EAAE,EAAE;IAC1C,IAAID,QAAQ,CAACD,KAAK,CAACE,CAAC,CAAC,CAAC,EAAE;MACtB,OAAOA,CAAC;IACV;EACF;EAEA,OAAO,CAAC,CAAC;AACX","ignoreList":[]}
@@ -1,12 +0,0 @@
1
- "use strict";
2
-
3
- import * as React from 'react';
4
- import { GestureHandlerRefContext } from "./GestureHandlerRefContext.js";
5
- export function useGestureHandlerRef() {
6
- const ref = React.use(GestureHandlerRefContext);
7
- if (ref === undefined) {
8
- throw new Error("Couldn't find a ref for gesture handler. Are you inside a screen in Stack?");
9
- }
10
- return ref;
11
- }
12
- //# sourceMappingURL=useGestureHandlerRef.js.map
@@ -1 +0,0 @@
1
- {"version":3,"names":["React","GestureHandlerRefContext","useGestureHandlerRef","ref","use","undefined","Error"],"sourceRoot":"../../../src","sources":["utils/useGestureHandlerRef.tsx"],"mappings":";;AAAA,OAAO,KAAKA,KAAK,MAAM,OAAO;AAE9B,SAASC,wBAAwB,QAAQ,+BAA4B;AAErE,OAAO,SAASC,oBAAoBA,CAAA,EAAG;EACrC,MAAMC,GAAG,GAAGH,KAAK,CAACI,GAAG,CAACH,wBAAwB,CAAC;EAE/C,IAAIE,GAAG,KAAKE,SAAS,EAAE;IACrB,MAAM,IAAIC,KAAK,CACb,4EACF,CAAC;EACH;EAEA,OAAOH,GAAG;AACZ","ignoreList":[]}
@@ -1,3 +0,0 @@
1
- import * as React from 'react';
2
- export declare const GestureHandlerRefContext: React.Context<React.Ref<React.ComponentType<import("react-native-gesture-handler").PanGestureHandlerProps & React.RefAttributes<any>>>>;
3
- //# sourceMappingURL=GestureHandlerRefContext.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"GestureHandlerRefContext.d.ts","sourceRoot":"","sources":["../../../../src/utils/GestureHandlerRefContext.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,eAAO,MAAM,wBAAwB,yIAEtB,CAAC"}
@@ -1,2 +0,0 @@
1
- export declare function findLastIndex<T>(array: T[], callback: (value: T) => boolean): number;
2
- //# sourceMappingURL=findLastIndex.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"findLastIndex.d.ts","sourceRoot":"","sources":["../../../../src/utils/findLastIndex.tsx"],"names":[],"mappings":"AAAA,wBAAgB,aAAa,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,OAAO,UAQ3E"}
@@ -1,3 +0,0 @@
1
- import * as React from 'react';
2
- export declare function useGestureHandlerRef(): React.Ref<React.ComponentType<import("react-native-gesture-handler").PanGestureHandlerProps & React.RefAttributes<any>>>;
3
- //# sourceMappingURL=useGestureHandlerRef.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"useGestureHandlerRef.d.ts","sourceRoot":"","sources":["../../../../src/utils/useGestureHandlerRef.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAI/B,wBAAgB,oBAAoB,6HAUnC"}
@@ -1,5 +0,0 @@
1
- import * as React from 'react';
2
-
3
- export const GestureHandlerRefContext = React.createContext<React.Ref<
4
- import('react-native-gesture-handler').PanGestureHandler
5
- > | null>(null);
@@ -1,9 +0,0 @@
1
- export function findLastIndex<T>(array: T[], callback: (value: T) => boolean) {
2
- for (let i = array.length - 1; i >= 0; i--) {
3
- if (callback(array[i])) {
4
- return i;
5
- }
6
- }
7
-
8
- return -1;
9
- }
@@ -1,15 +0,0 @@
1
- import * as React from 'react';
2
-
3
- import { GestureHandlerRefContext } from './GestureHandlerRefContext';
4
-
5
- export function useGestureHandlerRef() {
6
- const ref = React.use(GestureHandlerRefContext);
7
-
8
- if (ref === undefined) {
9
- throw new Error(
10
- "Couldn't find a ref for gesture handler. Are you inside a screen in Stack?"
11
- );
12
- }
13
-
14
- return ref;
15
- }