react-native-screen-transitions 2.3.0 → 2.3.2

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 (184) hide show
  1. package/lib/commonjs/__configs__/index.js.map +1 -0
  2. package/lib/commonjs/__configs__/presets.js.map +1 -0
  3. package/lib/commonjs/__configs__/specs.js.map +1 -0
  4. package/lib/commonjs/components/controllers/screen-lifecycle.js +5 -5
  5. package/lib/commonjs/components/controllers/screen-lifecycle.js.map +1 -1
  6. package/lib/commonjs/components/create-transition-aware-component.js +13 -32
  7. package/lib/commonjs/components/create-transition-aware-component.js.map +1 -1
  8. package/lib/commonjs/components/integrations/masked-view.js +3 -4
  9. package/lib/commonjs/components/integrations/masked-view.js.map +1 -1
  10. package/lib/commonjs/components/root-transition-aware.js +3 -3
  11. package/lib/commonjs/components/root-transition-aware.js.map +1 -1
  12. package/lib/commonjs/constants.js +103 -0
  13. package/lib/commonjs/constants.js.map +1 -0
  14. package/lib/commonjs/hooks/animation/use-associated-style.js +10 -9
  15. package/lib/commonjs/hooks/animation/use-associated-style.js.map +1 -1
  16. package/lib/commonjs/hooks/animation/use-screen-animation.js +7 -20
  17. package/lib/commonjs/hooks/animation/use-screen-animation.js.map +1 -1
  18. package/lib/commonjs/hooks/bounds/use-bound-registry.js +93 -31
  19. package/lib/commonjs/hooks/bounds/use-bound-registry.js.map +1 -1
  20. package/lib/commonjs/hooks/gestures/use-build-gestures.js +9 -13
  21. package/lib/commonjs/hooks/gestures/use-build-gestures.js.map +1 -1
  22. package/lib/commonjs/index.js +3 -3
  23. package/lib/commonjs/index.js.map +1 -1
  24. package/lib/commonjs/integrations/native-stack/utils/debounce.js.map +1 -1
  25. package/lib/commonjs/integrations/native-stack/utils/useAnimatedHeaderHeight.js.map +1 -1
  26. package/lib/commonjs/integrations/native-stack/utils/useDismissedRouteError.js.map +1 -1
  27. package/lib/commonjs/integrations/native-stack/views/FontProcessor.js +1 -1
  28. package/lib/commonjs/integrations/native-stack/views/FontProcessor.js.map +1 -1
  29. package/lib/commonjs/integrations/native-stack/views/FontProcessor.native.js +1 -1
  30. package/lib/commonjs/integrations/native-stack/views/FontProcessor.native.js.map +1 -1
  31. package/lib/commonjs/integrations/native-stack/views/NativeStackView.native.js +3 -15
  32. package/lib/commonjs/integrations/native-stack/views/NativeStackView.native.js.map +1 -1
  33. package/lib/commonjs/providers/gestures.js +1 -9
  34. package/lib/commonjs/providers/gestures.js.map +1 -1
  35. package/lib/commonjs/providers/screen-transition-provider.js +34 -0
  36. package/lib/commonjs/providers/screen-transition-provider.js.map +1 -0
  37. package/lib/commonjs/providers/transition-styles.js +4 -4
  38. package/lib/commonjs/providers/transition-styles.js.map +1 -1
  39. package/lib/commonjs/utils/animation/{run-transition.js → start-screen-transition.js} +9 -9
  40. package/lib/commonjs/utils/animation/start-screen-transition.js.map +1 -0
  41. package/lib/commonjs/utils/bounds/index.js +6 -18
  42. package/lib/commonjs/utils/bounds/index.js.map +1 -1
  43. package/lib/commonjs/utils/gesture/apply-offset-rules.js +12 -21
  44. package/lib/commonjs/utils/gesture/apply-offset-rules.js.map +1 -1
  45. package/lib/module/__configs__/index.js.map +1 -0
  46. package/lib/module/__configs__/presets.js.map +1 -0
  47. package/lib/module/__configs__/specs.js.map +1 -0
  48. package/lib/module/components/controllers/screen-lifecycle.js +5 -5
  49. package/lib/module/components/controllers/screen-lifecycle.js.map +1 -1
  50. package/lib/module/components/create-transition-aware-component.js +13 -32
  51. package/lib/module/components/create-transition-aware-component.js.map +1 -1
  52. package/lib/module/components/integrations/masked-view.js +1 -2
  53. package/lib/module/components/integrations/masked-view.js.map +1 -1
  54. package/lib/module/components/root-transition-aware.js +3 -3
  55. package/lib/module/components/root-transition-aware.js.map +1 -1
  56. package/lib/module/constants.js +98 -0
  57. package/lib/module/constants.js.map +1 -0
  58. package/lib/module/hooks/animation/use-associated-style.js +10 -9
  59. package/lib/module/hooks/animation/use-associated-style.js.map +1 -1
  60. package/lib/module/hooks/animation/use-screen-animation.js +7 -20
  61. package/lib/module/hooks/animation/use-screen-animation.js.map +1 -1
  62. package/lib/module/hooks/bounds/use-bound-registry.js +94 -33
  63. package/lib/module/hooks/bounds/use-bound-registry.js.map +1 -1
  64. package/lib/module/hooks/gestures/use-build-gestures.js +4 -8
  65. package/lib/module/hooks/gestures/use-build-gestures.js.map +1 -1
  66. package/lib/module/index.js +1 -1
  67. package/lib/module/index.js.map +1 -1
  68. package/lib/module/integrations/native-stack/utils/debounce.js.map +1 -1
  69. package/lib/module/integrations/native-stack/utils/useAnimatedHeaderHeight.js +1 -1
  70. package/lib/module/integrations/native-stack/utils/useAnimatedHeaderHeight.js.map +1 -1
  71. package/lib/module/integrations/native-stack/utils/useDismissedRouteError.js +1 -1
  72. package/lib/module/integrations/native-stack/utils/useDismissedRouteError.js.map +1 -1
  73. package/lib/module/integrations/native-stack/views/FontProcessor.js +1 -1
  74. package/lib/module/integrations/native-stack/views/FontProcessor.js.map +1 -1
  75. package/lib/module/integrations/native-stack/views/FontProcessor.native.js +2 -2
  76. package/lib/module/integrations/native-stack/views/FontProcessor.native.js.map +1 -1
  77. package/lib/module/integrations/native-stack/views/NativeStackView.native.js +3 -15
  78. package/lib/module/integrations/native-stack/views/NativeStackView.native.js.map +1 -1
  79. package/lib/module/providers/gestures.js +0 -8
  80. package/lib/module/providers/gestures.js.map +1 -1
  81. package/lib/module/providers/screen-transition-provider.js +30 -0
  82. package/lib/module/providers/screen-transition-provider.js.map +1 -0
  83. package/lib/module/providers/transition-styles.js +4 -4
  84. package/lib/module/providers/transition-styles.js.map +1 -1
  85. package/lib/module/utils/animation/{run-transition.js → start-screen-transition.js} +7 -7
  86. package/lib/module/utils/animation/start-screen-transition.js.map +1 -0
  87. package/lib/module/utils/bounds/index.js +5 -17
  88. package/lib/module/utils/bounds/index.js.map +1 -1
  89. package/lib/module/utils/gesture/apply-offset-rules.js +1 -10
  90. package/lib/module/utils/gesture/apply-offset-rules.js.map +1 -1
  91. package/lib/typescript/__configs__/index.d.ts.map +1 -0
  92. package/lib/typescript/__configs__/presets.d.ts.map +1 -0
  93. package/lib/typescript/__configs__/specs.d.ts.map +1 -0
  94. package/lib/typescript/components/create-transition-aware-component.d.ts +20 -2
  95. package/lib/typescript/components/create-transition-aware-component.d.ts.map +1 -1
  96. package/lib/typescript/components/integrations/masked-view.d.ts.map +1 -1
  97. package/lib/typescript/components/root-transition-aware.d.ts.map +1 -1
  98. package/lib/typescript/constants.d.ts +57 -0
  99. package/lib/typescript/constants.d.ts.map +1 -0
  100. package/lib/typescript/hooks/animation/use-associated-style.d.ts +1 -1
  101. package/lib/typescript/hooks/animation/use-associated-style.d.ts.map +1 -1
  102. package/lib/typescript/hooks/animation/use-screen-animation.d.ts.map +1 -1
  103. package/lib/typescript/hooks/bounds/use-bound-registry.d.ts +12 -9
  104. package/lib/typescript/hooks/bounds/use-bound-registry.d.ts.map +1 -1
  105. package/lib/typescript/hooks/gestures/use-build-gestures.d.ts.map +1 -1
  106. package/lib/typescript/index.d.ts +2 -6
  107. package/lib/typescript/index.d.ts.map +1 -1
  108. package/lib/typescript/integrations/native-stack/utils/debounce.d.ts.map +1 -1
  109. package/lib/typescript/integrations/native-stack/utils/useAnimatedHeaderHeight.d.ts +2 -2
  110. package/lib/typescript/integrations/native-stack/utils/useDismissedRouteError.d.ts +2 -2
  111. package/lib/typescript/integrations/native-stack/utils/useDismissedRouteError.d.ts.map +1 -1
  112. package/lib/typescript/integrations/native-stack/views/FontProcessor.d.ts.map +1 -1
  113. package/lib/typescript/integrations/native-stack/views/FontProcessor.native.d.ts.map +1 -1
  114. package/lib/typescript/integrations/native-stack/views/NativeStackView.native.d.ts.map +1 -1
  115. package/lib/typescript/providers/gestures.d.ts +0 -1
  116. package/lib/typescript/providers/gestures.d.ts.map +1 -1
  117. package/lib/typescript/providers/screen-transition-provider.d.ts +11 -0
  118. package/lib/typescript/providers/screen-transition-provider.d.ts.map +1 -0
  119. package/lib/typescript/providers/transition-styles.d.ts.map +1 -1
  120. package/lib/typescript/types/core.d.ts +0 -8
  121. package/lib/typescript/types/core.d.ts.map +1 -1
  122. package/lib/typescript/utils/animation/start-screen-transition.d.ts +12 -0
  123. package/lib/typescript/utils/animation/start-screen-transition.d.ts.map +1 -0
  124. package/lib/typescript/utils/bounds/_types/get-bounds.d.ts +2 -2
  125. package/lib/typescript/utils/bounds/_types/get-bounds.d.ts.map +1 -1
  126. package/lib/typescript/utils/bounds/index.d.ts.map +1 -1
  127. package/lib/typescript/utils/gesture/apply-offset-rules.d.ts.map +1 -1
  128. package/package.json +1 -1
  129. package/src/components/controllers/screen-lifecycle.tsx +5 -5
  130. package/src/components/create-transition-aware-component.tsx +23 -38
  131. package/src/components/integrations/masked-view.tsx +1 -3
  132. package/src/components/root-transition-aware.tsx +4 -8
  133. package/src/constants.ts +106 -0
  134. package/src/hooks/animation/use-associated-style.tsx +14 -10
  135. package/src/hooks/animation/use-screen-animation.tsx +17 -24
  136. package/src/hooks/bounds/use-bound-registry.tsx +113 -25
  137. package/src/hooks/gestures/use-build-gestures.tsx +11 -10
  138. package/src/index.ts +1 -1
  139. package/src/integrations/native-stack/utils/debounce.tsx +9 -9
  140. package/src/integrations/native-stack/utils/useAnimatedHeaderHeight.tsx +10 -10
  141. package/src/integrations/native-stack/utils/useDismissedRouteError.tsx +21 -21
  142. package/src/integrations/native-stack/views/FontProcessor.native.tsx +7 -7
  143. package/src/integrations/native-stack/views/FontProcessor.tsx +2 -2
  144. package/src/integrations/native-stack/views/NativeStackView.native.tsx +4 -14
  145. package/src/providers/gestures.tsx +0 -9
  146. package/src/providers/screen-transition-provider.tsx +33 -0
  147. package/src/providers/transition-styles.tsx +6 -5
  148. package/src/types/core.ts +0 -9
  149. package/src/utils/animation/{run-transition.ts → start-screen-transition.ts} +9 -9
  150. package/src/utils/bounds/_types/get-bounds.ts +7 -7
  151. package/src/utils/bounds/index.ts +12 -19
  152. package/src/utils/gesture/apply-offset-rules.ts +9 -11
  153. package/lib/commonjs/components/bound-capture.js +0 -38
  154. package/lib/commonjs/components/bound-capture.js.map +0 -1
  155. package/lib/commonjs/configs/index.js.map +0 -1
  156. package/lib/commonjs/configs/presets.js.map +0 -1
  157. package/lib/commonjs/configs/specs.js.map +0 -1
  158. package/lib/commonjs/utils/animation/run-transition.js.map +0 -1
  159. package/lib/module/components/bound-capture.js +0 -33
  160. package/lib/module/components/bound-capture.js.map +0 -1
  161. package/lib/module/configs/index.js.map +0 -1
  162. package/lib/module/configs/presets.js.map +0 -1
  163. package/lib/module/configs/specs.js.map +0 -1
  164. package/lib/module/utils/animation/run-transition.js.map +0 -1
  165. package/lib/typescript/components/bound-capture.d.ts +0 -8
  166. package/lib/typescript/components/bound-capture.d.ts.map +0 -1
  167. package/lib/typescript/configs/index.d.ts.map +0 -1
  168. package/lib/typescript/configs/presets.d.ts.map +0 -1
  169. package/lib/typescript/configs/specs.d.ts.map +0 -1
  170. package/lib/typescript/utils/animation/run-transition.d.ts +0 -12
  171. package/lib/typescript/utils/animation/run-transition.d.ts.map +0 -1
  172. package/src/components/bound-capture.tsx +0 -32
  173. /package/lib/commonjs/{configs → __configs__}/index.js +0 -0
  174. /package/lib/commonjs/{configs → __configs__}/presets.js +0 -0
  175. /package/lib/commonjs/{configs → __configs__}/specs.js +0 -0
  176. /package/lib/module/{configs → __configs__}/index.js +0 -0
  177. /package/lib/module/{configs → __configs__}/presets.js +0 -0
  178. /package/lib/module/{configs → __configs__}/specs.js +0 -0
  179. /package/lib/typescript/{configs → __configs__}/index.d.ts +0 -0
  180. /package/lib/typescript/{configs → __configs__}/presets.d.ts +0 -0
  181. /package/lib/typescript/{configs → __configs__}/specs.d.ts +0 -0
  182. /package/src/{configs → __configs__}/index.ts +0 -0
  183. /package/src/{configs → __configs__}/presets.ts +0 -0
  184. /package/src/{configs → __configs__}/specs.ts +0 -0
@@ -3,6 +3,10 @@ import { useMemo } from "react";
3
3
  import { useWindowDimensions } from "react-native";
4
4
  import { type SharedValue, useDerivedValue } from "react-native-reanimated";
5
5
  import { useSafeAreaInsets } from "react-native-safe-area-context";
6
+ import {
7
+ DEFAULT_SCREEN_TRANSITION_STATE,
8
+ NO_BOUNDS_MAP,
9
+ } from "../../constants";
6
10
  import { useKeys } from "../../providers/keys";
7
11
  import { Animations } from "../../stores/animations";
8
12
  import { Bounds } from "../../stores/bounds";
@@ -11,7 +15,7 @@ import type {
11
15
  ScreenInterpolationProps,
12
16
  ScreenTransitionState,
13
17
  } from "../../types/animation";
14
- import type { BoundEntry } from "../../types/bounds";
18
+
15
19
  import type { NativeStackDescriptor } from "../../types/navigator";
16
20
  import { derivations } from "../../utils/animation/derivations";
17
21
 
@@ -23,24 +27,6 @@ type BuiltState = {
23
27
  route: RouteProp<ParamListBase>;
24
28
  };
25
29
 
26
- const EMPTY_BOUNDS = Object.freeze({}) as Record<string, BoundEntry>;
27
-
28
- const FALLBACK: ScreenTransitionState = Object.freeze({
29
- progress: 0,
30
- closing: 0,
31
- animating: 0,
32
- gesture: {
33
- x: 0,
34
- y: 0,
35
- normalizedX: 0,
36
- normalizedY: 0,
37
- isDismissing: 0,
38
- isDragging: 0,
39
- },
40
- bounds: {} as Record<string, BoundEntry>,
41
- route: {} as RouteProp<ParamListBase>,
42
- });
43
-
44
30
  const unwrap = (
45
31
  s: BuiltState | undefined,
46
32
  key: string | undefined,
@@ -60,7 +46,7 @@ const unwrap = (
60
46
  isDismissing: s.gesture.isDismissing.value,
61
47
  isDragging: s.gesture.isDragging.value,
62
48
  },
63
- bounds: Bounds.getBounds(key) || EMPTY_BOUNDS,
49
+ bounds: Bounds.getBounds(key) || NO_BOUNDS_MAP,
64
50
  route: s.route,
65
51
  };
66
52
  };
@@ -102,9 +88,14 @@ export function _useScreenAnimation() {
102
88
  "worklet";
103
89
 
104
90
  const previous = unwrap(prevAnimation, previousDescriptor?.route.key);
105
- const next = unwrap(nextAnimation, nextDescriptor?.route.key);
91
+
92
+ const next = nextDescriptor?.options?.enableTransitions
93
+ ? unwrap(nextAnimation, nextDescriptor?.route.key)
94
+ : undefined;
95
+
106
96
  const current =
107
- unwrap(currentAnimation, currentDescriptor?.route.key) ?? FALLBACK;
97
+ unwrap(currentAnimation, currentDescriptor?.route.key) ??
98
+ DEFAULT_SCREEN_TRANSITION_STATE;
108
99
 
109
100
  const {
110
101
  progress,
@@ -138,10 +129,12 @@ export function _useScreenAnimation() {
138
129
  },
139
130
  );
140
131
 
141
- const screenStyleInterpolator =
142
- nextDescriptor?.options.screenStyleInterpolator ||
132
+ const nextInterpolator = nextDescriptor?.options.screenStyleInterpolator;
133
+ const currentInterpolator =
143
134
  currentDescriptor?.options.screenStyleInterpolator;
144
135
 
136
+ const screenStyleInterpolator = nextInterpolator ?? currentInterpolator;
137
+
145
138
  return { screenInterpolatorProps, screenStyleInterpolator };
146
139
  }
147
140
 
@@ -1,72 +1,160 @@
1
- import { useCallback } from "react";
1
+ import {
2
+ createContext,
3
+ Fragment,
4
+ useCallback,
5
+ useContext,
6
+ useMemo,
7
+ } from "react";
2
8
  import type { View } from "react-native";
3
9
  import {
4
10
  type AnimatedRef,
5
11
  measure,
12
+ runOnJS,
13
+ runOnUI,
6
14
  type StyleProps,
15
+ useAnimatedReaction,
7
16
  useSharedValue,
8
17
  } from "react-native-reanimated";
18
+ import type { SharedValue } from "react-native-reanimated/lib/typescript/commonTypes";
9
19
  import { useKeys } from "../../providers/keys";
10
20
  import { Bounds } from "../../stores/bounds";
11
21
  import { flattenStyle } from "../../utils/bounds/_utils/flatten-styles";
12
22
  import { isBoundsEqual } from "../../utils/bounds/_utils/is-bounds-equal";
23
+ import useStableCallback from "../use-stable-callback";
13
24
 
14
25
  interface BoundMeasurerHookProps {
15
- sharedBoundTag: string;
26
+ sharedBoundTag?: string;
16
27
  animatedRef: AnimatedRef<View>;
17
- current: { route: { key: string } };
28
+
18
29
  style: StyleProps;
30
+ onPress?: ((...args: unknown[]) => void) | undefined;
31
+ }
32
+
33
+ interface MeasurementUpdateContextType {
34
+ updateSignal: SharedValue<number>;
19
35
  }
20
36
 
37
+ const MeasurementUpdateContext =
38
+ createContext<MeasurementUpdateContextType | null>(null);
39
+
21
40
  export const useBoundsRegistry = ({
22
41
  sharedBoundTag,
23
42
  animatedRef,
24
- current,
25
43
  style,
44
+ onPress,
26
45
  }: BoundMeasurerHookProps) => {
27
- const { previous } = useKeys();
46
+ const { previous, current } = useKeys();
28
47
 
29
- const isMeasured = useSharedValue(false);
48
+ const ROOT_MEASUREMENT_SIGNAL = useContext(MeasurementUpdateContext);
49
+ const ROOT_SIGNAL = useSharedValue(0);
50
+ const IS_ROOT = !ROOT_MEASUREMENT_SIGNAL;
51
+ const hasMeasured = useSharedValue(false);
30
52
 
31
- const measureBounds = useCallback(() => {
53
+ const emitUpdate = useCallback(() => {
32
54
  "worklet";
33
- if (!sharedBoundTag) return;
34
- const measured = measure(animatedRef);
35
- if (measured) {
55
+ if (IS_ROOT) ROOT_SIGNAL.value = ROOT_SIGNAL.value + 1;
56
+ }, [IS_ROOT, ROOT_SIGNAL]);
57
+
58
+ const maybeMeasureAndStore = useCallback(
59
+ ({
60
+ onPress,
61
+ skipMarkingActive,
62
+ }: {
63
+ onPress?: () => void;
64
+ skipMarkingActive?: boolean;
65
+ }) => {
66
+ "worklet";
67
+ if (!sharedBoundTag) return;
68
+
69
+ const measured = measure(animatedRef);
70
+
71
+ if (!measured) {
72
+ console.warn(
73
+ `[react-native-screen-transitions] measure() returned null for sharedBoundTag="${sharedBoundTag}"`,
74
+ );
75
+ return;
76
+ }
77
+
36
78
  const key = current.route.key;
79
+
37
80
  if (isBoundsEqual({ measured, key, sharedBoundTag })) {
38
- if (Bounds.getRouteActive(key) === sharedBoundTag) {
81
+ emitUpdate();
82
+ if (!skipMarkingActive) {
39
83
  Bounds.setRouteActive(key, sharedBoundTag);
40
84
  }
85
+ if (onPress) runOnJS(onPress)();
41
86
  return;
42
87
  }
43
88
 
89
+ emitUpdate();
90
+
44
91
  Bounds.setBounds(key, sharedBoundTag, measured, flattenStyle(style));
45
- if (Bounds.getRouteActive(key) === sharedBoundTag) {
92
+ if (!skipMarkingActive) {
46
93
  Bounds.setRouteActive(key, sharedBoundTag);
47
94
  }
48
- }
49
- }, [sharedBoundTag, animatedRef, current.route.key, style]);
50
95
 
51
- const handleLayout = useCallback(() => {
96
+ if (onPress) runOnJS(onPress)();
97
+ },
98
+ [sharedBoundTag, animatedRef, current.route.key, style, emitUpdate],
99
+ );
100
+
101
+ const handleTransitionLayout = useCallback(() => {
52
102
  "worklet";
53
- const previousRouteKey = previous?.route.key;
54
103
 
55
- if (!sharedBoundTag || isMeasured.value || !previousRouteKey) {
104
+ const prevKey = previous?.route.key;
105
+ if (!sharedBoundTag || hasMeasured.value || !prevKey) {
106
+ return;
107
+ }
108
+
109
+ const prevBounds = Bounds.getBounds(prevKey)?.[sharedBoundTag];
110
+
111
+ if (prevBounds) {
112
+ // Should skip mark active if we are in a transition
113
+ maybeMeasureAndStore({ skipMarkingActive: true });
114
+ // Should not measure again while in transition
115
+ hasMeasured.value = true;
116
+ }
117
+ }, [maybeMeasureAndStore, sharedBoundTag, previous?.route.key, hasMeasured]);
118
+
119
+ const captureActiveOnPress = useStableCallback(() => {
120
+ if (!sharedBoundTag) {
121
+ if (onPress) onPress();
56
122
  return;
57
123
  }
58
124
 
59
- const previousBounds = Bounds.getBounds(previousRouteKey);
60
- const hasPreviousBoundForTag = previousBounds[sharedBoundTag];
125
+ // In this case, we DO want to mark active
126
+ runOnUI(maybeMeasureAndStore)({ onPress });
127
+ });
61
128
 
62
- if (hasPreviousBoundForTag) {
63
- measureBounds();
64
- isMeasured.value = true;
129
+ const MeasurementSyncProvider = useMemo(() => {
130
+ if (!IS_ROOT || !sharedBoundTag) {
131
+ return Fragment;
65
132
  }
66
- }, [measureBounds, sharedBoundTag, previous?.route.key, isMeasured]);
133
+
134
+ return ({ children }: { children: React.ReactNode }) => (
135
+ <MeasurementUpdateContext.Provider value={{ updateSignal: ROOT_SIGNAL }}>
136
+ {children}
137
+ </MeasurementUpdateContext.Provider>
138
+ );
139
+ }, [IS_ROOT, sharedBoundTag, ROOT_SIGNAL]);
140
+
141
+ useAnimatedReaction(
142
+ () => ROOT_MEASUREMENT_SIGNAL?.updateSignal.value,
143
+ (current) => {
144
+ "worklet";
145
+
146
+ // We don't want to run on the initial amount)
147
+ if (current === 0 || current === undefined) return;
148
+
149
+ // Children should not have the ability to mark active
150
+ maybeMeasureAndStore({ skipMarkingActive: true });
151
+ },
152
+ );
67
153
 
68
154
  return {
69
- measureBounds,
70
- handleLayout,
155
+ maybeMeasureAndStore,
156
+ handleTransitionLayout,
157
+ captureActiveOnPress,
158
+ MeasurementSyncProvider,
71
159
  };
72
160
  };
@@ -14,25 +14,26 @@ import {
14
14
  type SharedValue,
15
15
  useSharedValue,
16
16
  } from "react-native-reanimated";
17
+ import {
18
+ DEFAULT_GESTURE_ACTIVATION_AREA,
19
+ DEFAULT_GESTURE_DIRECTION,
20
+ DEFAULT_GESTURE_DRIVES_PROGRESS,
21
+ DEFAULT_GESTURE_ENABLED,
22
+ GESTURE_VELOCITY_IMPACT,
23
+ } from "../../constants";
17
24
  import type { ScrollConfig } from "../../providers/gestures";
18
25
  import { useKeys } from "../../providers/keys";
19
26
  import { Animations } from "../../stores/animations";
20
27
  import { Gestures } from "../../stores/gestures";
21
28
  import { NavigatorDismissState } from "../../stores/navigator-dismiss-state";
22
- import { type ActivationArea, GestureOffsetState } from "../../types/gesture";
29
+ import { GestureOffsetState } from "../../types/gesture";
23
30
  import { animate } from "../../utils/animation/animate";
24
- import { runTransition } from "../../utils/animation/run-transition";
31
+ import { startScreenTransition } from "../../utils/animation/start-screen-transition";
25
32
  import { applyOffsetRules } from "../../utils/gesture/check-gesture-activation";
26
33
  import { determineDismissal } from "../../utils/gesture/determine-dismissal";
27
34
  import { mapGestureToProgress } from "../../utils/gesture/map-gesture-to-progress";
28
35
  import useStableCallback from "../use-stable-callback";
29
36
 
30
- const GESTURE_VELOCITY_IMPACT = 0.3;
31
- const DEFAULT_GESTURE_DIRECTION = "horizontal";
32
- const DEFAULT_GESTURE_ENABLED = false;
33
- const DEFAULT_GESTURE_DRIVES_PROGRESS = true;
34
- const DEFAULT_GESTURE_ACTIVATION_AREA: ActivationArea = "screen";
35
-
36
37
  interface BuildGesturesHookProps {
37
38
  scrollConfig: SharedValue<ScrollConfig | null>;
38
39
  }
@@ -293,9 +294,9 @@ export const useBuildGestures = ({
293
294
  runOnJS(setNavigatorDismissal)();
294
295
  }
295
296
 
296
- runTransition({
297
+ startScreenTransition({
297
298
  target: shouldDismiss ? "close" : "open",
298
- onFinish: shouldDismiss ? handleDismiss : undefined,
299
+ onAnimationFinish: shouldDismiss ? handleDismiss : undefined,
299
300
  spec: transitionSpec,
300
301
  velocity,
301
302
  animations,
package/src/index.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { FlatList, Pressable, ScrollView, View } from "react-native";
2
+ import { presets, specs } from "./__configs__";
2
3
  import { createTransitionAwareComponent } from "./components/create-transition-aware-component";
3
4
  import MaskedView from "./components/integrations/masked-view";
4
- import { presets, specs } from "./configs";
5
5
 
6
6
  export default {
7
7
  View: createTransitionAwareComponent(View),
@@ -1,14 +1,14 @@
1
1
  export function debounce<T extends (...args: any[]) => void>(
2
- func: T,
3
- duration: number
2
+ func: T,
3
+ duration: number,
4
4
  ): T {
5
- let timeout: ReturnType<typeof setTimeout>;
5
+ let timeout: ReturnType<typeof setTimeout>;
6
6
 
7
- return function (this: unknown, ...args) {
8
- clearTimeout(timeout);
7
+ return function (this: unknown, ...args) {
8
+ clearTimeout(timeout);
9
9
 
10
- timeout = setTimeout(() => {
11
- func.apply(this, args);
12
- }, duration);
13
- } as T;
10
+ timeout = setTimeout(() => {
11
+ func.apply(this, args);
12
+ }, duration);
13
+ } as T;
14
14
  }
@@ -1,18 +1,18 @@
1
- import * as React from 'react';
2
- import type { Animated } from 'react-native';
1
+ import * as React from "react";
2
+ import type { Animated } from "react-native";
3
3
 
4
4
  export const AnimatedHeaderHeightContext = React.createContext<
5
- Animated.AnimatedInterpolation<number> | undefined
5
+ Animated.AnimatedInterpolation<number> | undefined
6
6
  >(undefined);
7
7
 
8
8
  export function useAnimatedHeaderHeight() {
9
- const animatedValue = React.useContext(AnimatedHeaderHeightContext);
9
+ const animatedValue = React.useContext(AnimatedHeaderHeightContext);
10
10
 
11
- if (animatedValue === undefined) {
12
- throw new Error(
13
- "Couldn't find the header height. Are you inside a screen in a native stack navigator?"
14
- );
15
- }
11
+ if (animatedValue === undefined) {
12
+ throw new Error(
13
+ "Couldn't find the header height. Are you inside a screen in a native stack navigator?",
14
+ );
15
+ }
16
16
 
17
- return animatedValue;
17
+ return animatedValue;
18
18
  }
@@ -1,30 +1,30 @@
1
1
  import type {
2
- ParamListBase,
3
- StackNavigationState,
4
- } from '@react-navigation/native';
5
- import * as React from 'react';
2
+ ParamListBase,
3
+ StackNavigationState,
4
+ } from "@react-navigation/native";
5
+ import * as React from "react";
6
6
 
7
7
  export function useDismissedRouteError(
8
- state: StackNavigationState<ParamListBase>
8
+ state: StackNavigationState<ParamListBase>,
9
9
  ) {
10
- const [nextDismissedKey, setNextDismissedKey] = React.useState<string | null>(
11
- null
12
- );
10
+ const [nextDismissedKey, setNextDismissedKey] = React.useState<string | null>(
11
+ null,
12
+ );
13
13
 
14
- const dismissedRouteName = nextDismissedKey
15
- ? state.routes.find((route) => route.key === nextDismissedKey)?.name
16
- : null;
14
+ const dismissedRouteName = nextDismissedKey
15
+ ? state.routes.find((route) => route.key === nextDismissedKey)?.name
16
+ : null;
17
17
 
18
- React.useEffect(() => {
19
- if (dismissedRouteName) {
20
- const message =
21
- `The screen '${dismissedRouteName}' was removed natively but didn't get removed from JS state. ` +
22
- `This can happen if the action was prevented in a 'beforeRemove' listener, which is not fully supported in native-stack.\n\n` +
23
- `Consider using a 'usePreventRemove' hook with 'headerBackButtonMenuEnabled: false' to prevent users from natively going back multiple screens.`;
18
+ React.useEffect(() => {
19
+ if (dismissedRouteName) {
20
+ const message =
21
+ `The screen '${dismissedRouteName}' was removed natively but didn't get removed from JS state. ` +
22
+ `This can happen if the action was prevented in a 'beforeRemove' listener, which is not fully supported in native-stack.\n\n` +
23
+ `Consider using a 'usePreventRemove' hook with 'headerBackButtonMenuEnabled: false' to prevent users from natively going back multiple screens.`;
24
24
 
25
- console.error(message);
26
- }
27
- }, [dismissedRouteName]);
25
+ console.error(message);
26
+ }
27
+ }, [dismissedRouteName]);
28
28
 
29
- return { setNextDismissedKey };
29
+ return { setNextDismissedKey };
30
30
  }
@@ -1,12 +1,12 @@
1
1
  // @ts-expect-error importing private module
2
- import ReactNativeStyleAttributes from 'react-native/Libraries/Components/View/ReactNativeStyleAttributes';
2
+ import ReactNativeStyleAttributes from "react-native/Libraries/Components/View/ReactNativeStyleAttributes";
3
3
 
4
4
  export function processFonts(
5
- fontFamilies: (string | undefined)[]
5
+ fontFamilies: (string | undefined)[],
6
6
  ): (string | undefined)[] {
7
- const fontFamilyProcessor = ReactNativeStyleAttributes.fontFamily?.process;
8
- if (typeof fontFamilyProcessor === 'function') {
9
- return fontFamilies.map(fontFamilyProcessor);
10
- }
11
- return fontFamilies;
7
+ const fontFamilyProcessor = ReactNativeStyleAttributes.fontFamily?.process;
8
+ if (typeof fontFamilyProcessor === "function") {
9
+ return fontFamilies.map(fontFamilyProcessor);
10
+ }
11
+ return fontFamilies;
12
12
  }
@@ -1,5 +1,5 @@
1
1
  export function processFonts(
2
- _: (string | undefined)[]
2
+ _: (string | undefined)[],
3
3
  ): (string | undefined)[] {
4
- throw new Error('Not supported on Web');
4
+ throw new Error("Not supported on Web");
5
5
  }
@@ -32,11 +32,7 @@ import {
32
32
  ScreenStack,
33
33
  ScreenStackItem,
34
34
  } from "react-native-screens";
35
- import { ScreenLifecycleController } from "../../../components/controllers/screen-lifecycle";
36
- import { RootTransitionAware } from "../../../components/root-transition-aware";
37
- import { ScreenGestureProvider } from "../../../providers/gestures";
38
- import { KeysProvider } from "../../../providers/keys";
39
- import { TransitionStylesProvider } from "../../../providers/transition-styles";
35
+ import { ScreenTransitionProvider } from "../../../providers/screen-transition-provider";
40
36
  import type {
41
37
  NativeStackDescriptor,
42
38
  NativeStackDescriptorMap,
@@ -469,19 +465,13 @@ const SceneView = ({
469
465
  value={isParentHeaderShown || headerShown !== false}
470
466
  >
471
467
  <HeaderBackContext.Provider value={headerBack}>
472
- <KeysProvider
468
+ <ScreenTransitionProvider
473
469
  previous={previousDescriptor}
474
470
  current={descriptor}
475
471
  next={nextDescriptor}
476
472
  >
477
- <ScreenGestureProvider>
478
- <ScreenLifecycleController>
479
- <TransitionStylesProvider>
480
- <RootTransitionAware>{render()}</RootTransitionAware>
481
- </TransitionStylesProvider>
482
- </ScreenLifecycleController>
483
- </ScreenGestureProvider>
484
- </KeysProvider>
473
+ {render()}
474
+ </ScreenTransitionProvider>
485
475
  </HeaderBackContext.Provider>
486
476
  </HeaderShownContext.Provider>
487
477
  </HeaderHeightContext.Provider>
@@ -26,15 +26,6 @@ type ScreenGestureProviderProps = {
26
26
  children: React.ReactNode;
27
27
  };
28
28
 
29
- export const DEFAULT_SCROLL_CONFIG: ScrollConfig = {
30
- x: 0,
31
- y: 0,
32
- contentHeight: 0,
33
- contentWidth: 0,
34
- layoutHeight: 0,
35
- layoutWidth: 0,
36
- };
37
-
38
29
  const GestureContext = createContext<GestureContextType | undefined>(undefined);
39
30
 
40
31
  export const ScreenGestureProvider = ({
@@ -0,0 +1,33 @@
1
+ import type React from "react";
2
+ import { ScreenLifecycleController } from "../components/controllers/screen-lifecycle";
3
+ import { RootTransitionAware } from "../components/root-transition-aware";
4
+ import { ScreenGestureProvider } from "../providers/gestures";
5
+ import { KeysProvider } from "../providers/keys";
6
+ import { TransitionStylesProvider } from "../providers/transition-styles";
7
+ import type { NativeStackDescriptor } from "../types/navigator";
8
+
9
+ type Props = {
10
+ previous?: NativeStackDescriptor;
11
+ current: NativeStackDescriptor;
12
+ next?: NativeStackDescriptor;
13
+ children: React.ReactNode;
14
+ };
15
+
16
+ export function ScreenTransitionProvider({
17
+ previous,
18
+ current,
19
+ next,
20
+ children,
21
+ }: Props) {
22
+ return (
23
+ <KeysProvider previous={previous} current={current} next={next}>
24
+ <ScreenGestureProvider>
25
+ <ScreenLifecycleController>
26
+ <TransitionStylesProvider>
27
+ <RootTransitionAware>{children}</RootTransitionAware>
28
+ </TransitionStylesProvider>
29
+ </ScreenLifecycleController>
30
+ </ScreenGestureProvider>
31
+ </KeysProvider>
32
+ );
33
+ }
@@ -1,5 +1,6 @@
1
1
  import { createContext, useContext, useMemo } from "react";
2
2
  import { isWorkletFunction, useDerivedValue } from "react-native-reanimated";
3
+ import { NO_STYLES } from "../constants";
3
4
  import { _useScreenAnimation } from "../hooks/animation/use-screen-animation";
4
5
  import type { TransitionInterpolatedStyle } from "../types/animation";
5
6
 
@@ -7,8 +8,6 @@ type Props = {
7
8
  children: React.ReactNode;
8
9
  };
9
10
 
10
- const EMPTY_MAP = Object.freeze({});
11
-
12
11
  const TransitionStylesContext = createContext<ReturnType<
13
12
  typeof useMemo<{
14
13
  stylesMap: ReturnType<typeof useDerivedValue<TransitionInterpolatedStyle>>;
@@ -25,13 +24,15 @@ export function TransitionStylesProvider({ children }: Props) {
25
24
  "worklet";
26
25
 
27
26
  if (screenStyleInterpolator && !isFunctionWorklet && __DEV__) {
28
- console.warn("screenStyleInterpolator is not a worklet function");
29
- return EMPTY_MAP;
27
+ console.warn(
28
+ `[react-native-screen-transitions] screenStyleInterpolator is not a worklet function`,
29
+ );
30
+ return NO_STYLES;
30
31
  }
31
32
 
32
33
  return screenStyleInterpolator
33
34
  ? screenStyleInterpolator(screenInterpolatorProps.value)
34
- : EMPTY_MAP;
35
+ : NO_STYLES;
35
36
  });
36
37
 
37
38
  const value = useMemo(() => {
package/src/types/core.ts CHANGED
@@ -42,15 +42,6 @@ export type TransitionAwareProps<T extends object> = AnimatedProps<T> & {
42
42
  * </Transition.View>
43
43
  */
44
44
  sharedBoundTag?: string;
45
-
46
- /**
47
- * Eagerly measure this component on layout and store the result in the
48
- * Bounds registry. Useful for nested shared elements that may not receive
49
- * the press event but still need up-to-date measurements at navigation time.
50
- *
51
- * Only has an effect when used together with `sharedBoundTag`.
52
- */
53
- measureOnLayout?: boolean;
54
45
  };
55
46
 
56
47
  export type TransitionConfig = {
@@ -3,21 +3,21 @@ import type { AnimationMap } from "../../stores/animations";
3
3
  import type { TransitionSpec } from "../../types/animation";
4
4
  import { animate } from "./animate";
5
5
 
6
- interface RunTransitionProps {
6
+ interface StartScreenTransitionProps {
7
7
  target: "open" | "close";
8
8
  spec?: TransitionSpec;
9
- onFinish?: (finished: boolean) => void;
9
+ onAnimationFinish?: (finished: boolean) => void;
10
10
  animations: AnimationMap;
11
11
  velocity?: number;
12
12
  }
13
13
 
14
- export const runTransition = ({
14
+ export const startScreenTransition = ({
15
15
  target,
16
16
  spec,
17
- onFinish,
17
+ onAnimationFinish,
18
18
  animations,
19
19
  velocity,
20
- }: RunTransitionProps) => {
20
+ }: StartScreenTransitionProps) => {
21
21
  "worklet";
22
22
  const value = target === "open" ? 1 : 0;
23
23
  const config = target === "open" ? spec?.open : spec?.close;
@@ -32,8 +32,8 @@ export const runTransition = ({
32
32
  animating.value = 0;
33
33
  progress.value = value;
34
34
 
35
- if (onFinish) {
36
- runOnJS(onFinish)(true);
35
+ if (onAnimationFinish) {
36
+ runOnJS(onAnimationFinish)(true);
37
37
  }
38
38
  return;
39
39
  }
@@ -44,8 +44,8 @@ export const runTransition = ({
44
44
  "worklet";
45
45
  if (finished) {
46
46
  animating.value = 0;
47
- if (onFinish) {
48
- runOnJS(onFinish)(finished);
47
+ if (onAnimationFinish) {
48
+ runOnJS(onAnimationFinish)(finished);
49
49
  }
50
50
  }
51
51
  });
@@ -1,10 +1,10 @@
1
- import type { ScreenPhase } from '../../../types/core';
2
- import type { ScreenTransitionState } from '../../../types/animation';
1
+ import type { ScreenTransitionState } from "../../../types/animation";
2
+ import type { ScreenPhase } from "../../../types/core";
3
3
 
4
4
  export type GetBoundsParams = {
5
- id: string | null;
6
- phase?: ScreenPhase;
7
- previous?: ScreenTransitionState;
8
- current: ScreenTransitionState;
9
- next?: ScreenTransitionState;
5
+ id: string | null;
6
+ phase?: ScreenPhase;
7
+ previous?: ScreenTransitionState;
8
+ current: ScreenTransitionState;
9
+ next?: ScreenTransitionState;
10
10
  };