react-native-screen-transitions 3.0.0-rc.3 → 3.0.0-rc.4

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 (120) hide show
  1. package/lib/commonjs/blank-stack/components/screens.js +16 -11
  2. package/lib/commonjs/blank-stack/components/screens.js.map +1 -1
  3. package/lib/commonjs/blank-stack/components/stack-view.js +42 -36
  4. package/lib/commonjs/blank-stack/components/stack-view.js.map +1 -1
  5. package/lib/commonjs/native-stack/views/NativeStackView.native.js +110 -103
  6. package/lib/commonjs/native-stack/views/NativeStackView.native.js.map +1 -1
  7. package/lib/commonjs/shared/components/controllers/blank-stack-lifecycle.js +72 -0
  8. package/lib/commonjs/shared/components/controllers/blank-stack-lifecycle.js.map +1 -0
  9. package/lib/commonjs/shared/components/controllers/native-stack-lifecycle.js +79 -0
  10. package/lib/commonjs/shared/components/controllers/native-stack-lifecycle.js.map +1 -0
  11. package/lib/commonjs/shared/hooks/animation/use-screen-animation.js +11 -1
  12. package/lib/commonjs/shared/hooks/animation/use-screen-animation.js.map +1 -1
  13. package/lib/commonjs/shared/hooks/gestures/use-build-gestures.js +11 -6
  14. package/lib/commonjs/shared/hooks/gestures/use-build-gestures.js.map +1 -1
  15. package/lib/commonjs/shared/hooks/gestures/use-scroll-registry.js +7 -7
  16. package/lib/commonjs/shared/hooks/gestures/use-scroll-registry.js.map +1 -1
  17. package/lib/commonjs/shared/providers/gestures.provider.js +32 -5
  18. package/lib/commonjs/shared/providers/gestures.provider.js.map +1 -1
  19. package/lib/commonjs/shared/providers/register-bounds.provider.js +4 -3
  20. package/lib/commonjs/shared/providers/register-bounds.provider.js.map +1 -1
  21. package/lib/commonjs/shared/providers/routes.provider.js +48 -0
  22. package/lib/commonjs/shared/providers/routes.provider.js.map +1 -0
  23. package/lib/commonjs/shared/providers/screen-transition.provider.js.map +1 -1
  24. package/lib/commonjs/shared/types/state.types.js +9 -0
  25. package/lib/commonjs/shared/types/state.types.js.map +1 -0
  26. package/lib/commonjs/shared/utils/animation/compute-stack-progress.js +20 -0
  27. package/lib/commonjs/shared/utils/animation/compute-stack-progress.js.map +1 -0
  28. package/lib/commonjs/shared/utils/animation/derivations.js +1 -1
  29. package/lib/commonjs/shared/utils/animation/start-screen-transition.js +11 -11
  30. package/lib/commonjs/shared/utils/animation/start-screen-transition.js.map +1 -1
  31. package/lib/module/blank-stack/components/screens.js +16 -11
  32. package/lib/module/blank-stack/components/screens.js.map +1 -1
  33. package/lib/module/blank-stack/components/stack-view.js +42 -36
  34. package/lib/module/blank-stack/components/stack-view.js.map +1 -1
  35. package/lib/module/native-stack/views/NativeStackView.native.js +109 -102
  36. package/lib/module/native-stack/views/NativeStackView.native.js.map +1 -1
  37. package/lib/module/shared/components/controllers/blank-stack-lifecycle.js +66 -0
  38. package/lib/module/shared/components/controllers/blank-stack-lifecycle.js.map +1 -0
  39. package/lib/module/shared/components/controllers/native-stack-lifecycle.js +73 -0
  40. package/lib/module/shared/components/controllers/native-stack-lifecycle.js.map +1 -0
  41. package/lib/module/shared/hooks/animation/use-screen-animation.js +11 -1
  42. package/lib/module/shared/hooks/animation/use-screen-animation.js.map +1 -1
  43. package/lib/module/shared/hooks/gestures/use-build-gestures.js +11 -6
  44. package/lib/module/shared/hooks/gestures/use-build-gestures.js.map +1 -1
  45. package/lib/module/shared/hooks/gestures/use-scroll-registry.js +7 -7
  46. package/lib/module/shared/hooks/gestures/use-scroll-registry.js.map +1 -1
  47. package/lib/module/shared/providers/gestures.provider.js +31 -4
  48. package/lib/module/shared/providers/gestures.provider.js.map +1 -1
  49. package/lib/module/shared/providers/register-bounds.provider.js +4 -3
  50. package/lib/module/shared/providers/register-bounds.provider.js.map +1 -1
  51. package/lib/module/shared/providers/routes.provider.js +42 -0
  52. package/lib/module/shared/providers/routes.provider.js.map +1 -0
  53. package/lib/module/shared/providers/screen-transition.provider.js.map +1 -1
  54. package/lib/module/shared/types/state.types.js +5 -0
  55. package/lib/module/shared/types/state.types.js.map +1 -0
  56. package/lib/module/shared/utils/animation/compute-stack-progress.js +15 -0
  57. package/lib/module/shared/utils/animation/compute-stack-progress.js.map +1 -0
  58. package/lib/module/shared/utils/animation/derivations.js +1 -1
  59. package/lib/module/shared/utils/animation/start-screen-transition.js +11 -11
  60. package/lib/module/shared/utils/animation/start-screen-transition.js.map +1 -1
  61. package/lib/typescript/blank-stack/components/screens.d.ts.map +1 -1
  62. package/lib/typescript/blank-stack/components/stack-view.d.ts.map +1 -1
  63. package/lib/typescript/blank-stack/types.d.ts +1 -39
  64. package/lib/typescript/blank-stack/types.d.ts.map +1 -1
  65. package/lib/typescript/native-stack/views/NativeStackView.native.d.ts.map +1 -1
  66. package/lib/typescript/shared/components/controllers/blank-stack-lifecycle.d.ts +8 -0
  67. package/lib/typescript/shared/components/controllers/blank-stack-lifecycle.d.ts.map +1 -0
  68. package/lib/typescript/shared/components/controllers/native-stack-lifecycle.d.ts +8 -0
  69. package/lib/typescript/shared/components/controllers/native-stack-lifecycle.d.ts.map +1 -0
  70. package/lib/typescript/shared/hooks/animation/use-screen-animation.d.ts.map +1 -1
  71. package/lib/typescript/shared/hooks/gestures/use-build-gestures.d.ts +2 -2
  72. package/lib/typescript/shared/hooks/gestures/use-build-gestures.d.ts.map +1 -1
  73. package/lib/typescript/shared/providers/gestures.provider.d.ts +8 -2
  74. package/lib/typescript/shared/providers/gestures.provider.d.ts.map +1 -1
  75. package/lib/typescript/shared/providers/register-bounds.provider.d.ts.map +1 -1
  76. package/lib/typescript/shared/providers/routes.provider.d.ts +19 -0
  77. package/lib/typescript/shared/providers/routes.provider.d.ts.map +1 -0
  78. package/lib/typescript/shared/providers/screen-transition.provider.d.ts +2 -2
  79. package/lib/typescript/shared/providers/screen-transition.provider.d.ts.map +1 -1
  80. package/lib/typescript/shared/types/animation.types.d.ts +12 -0
  81. package/lib/typescript/shared/types/animation.types.d.ts.map +1 -1
  82. package/lib/typescript/shared/types/state.types.d.ts +3 -0
  83. package/lib/typescript/shared/types/state.types.d.ts.map +1 -0
  84. package/lib/typescript/shared/utils/animation/compute-stack-progress.d.ts +3 -0
  85. package/lib/typescript/shared/utils/animation/compute-stack-progress.d.ts.map +1 -0
  86. package/lib/typescript/shared/utils/animation/start-screen-transition.d.ts.map +1 -1
  87. package/package.json +1 -1
  88. package/src/blank-stack/components/screens.tsx +21 -15
  89. package/src/blank-stack/components/stack-view.tsx +55 -44
  90. package/src/blank-stack/types.ts +1 -24
  91. package/src/native-stack/views/NativeStackView.native.tsx +121 -112
  92. package/src/shared/__tests__/bounds.store.test.ts +14 -36
  93. package/src/shared/components/controllers/blank-stack-lifecycle.tsx +70 -0
  94. package/src/shared/components/controllers/native-stack-lifecycle.tsx +87 -0
  95. package/src/shared/hooks/animation/use-screen-animation.tsx +11 -6
  96. package/src/shared/hooks/gestures/use-build-gestures.tsx +12 -6
  97. package/src/shared/hooks/gestures/use-scroll-registry.tsx +7 -7
  98. package/src/shared/providers/gestures.provider.tsx +34 -5
  99. package/src/shared/providers/register-bounds.provider.tsx +4 -3
  100. package/src/shared/providers/routes.provider.tsx +54 -0
  101. package/src/shared/providers/screen-transition.provider.tsx +2 -2
  102. package/src/shared/types/animation.types.ts +13 -0
  103. package/src/shared/types/state.types.ts +2 -0
  104. package/src/shared/utils/animation/compute-stack-progress.ts +16 -0
  105. package/src/shared/utils/animation/derivations.ts +1 -1
  106. package/src/shared/utils/animation/start-screen-transition.ts +13 -10
  107. package/lib/commonjs/shared/components/controllers/screen-lifecycle.js +0 -142
  108. package/lib/commonjs/shared/components/controllers/screen-lifecycle.js.map +0 -1
  109. package/lib/commonjs/shared/hooks/gestures/use-parent-gesture-registry.js +0 -28
  110. package/lib/commonjs/shared/hooks/gestures/use-parent-gesture-registry.js.map +0 -1
  111. package/lib/module/shared/components/controllers/screen-lifecycle.js +0 -136
  112. package/lib/module/shared/components/controllers/screen-lifecycle.js.map +0 -1
  113. package/lib/module/shared/hooks/gestures/use-parent-gesture-registry.js +0 -23
  114. package/lib/module/shared/hooks/gestures/use-parent-gesture-registry.js.map +0 -1
  115. package/lib/typescript/shared/components/controllers/screen-lifecycle.d.ts +0 -12
  116. package/lib/typescript/shared/components/controllers/screen-lifecycle.d.ts.map +0 -1
  117. package/lib/typescript/shared/hooks/gestures/use-parent-gesture-registry.d.ts +0 -6
  118. package/lib/typescript/shared/hooks/gestures/use-parent-gesture-registry.d.ts.map +0 -1
  119. package/src/shared/components/controllers/screen-lifecycle.tsx +0 -154
  120. package/src/shared/hooks/gestures/use-parent-gesture-registry.tsx +0 -18
@@ -0,0 +1,87 @@
1
+ import { useEffect, useLayoutEffect } from "react";
2
+ import { useDerivedValue } from "react-native-reanimated";
3
+ import type { NativeStackDescriptor } from "../../../native-stack/types";
4
+ import { useSharedValueState } from "../../hooks/reanimated/use-shared-value-state";
5
+ import useStableCallback from "../../hooks/use-stable-callback";
6
+ import { useGestureContext } from "../../providers/gestures.provider";
7
+ import { useKeys } from "../../providers/keys.provider";
8
+ import { AnimationStore } from "../../stores/animation.store";
9
+ import { TRUE } from "../../types/state.types";
10
+ import { startScreenTransition } from "../../utils/animation/start-screen-transition";
11
+ import { resetStoresForScreen } from "../../utils/reset-stores-for-screen";
12
+
13
+ export interface Props {
14
+ children: React.ReactNode;
15
+ }
16
+
17
+ /**
18
+ * Lifecycle controller built out for Native Stack implementation.
19
+ */
20
+ export const NativeStackScreenLifecycleController = ({ children }: Props) => {
21
+ const { current } = useKeys<NativeStackDescriptor>();
22
+ const { ancestorContext } = useGestureContext();
23
+
24
+ const isAncestorDismissingViaGesture = useSharedValueState(
25
+ useDerivedValue(() => {
26
+ "worklet";
27
+ return (
28
+ ancestorContext?.gestureAnimationValues.isDismissing?.value ?? false
29
+ );
30
+ }),
31
+ );
32
+
33
+ const animations = AnimationStore.getAll(current.route.key);
34
+
35
+ const handleBeforeRemove = useStableCallback((e: any) => {
36
+ const isEnabled = current.options.enableTransitions;
37
+
38
+ const isFirstScreen = current.navigation.getState().index === 0;
39
+
40
+ // If transitions are disabled, or an ancestor is dismissing via gesture, or this is the first screen of the stack, reset the stores
41
+ if (!isEnabled || isAncestorDismissingViaGesture || isFirstScreen) {
42
+ animations.closing.set(TRUE);
43
+ resetStoresForScreen(current);
44
+ return;
45
+ }
46
+
47
+ e.preventDefault();
48
+ const onAnimationFinish = (finished: boolean) => {
49
+ if (finished) {
50
+ current.navigation.dispatch(e.data.action);
51
+
52
+ // we'll ensure the dispatch is complete before resetting stores
53
+ requestAnimationFrame(() => {
54
+ resetStoresForScreen(current);
55
+ });
56
+ }
57
+ };
58
+
59
+ startScreenTransition({
60
+ target: "close",
61
+ spec: current.options.transitionSpec,
62
+ onAnimationFinish,
63
+ animations,
64
+ });
65
+ });
66
+
67
+ const handleInitialize = useStableCallback(() => {
68
+ startScreenTransition({
69
+ target: "open",
70
+ spec: current.options.transitionSpec,
71
+ animations,
72
+ });
73
+ });
74
+
75
+ useEffect(() => {
76
+ const unsubscribe = current.navigation.addListener(
77
+ "beforeRemove",
78
+ handleBeforeRemove,
79
+ );
80
+
81
+ return unsubscribe;
82
+ }, [current.navigation, handleBeforeRemove]);
83
+
84
+ useLayoutEffect(handleInitialize, []);
85
+
86
+ return children;
87
+ };
@@ -10,6 +10,7 @@ import {
10
10
  type TransitionDescriptor,
11
11
  useKeys,
12
12
  } from "../../providers/keys.provider";
13
+ import { useStackAnimationValues } from "../../providers/routes.provider";
13
14
  import { AnimationStore } from "../../stores/animation.store";
14
15
  import { GestureStore, type GestureStoreMap } from "../../stores/gesture.store";
15
16
  import type {
@@ -17,7 +18,7 @@ import type {
17
18
  ScreenTransitionState,
18
19
  } from "../../types/animation.types";
19
20
  import type { ScreenTransitionConfig } from "../../types/core.types";
20
- import type { GestureDirection } from "../../types/gesture.types";
21
+ import { computeStackProgress } from "../../utils/animation/compute-stack-progress";
21
22
  import { derivations } from "../../utils/animation/derivations";
22
23
  import { createBounds } from "../../utils/bounds";
23
24
 
@@ -60,10 +61,7 @@ const unwrapInto = (s: BuiltState): ScreenTransitionState => {
60
61
  out.gesture.normalizedY = s.gesture.normalizedY.value;
61
62
  out.gesture.isDismissing = s.gesture.isDismissing.value;
62
63
  out.gesture.isDragging = s.gesture.isDragging.value;
63
- out.gesture.direction = s.gesture.direction.value as Omit<
64
- GestureDirection,
65
- "bidirectional"
66
- > | null;
64
+ out.gesture.direction = s.gesture.direction.value;
67
65
 
68
66
  return out;
69
67
  };
@@ -112,6 +110,9 @@ export function _useScreenAnimation() {
112
110
  const nextAnimation = useBuildScreenTransitionState(nextDescriptor);
113
111
  const prevAnimation = useBuildScreenTransitionState(previousDescriptor);
114
112
 
113
+ const currentRouteKey = currentDescriptor?.route?.key;
114
+ const stackAnimationValues = useStackAnimationValues(currentRouteKey);
115
+
115
116
  const screenInterpolatorProps = useDerivedValue<
116
117
  Omit<ScreenInterpolationProps, "bounds">
117
118
  >(() => {
@@ -129,17 +130,21 @@ export function _useScreenAnimation() {
129
130
  ? unwrapInto(currentAnimation)
130
131
  : DEFAULT_SCREEN_TRANSITION_STATE;
131
132
 
132
- const helpers = derivations({
133
+ const { progress, ...helpers } = derivations({
133
134
  current,
134
135
  next,
135
136
  });
136
137
 
138
+ const stackProgress = computeStackProgress(stackAnimationValues, progress);
139
+
137
140
  return {
138
141
  layouts: { screen: dimensions },
139
142
  insets,
140
143
  previous,
141
144
  current,
142
145
  next,
146
+ progress,
147
+ stackProgress,
143
148
  ...helpers,
144
149
  };
145
150
  });
@@ -40,12 +40,12 @@ import useStableCallbackValue from "../use-stable-callback-value";
40
40
 
41
41
  interface BuildGesturesHookProps {
42
42
  scrollConfig: SharedValue<ScrollConfig | null>;
43
- parentContext?: GestureContextType | null;
43
+ ancestorContext?: GestureContextType | null;
44
44
  }
45
45
 
46
46
  export const useBuildGestures = ({
47
47
  scrollConfig,
48
- parentContext,
48
+ ancestorContext,
49
49
  }: BuildGesturesHookProps): {
50
50
  panGesture: GestureType;
51
51
  nativeGesture: GestureType;
@@ -96,8 +96,8 @@ export const useBuildGestures = ({
96
96
 
97
97
  const handleDismiss = useCallback(() => {
98
98
  // If an ancestor navigator is already dismissing, skip this dismiss to
99
- // avoid racing with the parent
100
- if (parentContext?.gestureAnimationValues.isDismissing?.value) {
99
+ // avoid racing with the ancestor
100
+ if (ancestorContext?.gestureAnimationValues.isDismissing?.value) {
101
101
  return;
102
102
  }
103
103
 
@@ -116,7 +116,7 @@ export const useBuildGestures = ({
116
116
  source: current.route.key,
117
117
  target: state.key,
118
118
  });
119
- }, [current, parentContext]);
119
+ }, [current, ancestorContext]);
120
120
 
121
121
  const onTouchesDown = useStableCallbackValue((e: GestureTouchEvent) => {
122
122
  "worklet";
@@ -130,7 +130,7 @@ export const useBuildGestures = ({
130
130
  "worklet";
131
131
 
132
132
  // If an ancestor navigator is already dismissing via gesture, block new gestures here.
133
- if (parentContext?.gestureAnimationValues.isDismissing?.value) {
133
+ if (ancestorContext?.gestureAnimationValues.isDismissing?.value) {
134
134
  gestureOffsetState.value = GestureOffsetState.FAILED;
135
135
  manager.fail();
136
136
  return;
@@ -338,6 +338,11 @@ export const useBuildGestures = ({
338
338
  .onEnd(onEnd)
339
339
  .blocksExternalGesture(nativeGesture);
340
340
 
341
+ // Allow ancestors to block child native gestures
342
+ if (ancestorContext?.panGesture && nativeGesture) {
343
+ ancestorContext.panGesture.blocksExternalGesture(nativeGesture);
344
+ }
345
+
341
346
  return {
342
347
  panGesture,
343
348
  nativeGesture,
@@ -351,5 +356,6 @@ export const useBuildGestures = ({
351
356
  onUpdate,
352
357
  onEnd,
353
358
  gestureAnimationValues,
359
+ ancestorContext,
354
360
  ]);
355
361
  };
@@ -12,7 +12,7 @@ interface ScrollProgressHookProps {
12
12
  }
13
13
 
14
14
  export const useScrollRegistry = (props: ScrollProgressHookProps) => {
15
- const { scrollConfig, parentContext } = useGestureContext();
15
+ const { scrollConfig, ancestorContext } = useGestureContext();
16
16
 
17
17
  const scrollHandler = useAnimatedScrollHandler({
18
18
  onScroll: (event) => {
@@ -35,8 +35,8 @@ export const useScrollRegistry = (props: ScrollProgressHookProps) => {
35
35
  return v;
36
36
  });
37
37
 
38
- if (parentContext?.scrollConfig) {
39
- parentContext.scrollConfig.modify((v: Any) => {
38
+ if (ancestorContext?.scrollConfig) {
39
+ ancestorContext.scrollConfig.modify((v: Any) => {
40
40
  "worklet";
41
41
  if (v === null) {
42
42
  return {
@@ -76,8 +76,8 @@ export const useScrollRegistry = (props: ScrollProgressHookProps) => {
76
76
  v.contentHeight = height;
77
77
  return v;
78
78
  });
79
- if (parentContext?.scrollConfig) {
80
- parentContext.scrollConfig.modify((v: Any) => {
79
+ if (ancestorContext?.scrollConfig) {
80
+ ancestorContext.scrollConfig.modify((v: Any) => {
81
81
  "worklet";
82
82
  if (v === null) {
83
83
  return {
@@ -117,8 +117,8 @@ export const useScrollRegistry = (props: ScrollProgressHookProps) => {
117
117
  v.layoutWidth = width;
118
118
  return v;
119
119
  });
120
- if (parentContext?.scrollConfig) {
121
- parentContext.scrollConfig.modify((v: Any) => {
120
+ if (ancestorContext?.scrollConfig) {
121
+ ancestorContext.scrollConfig.modify((v: Any) => {
122
122
  "worklet";
123
123
  if (v === null) {
124
124
  return {
@@ -6,6 +6,7 @@ import type { SharedValue } from "react-native-reanimated";
6
6
  import { useSharedValue } from "react-native-reanimated";
7
7
  import { useBuildGestures } from "../hooks/gestures/use-build-gestures";
8
8
  import type { GestureStoreMap } from "../stores/gesture.store";
9
+ import { useKeys } from "./keys.provider";
9
10
 
10
11
  export type ScrollConfig = {
11
12
  x: number;
@@ -21,7 +22,7 @@ export interface GestureContextType {
21
22
  nativeGesture: GestureType;
22
23
  scrollConfig: SharedValue<ScrollConfig | null>;
23
24
  gestureAnimationValues: GestureStoreMap;
24
- parentContext: GestureContextType | null;
25
+ ancestorContext: GestureContextType | undefined;
25
26
  }
26
27
 
27
28
  type GestureProviderProps = {
@@ -30,15 +31,43 @@ type GestureProviderProps = {
30
31
 
31
32
  const GestureContext = createContext<GestureContextType | undefined>(undefined);
32
33
 
34
+ /**
35
+ * Provider that creates gesture handling for a screen.
36
+ * If the current screen doesn't have gestures enabled but a parent does,
37
+ * we pass through the parent's context so scrollable children can coordinate
38
+ * with the ancestor's gestures.
39
+ */
33
40
  export const ScreenGestureProvider = ({ children }: GestureProviderProps) => {
34
- const parentContext = useContext(GestureContext);
41
+ const ancestorContext = useContext(GestureContext);
42
+ const { current } = useKeys();
35
43
 
44
+ const hasOwnGestures = current.options.gestureEnabled === true;
45
+
46
+ // If this screen doesn't have its own gestures but an ancestor does,
47
+ // pass through so scrollable children coordinate with that ancestor
48
+ if (!hasOwnGestures && ancestorContext) {
49
+ return children;
50
+ }
51
+
52
+ return (
53
+ <ScreenGestureProviderInner ancestorContext={ancestorContext}>
54
+ {children}
55
+ </ScreenGestureProviderInner>
56
+ );
57
+ };
58
+
59
+ const ScreenGestureProviderInner = ({
60
+ children,
61
+ ancestorContext,
62
+ }: GestureProviderProps & {
63
+ ancestorContext: GestureContextType | undefined;
64
+ }) => {
36
65
  const scrollConfig = useSharedValue<ScrollConfig | null>(null);
37
66
 
38
67
  const { panGesture, nativeGesture, gestureAnimationValues } =
39
68
  useBuildGestures({
40
69
  scrollConfig,
41
- parentContext,
70
+ ancestorContext,
42
71
  });
43
72
 
44
73
  const value: GestureContextType = useMemo(
@@ -47,14 +76,14 @@ export const ScreenGestureProvider = ({ children }: GestureProviderProps) => {
47
76
  scrollConfig,
48
77
  nativeGesture,
49
78
  gestureAnimationValues,
50
- parentContext: parentContext || null,
79
+ ancestorContext,
51
80
  }),
52
81
  [
53
82
  panGesture,
54
83
  scrollConfig,
55
84
  nativeGesture,
56
85
  gestureAnimationValues,
57
- parentContext,
86
+ ancestorContext,
58
87
  ],
59
88
  );
60
89
 
@@ -148,9 +148,10 @@ const useBlurMeasurement = (params: {
148
148
  const maybeMeasureOnBlur = useStableCallbackValue(() => {
149
149
  "worklet";
150
150
 
151
- // Don't measure if current / any ancestor is closing
152
- const isOneClosing = ancestorClosing.some((closing) => closing.get());
153
- if (isOneClosing) return;
151
+ //.some doesnt work here apparently... :-(
152
+ for (const closing of ancestorClosing) {
153
+ if (closing.get()) return;
154
+ }
154
155
 
155
156
  maybeMeasureAndStore({ shouldSetSource: true });
156
157
  });
@@ -0,0 +1,54 @@
1
+ import { useMemo } from "react";
2
+ import {
3
+ AnimationStore,
4
+ type AnimationStoreMap,
5
+ } from "../stores/animation.store";
6
+ import createProvider from "../utils/create-provider";
7
+
8
+ interface RoutesProviderProps {
9
+ children: React.ReactNode;
10
+ routeKeys: string[];
11
+ }
12
+
13
+ interface RoutesContextValue {
14
+ /**
15
+ * Array of route keys for all routes in the stack, in order.
16
+ */
17
+ routeKeys: string[];
18
+ }
19
+
20
+ const { RoutesProvider, useRoutesContext } = createProvider("Routes", {
21
+ guarded: false,
22
+ })<RoutesProviderProps, RoutesContextValue>(({ routeKeys }) => ({
23
+ value: { routeKeys },
24
+ }));
25
+
26
+ export { RoutesProvider, useRoutesContext };
27
+
28
+ /**
29
+ * Hook to get animation values for all screens from a given index onwards.
30
+ * Useful for computing accumulated progress across multiple screens.
31
+ */
32
+ export function useStackAnimationValues(
33
+ currentRouteKey: string | undefined,
34
+ ): AnimationStoreMap[] {
35
+ const routesContext = useRoutesContext();
36
+
37
+ return useMemo(() => {
38
+ if (!currentRouteKey || !routesContext) {
39
+ return [];
40
+ }
41
+
42
+ const { routeKeys } = routesContext;
43
+ const currentIndex = routeKeys.indexOf(currentRouteKey);
44
+
45
+ if (currentIndex === -1) {
46
+ return [];
47
+ }
48
+
49
+ // Get animation values for all screens from current index onwards
50
+ return routeKeys
51
+ .slice(currentIndex)
52
+ .map((key) => AnimationStore.getAll(key));
53
+ }, [currentRouteKey, routesContext]);
54
+ }
@@ -1,7 +1,7 @@
1
1
  import type React from "react";
2
2
  import type { ComponentType } from "react";
3
- import type { ScreenLifecycleProps } from "../components/controllers/screen-lifecycle";
4
3
  import { RootTransitionAware } from "../components/root-transition-aware";
4
+ import type { Any } from "../types/utils.types";
5
5
  import { ScreenGestureProvider } from "./gestures.provider";
6
6
  import { KeysProvider, type TransitionDescriptor } from "./keys.provider";
7
7
  import { TransitionStylesProvider } from "./transition-styles.provider";
@@ -11,7 +11,7 @@ type Props<TDescriptor extends TransitionDescriptor> = {
11
11
  current: TDescriptor;
12
12
  next?: TDescriptor;
13
13
  children: React.ReactNode;
14
- LifecycleController: ComponentType<ScreenLifecycleProps>;
14
+ LifecycleController: ComponentType<Any>;
15
15
  };
16
16
 
17
17
  export function ScreenTransitionProvider<
@@ -75,6 +75,19 @@ export interface ScreenInterpolationProps {
75
75
  */
76
76
  progress: number;
77
77
 
78
+ /**
79
+ * Accumulated progress from the current screen's position onwards in the stack.
80
+ * Unlike `progress` (0-2), this ranges from 0-N where N is the number of screens
81
+ * above the current screen. Each screen at index I sees stackProgress as the
82
+ * sum of all progress values from index I to the top of the stack.
83
+ *
84
+ * Example: With 4 screens pushed, screen at index 1 would see stackProgress = 3
85
+ * when all screens are fully transitioned.
86
+ *
87
+ * Falls back to `progress` when not in blank-stack.
88
+ */
89
+ stackProgress: number;
90
+
78
91
  /**
79
92
  * Function that provides access to bounds builders for creating shared element transitions.
80
93
  */
@@ -0,0 +1,2 @@
1
+ export const TRUE = 1;
2
+ export const FALSE = 0;
@@ -0,0 +1,16 @@
1
+ import type { AnimationStoreMap } from "../../stores/animation.store";
2
+
3
+ export const computeStackProgress = (
4
+ stackAnimationValues: AnimationStoreMap[],
5
+ fallback: number = 0,
6
+ ) => {
7
+ "worklet";
8
+ let computedStackProgress: number | undefined;
9
+ if (stackAnimationValues.length > 0) {
10
+ computedStackProgress = 0;
11
+ for (let i = 0; i < stackAnimationValues.length; i += 1) {
12
+ computedStackProgress += stackAnimationValues[i].progress.value;
13
+ }
14
+ }
15
+ return computedStackProgress ?? fallback;
16
+ };
@@ -11,7 +11,7 @@ interface DerivationsParams {
11
11
  export const derivations = ({ current, next }: DerivationsParams) => {
12
12
  "worklet";
13
13
 
14
- // The combined progress
14
+ // The combined progress (current + next, 0-2 range)
15
15
  const progress = current.progress + (next?.progress ?? 0);
16
16
 
17
17
  // Whether the current screen is focused
@@ -1,6 +1,7 @@
1
1
  import { runOnJS } from "react-native-reanimated";
2
2
  import type { AnimationStoreMap } from "../../stores/animation.store";
3
3
  import type { TransitionSpec } from "../../types/animation.types";
4
+ import { FALSE, TRUE } from "../../types/state.types";
4
5
  import { animate } from "./animate";
5
6
 
6
7
  interface StartScreenTransitionProps {
@@ -34,12 +35,12 @@ export const startScreenTransition = ({
34
35
  const { progress, animating, closing } = animations;
35
36
 
36
37
  if (target === "close") {
37
- closing.value = 1;
38
+ closing.set(TRUE);
38
39
  }
39
40
 
40
41
  if (!config) {
41
- animating.value = 0;
42
- progress.value = value;
42
+ animating.set(FALSE);
43
+ progress.set(value);
43
44
 
44
45
  if (onAnimationFinish) {
45
46
  runOnJS(onAnimationFinish)(true);
@@ -47,15 +48,17 @@ export const startScreenTransition = ({
47
48
  return;
48
49
  }
49
50
 
50
- animating.value = 1;
51
+ animating.set(TRUE); //<-- Do not move this into the callback
52
+ progress.set(
53
+ animate(value, effectiveConfig, (finished) => {
54
+ "worklet";
55
+ if (!finished) return;
51
56
 
52
- progress.value = animate(value, effectiveConfig, (finished) => {
53
- "worklet";
54
- if (finished) {
55
57
  if (onAnimationFinish) {
56
58
  runOnJS(onAnimationFinish)(finished);
57
59
  }
58
- animating.value = 0;
59
- }
60
- });
60
+
61
+ animating.set(FALSE);
62
+ }),
63
+ );
61
64
  };
@@ -1,142 +0,0 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.NativeStackScreenLifecycleController = exports.BlankStackScreenLifecycleController = void 0;
7
- var _react = require("react");
8
- var _reactNativeReanimated = require("react-native-reanimated");
9
- var _withStackNavigation = require("../../../blank-stack/utils/with-stack-navigation");
10
- var _useParentGestureRegistry = require("../../hooks/gestures/use-parent-gesture-registry");
11
- var _useSharedValueState = require("../../hooks/reanimated/use-shared-value-state");
12
- var _useStableCallback = _interopRequireDefault(require("../../hooks/use-stable-callback"));
13
- var _gestures = require("../../providers/gestures.provider");
14
- var _keys = require("../../providers/keys.provider");
15
- var _animation = require("../../stores/animation.store");
16
- var _startScreenTransition = require("../../utils/animation/start-screen-transition");
17
- var _resetStoresForScreen = require("../../utils/reset-stores-for-screen");
18
- function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
19
- /**
20
- * ScreenLifecycleController built out for Native Stack implementation.
21
- */
22
- const NativeStackScreenLifecycleController = ({
23
- children
24
- }) => {
25
- const {
26
- current
27
- } = (0, _keys.useKeys)();
28
- const {
29
- parentContext
30
- } = (0, _gestures.useGestureContext)();
31
- const isParentDismissingViaGesture = (0, _useSharedValueState.useSharedValueState)((0, _reactNativeReanimated.useDerivedValue)(() => {
32
- "worklet";
33
-
34
- return parentContext?.gestureAnimationValues.isDismissing?.value ?? false;
35
- }));
36
- const animations = _animation.AnimationStore.getAll(current.route.key);
37
- const handleBeforeRemove = (0, _useStableCallback.default)(e => {
38
- const isEnabled = current.options.enableTransitions;
39
- const isFirstScreen = current.navigation.getState().index === 0;
40
-
41
- // If transitions are disabled, or the dismissal was on the local root, or this is the first screen of the stack, reset the stores
42
- if (!isEnabled || isParentDismissingViaGesture || isFirstScreen) {
43
- (0, _resetStoresForScreen.resetStoresForScreen)(current);
44
- return;
45
- }
46
- e.preventDefault();
47
- const onAnimationFinish = finished => {
48
- if (finished) {
49
- current.navigation.dispatch(e.data.action);
50
-
51
- // we'll ensure the dispatch is complete before resetting stores
52
- requestAnimationFrame(() => {
53
- (0, _resetStoresForScreen.resetStoresForScreen)(current);
54
- });
55
- }
56
- };
57
- (0, _startScreenTransition.startScreenTransition)({
58
- target: "close",
59
- spec: current.options.transitionSpec,
60
- onAnimationFinish,
61
- animations
62
- });
63
- });
64
- const handleInitialize = (0, _useStableCallback.default)(() => {
65
- (0, _startScreenTransition.startScreenTransition)({
66
- target: "open",
67
- spec: current.options.transitionSpec,
68
- animations
69
- });
70
- });
71
- (0, _react.useEffect)(() => {
72
- const unsubscribe = current.navigation.addListener("beforeRemove", handleBeforeRemove);
73
- return unsubscribe;
74
- }, [current.navigation, handleBeforeRemove]);
75
- (0, _react.useLayoutEffect)(handleInitialize, []);
76
-
77
- // important for t.a scrollviews inside nested navigators.
78
- (0, _useParentGestureRegistry.useParentGestureRegistry)();
79
- return children;
80
- };
81
-
82
- /**
83
- * ScreenLifecycleController built out for Blank Stack implementation.
84
- */
85
- exports.NativeStackScreenLifecycleController = NativeStackScreenLifecycleController;
86
- const BlankStackScreenLifecycleController = ({
87
- children
88
- }) => {
89
- const {
90
- current
91
- } = (0, _keys.useKeys)();
92
- const {
93
- handleCloseRoute,
94
- closingRouteKeysShared
95
- } = (0, _withStackNavigation.useStackNavigationContext)();
96
- const animations = _animation.AnimationStore.getAll(current.route.key);
97
- const handleInitialize = (0, _useStableCallback.default)(() => {
98
- (0, _startScreenTransition.startScreenTransition)({
99
- target: "open",
100
- spec: current.options.transitionSpec,
101
- animations
102
- });
103
- });
104
- const handleCleanup = (0, _useStableCallback.default)(() => {
105
- (0, _resetStoresForScreen.resetStoresForScreen)(current);
106
- });
107
- const handleCloseEnd = (0, _useStableCallback.default)(finished => {
108
- if (!finished) {
109
- return;
110
- }
111
- handleCloseRoute({
112
- route: current.route
113
- });
114
- });
115
- (0, _reactNativeReanimated.useAnimatedReaction)(() => ({
116
- keys: closingRouteKeysShared.value
117
- }), ({
118
- keys
119
- }) => {
120
- if (!keys.includes(current.route.key)) {
121
- return;
122
- }
123
- (0, _startScreenTransition.startScreenTransition)({
124
- target: "close",
125
- spec: current.options.transitionSpec,
126
- animations,
127
- onAnimationFinish: handleCloseEnd
128
- });
129
- });
130
- (0, _react.useLayoutEffect)(() => {
131
- handleInitialize();
132
- return () => {
133
- handleCleanup();
134
- };
135
- }, [handleInitialize, handleCleanup]);
136
-
137
- // important for t.a scrollviews inside nested navigators.
138
- (0, _useParentGestureRegistry.useParentGestureRegistry)();
139
- return children;
140
- };
141
- exports.BlankStackScreenLifecycleController = BlankStackScreenLifecycleController;
142
- //# sourceMappingURL=screen-lifecycle.js.map
@@ -1 +0,0 @@
1
- {"version":3,"names":["_react","require","_reactNativeReanimated","_withStackNavigation","_useParentGestureRegistry","_useSharedValueState","_useStableCallback","_interopRequireDefault","_gestures","_keys","_animation","_startScreenTransition","_resetStoresForScreen","e","__esModule","default","NativeStackScreenLifecycleController","children","current","useKeys","parentContext","useGestureContext","isParentDismissingViaGesture","useSharedValueState","useDerivedValue","gestureAnimationValues","isDismissing","value","animations","AnimationStore","getAll","route","key","handleBeforeRemove","useStableCallback","isEnabled","options","enableTransitions","isFirstScreen","navigation","getState","index","resetStoresForScreen","preventDefault","onAnimationFinish","finished","dispatch","data","action","requestAnimationFrame","startScreenTransition","target","spec","transitionSpec","handleInitialize","useEffect","unsubscribe","addListener","useLayoutEffect","useParentGestureRegistry","exports","BlankStackScreenLifecycleController","handleCloseRoute","closingRouteKeysShared","useStackNavigationContext","handleCleanup","handleCloseEnd","useAnimatedReaction","keys","includes"],"sourceRoot":"../../../../../src","sources":["shared/components/controllers/screen-lifecycle.tsx"],"mappings":"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","ignoreList":[]}