react-native-screen-transitions 3.0.0-rc.2 → 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 (241) hide show
  1. package/README.md +421 -371
  2. package/lib/commonjs/blank-stack/components/{Overlay.js → overlay.js} +7 -5
  3. package/lib/commonjs/blank-stack/components/overlay.js.map +1 -0
  4. package/lib/commonjs/blank-stack/components/{Screens.js → screens.js} +20 -17
  5. package/lib/commonjs/blank-stack/components/screens.js.map +1 -0
  6. package/lib/commonjs/blank-stack/components/stack-view.js +101 -0
  7. package/lib/commonjs/blank-stack/components/stack-view.js.map +1 -0
  8. package/lib/commonjs/blank-stack/index.js +1 -8
  9. package/lib/commonjs/blank-stack/index.js.map +1 -1
  10. package/lib/commonjs/blank-stack/navigators/{createBlankStackNavigator.js → create-blank-stack-navigator.js} +3 -3
  11. package/lib/commonjs/blank-stack/navigators/create-blank-stack-navigator.js.map +1 -0
  12. package/lib/commonjs/blank-stack/utils/with-stack-navigation/helpers/compose-descriptors.js +1 -11
  13. package/lib/commonjs/blank-stack/utils/with-stack-navigation/helpers/compose-descriptors.js.map +1 -1
  14. package/lib/commonjs/blank-stack/utils/with-stack-navigation/hooks/use-closing-route-keys.js +1 -12
  15. package/lib/commonjs/blank-stack/utils/with-stack-navigation/hooks/use-closing-route-keys.js.map +1 -1
  16. package/lib/commonjs/blank-stack/utils/with-stack-navigation/hooks/use-stack-navigation-state.js.map +1 -1
  17. package/lib/commonjs/blank-stack/utils/with-stack-navigation/index.js +49 -55
  18. package/lib/commonjs/blank-stack/utils/with-stack-navigation/index.js.map +1 -1
  19. package/lib/commonjs/blank-stack/utils/with-stack-navigation/{_types.js → types.js} +1 -1
  20. package/lib/commonjs/blank-stack/utils/with-stack-navigation/types.js.map +1 -0
  21. package/lib/commonjs/native-stack/views/NativeStackView.native.js +110 -103
  22. package/lib/commonjs/native-stack/views/NativeStackView.native.js.map +1 -1
  23. package/lib/commonjs/shared/components/controllers/blank-stack-lifecycle.js +72 -0
  24. package/lib/commonjs/shared/components/controllers/blank-stack-lifecycle.js.map +1 -0
  25. package/lib/commonjs/shared/components/controllers/native-stack-lifecycle.js +79 -0
  26. package/lib/commonjs/shared/components/controllers/native-stack-lifecycle.js.map +1 -0
  27. package/lib/commonjs/shared/hooks/animation/use-screen-animation.js +49 -23
  28. package/lib/commonjs/shared/hooks/animation/use-screen-animation.js.map +1 -1
  29. package/lib/commonjs/shared/hooks/gestures/use-build-gestures.js +11 -6
  30. package/lib/commonjs/shared/hooks/gestures/use-build-gestures.js.map +1 -1
  31. package/lib/commonjs/shared/hooks/gestures/use-scroll-registry.js +7 -7
  32. package/lib/commonjs/shared/hooks/gestures/use-scroll-registry.js.map +1 -1
  33. package/lib/commonjs/shared/providers/flags.provider.js +25 -0
  34. package/lib/commonjs/shared/providers/flags.provider.js.map +1 -0
  35. package/lib/commonjs/shared/providers/gestures.provider.js +32 -5
  36. package/lib/commonjs/shared/providers/gestures.provider.js.map +1 -1
  37. package/lib/commonjs/shared/providers/register-bounds.provider.js +72 -45
  38. package/lib/commonjs/shared/providers/register-bounds.provider.js.map +1 -1
  39. package/lib/commonjs/shared/providers/routes.provider.js +48 -0
  40. package/lib/commonjs/shared/providers/routes.provider.js.map +1 -0
  41. package/lib/commonjs/shared/providers/screen-transition.provider.js.map +1 -1
  42. package/lib/commonjs/shared/stores/bounds.store.js +91 -47
  43. package/lib/commonjs/shared/stores/bounds.store.js.map +1 -1
  44. package/lib/commonjs/shared/types/state.types.js +9 -0
  45. package/lib/commonjs/shared/types/state.types.js.map +1 -0
  46. package/lib/commonjs/shared/utils/animation/compute-stack-progress.js +20 -0
  47. package/lib/commonjs/shared/utils/animation/compute-stack-progress.js.map +1 -0
  48. package/lib/commonjs/shared/utils/animation/derivations.js +1 -1
  49. package/lib/commonjs/shared/utils/animation/start-screen-transition.js +11 -11
  50. package/lib/commonjs/shared/utils/animation/start-screen-transition.js.map +1 -1
  51. package/lib/commonjs/shared/utils/bounds/helpers/is-bounds-equal.js +1 -1
  52. package/lib/commonjs/shared/utils/bounds/helpers/is-bounds-equal.js.map +1 -1
  53. package/lib/commonjs/shared/utils/bounds/index.js +4 -5
  54. package/lib/commonjs/shared/utils/bounds/index.js.map +1 -1
  55. package/lib/commonjs/shared/utils/create-provider.js +20 -1
  56. package/lib/commonjs/shared/utils/create-provider.js.map +1 -1
  57. package/lib/commonjs/shared/utils/reset-stores-for-screen.js +2 -0
  58. package/lib/commonjs/shared/utils/reset-stores-for-screen.js.map +1 -1
  59. package/lib/module/blank-stack/components/{Overlay.js → overlay.js} +7 -5
  60. package/lib/module/blank-stack/components/overlay.js.map +1 -0
  61. package/lib/module/blank-stack/components/screens.js +61 -0
  62. package/lib/module/blank-stack/components/screens.js.map +1 -0
  63. package/lib/module/blank-stack/components/stack-view.js +96 -0
  64. package/lib/module/blank-stack/components/stack-view.js.map +1 -0
  65. package/lib/module/blank-stack/index.js +1 -2
  66. package/lib/module/blank-stack/index.js.map +1 -1
  67. package/lib/module/blank-stack/navigators/{createBlankStackNavigator.js → create-blank-stack-navigator.js} +2 -2
  68. package/lib/module/blank-stack/navigators/create-blank-stack-navigator.js.map +1 -0
  69. package/lib/module/blank-stack/utils/with-stack-navigation/helpers/compose-descriptors.js +1 -11
  70. package/lib/module/blank-stack/utils/with-stack-navigation/helpers/compose-descriptors.js.map +1 -1
  71. package/lib/module/blank-stack/utils/with-stack-navigation/hooks/use-closing-route-keys.js +1 -12
  72. package/lib/module/blank-stack/utils/with-stack-navigation/hooks/use-closing-route-keys.js.map +1 -1
  73. package/lib/module/blank-stack/utils/with-stack-navigation/hooks/use-stack-navigation-state.js.map +1 -1
  74. package/lib/module/blank-stack/utils/with-stack-navigation/index.js +48 -54
  75. package/lib/module/blank-stack/utils/with-stack-navigation/index.js.map +1 -1
  76. package/lib/module/blank-stack/utils/with-stack-navigation/types.js +4 -0
  77. package/lib/module/blank-stack/utils/with-stack-navigation/types.js.map +1 -0
  78. package/lib/module/native-stack/views/NativeStackView.native.js +109 -102
  79. package/lib/module/native-stack/views/NativeStackView.native.js.map +1 -1
  80. package/lib/module/shared/components/controllers/blank-stack-lifecycle.js +66 -0
  81. package/lib/module/shared/components/controllers/blank-stack-lifecycle.js.map +1 -0
  82. package/lib/module/shared/components/controllers/native-stack-lifecycle.js +73 -0
  83. package/lib/module/shared/components/controllers/native-stack-lifecycle.js.map +1 -0
  84. package/lib/module/shared/hooks/animation/use-screen-animation.js +49 -23
  85. package/lib/module/shared/hooks/animation/use-screen-animation.js.map +1 -1
  86. package/lib/module/shared/hooks/gestures/use-build-gestures.js +11 -6
  87. package/lib/module/shared/hooks/gestures/use-build-gestures.js.map +1 -1
  88. package/lib/module/shared/hooks/gestures/use-scroll-registry.js +7 -7
  89. package/lib/module/shared/hooks/gestures/use-scroll-registry.js.map +1 -1
  90. package/lib/module/shared/providers/flags.provider.js +19 -0
  91. package/lib/module/shared/providers/flags.provider.js.map +1 -0
  92. package/lib/module/shared/providers/gestures.provider.js +31 -4
  93. package/lib/module/shared/providers/gestures.provider.js.map +1 -1
  94. package/lib/module/shared/providers/register-bounds.provider.js +72 -45
  95. package/lib/module/shared/providers/register-bounds.provider.js.map +1 -1
  96. package/lib/module/shared/providers/routes.provider.js +42 -0
  97. package/lib/module/shared/providers/routes.provider.js.map +1 -0
  98. package/lib/module/shared/providers/screen-transition.provider.js.map +1 -1
  99. package/lib/module/shared/stores/bounds.store.js +91 -47
  100. package/lib/module/shared/stores/bounds.store.js.map +1 -1
  101. package/lib/module/shared/types/state.types.js +5 -0
  102. package/lib/module/shared/types/state.types.js.map +1 -0
  103. package/lib/module/shared/utils/animation/compute-stack-progress.js +15 -0
  104. package/lib/module/shared/utils/animation/compute-stack-progress.js.map +1 -0
  105. package/lib/module/shared/utils/animation/derivations.js +1 -1
  106. package/lib/module/shared/utils/animation/start-screen-transition.js +11 -11
  107. package/lib/module/shared/utils/animation/start-screen-transition.js.map +1 -1
  108. package/lib/module/shared/utils/bounds/helpers/is-bounds-equal.js +1 -1
  109. package/lib/module/shared/utils/bounds/helpers/is-bounds-equal.js.map +1 -1
  110. package/lib/module/shared/utils/bounds/index.js +4 -5
  111. package/lib/module/shared/utils/bounds/index.js.map +1 -1
  112. package/lib/module/shared/utils/create-provider.js +20 -1
  113. package/lib/module/shared/utils/create-provider.js.map +1 -1
  114. package/lib/module/shared/utils/reset-stores-for-screen.js +2 -0
  115. package/lib/module/shared/utils/reset-stores-for-screen.js.map +1 -1
  116. package/lib/typescript/blank-stack/components/{Overlay.d.ts → overlay.d.ts} +1 -1
  117. package/lib/typescript/blank-stack/components/overlay.d.ts.map +1 -0
  118. package/lib/typescript/blank-stack/components/{Screens.d.ts → screens.d.ts} +1 -1
  119. package/lib/typescript/blank-stack/components/screens.d.ts.map +1 -0
  120. package/lib/typescript/blank-stack/components/stack-view.d.ts +3 -0
  121. package/lib/typescript/blank-stack/components/stack-view.d.ts.map +1 -0
  122. package/lib/typescript/blank-stack/index.d.ts +1 -2
  123. package/lib/typescript/blank-stack/index.d.ts.map +1 -1
  124. package/lib/typescript/blank-stack/navigators/{createBlankStackNavigator.d.ts → create-blank-stack-navigator.d.ts} +1 -1
  125. package/lib/typescript/blank-stack/navigators/create-blank-stack-navigator.d.ts.map +1 -0
  126. package/lib/typescript/blank-stack/types.d.ts +5 -39
  127. package/lib/typescript/blank-stack/types.d.ts.map +1 -1
  128. package/lib/typescript/blank-stack/utils/with-stack-navigation/helpers/compose-descriptors.d.ts.map +1 -1
  129. package/lib/typescript/blank-stack/utils/with-stack-navigation/hooks/use-closing-route-keys.d.ts.map +1 -1
  130. package/lib/typescript/blank-stack/utils/with-stack-navigation/hooks/use-stack-navigation-state.d.ts +1 -1
  131. package/lib/typescript/blank-stack/utils/with-stack-navigation/hooks/use-stack-navigation-state.d.ts.map +1 -1
  132. package/lib/typescript/blank-stack/utils/with-stack-navigation/index.d.ts +3 -5
  133. package/lib/typescript/blank-stack/utils/with-stack-navigation/index.d.ts.map +1 -1
  134. package/lib/typescript/blank-stack/utils/with-stack-navigation/{_types.d.ts → types.d.ts} +1 -1
  135. package/lib/typescript/blank-stack/utils/with-stack-navigation/types.d.ts.map +1 -0
  136. package/lib/typescript/native-stack/views/NativeStackView.native.d.ts.map +1 -1
  137. package/lib/typescript/shared/components/controllers/blank-stack-lifecycle.d.ts +8 -0
  138. package/lib/typescript/shared/components/controllers/blank-stack-lifecycle.d.ts.map +1 -0
  139. package/lib/typescript/shared/components/controllers/native-stack-lifecycle.d.ts +8 -0
  140. package/lib/typescript/shared/components/controllers/native-stack-lifecycle.d.ts.map +1 -0
  141. package/lib/typescript/shared/hooks/animation/use-screen-animation.d.ts.map +1 -1
  142. package/lib/typescript/shared/hooks/gestures/use-build-gestures.d.ts +2 -2
  143. package/lib/typescript/shared/hooks/gestures/use-build-gestures.d.ts.map +1 -1
  144. package/lib/typescript/shared/index.d.ts +20 -20
  145. package/lib/typescript/shared/providers/flags.provider.d.ts +10 -0
  146. package/lib/typescript/shared/providers/flags.provider.d.ts.map +1 -0
  147. package/lib/typescript/shared/providers/gestures.provider.d.ts +8 -2
  148. package/lib/typescript/shared/providers/gestures.provider.d.ts.map +1 -1
  149. package/lib/typescript/shared/providers/register-bounds.provider.d.ts.map +1 -1
  150. package/lib/typescript/shared/providers/routes.provider.d.ts +19 -0
  151. package/lib/typescript/shared/providers/routes.provider.d.ts.map +1 -0
  152. package/lib/typescript/shared/providers/screen-transition.provider.d.ts +2 -2
  153. package/lib/typescript/shared/providers/screen-transition.provider.d.ts.map +1 -1
  154. package/lib/typescript/shared/stores/bounds.store.d.ts +23 -11
  155. package/lib/typescript/shared/stores/bounds.store.d.ts.map +1 -1
  156. package/lib/typescript/shared/types/animation.types.d.ts +12 -0
  157. package/lib/typescript/shared/types/animation.types.d.ts.map +1 -1
  158. package/lib/typescript/shared/types/bounds.types.d.ts +2 -2
  159. package/lib/typescript/shared/types/bounds.types.d.ts.map +1 -1
  160. package/lib/typescript/shared/types/state.types.d.ts +3 -0
  161. package/lib/typescript/shared/types/state.types.d.ts.map +1 -0
  162. package/lib/typescript/shared/utils/animation/compute-stack-progress.d.ts +3 -0
  163. package/lib/typescript/shared/utils/animation/compute-stack-progress.d.ts.map +1 -0
  164. package/lib/typescript/shared/utils/animation/start-screen-transition.d.ts.map +1 -1
  165. package/lib/typescript/shared/utils/bounds/index.d.ts.map +1 -1
  166. package/lib/typescript/shared/utils/create-provider.d.ts +2 -2
  167. package/lib/typescript/shared/utils/create-provider.d.ts.map +1 -1
  168. package/lib/typescript/shared/utils/reset-stores-for-screen.d.ts.map +1 -1
  169. package/package.json +2 -1
  170. package/src/blank-stack/components/{Overlay.tsx → overlay.tsx} +4 -3
  171. package/src/blank-stack/components/{Screens.tsx → screens.tsx} +24 -20
  172. package/src/blank-stack/components/stack-view.tsx +115 -0
  173. package/src/blank-stack/index.ts +1 -2
  174. package/src/blank-stack/navigators/{createBlankStackNavigator.tsx → create-blank-stack-navigator.tsx} +1 -1
  175. package/src/blank-stack/types.ts +6 -31
  176. package/src/blank-stack/utils/with-stack-navigation/helpers/compose-descriptors.ts +1 -8
  177. package/src/blank-stack/utils/with-stack-navigation/hooks/use-closing-route-keys.tsx +1 -12
  178. package/src/blank-stack/utils/with-stack-navigation/hooks/use-stack-navigation-state.tsx +1 -1
  179. package/src/blank-stack/utils/with-stack-navigation/index.tsx +42 -62
  180. package/src/native-stack/views/NativeStackView.native.tsx +121 -112
  181. package/src/shared/__tests__/bounds.store.test.ts +376 -167
  182. package/src/shared/__tests__/determine-dismissal.test.ts +2 -12
  183. package/src/shared/__tests__/geometry.test.ts +1 -1
  184. package/src/shared/__tests__/gesture.velocity.test.ts +2 -10
  185. package/src/shared/components/controllers/blank-stack-lifecycle.tsx +70 -0
  186. package/src/shared/components/controllers/native-stack-lifecycle.tsx +87 -0
  187. package/src/shared/hooks/animation/use-screen-animation.tsx +61 -30
  188. package/src/shared/hooks/gestures/use-build-gestures.tsx +16 -7
  189. package/src/shared/hooks/gestures/use-scroll-registry.tsx +7 -7
  190. package/src/shared/providers/flags.provider.tsx +21 -0
  191. package/src/shared/providers/gestures.provider.tsx +34 -5
  192. package/src/shared/providers/register-bounds.provider.tsx +86 -54
  193. package/src/shared/providers/routes.provider.tsx +54 -0
  194. package/src/shared/providers/screen-transition.provider.tsx +2 -2
  195. package/src/shared/stores/bounds.store.ts +90 -54
  196. package/src/shared/types/animation.types.ts +13 -0
  197. package/src/shared/types/bounds.types.ts +2 -2
  198. package/src/shared/types/state.types.ts +2 -0
  199. package/src/shared/utils/animation/compute-stack-progress.ts +16 -0
  200. package/src/shared/utils/animation/derivations.ts +1 -1
  201. package/src/shared/utils/animation/start-screen-transition.ts +13 -10
  202. package/src/shared/utils/bounds/helpers/is-bounds-equal.ts +1 -1
  203. package/src/shared/utils/bounds/index.ts +7 -10
  204. package/src/shared/utils/create-provider.tsx +35 -1
  205. package/src/shared/utils/reset-stores-for-screen.ts +2 -0
  206. package/lib/commonjs/blank-stack/components/Overlay.js.map +0 -1
  207. package/lib/commonjs/blank-stack/components/Screens.js.map +0 -1
  208. package/lib/commonjs/blank-stack/components/StackView.js +0 -93
  209. package/lib/commonjs/blank-stack/components/StackView.js.map +0 -1
  210. package/lib/commonjs/blank-stack/navigators/createBlankStackNavigator.js.map +0 -1
  211. package/lib/commonjs/blank-stack/utils/with-stack-navigation/_types.js.map +0 -1
  212. package/lib/commonjs/shared/components/controllers/screen-lifecycle.js +0 -142
  213. package/lib/commonjs/shared/components/controllers/screen-lifecycle.js.map +0 -1
  214. package/lib/commonjs/shared/hooks/gestures/use-parent-gesture-registry.js +0 -28
  215. package/lib/commonjs/shared/hooks/gestures/use-parent-gesture-registry.js.map +0 -1
  216. package/lib/module/blank-stack/components/Overlay.js.map +0 -1
  217. package/lib/module/blank-stack/components/Screens.js +0 -58
  218. package/lib/module/blank-stack/components/Screens.js.map +0 -1
  219. package/lib/module/blank-stack/components/StackView.js +0 -88
  220. package/lib/module/blank-stack/components/StackView.js.map +0 -1
  221. package/lib/module/blank-stack/navigators/createBlankStackNavigator.js.map +0 -1
  222. package/lib/module/blank-stack/utils/with-stack-navigation/_types.js +0 -4
  223. package/lib/module/blank-stack/utils/with-stack-navigation/_types.js.map +0 -1
  224. package/lib/module/shared/components/controllers/screen-lifecycle.js +0 -136
  225. package/lib/module/shared/components/controllers/screen-lifecycle.js.map +0 -1
  226. package/lib/module/shared/hooks/gestures/use-parent-gesture-registry.js +0 -23
  227. package/lib/module/shared/hooks/gestures/use-parent-gesture-registry.js.map +0 -1
  228. package/lib/typescript/blank-stack/components/Overlay.d.ts.map +0 -1
  229. package/lib/typescript/blank-stack/components/Screens.d.ts.map +0 -1
  230. package/lib/typescript/blank-stack/components/StackView.d.ts +0 -2
  231. package/lib/typescript/blank-stack/components/StackView.d.ts.map +0 -1
  232. package/lib/typescript/blank-stack/navigators/createBlankStackNavigator.d.ts.map +0 -1
  233. package/lib/typescript/blank-stack/utils/with-stack-navigation/_types.d.ts.map +0 -1
  234. package/lib/typescript/shared/components/controllers/screen-lifecycle.d.ts +0 -12
  235. package/lib/typescript/shared/components/controllers/screen-lifecycle.d.ts.map +0 -1
  236. package/lib/typescript/shared/hooks/gestures/use-parent-gesture-registry.d.ts +0 -6
  237. package/lib/typescript/shared/hooks/gestures/use-parent-gesture-registry.d.ts.map +0 -1
  238. package/src/blank-stack/components/StackView.tsx +0 -108
  239. package/src/shared/components/controllers/screen-lifecycle.tsx +0 -154
  240. package/src/shared/hooks/gestures/use-parent-gesture-registry.tsx +0 -18
  241. /package/src/blank-stack/utils/with-stack-navigation/{_types.ts → types.ts} +0 -0
@@ -0,0 +1,70 @@
1
+ import { useLayoutEffect } from "react";
2
+ import { useAnimatedReaction } from "react-native-reanimated";
3
+ import type { BlankStackDescriptor } from "../../../blank-stack/types";
4
+ import { useStackNavigationContext } from "../../../blank-stack/utils/with-stack-navigation";
5
+ import useStableCallback from "../../hooks/use-stable-callback";
6
+ import { useKeys } from "../../providers/keys.provider";
7
+ import { AnimationStore } from "../../stores/animation.store";
8
+ import { startScreenTransition } from "../../utils/animation/start-screen-transition";
9
+ import { resetStoresForScreen } from "../../utils/reset-stores-for-screen";
10
+
11
+ export interface Props {
12
+ children: React.ReactNode;
13
+ }
14
+
15
+ /**
16
+ * Lifecycle controller built out for Blank Stack implementation.
17
+ */
18
+ export const BlankStackScreenLifecycleController = ({ children }: Props) => {
19
+ const { current } = useKeys<BlankStackDescriptor>();
20
+ const { handleCloseRoute, closingRouteKeysShared } =
21
+ useStackNavigationContext();
22
+
23
+ const animations = AnimationStore.getAll(current.route.key);
24
+
25
+ const handleInitialize = useStableCallback(() => {
26
+ startScreenTransition({
27
+ target: "open",
28
+ spec: current.options.transitionSpec,
29
+ animations,
30
+ });
31
+ });
32
+
33
+ const handleCleanup = useStableCallback(() => {
34
+ resetStoresForScreen(current);
35
+ });
36
+
37
+ const handleCloseEnd = useStableCallback((finished: boolean) => {
38
+ if (!finished) {
39
+ return;
40
+ }
41
+ handleCloseRoute({ route: current.route });
42
+ });
43
+
44
+ useAnimatedReaction(
45
+ () => ({
46
+ keys: closingRouteKeysShared.value,
47
+ }),
48
+ ({ keys }) => {
49
+ if (!keys.includes(current.route.key)) {
50
+ return;
51
+ }
52
+
53
+ startScreenTransition({
54
+ target: "close",
55
+ spec: current.options.transitionSpec,
56
+ animations,
57
+ onAnimationFinish: handleCloseEnd,
58
+ });
59
+ },
60
+ );
61
+
62
+ useLayoutEffect(() => {
63
+ handleInitialize();
64
+ return () => {
65
+ handleCleanup();
66
+ };
67
+ }, [handleInitialize, handleCleanup]);
68
+
69
+ return children;
70
+ };
@@ -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
+ };
@@ -5,10 +5,12 @@ import { type SharedValue, useDerivedValue } from "react-native-reanimated";
5
5
  import { useSafeAreaInsets } from "react-native-safe-area-context";
6
6
  import type { NativeStackScreenTransitionConfig } from "../../../native-stack/types";
7
7
  import { DEFAULT_SCREEN_TRANSITION_STATE } from "../../constants";
8
+ import { useFlagsContext } from "../../providers/flags.provider";
8
9
  import {
9
10
  type TransitionDescriptor,
10
11
  useKeys,
11
12
  } from "../../providers/keys.provider";
13
+ import { useStackAnimationValues } from "../../providers/routes.provider";
12
14
  import { AnimationStore } from "../../stores/animation.store";
13
15
  import { GestureStore, type GestureStoreMap } from "../../stores/gesture.store";
14
16
  import type {
@@ -16,6 +18,7 @@ import type {
16
18
  ScreenTransitionState,
17
19
  } from "../../types/animation.types";
18
20
  import type { ScreenTransitionConfig } from "../../types/core.types";
21
+ import { computeStackProgress } from "../../utils/animation/compute-stack-progress";
19
22
  import { derivations } from "../../utils/animation/derivations";
20
23
  import { createBounds } from "../../utils/bounds";
21
24
 
@@ -25,30 +28,42 @@ type BuiltState = {
25
28
  animating: SharedValue<number>;
26
29
  gesture: GestureStoreMap;
27
30
  route: RouteProp<ParamListBase>;
31
+ unwrapped: ScreenTransitionState;
28
32
  };
29
33
 
30
- const unwrap = (
31
- s: BuiltState | undefined,
32
- key: string | undefined,
33
- ): ScreenTransitionState | undefined => {
34
+ const createScreenTransitionState = (
35
+ route: RouteProp<ParamListBase>,
36
+ ): ScreenTransitionState => ({
37
+ progress: 0,
38
+ closing: 0,
39
+ animating: 0,
40
+ gesture: {
41
+ x: 0,
42
+ y: 0,
43
+ normalizedX: 0,
44
+ normalizedY: 0,
45
+ isDismissing: 0,
46
+ isDragging: 0,
47
+ direction: null,
48
+ },
49
+ route,
50
+ });
51
+
52
+ const unwrapInto = (s: BuiltState): ScreenTransitionState => {
34
53
  "worklet";
35
- if (!s || !key) return undefined;
36
-
37
- return {
38
- progress: s.progress.value,
39
- closing: s.closing.value,
40
- animating: s.animating.value,
41
- gesture: {
42
- x: s.gesture.x.value,
43
- y: s.gesture.y.value,
44
- normalizedX: s.gesture.normalizedX.value,
45
- normalizedY: s.gesture.normalizedY.value,
46
- isDismissing: s.gesture.isDismissing.value,
47
- isDragging: s.gesture.isDragging.value,
48
- direction: s.gesture.direction.value,
49
- },
50
- route: s.route,
51
- };
54
+ const out = s.unwrapped;
55
+ out.progress = s.progress.value;
56
+ out.closing = s.closing.value;
57
+ out.animating = s.animating.value;
58
+ out.gesture.x = s.gesture.x.value;
59
+ out.gesture.y = s.gesture.y.value;
60
+ out.gesture.normalizedX = s.gesture.normalizedX.value;
61
+ out.gesture.normalizedY = s.gesture.normalizedY.value;
62
+ out.gesture.isDismissing = s.gesture.isDismissing.value;
63
+ out.gesture.isDragging = s.gesture.isDragging.value;
64
+ out.gesture.direction = s.gesture.direction.value;
65
+
66
+ return out;
52
67
  };
53
68
 
54
69
  const useBuildScreenTransitionState = (
@@ -65,18 +80,25 @@ const useBuildScreenTransitionState = (
65
80
  animating: AnimationStore.getAnimation(key, "animating"),
66
81
  gesture: GestureStore.getRouteGestures(key),
67
82
  route: descriptor.route,
83
+ unwrapped: createScreenTransitionState(descriptor.route),
68
84
  };
69
85
  }, [key, descriptor?.route]);
70
86
  };
71
87
 
72
- const hasTransitionsEnabled = (options?: ScreenTransitionConfig) => {
88
+ const hasTransitionsEnabled = (
89
+ options: ScreenTransitionConfig | undefined,
90
+ alwaysOn: boolean,
91
+ ) => {
73
92
  "worklet";
93
+ if (alwaysOn) return true;
74
94
  return !!(options as NativeStackScreenTransitionConfig)?.enableTransitions;
75
95
  };
76
96
 
77
97
  export function _useScreenAnimation() {
78
98
  const dimensions = useWindowDimensions();
79
99
  const insets = useSafeAreaInsets();
100
+ const flags = useFlagsContext();
101
+ const transitionsAlwaysOn = flags?.TRANSITIONS_ALWAYS_ON ?? false;
80
102
 
81
103
  const {
82
104
  current: currentDescriptor,
@@ -88,32 +110,41 @@ export function _useScreenAnimation() {
88
110
  const nextAnimation = useBuildScreenTransitionState(nextDescriptor);
89
111
  const prevAnimation = useBuildScreenTransitionState(previousDescriptor);
90
112
 
113
+ const currentRouteKey = currentDescriptor?.route?.key;
114
+ const stackAnimationValues = useStackAnimationValues(currentRouteKey);
115
+
91
116
  const screenInterpolatorProps = useDerivedValue<
92
117
  Omit<ScreenInterpolationProps, "bounds">
93
118
  >(() => {
94
119
  "worklet";
95
120
 
96
- const previous = unwrap(prevAnimation, previousDescriptor?.route.key);
121
+ const previous = prevAnimation ? unwrapInto(prevAnimation) : undefined;
97
122
 
98
- const next = hasTransitionsEnabled(nextDescriptor?.options)
99
- ? unwrap(nextAnimation, nextDescriptor?.route.key)
100
- : undefined;
123
+ const next =
124
+ nextAnimation &&
125
+ hasTransitionsEnabled(nextDescriptor?.options, transitionsAlwaysOn)
126
+ ? unwrapInto(nextAnimation)
127
+ : undefined;
101
128
 
102
- const current =
103
- unwrap(currentAnimation, currentDescriptor?.route.key) ??
104
- DEFAULT_SCREEN_TRANSITION_STATE;
129
+ const current = currentAnimation
130
+ ? unwrapInto(currentAnimation)
131
+ : DEFAULT_SCREEN_TRANSITION_STATE;
105
132
 
106
- const helpers = derivations({
133
+ const { progress, ...helpers } = derivations({
107
134
  current,
108
135
  next,
109
136
  });
110
137
 
138
+ const stackProgress = computeStackProgress(stackAnimationValues, progress);
139
+
111
140
  return {
112
141
  layouts: { screen: dimensions },
113
142
  insets,
114
143
  previous,
115
144
  current,
116
145
  next,
146
+ progress,
147
+ stackProgress,
117
148
  ...helpers,
118
149
  };
119
150
  });
@@ -26,7 +26,10 @@ import { useKeys } from "../../providers/keys.provider";
26
26
  import { AnimationStore } from "../../stores/animation.store";
27
27
  import { GestureStore, type GestureStoreMap } from "../../stores/gesture.store";
28
28
 
29
- import { type GestureDirection, GestureOffsetState } from "../../types/gesture.types";
29
+ import {
30
+ type GestureDirection,
31
+ GestureOffsetState,
32
+ } from "../../types/gesture.types";
30
33
  import { startScreenTransition } from "../../utils/animation/start-screen-transition";
31
34
  import { applyOffsetRules } from "../../utils/gesture/check-gesture-activation";
32
35
  import { determineDismissal } from "../../utils/gesture/determine-dismissal";
@@ -37,12 +40,12 @@ import useStableCallbackValue from "../use-stable-callback-value";
37
40
 
38
41
  interface BuildGesturesHookProps {
39
42
  scrollConfig: SharedValue<ScrollConfig | null>;
40
- parentContext?: GestureContextType | null;
43
+ ancestorContext?: GestureContextType | null;
41
44
  }
42
45
 
43
46
  export const useBuildGestures = ({
44
47
  scrollConfig,
45
- parentContext,
48
+ ancestorContext,
46
49
  }: BuildGesturesHookProps): {
47
50
  panGesture: GestureType;
48
51
  nativeGesture: GestureType;
@@ -93,8 +96,8 @@ export const useBuildGestures = ({
93
96
 
94
97
  const handleDismiss = useCallback(() => {
95
98
  // If an ancestor navigator is already dismissing, skip this dismiss to
96
- // avoid racing with the parent
97
- if (parentContext?.gestureAnimationValues.isDismissing?.value) {
99
+ // avoid racing with the ancestor
100
+ if (ancestorContext?.gestureAnimationValues.isDismissing?.value) {
98
101
  return;
99
102
  }
100
103
 
@@ -113,7 +116,7 @@ export const useBuildGestures = ({
113
116
  source: current.route.key,
114
117
  target: state.key,
115
118
  });
116
- }, [current, parentContext]);
119
+ }, [current, ancestorContext]);
117
120
 
118
121
  const onTouchesDown = useStableCallbackValue((e: GestureTouchEvent) => {
119
122
  "worklet";
@@ -127,7 +130,7 @@ export const useBuildGestures = ({
127
130
  "worklet";
128
131
 
129
132
  // If an ancestor navigator is already dismissing via gesture, block new gestures here.
130
- if (parentContext?.gestureAnimationValues.isDismissing?.value) {
133
+ if (ancestorContext?.gestureAnimationValues.isDismissing?.value) {
131
134
  gestureOffsetState.value = GestureOffsetState.FAILED;
132
135
  manager.fail();
133
136
  return;
@@ -335,6 +338,11 @@ export const useBuildGestures = ({
335
338
  .onEnd(onEnd)
336
339
  .blocksExternalGesture(nativeGesture);
337
340
 
341
+ // Allow ancestors to block child native gestures
342
+ if (ancestorContext?.panGesture && nativeGesture) {
343
+ ancestorContext.panGesture.blocksExternalGesture(nativeGesture);
344
+ }
345
+
338
346
  return {
339
347
  panGesture,
340
348
  nativeGesture,
@@ -348,5 +356,6 @@ export const useBuildGestures = ({
348
356
  onUpdate,
349
357
  onEnd,
350
358
  gestureAnimationValues,
359
+ ancestorContext,
351
360
  ]);
352
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 {
@@ -0,0 +1,21 @@
1
+ import createProvider from "../utils/create-provider";
2
+
3
+ interface FlagsValue {
4
+ TRANSITIONS_ALWAYS_ON: boolean;
5
+ }
6
+
7
+ interface FlagsProviderProps {
8
+ TRANSITIONS_ALWAYS_ON?: boolean;
9
+ children: React.ReactNode;
10
+ }
11
+
12
+ const { FlagsProvider, useFlagsContext } = createProvider("Flags", {
13
+ guarded: false,
14
+ })<FlagsProviderProps, FlagsValue>(
15
+ ({ TRANSITIONS_ALWAYS_ON = false, children }) => ({
16
+ value: { TRANSITIONS_ALWAYS_ON },
17
+ children,
18
+ }),
19
+ );
20
+
21
+ export { FlagsProvider, useFlagsContext };
@@ -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