react-native-screen-transitions 3.2.0-beta.1 → 3.2.0-beta.3

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 (215) hide show
  1. package/README.md +108 -37
  2. package/lib/commonjs/blank-stack/components/stack-view.js +0 -2
  3. package/lib/commonjs/blank-stack/components/stack-view.js.map +1 -1
  4. package/lib/commonjs/blank-stack/components/stack-view.native.js +0 -2
  5. package/lib/commonjs/blank-stack/components/stack-view.native.js.map +1 -1
  6. package/lib/commonjs/component-stack/components/component-screen.js +3 -1
  7. package/lib/commonjs/component-stack/components/component-screen.js.map +1 -1
  8. package/lib/commonjs/component-stack/components/stack-view.js +19 -22
  9. package/lib/commonjs/component-stack/components/stack-view.js.map +1 -1
  10. package/lib/commonjs/component-stack/navigators/create-component-stack-navigator.js +39 -9
  11. package/lib/commonjs/component-stack/navigators/create-component-stack-navigator.js.map +1 -1
  12. package/lib/commonjs/native-stack/views/NativeStackView.native.js +3 -3
  13. package/lib/commonjs/native-stack/views/NativeStackView.native.js.map +1 -1
  14. package/lib/commonjs/shared/components/overlay/variations/float-overlay.js +1 -6
  15. package/lib/commonjs/shared/components/overlay/variations/float-overlay.js.map +1 -1
  16. package/lib/commonjs/shared/components/overlay/variations/overlay-host.js +16 -64
  17. package/lib/commonjs/shared/components/overlay/variations/overlay-host.js.map +1 -1
  18. package/lib/commonjs/shared/components/overlay/variations/screen-overlay.js +5 -8
  19. package/lib/commonjs/shared/components/overlay/variations/screen-overlay.js.map +1 -1
  20. package/lib/commonjs/shared/components/root-transition-aware.js +5 -1
  21. package/lib/commonjs/shared/components/root-transition-aware.js.map +1 -1
  22. package/lib/commonjs/shared/components/screen-lifecycle.js +153 -0
  23. package/lib/commonjs/shared/components/screen-lifecycle.js.map +1 -0
  24. package/lib/commonjs/shared/constants.js +3 -2
  25. package/lib/commonjs/shared/constants.js.map +1 -1
  26. package/lib/commonjs/shared/hooks/animation/use-screen-animation.js.map +1 -1
  27. package/lib/commonjs/shared/hooks/gestures/use-build-gestures.js.map +1 -1
  28. package/lib/commonjs/shared/hooks/navigation/use-screen-state.js +45 -0
  29. package/lib/commonjs/shared/hooks/navigation/use-screen-state.js.map +1 -0
  30. package/lib/commonjs/shared/hooks/use-stable-callback-value.js +0 -2
  31. package/lib/commonjs/shared/hooks/use-stable-callback-value.js.map +1 -1
  32. package/lib/commonjs/shared/hooks/use-stack-pointer-events.js +23 -0
  33. package/lib/commonjs/shared/hooks/use-stack-pointer-events.js.map +1 -0
  34. package/lib/commonjs/shared/index.js +7 -0
  35. package/lib/commonjs/shared/index.js.map +1 -1
  36. package/lib/commonjs/shared/providers/gestures.provider.js +3 -0
  37. package/lib/commonjs/shared/providers/gestures.provider.js.map +1 -1
  38. package/lib/commonjs/shared/providers/screen/keys.provider.js +0 -2
  39. package/lib/commonjs/shared/providers/screen/keys.provider.js.map +1 -1
  40. package/lib/commonjs/shared/providers/screen/screen-composer.js +3 -3
  41. package/lib/commonjs/shared/providers/screen/screen-composer.js.map +1 -1
  42. package/lib/commonjs/shared/providers/screen/styles.provider.js +1 -1
  43. package/lib/commonjs/shared/providers/screen/styles.provider.js.map +1 -1
  44. package/lib/commonjs/shared/providers/stack/core.provider.js +1 -0
  45. package/lib/commonjs/shared/providers/stack/core.provider.js.map +1 -1
  46. package/lib/commonjs/shared/types/index.js +3 -3
  47. package/lib/commonjs/shared/types/index.js.map +1 -1
  48. package/lib/commonjs/shared/types/stack.types.js +5 -0
  49. package/lib/commonjs/shared/types/stack.types.js.map +1 -1
  50. package/lib/commonjs/shared/utils/animation/start-screen-transition.js +5 -5
  51. package/lib/commonjs/shared/utils/animation/start-screen-transition.js.map +1 -1
  52. package/lib/commonjs/shared/utils/bounds/index.js.map +1 -1
  53. package/lib/module/blank-stack/components/stack-view.js +0 -2
  54. package/lib/module/blank-stack/components/stack-view.js.map +1 -1
  55. package/lib/module/blank-stack/components/stack-view.native.js +0 -2
  56. package/lib/module/blank-stack/components/stack-view.native.js.map +1 -1
  57. package/lib/module/component-stack/components/component-screen.js +3 -1
  58. package/lib/module/component-stack/components/component-screen.js.map +1 -1
  59. package/lib/module/component-stack/components/stack-view.js +19 -22
  60. package/lib/module/component-stack/components/stack-view.js.map +1 -1
  61. package/lib/module/component-stack/navigators/create-component-stack-navigator.js +38 -9
  62. package/lib/module/component-stack/navigators/create-component-stack-navigator.js.map +1 -1
  63. package/lib/module/native-stack/views/NativeStackView.native.js +3 -3
  64. package/lib/module/native-stack/views/NativeStackView.native.js.map +1 -1
  65. package/lib/module/shared/components/overlay/variations/float-overlay.js +1 -6
  66. package/lib/module/shared/components/overlay/variations/float-overlay.js.map +1 -1
  67. package/lib/module/shared/components/overlay/variations/overlay-host.js +16 -64
  68. package/lib/module/shared/components/overlay/variations/overlay-host.js.map +1 -1
  69. package/lib/module/shared/components/overlay/variations/screen-overlay.js +5 -8
  70. package/lib/module/shared/components/overlay/variations/screen-overlay.js.map +1 -1
  71. package/lib/module/shared/components/root-transition-aware.js +5 -1
  72. package/lib/module/shared/components/root-transition-aware.js.map +1 -1
  73. package/lib/module/shared/components/screen-lifecycle.js +147 -0
  74. package/lib/module/shared/components/screen-lifecycle.js.map +1 -0
  75. package/lib/module/shared/constants.js +2 -1
  76. package/lib/module/shared/constants.js.map +1 -1
  77. package/lib/module/shared/hooks/animation/use-screen-animation.js.map +1 -1
  78. package/lib/module/shared/hooks/gestures/use-build-gestures.js.map +1 -1
  79. package/lib/module/shared/hooks/navigation/use-screen-state.js +41 -0
  80. package/lib/module/shared/hooks/navigation/use-screen-state.js.map +1 -0
  81. package/lib/module/shared/hooks/use-stable-callback-value.js +0 -3
  82. package/lib/module/shared/hooks/use-stable-callback-value.js.map +1 -1
  83. package/lib/module/shared/hooks/use-stack-pointer-events.js +20 -0
  84. package/lib/module/shared/hooks/use-stack-pointer-events.js.map +1 -0
  85. package/lib/module/shared/index.js +1 -0
  86. package/lib/module/shared/index.js.map +1 -1
  87. package/lib/module/shared/providers/gestures.provider.js +3 -0
  88. package/lib/module/shared/providers/gestures.provider.js.map +1 -1
  89. package/lib/module/shared/providers/screen/keys.provider.js +0 -2
  90. package/lib/module/shared/providers/screen/keys.provider.js.map +1 -1
  91. package/lib/module/shared/providers/screen/screen-composer.js +3 -3
  92. package/lib/module/shared/providers/screen/screen-composer.js.map +1 -1
  93. package/lib/module/shared/providers/screen/styles.provider.js +1 -1
  94. package/lib/module/shared/providers/screen/styles.provider.js.map +1 -1
  95. package/lib/module/shared/providers/stack/core.provider.js +1 -0
  96. package/lib/module/shared/providers/stack/core.provider.js.map +1 -1
  97. package/lib/module/shared/types/index.js +1 -1
  98. package/lib/module/shared/types/index.js.map +1 -1
  99. package/lib/module/shared/types/stack.types.js +6 -0
  100. package/lib/module/shared/types/stack.types.js.map +1 -1
  101. package/lib/module/shared/utils/animation/start-screen-transition.js +1 -1
  102. package/lib/module/shared/utils/animation/start-screen-transition.js.map +1 -1
  103. package/lib/module/shared/utils/bounds/index.js.map +1 -1
  104. package/lib/typescript/blank-stack/components/stack-view.d.ts.map +1 -1
  105. package/lib/typescript/blank-stack/components/stack-view.native.d.ts.map +1 -1
  106. package/lib/typescript/blank-stack/types.d.ts +4 -8
  107. package/lib/typescript/blank-stack/types.d.ts.map +1 -1
  108. package/lib/typescript/component-stack/components/component-screen.d.ts.map +1 -1
  109. package/lib/typescript/component-stack/components/stack-view.d.ts.map +1 -1
  110. package/lib/typescript/component-stack/navigators/create-component-stack-navigator.d.ts +9 -2
  111. package/lib/typescript/component-stack/navigators/create-component-stack-navigator.d.ts.map +1 -1
  112. package/lib/typescript/component-stack/types.d.ts +4 -8
  113. package/lib/typescript/component-stack/types.d.ts.map +1 -1
  114. package/lib/typescript/native-stack/types.d.ts +2 -3
  115. package/lib/typescript/native-stack/types.d.ts.map +1 -1
  116. package/lib/typescript/native-stack/views/NativeStackView.native.d.ts.map +1 -1
  117. package/lib/typescript/shared/components/overlay/variations/float-overlay.d.ts.map +1 -1
  118. package/lib/typescript/shared/components/overlay/variations/overlay-host.d.ts +1 -6
  119. package/lib/typescript/shared/components/overlay/variations/overlay-host.d.ts.map +1 -1
  120. package/lib/typescript/shared/components/overlay/variations/screen-overlay.d.ts +4 -0
  121. package/lib/typescript/shared/components/overlay/variations/screen-overlay.d.ts.map +1 -1
  122. package/lib/typescript/shared/components/root-transition-aware.d.ts.map +1 -1
  123. package/lib/typescript/shared/components/screen-lifecycle.d.ts +9 -0
  124. package/lib/typescript/shared/components/screen-lifecycle.d.ts.map +1 -0
  125. package/lib/typescript/shared/constants.d.ts +2 -1
  126. package/lib/typescript/shared/constants.d.ts.map +1 -1
  127. package/lib/typescript/shared/hooks/animation/use-screen-animation.d.ts.map +1 -1
  128. package/lib/typescript/shared/hooks/gestures/use-build-gestures.d.ts.map +1 -1
  129. package/lib/typescript/shared/hooks/navigation/use-screen-state.d.ts +40 -0
  130. package/lib/typescript/shared/hooks/navigation/use-screen-state.d.ts.map +1 -0
  131. package/lib/typescript/shared/hooks/use-stable-callback-value.d.ts.map +1 -1
  132. package/lib/typescript/shared/hooks/use-stack-pointer-events.d.ts +10 -0
  133. package/lib/typescript/shared/hooks/use-stack-pointer-events.d.ts.map +1 -0
  134. package/lib/typescript/shared/index.d.ts +21 -20
  135. package/lib/typescript/shared/index.d.ts.map +1 -1
  136. package/lib/typescript/shared/providers/gestures.provider.d.ts.map +1 -1
  137. package/lib/typescript/shared/providers/screen/keys.provider.d.ts +2 -3
  138. package/lib/typescript/shared/providers/screen/keys.provider.d.ts.map +1 -1
  139. package/lib/typescript/shared/providers/screen/screen-composer.d.ts +1 -3
  140. package/lib/typescript/shared/providers/screen/screen-composer.d.ts.map +1 -1
  141. package/lib/typescript/shared/providers/stack/core.provider.d.ts.map +1 -1
  142. package/lib/typescript/shared/types/animation.types.d.ts +2 -6
  143. package/lib/typescript/shared/types/animation.types.d.ts.map +1 -1
  144. package/lib/typescript/shared/types/index.d.ts +2 -2
  145. package/lib/typescript/shared/types/index.d.ts.map +1 -1
  146. package/lib/typescript/shared/types/overlay.types.d.ts +21 -0
  147. package/lib/typescript/shared/types/overlay.types.d.ts.map +1 -1
  148. package/lib/typescript/shared/types/screen.types.d.ts +5 -4
  149. package/lib/typescript/shared/types/screen.types.d.ts.map +1 -1
  150. package/lib/typescript/shared/types/stack.types.d.ts +11 -1
  151. package/lib/typescript/shared/types/stack.types.d.ts.map +1 -1
  152. package/lib/typescript/shared/utils/animation/start-screen-transition.d.ts.map +1 -1
  153. package/lib/typescript/shared/utils/bounds/index.d.ts.map +1 -1
  154. package/package.json +1 -1
  155. package/src/blank-stack/components/stack-view.native.tsx +0 -2
  156. package/src/blank-stack/components/stack-view.tsx +0 -2
  157. package/src/blank-stack/types.ts +6 -8
  158. package/src/component-stack/components/component-screen.tsx +3 -3
  159. package/src/component-stack/components/stack-view.tsx +21 -25
  160. package/src/component-stack/navigators/create-component-stack-navigator.tsx +68 -37
  161. package/src/component-stack/types.ts +7 -8
  162. package/src/native-stack/types.ts +2 -3
  163. package/src/native-stack/views/NativeStackView.native.tsx +2 -3
  164. package/src/shared/components/overlay/variations/float-overlay.tsx +2 -8
  165. package/src/shared/components/overlay/variations/overlay-host.tsx +18 -84
  166. package/src/shared/components/overlay/variations/screen-overlay.tsx +6 -15
  167. package/src/shared/components/root-transition-aware.tsx +7 -2
  168. package/src/shared/components/screen-lifecycle.tsx +168 -0
  169. package/src/shared/constants.ts +3 -1
  170. package/src/shared/hooks/animation/use-screen-animation.tsx +3 -3
  171. package/src/shared/hooks/gestures/use-build-gestures.tsx +0 -2
  172. package/src/shared/hooks/navigation/use-screen-state.tsx +99 -0
  173. package/src/shared/hooks/use-stable-callback-value.ts +0 -1
  174. package/src/shared/hooks/use-stack-pointer-events.ts +15 -0
  175. package/src/shared/index.ts +4 -0
  176. package/src/shared/providers/gestures.provider.tsx +5 -1
  177. package/src/shared/providers/screen/keys.provider.tsx +1 -9
  178. package/src/shared/providers/screen/screen-composer.tsx +3 -5
  179. package/src/shared/providers/screen/styles.provider.tsx +1 -1
  180. package/src/shared/providers/stack/core.provider.tsx +6 -1
  181. package/src/shared/types/animation.types.ts +2 -6
  182. package/src/shared/types/index.ts +2 -7
  183. package/src/shared/types/overlay.types.ts +23 -0
  184. package/src/shared/types/screen.types.ts +5 -4
  185. package/src/shared/types/stack.types.ts +17 -1
  186. package/src/shared/utils/animation/start-screen-transition.ts +1 -1
  187. package/src/shared/utils/bounds/index.ts +6 -1
  188. package/lib/commonjs/component-stack/components/component-screen-container.js +0 -23
  189. package/lib/commonjs/component-stack/components/component-screen-container.js.map +0 -1
  190. package/lib/commonjs/native-stack/controllers/native-stack-lifecycle.js +0 -90
  191. package/lib/commonjs/native-stack/controllers/native-stack-lifecycle.js.map +0 -1
  192. package/lib/commonjs/shared/controller/managed-lifecycle.js +0 -78
  193. package/lib/commonjs/shared/controller/managed-lifecycle.js.map +0 -1
  194. package/lib/commonjs/shared/types/state.types.js +0 -9
  195. package/lib/commonjs/shared/types/state.types.js.map +0 -1
  196. package/lib/module/component-stack/components/component-screen-container.js +0 -18
  197. package/lib/module/component-stack/components/component-screen-container.js.map +0 -1
  198. package/lib/module/native-stack/controllers/native-stack-lifecycle.js +0 -83
  199. package/lib/module/native-stack/controllers/native-stack-lifecycle.js.map +0 -1
  200. package/lib/module/shared/controller/managed-lifecycle.js +0 -72
  201. package/lib/module/shared/controller/managed-lifecycle.js.map +0 -1
  202. package/lib/module/shared/types/state.types.js +0 -5
  203. package/lib/module/shared/types/state.types.js.map +0 -1
  204. package/lib/typescript/component-stack/components/component-screen-container.d.ts +0 -6
  205. package/lib/typescript/component-stack/components/component-screen-container.d.ts.map +0 -1
  206. package/lib/typescript/native-stack/controllers/native-stack-lifecycle.d.ts +0 -8
  207. package/lib/typescript/native-stack/controllers/native-stack-lifecycle.d.ts.map +0 -1
  208. package/lib/typescript/shared/controller/managed-lifecycle.d.ts +0 -9
  209. package/lib/typescript/shared/controller/managed-lifecycle.d.ts.map +0 -1
  210. package/lib/typescript/shared/types/state.types.d.ts +0 -3
  211. package/lib/typescript/shared/types/state.types.d.ts.map +0 -1
  212. package/src/component-stack/components/component-screen-container.tsx +0 -15
  213. package/src/native-stack/controllers/native-stack-lifecycle.tsx +0 -96
  214. package/src/shared/controller/managed-lifecycle.tsx +0 -73
  215. package/src/shared/types/state.types.ts +0 -2
@@ -1,131 +1,65 @@
1
1
  import {
2
2
  NavigationContext,
3
3
  NavigationRouteContext,
4
- type Route,
5
4
  } from "@react-navigation/native";
6
5
  import { memo, useMemo } from "react";
7
6
  import { Animated, StyleSheet, useWindowDimensions, View } from "react-native";
8
7
  import { useDerivedValue } from "react-native-reanimated";
9
8
  import { useSafeAreaInsets } from "react-native-safe-area-context";
10
9
  import { useScreenAnimation } from "../../../hooks/animation/use-screen-animation";
11
- import { type StackScene, useStack } from "../../../hooks/navigation/use-stack";
12
- import { useSharedValueState } from "../../../hooks/reanimated/use-shared-value-state";
10
+ import { useScreenState } from "../../../hooks/navigation/use-screen-state";
11
+ import type { StackScene } from "../../../hooks/navigation/use-stack";
12
+ import type { BaseDescriptor } from "../../../providers/screen/keys.provider";
13
13
  import type { OverlayInterpolationProps } from "../../../types/animation.types";
14
14
  import type { OverlayProps } from "../../../types/overlay.types";
15
15
 
16
16
  type OverlayHostProps = {
17
17
  scene: StackScene;
18
- scenes: StackScene[];
19
- routes: Route<string>[];
20
- overlayIndex: number;
21
- isFloating?: boolean;
22
18
  };
23
19
 
24
20
  export const OverlayHost = memo(function OverlayHost({
25
21
  scene,
26
- scenes,
27
- routes,
28
- overlayIndex,
29
- isFloating,
30
22
  }: OverlayHostProps) {
31
23
  const OverlayComponent = scene.descriptor.options.overlay;
32
24
  const screen = useWindowDimensions();
33
-
34
- const { stackProgress, optimisticFocusedIndex, routeKeys } = useStack();
35
25
  const insets = useSafeAreaInsets();
36
26
 
27
+ const screenAnimation = useScreenAnimation();
28
+ const screenState = useScreenState();
37
29
  const relativeProgress = useDerivedValue(() => {
38
30
  "worklet";
39
- return stackProgress.value - overlayIndex;
31
+ return screenAnimation.value.stackProgress;
40
32
  });
41
33
 
42
- // For float overlays: global focused index (can be any screen in the stack)
43
- // For screen overlays: relative to overlay position (only screens at or after)
44
- const optimisticActiveIndex = useSharedValueState(
45
- useDerivedValue(() => {
46
- "worklet";
47
- if (isFloating) {
48
- // For float overlays, use global optimistic focused index directly
49
- const globalIndex = optimisticFocusedIndex.get();
50
- const clampedIndex = Math.max(
51
- 0,
52
- Math.min(globalIndex, routeKeys.length - 1),
53
- );
54
- return clampedIndex;
55
- }
56
-
57
- // For screen overlays, compute relative to overlay position
58
- const screensAbove = routeKeys.length - 1 - overlayIndex;
59
- const relativeOptimistic = optimisticFocusedIndex.value - overlayIndex;
60
- const result = Math.max(0, Math.min(relativeOptimistic, screensAbove));
61
-
62
- return result;
63
- }),
64
- );
65
-
66
34
  const overlayAnimation = useDerivedValue<OverlayInterpolationProps>(() => ({
67
35
  progress: relativeProgress.value,
68
36
  layouts: { screen },
69
37
  insets,
70
38
  }));
71
39
 
72
- const focusedScene = useMemo(() => {
73
- if (overlayIndex === -1) {
74
- return scene;
75
- }
76
-
77
- if (isFloating) {
78
- // For float overlays, optimisticActiveIndex is the global focused index
79
- return scenes[optimisticActiveIndex] ?? scene;
80
- }
81
-
82
- // For screen overlays, optimisticActiveIndex is relative to overlayIndex
83
- const maxOffset = Math.max(scenes.length - overlayIndex - 1, 0);
84
- const normalizedIndex = Math.min(
85
- Math.max(optimisticActiveIndex, 0),
86
- maxOffset,
87
- );
88
-
89
- return scenes[overlayIndex + normalizedIndex] ?? scene;
90
- }, [overlayIndex, optimisticActiveIndex, scenes, scene, isFloating]);
91
-
92
- const screenAnimation = useScreenAnimation();
40
+ const overlayProps: OverlayProps<BaseDescriptor["navigation"]> = useMemo(
41
+ () => ({
42
+ ...screenState,
43
+ progress: relativeProgress,
44
+ overlayAnimation, //Deprecated
45
+ screenAnimation, //Deprecated
46
+ }),
47
+ [relativeProgress, overlayAnimation, screenAnimation, screenState],
48
+ );
93
49
 
94
50
  if (!OverlayComponent) {
95
51
  return null;
96
52
  }
97
53
 
98
- const overlayProps: OverlayProps<typeof scene.descriptor.navigation> = {
99
- routes,
100
- overlayAnimation,
101
- screenAnimation,
102
- focusedRoute: focusedScene.route,
103
- focusedIndex: optimisticActiveIndex,
104
- meta: focusedScene.descriptor.options.meta,
105
- navigation: scene.descriptor.navigation,
106
- };
107
-
108
- // Cast to OverlayProps function - container overlays are handled by ContainerOverlay component
109
- const renderOverlay = OverlayComponent as (
110
- props: OverlayProps,
111
- ) => React.ReactNode;
112
-
113
54
  return (
114
55
  <Animated.View
115
56
  pointerEvents="box-none"
116
- style={[
117
- styles.container,
118
- isFloating ? styles.floating : { zIndex: 1 },
119
- styles.absolute,
120
- ]}
57
+ style={[styles.container, styles.floating, styles.absolute]}
121
58
  >
122
- <NavigationContext.Provider
123
- // biome-ignore lint/suspicious/noExplicitAny: navigation type varies by stack
124
- value={scene.descriptor.navigation as any}
125
- >
59
+ <NavigationContext.Provider value={scene.descriptor.navigation as any}>
126
60
  <NavigationRouteContext.Provider value={scene.route}>
127
61
  <View pointerEvents="box-none" style={styles.overlay}>
128
- {renderOverlay(overlayProps)}
62
+ <OverlayComponent {...overlayProps} />
129
63
  </View>
130
64
  </NavigationRouteContext.Provider>
131
65
  </NavigationContext.Provider>
@@ -10,10 +10,14 @@ import { OverlayHost } from "./overlay-host";
10
10
  /**
11
11
  * Screen overlay component that renders per-screen.
12
12
  * Gets current descriptor from keys context.
13
+ *
14
+ * @deprecated Screen overlays are deprecated. For per-screen overlays, render an
15
+ * absolute-positioned view directly in your screen component and use `useScreenAnimation()`
16
+ * to access animation values. This component will be removed in a future version.
13
17
  */
14
18
  export function ScreenOverlay() {
15
19
  const { current } = useKeys<StackDescriptor>();
16
- const { routeKeys, flags } = useStack();
20
+ const { flags } = useStack();
17
21
 
18
22
  const options = current.options;
19
23
 
@@ -25,12 +29,6 @@ export function ScreenOverlay() {
25
29
  [current],
26
30
  );
27
31
 
28
- // Find the index of this screen in the stack
29
- const overlayIndex = useMemo(
30
- () => routeKeys.indexOf(current.route.key),
31
- [routeKeys, current.route.key],
32
- );
33
-
34
32
  // Skip screens without enableTransitions (native-stack only)
35
33
  if (!flags.TRANSITIONS_ALWAYS_ON && !options.enableTransitions) {
36
34
  return null;
@@ -40,12 +38,5 @@ export function ScreenOverlay() {
40
38
  return null;
41
39
  }
42
40
 
43
- return (
44
- <OverlayHost
45
- scene={scene}
46
- scenes={[scene]}
47
- routes={[]}
48
- overlayIndex={overlayIndex}
49
- />
50
- );
41
+ return <OverlayHost scene={scene} />;
51
42
  }
@@ -2,6 +2,7 @@ import { memo } from "react";
2
2
  import { StyleSheet, View } from "react-native";
3
3
  import Animated, { useAnimatedStyle } from "react-native-reanimated";
4
4
  import { NO_STYLES } from "../constants";
5
+ import { useStackPointerEvents } from "../hooks/use-stack-pointer-events";
5
6
  import { useScreenStyles } from "../providers/screen/styles.provider";
6
7
 
7
8
  type Props = {
@@ -10,6 +11,7 @@ type Props = {
10
11
 
11
12
  export const RootTransitionAware = memo(({ children }: Props) => {
12
13
  const { stylesMap } = useScreenStyles();
14
+ const pointerEvents = useStackPointerEvents();
13
15
 
14
16
  const animatedContentStyle = useAnimatedStyle(() => {
15
17
  "worklet";
@@ -22,12 +24,15 @@ export const RootTransitionAware = memo(({ children }: Props) => {
22
24
  });
23
25
 
24
26
  return (
25
- <View style={styles.container}>
27
+ <View style={[styles.container]} pointerEvents={pointerEvents}>
26
28
  <Animated.View
27
29
  style={[StyleSheet.absoluteFillObject, animatedOverlayStyle]}
28
30
  pointerEvents="none"
29
31
  />
30
- <Animated.View style={[styles.content, animatedContentStyle]}>
32
+ <Animated.View
33
+ style={[styles.content, animatedContentStyle]}
34
+ pointerEvents={pointerEvents}
35
+ >
31
36
  {children}
32
37
  </Animated.View>
33
38
  </View>
@@ -0,0 +1,168 @@
1
+ import { useLayoutEffect } from "react";
2
+ import {
3
+ runOnJS,
4
+ useAnimatedReaction,
5
+ useDerivedValue,
6
+ } from "react-native-reanimated";
7
+ import { useHighRefreshRate } from "../hooks/animation/use-high-refresh-rate";
8
+ import { useSharedValueState } from "../hooks/reanimated/use-shared-value-state";
9
+ import useStableCallback from "../hooks/use-stable-callback";
10
+ import { useGestureContext } from "../providers/gestures.provider";
11
+ import {
12
+ type BaseDescriptor,
13
+ useKeys,
14
+ } from "../providers/screen/keys.provider";
15
+ import { useStackCoreContext } from "../providers/stack/core.provider";
16
+ import { useManagedStackContext } from "../providers/stack/managed.provider";
17
+ import { AnimationStore } from "../stores/animation.store";
18
+ import { StackType } from "../types/stack.types";
19
+ import { startScreenTransition } from "../utils/animation/start-screen-transition";
20
+ import { resetStoresForScreen } from "../utils/reset-stores-for-screen";
21
+
22
+ interface Props {
23
+ children: React.ReactNode;
24
+ }
25
+
26
+ interface CloseHookParams {
27
+ current: BaseDescriptor;
28
+ animations: ReturnType<typeof AnimationStore.getAll>;
29
+ activate: () => void;
30
+ deactivate: () => void;
31
+ }
32
+
33
+ /**
34
+ * Managed close - reacts to closingRouteKeysShared from ManagedStackContext.
35
+ * Used by blank-stack and component-stack.
36
+ */
37
+ const useManagedClose = ({
38
+ current,
39
+ animations,
40
+ activate,
41
+ deactivate,
42
+ }: CloseHookParams) => {
43
+ const { handleCloseRoute, closingRouteKeysShared } = useManagedStackContext();
44
+
45
+ const handleCloseEnd = useStableCallback((finished: boolean) => {
46
+ if (!finished) return;
47
+ handleCloseRoute({ route: current.route });
48
+ requestAnimationFrame(() => {
49
+ deactivate();
50
+ resetStoresForScreen(current);
51
+ });
52
+ });
53
+
54
+ useAnimatedReaction(
55
+ () => closingRouteKeysShared.value,
56
+ (keys) => {
57
+ if (!keys?.includes(current.route.key)) return;
58
+
59
+ runOnJS(activate)();
60
+ startScreenTransition({
61
+ target: "close",
62
+ spec: current.options.transitionSpec,
63
+ animations,
64
+ onAnimationFinish: handleCloseEnd,
65
+ });
66
+ },
67
+ );
68
+ };
69
+
70
+ /**
71
+ * Native stack close - listens to beforeRemove navigation event.
72
+ */
73
+ const useNativeStackClose = ({
74
+ current,
75
+ animations,
76
+ activate,
77
+ deactivate,
78
+ }: CloseHookParams) => {
79
+ const gestureCtx = useGestureContext();
80
+
81
+ const isAncestorDismissingViaGesture = useSharedValueState(
82
+ useDerivedValue(() => {
83
+ "worklet";
84
+ return (
85
+ gestureCtx?.ancestorContext?.gestureAnimationValues.isDismissing
86
+ ?.value ?? false
87
+ );
88
+ }),
89
+ );
90
+
91
+ const handleBeforeRemove = useStableCallback((e: any) => {
92
+ const options = current.options as { enableTransitions?: boolean };
93
+ const isEnabled = options.enableTransitions;
94
+ const navigation = current.navigation;
95
+ const isFirstScreen = navigation.getState().index === 0;
96
+
97
+ // If transitions are disabled, ancestor is dismissing, or first screen - let native handle it
98
+ if (!isEnabled || isAncestorDismissingViaGesture || isFirstScreen) {
99
+ animations.closing.set(1);
100
+ resetStoresForScreen(current);
101
+ return;
102
+ }
103
+
104
+ e.preventDefault();
105
+ activate();
106
+
107
+ startScreenTransition({
108
+ target: "close",
109
+ spec: current.options.transitionSpec,
110
+ animations,
111
+ onAnimationFinish: (finished: boolean) => {
112
+ deactivate();
113
+ if (finished) {
114
+ navigation.dispatch(e.data.action);
115
+ requestAnimationFrame(() => {
116
+ resetStoresForScreen(current);
117
+ });
118
+ }
119
+ },
120
+ });
121
+ });
122
+
123
+ // biome-ignore lint/correctness/useExhaustiveDependencies: Only re-subscribe when navigation changes
124
+ useLayoutEffect(() => {
125
+ return current.navigation.addListener?.("beforeRemove", handleBeforeRemove);
126
+ }, [current.navigation]);
127
+ };
128
+
129
+ /**
130
+ * Unified lifecycle controller for all stack types.
131
+ */
132
+ export const ScreenLifecycle = ({ children }: Props) => {
133
+ const { flags } = useStackCoreContext();
134
+ const { current } = useKeys();
135
+ const animations = AnimationStore.getAll(current.route.key);
136
+ const { activateHighRefreshRate, deactivateHighRefreshRate } =
137
+ useHighRefreshRate(current);
138
+
139
+ const isNativeStack = flags.STACK_TYPE === StackType.NATIVE;
140
+
141
+ // biome-ignore lint/correctness/useExhaustiveDependencies: Must only run once on mount
142
+ useLayoutEffect(() => {
143
+ activateHighRefreshRate();
144
+ startScreenTransition({
145
+ target: "open",
146
+ spec: current.options.transitionSpec,
147
+ animations,
148
+ onAnimationFinish: deactivateHighRefreshRate,
149
+ });
150
+ }, []);
151
+
152
+ const closeParams: CloseHookParams = {
153
+ current,
154
+ animations,
155
+ activate: activateHighRefreshRate,
156
+ deactivate: deactivateHighRefreshRate,
157
+ };
158
+
159
+ if (isNativeStack) {
160
+ // biome-ignore lint/correctness/useHookAtTopLevel: STACK_TYPE is stable per screen instance
161
+ useNativeStackClose(closeParams);
162
+ } else {
163
+ // biome-ignore lint/correctness/useHookAtTopLevel: STACK_TYPE is stable per screen instance
164
+ useManagedClose(closeParams);
165
+ }
166
+
167
+ return children;
168
+ };
@@ -71,8 +71,10 @@ export const FULLSCREEN_DIMENSIONS = (
71
71
  */
72
72
  export const GESTURE_VELOCITY_IMPACT = 0.3;
73
73
  export const DEFAULT_GESTURE_DIRECTION = "horizontal";
74
- export const DEFAULT_GESTURE_ENABLED = false;
75
74
  export const DEFAULT_GESTURE_DRIVES_PROGRESS = true;
76
75
  export const DEFAULT_GESTURE_ACTIVATION_AREA: ActivationArea = "screen";
77
76
 
78
77
  export const IS_WEB = Platform.OS === "web";
78
+
79
+ export const TRUE = 1;
80
+ export const FALSE = 0;
@@ -6,7 +6,6 @@ import type { NativeStackScreenTransitionConfig } from "../../../native-stack/ty
6
6
  import { DEFAULT_SCREEN_TRANSITION_STATE } from "../../constants";
7
7
  import {
8
8
  type BaseDescriptor,
9
- type BaseRoute,
10
9
  useKeys,
11
10
  } from "../../providers/screen/keys.provider";
12
11
  import { AnimationStore } from "../../stores/animation.store";
@@ -16,6 +15,7 @@ import type {
16
15
  ScreenTransitionState,
17
16
  } from "../../types/animation.types";
18
17
  import type { ScreenTransitionConfig } from "../../types/screen.types";
18
+ import type { BaseStackRoute } from "../../types/stack.types";
19
19
  import { derivations } from "../../utils/animation/derivations";
20
20
  import { createBounds } from "../../utils/bounds";
21
21
  import { useStack } from "../navigation/use-stack";
@@ -25,13 +25,13 @@ type BuiltState = {
25
25
  closing: SharedValue<number>;
26
26
  animating: SharedValue<number>;
27
27
  gesture: GestureStoreMap;
28
- route: BaseRoute;
28
+ route: BaseStackRoute;
29
29
  meta?: Record<string, unknown>;
30
30
  unwrapped: ScreenTransitionState;
31
31
  };
32
32
 
33
33
  const createScreenTransitionState = (
34
- route: BaseRoute,
34
+ route: BaseStackRoute,
35
35
  meta?: Record<string, unknown>,
36
36
  ): ScreenTransitionState => ({
37
37
  progress: 0,
@@ -15,7 +15,6 @@ import {
15
15
  DEFAULT_GESTURE_ACTIVATION_AREA,
16
16
  DEFAULT_GESTURE_DIRECTION,
17
17
  DEFAULT_GESTURE_DRIVES_PROGRESS,
18
- DEFAULT_GESTURE_ENABLED,
19
18
  GESTURE_VELOCITY_IMPACT,
20
19
  } from "../../constants";
21
20
  import type {
@@ -35,7 +34,6 @@ import { determineDismissal } from "../../utils/gesture/determine-dismissal";
35
34
  import { mapGestureToProgress } from "../../utils/gesture/map-gesture-to-progress";
36
35
  import { resetGestureValues } from "../../utils/gesture/reset-gesture-values";
37
36
  import { velocity } from "../../utils/gesture/velocity";
38
- import { useStack } from "../navigation/use-stack";
39
37
  import useStableCallbackValue from "../use-stable-callback-value";
40
38
 
41
39
  interface BuildGesturesHookProps {
@@ -0,0 +1,99 @@
1
+ import type { Route } from "@react-navigation/native";
2
+ import { useMemo } from "react";
3
+ import { useDerivedValue } from "react-native-reanimated";
4
+ import {
5
+ type BaseDescriptor,
6
+ useKeys,
7
+ } from "../../providers/screen/keys.provider";
8
+ import type { ScreenTransitionConfig } from "../../types/screen.types";
9
+ import type { BaseStackNavigation } from "../../types/stack.types";
10
+ import { useSharedValueState } from "../reanimated/use-shared-value-state";
11
+ import { type StackContextValue, useStack } from "./use-stack";
12
+
13
+ export interface ScreenState<
14
+ TNavigation extends BaseStackNavigation = BaseStackNavigation,
15
+ > {
16
+ /**
17
+ * The index of this screen in the stack.
18
+ */
19
+ index: number;
20
+
21
+ /**
22
+ * Screen options for the currently focused screen.
23
+ */
24
+ options: ScreenTransitionConfig;
25
+
26
+ /**
27
+ * All routes currently in the stack.
28
+ */
29
+ routes: Route<string>[];
30
+
31
+ /**
32
+ * Route of the currently focused screen in the stack.
33
+ */
34
+ focusedRoute: Route<string>;
35
+
36
+ /**
37
+ * Index of the focused route in the stack.
38
+ */
39
+ focusedIndex: number;
40
+
41
+ /**
42
+ * Custom metadata from the focused screen's options.
43
+ */
44
+ meta?: Record<string, unknown>;
45
+
46
+ /**
47
+ * Navigation object for this screen.
48
+ */
49
+ navigation: TNavigation;
50
+ }
51
+
52
+ /**
53
+ * Hook to access screen state information.
54
+ *
55
+ * Use this hook to get navigation state and screen information.
56
+ */
57
+ export function useScreenState<
58
+ TNavigation extends BaseStackNavigation = BaseStackNavigation,
59
+ >(): ScreenState<TNavigation> {
60
+ const { routes, scenes, routeKeys, optimisticFocusedIndex } =
61
+ useStack<StackContextValue>();
62
+ const { current } = useKeys<BaseDescriptor>();
63
+
64
+ const index = useMemo(
65
+ () => routeKeys.indexOf(current.route.key),
66
+ [routeKeys, current.route.key],
67
+ );
68
+
69
+ const focusedIndex = useSharedValueState(
70
+ useDerivedValue(() => {
71
+ const globalIndex = optimisticFocusedIndex.get();
72
+ return Math.max(0, Math.min(globalIndex, routeKeys.length - 1));
73
+ }),
74
+ );
75
+
76
+ const focusedScene = useMemo(() => {
77
+ return scenes[focusedIndex] ?? scenes[scenes.length - 1];
78
+ }, [scenes, focusedIndex]);
79
+
80
+ return useMemo(
81
+ () => ({
82
+ index,
83
+ options: focusedScene?.descriptor?.options ?? {},
84
+ routes,
85
+ focusedRoute: focusedScene?.route ?? current.route,
86
+ focusedIndex,
87
+ meta: focusedScene?.descriptor?.options?.meta,
88
+ navigation: current.navigation as TNavigation,
89
+ }),
90
+ [
91
+ index,
92
+ focusedScene,
93
+ routes,
94
+ focusedIndex,
95
+ current.navigation,
96
+ current.route,
97
+ ],
98
+ );
99
+ }
@@ -10,7 +10,6 @@ import {
10
10
  runOnJS,
11
11
  } from "react-native-reanimated";
12
12
 
13
- // biome-ignore lint/suspicious/noExplicitAny: <Does not matter>
14
13
  type AnyFunction = (...args: Array<any>) => any;
15
14
 
16
15
  function useMutableValue<T>(initialValue: T) {
@@ -0,0 +1,15 @@
1
+ import { useStackCoreContext } from "../providers/stack/core.provider";
2
+ import { StackType } from "../types/stack.types";
3
+
4
+ /**
5
+ * Hook that returns the appropriate pointer events value based on current stack type.
6
+ *
7
+ * - Component stack: "box-none" (allows touch pass-through to content behind)
8
+ * - Other stacks: undefined (default behavior, view receives touches)
9
+ *
10
+ * Must be used within a StackCoreProvider.
11
+ */
12
+ export function useStackPointerEvents(): "box-none" | undefined {
13
+ const { flags } = useStackCoreContext();
14
+ return flags.STACK_TYPE === StackType.COMPONENT ? "box-none" : undefined;
15
+ }
@@ -20,6 +20,10 @@ export default {
20
20
 
21
21
  export { useScreenAnimation } from "./hooks/animation/use-screen-animation";
22
22
  export { useScreenGesture } from "./hooks/gestures/use-screen-gesture";
23
+ export {
24
+ type ScreenState,
25
+ useScreenState,
26
+ } from "./hooks/navigation/use-screen-state";
23
27
 
24
28
  export type {
25
29
  AnimationConfig,
@@ -6,6 +6,7 @@ import {
6
6
  import type { SharedValue } from "react-native-reanimated";
7
7
  import { useSharedValue } from "react-native-reanimated";
8
8
  import { useBuildGestures } from "../hooks/gestures/use-build-gestures";
9
+ import { useStackPointerEvents } from "../hooks/use-stack-pointer-events";
9
10
  import type { GestureStoreMap } from "../stores/gesture.store";
10
11
  import createProvider from "../utils/create-provider";
11
12
  import { useKeys } from "./screen/keys.provider";
@@ -41,6 +42,7 @@ export const {
41
42
  GestureContextType
42
43
  >(({ children }) => {
43
44
  const { current } = useKeys();
45
+ const pointerEvents = useStackPointerEvents();
44
46
  const ancestorContext = useGestureContext();
45
47
  const scrollConfig = useSharedValue<ScrollConfig | null>(null);
46
48
 
@@ -66,7 +68,9 @@ export const {
66
68
  value,
67
69
  children: (
68
70
  <GestureDetector gesture={panGesture}>
69
- <View style={styles.container}>{children}</View>
71
+ <View style={styles.container} pointerEvents={pointerEvents}>
72
+ {children}
73
+ </View>
70
74
  </GestureDetector>
71
75
  ),
72
76
  };
@@ -6,15 +6,7 @@ import type {
6
6
  } from "@react-navigation/native";
7
7
  import { createContext, useContext, useMemo } from "react";
8
8
  import type { ScreenTransitionConfig } from "../../types/screen.types";
9
- import type {
10
- BaseStackDescriptor,
11
- BaseStackNavigation,
12
- BaseStackRoute,
13
- } from "../../types/stack.types";
14
-
15
- // Re-export for backward compatibility
16
- export type { BaseStackNavigation as BaseNavigation };
17
- export type { BaseStackRoute as BaseRoute };
9
+ import type { BaseStackDescriptor } from "../../types/stack.types";
18
10
 
19
11
  /**
20
12
  * Base descriptor interface - minimal contract for all stack types.
@@ -1,6 +1,6 @@
1
1
  import type React from "react";
2
- import type { ComponentType } from "react";
3
2
  import { RootTransitionAware } from "../../components/root-transition-aware";
3
+ import { ScreenLifecycle } from "../../components/screen-lifecycle";
4
4
  import { ScreenGestureProvider } from "../gestures.provider";
5
5
  import { type BaseDescriptor, KeysProvider } from "./keys.provider";
6
6
  import { ScreenStylesProvider } from "./styles.provider";
@@ -10,7 +10,6 @@ type Props<TDescriptor extends BaseDescriptor> = {
10
10
  current: TDescriptor;
11
11
  next?: TDescriptor;
12
12
  children: React.ReactNode;
13
- LifecycleController: ComponentType<any>;
14
13
  };
15
14
 
16
15
  export function ScreenComposer<TDescriptor extends BaseDescriptor>({
@@ -18,7 +17,6 @@ export function ScreenComposer<TDescriptor extends BaseDescriptor>({
18
17
  current,
19
18
  next,
20
19
  children,
21
- LifecycleController,
22
20
  }: Props<TDescriptor>) {
23
21
  return (
24
22
  <KeysProvider<TDescriptor>
@@ -27,11 +25,11 @@ export function ScreenComposer<TDescriptor extends BaseDescriptor>({
27
25
  next={next}
28
26
  >
29
27
  <ScreenGestureProvider>
30
- <LifecycleController>
28
+ <ScreenLifecycle>
31
29
  <ScreenStylesProvider>
32
30
  <RootTransitionAware>{children}</RootTransitionAware>
33
31
  </ScreenStylesProvider>
34
- </LifecycleController>
32
+ </ScreenLifecycle>
35
33
  </ScreenGestureProvider>
36
34
  </KeysProvider>
37
35
  );
@@ -113,7 +113,7 @@ export function useScreenStyles() {
113
113
  const ctx = useContext(ScreenStylesContext);
114
114
  if (!ctx) {
115
115
  throw new Error(
116
- "useTransitionStyles must be used within a TransitionStylesProvider",
116
+ "useScreenStyles must be used within a ScreenStylesProvider",
117
117
  );
118
118
  }
119
119
  return ctx;