react-native-screen-transitions 3.4.0-alpha.1 → 3.4.0-alpha.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 (243) hide show
  1. package/README.md +11 -1109
  2. package/lib/commonjs/blank-stack/navigators/create-blank-stack-navigator.js +69 -2
  3. package/lib/commonjs/blank-stack/navigators/create-blank-stack-navigator.js.map +1 -1
  4. package/lib/commonjs/component-stack/navigators/create-component-stack-navigator.js +9 -0
  5. package/lib/commonjs/component-stack/navigators/create-component-stack-navigator.js.map +1 -1
  6. package/lib/commonjs/shared/components/create-boundary-component/hooks/helpers/measurement-rules.js +195 -0
  7. package/lib/commonjs/shared/components/create-boundary-component/hooks/helpers/measurement-rules.js.map +1 -0
  8. package/lib/commonjs/shared/components/create-boundary-component/hooks/use-auto-source-measurement.js +7 -14
  9. package/lib/commonjs/shared/components/create-boundary-component/hooks/use-auto-source-measurement.js.map +1 -1
  10. package/lib/commonjs/shared/components/create-boundary-component/hooks/use-boundary-measure-and-store.js +19 -18
  11. package/lib/commonjs/shared/components/create-boundary-component/hooks/use-boundary-measure-and-store.js.map +1 -1
  12. package/lib/commonjs/shared/components/create-boundary-component/hooks/use-deferred-measurement-trigger.js +54 -0
  13. package/lib/commonjs/shared/components/create-boundary-component/hooks/use-deferred-measurement-trigger.js.map +1 -0
  14. package/lib/commonjs/shared/components/create-boundary-component/hooks/use-group-active-measurement.js +40 -8
  15. package/lib/commonjs/shared/components/create-boundary-component/hooks/use-group-active-measurement.js.map +1 -1
  16. package/lib/commonjs/shared/components/create-boundary-component/hooks/use-group-active-source-measurement.js +72 -0
  17. package/lib/commonjs/shared/components/create-boundary-component/hooks/use-group-active-source-measurement.js.map +1 -0
  18. package/lib/commonjs/shared/components/create-boundary-component/hooks/use-initial-layout-handler.js +16 -7
  19. package/lib/commonjs/shared/components/create-boundary-component/hooks/use-initial-layout-handler.js.map +1 -1
  20. package/lib/commonjs/shared/components/create-boundary-component/hooks/use-pending-destination-measurement.js +7 -4
  21. package/lib/commonjs/shared/components/create-boundary-component/hooks/use-pending-destination-measurement.js.map +1 -1
  22. package/lib/commonjs/shared/components/create-boundary-component/hooks/use-pending-destination-retry-measurement.js +14 -15
  23. package/lib/commonjs/shared/components/create-boundary-component/hooks/use-pending-destination-retry-measurement.js.map +1 -1
  24. package/lib/commonjs/shared/components/create-boundary-component/hooks/use-scroll-settled-measurement.js +27 -9
  25. package/lib/commonjs/shared/components/create-boundary-component/hooks/use-scroll-settled-measurement.js.map +1 -1
  26. package/lib/commonjs/shared/components/create-boundary-component/index.js +22 -8
  27. package/lib/commonjs/shared/components/create-boundary-component/index.js.map +1 -1
  28. package/lib/commonjs/shared/components/create-transition-aware-component.js +3 -2
  29. package/lib/commonjs/shared/components/create-transition-aware-component.js.map +1 -1
  30. package/lib/commonjs/shared/components/native-screen-container.js +12 -6
  31. package/lib/commonjs/shared/components/native-screen-container.js.map +1 -1
  32. package/lib/commonjs/shared/components/native-screen.js +35 -8
  33. package/lib/commonjs/shared/components/native-screen.js.map +1 -1
  34. package/lib/commonjs/shared/components/screen-container/hooks/use-content-layout.js +60 -0
  35. package/lib/commonjs/shared/components/screen-container/hooks/use-content-layout.js.map +1 -0
  36. package/lib/commonjs/shared/components/screen-container/layers/content.js +5 -37
  37. package/lib/commonjs/shared/components/screen-container/layers/content.js.map +1 -1
  38. package/lib/commonjs/shared/components/screen-container/layers/maybe-masked-navigation-container.js +21 -12
  39. package/lib/commonjs/shared/components/screen-container/layers/maybe-masked-navigation-container.js.map +1 -1
  40. package/lib/commonjs/shared/providers/gestures/handlers/use-handlers.js +6 -7
  41. package/lib/commonjs/shared/providers/gestures/handlers/use-handlers.js.map +1 -1
  42. package/lib/commonjs/shared/providers/gestures/helpers/gesture-activation.js +11 -6
  43. package/lib/commonjs/shared/providers/gestures/helpers/gesture-activation.js.map +1 -1
  44. package/lib/commonjs/shared/providers/layout-anchor.provider.js +4 -6
  45. package/lib/commonjs/shared/providers/layout-anchor.provider.js.map +1 -1
  46. package/lib/commonjs/shared/providers/screen/animation/helpers/pipeline.js +14 -7
  47. package/lib/commonjs/shared/providers/screen/animation/helpers/pipeline.js.map +1 -1
  48. package/lib/commonjs/shared/providers/stack/core.provider.js +14 -21
  49. package/lib/commonjs/shared/providers/stack/core.provider.js.map +1 -1
  50. package/lib/commonjs/shared/stores/animation.store.js +3 -1
  51. package/lib/commonjs/shared/stores/animation.store.js.map +1 -1
  52. package/lib/commonjs/shared/stores/bounds/internals/presence.js.map +1 -1
  53. package/lib/commonjs/shared/utils/bounds/helpers/compute-bounds-styles.js +14 -5
  54. package/lib/commonjs/shared/utils/bounds/helpers/compute-bounds-styles.js.map +1 -1
  55. package/lib/commonjs/shared/utils/bounds/helpers/resolve-bound-tag.js +0 -5
  56. package/lib/commonjs/shared/utils/bounds/helpers/resolve-bound-tag.js.map +1 -1
  57. package/lib/commonjs/shared/utils/bounds/index.js +10 -0
  58. package/lib/commonjs/shared/utils/bounds/index.js.map +1 -1
  59. package/lib/commonjs/shared/utils/bounds/types/frame-props.js +6 -0
  60. package/lib/commonjs/shared/utils/bounds/types/frame-props.js.map +1 -0
  61. package/lib/commonjs/shared/utils/bounds/zoom/build.js +33 -26
  62. package/lib/commonjs/shared/utils/bounds/zoom/build.js.map +1 -1
  63. package/lib/commonjs/shared/utils/resolve-screen-transition-options.js +25 -0
  64. package/lib/commonjs/shared/utils/resolve-screen-transition-options.js.map +1 -0
  65. package/lib/module/blank-stack/navigators/create-blank-stack-navigator.js +69 -3
  66. package/lib/module/blank-stack/navigators/create-blank-stack-navigator.js.map +1 -1
  67. package/lib/module/component-stack/navigators/create-component-stack-navigator.js +9 -0
  68. package/lib/module/component-stack/navigators/create-component-stack-navigator.js.map +1 -1
  69. package/lib/module/shared/components/create-boundary-component/hooks/helpers/measurement-rules.js +182 -0
  70. package/lib/module/shared/components/create-boundary-component/hooks/helpers/measurement-rules.js.map +1 -0
  71. package/lib/module/shared/components/create-boundary-component/hooks/use-auto-source-measurement.js +7 -14
  72. package/lib/module/shared/components/create-boundary-component/hooks/use-auto-source-measurement.js.map +1 -1
  73. package/lib/module/shared/components/create-boundary-component/hooks/use-boundary-measure-and-store.js +19 -18
  74. package/lib/module/shared/components/create-boundary-component/hooks/use-boundary-measure-and-store.js.map +1 -1
  75. package/lib/module/shared/components/create-boundary-component/hooks/use-deferred-measurement-trigger.js +49 -0
  76. package/lib/module/shared/components/create-boundary-component/hooks/use-deferred-measurement-trigger.js.map +1 -0
  77. package/lib/module/shared/components/create-boundary-component/hooks/use-group-active-measurement.js +41 -8
  78. package/lib/module/shared/components/create-boundary-component/hooks/use-group-active-measurement.js.map +1 -1
  79. package/lib/module/shared/components/create-boundary-component/hooks/use-group-active-source-measurement.js +67 -0
  80. package/lib/module/shared/components/create-boundary-component/hooks/use-group-active-source-measurement.js.map +1 -0
  81. package/lib/module/shared/components/create-boundary-component/hooks/use-initial-layout-handler.js +16 -7
  82. package/lib/module/shared/components/create-boundary-component/hooks/use-initial-layout-handler.js.map +1 -1
  83. package/lib/module/shared/components/create-boundary-component/hooks/use-pending-destination-measurement.js +7 -4
  84. package/lib/module/shared/components/create-boundary-component/hooks/use-pending-destination-measurement.js.map +1 -1
  85. package/lib/module/shared/components/create-boundary-component/hooks/use-pending-destination-retry-measurement.js +14 -15
  86. package/lib/module/shared/components/create-boundary-component/hooks/use-pending-destination-retry-measurement.js.map +1 -1
  87. package/lib/module/shared/components/create-boundary-component/hooks/use-scroll-settled-measurement.js +27 -9
  88. package/lib/module/shared/components/create-boundary-component/hooks/use-scroll-settled-measurement.js.map +1 -1
  89. package/lib/module/shared/components/create-boundary-component/index.js +22 -8
  90. package/lib/module/shared/components/create-boundary-component/index.js.map +1 -1
  91. package/lib/module/shared/components/create-transition-aware-component.js +3 -2
  92. package/lib/module/shared/components/create-transition-aware-component.js.map +1 -1
  93. package/lib/module/shared/components/native-screen-container.js +12 -6
  94. package/lib/module/shared/components/native-screen-container.js.map +1 -1
  95. package/lib/module/shared/components/native-screen.js +35 -8
  96. package/lib/module/shared/components/native-screen.js.map +1 -1
  97. package/lib/module/shared/components/screen-container/hooks/use-content-layout.js +56 -0
  98. package/lib/module/shared/components/screen-container/hooks/use-content-layout.js.map +1 -0
  99. package/lib/module/shared/components/screen-container/layers/content.js +9 -41
  100. package/lib/module/shared/components/screen-container/layers/content.js.map +1 -1
  101. package/lib/module/shared/components/screen-container/layers/maybe-masked-navigation-container.js +22 -13
  102. package/lib/module/shared/components/screen-container/layers/maybe-masked-navigation-container.js.map +1 -1
  103. package/lib/module/shared/providers/gestures/handlers/use-handlers.js +6 -7
  104. package/lib/module/shared/providers/gestures/handlers/use-handlers.js.map +1 -1
  105. package/lib/module/shared/providers/gestures/helpers/gesture-activation.js +11 -6
  106. package/lib/module/shared/providers/gestures/helpers/gesture-activation.js.map +1 -1
  107. package/lib/module/shared/providers/layout-anchor.provider.js +4 -6
  108. package/lib/module/shared/providers/layout-anchor.provider.js.map +1 -1
  109. package/lib/module/shared/providers/screen/animation/helpers/pipeline.js +14 -7
  110. package/lib/module/shared/providers/screen/animation/helpers/pipeline.js.map +1 -1
  111. package/lib/module/shared/providers/stack/core.provider.js +14 -21
  112. package/lib/module/shared/providers/stack/core.provider.js.map +1 -1
  113. package/lib/module/shared/stores/animation.store.js +3 -1
  114. package/lib/module/shared/stores/animation.store.js.map +1 -1
  115. package/lib/module/shared/stores/bounds/internals/presence.js.map +1 -1
  116. package/lib/module/shared/utils/bounds/helpers/compute-bounds-styles.js +14 -5
  117. package/lib/module/shared/utils/bounds/helpers/compute-bounds-styles.js.map +1 -1
  118. package/lib/module/shared/utils/bounds/helpers/resolve-bound-tag.js +0 -5
  119. package/lib/module/shared/utils/bounds/helpers/resolve-bound-tag.js.map +1 -1
  120. package/lib/module/shared/utils/bounds/index.js +10 -0
  121. package/lib/module/shared/utils/bounds/index.js.map +1 -1
  122. package/lib/module/shared/utils/bounds/types/frame-props.js +4 -0
  123. package/lib/module/shared/utils/bounds/types/frame-props.js.map +1 -0
  124. package/lib/module/shared/utils/bounds/zoom/build.js +33 -26
  125. package/lib/module/shared/utils/bounds/zoom/build.js.map +1 -1
  126. package/lib/module/shared/utils/resolve-screen-transition-options.js +19 -0
  127. package/lib/module/shared/utils/resolve-screen-transition-options.js.map +1 -0
  128. package/lib/typescript/blank-stack/index.d.ts +1 -1
  129. package/lib/typescript/blank-stack/index.d.ts.map +1 -1
  130. package/lib/typescript/blank-stack/navigators/create-blank-stack-navigator.d.ts +29 -4
  131. package/lib/typescript/blank-stack/navigators/create-blank-stack-navigator.d.ts.map +1 -1
  132. package/lib/typescript/blank-stack/types.d.ts +33 -4
  133. package/lib/typescript/blank-stack/types.d.ts.map +1 -1
  134. package/lib/typescript/component-stack/navigators/create-component-stack-navigator.d.ts +8 -0
  135. package/lib/typescript/component-stack/navigators/create-component-stack-navigator.d.ts.map +1 -1
  136. package/lib/typescript/shared/components/create-boundary-component/hooks/helpers/measurement-rules.d.ts +81 -0
  137. package/lib/typescript/shared/components/create-boundary-component/hooks/helpers/measurement-rules.d.ts.map +1 -0
  138. package/lib/typescript/shared/components/create-boundary-component/hooks/use-auto-source-measurement.d.ts.map +1 -1
  139. package/lib/typescript/shared/components/create-boundary-component/hooks/use-boundary-measure-and-store.d.ts +2 -3
  140. package/lib/typescript/shared/components/create-boundary-component/hooks/use-boundary-measure-and-store.d.ts.map +1 -1
  141. package/lib/typescript/shared/components/create-boundary-component/hooks/use-deferred-measurement-trigger.d.ts +11 -0
  142. package/lib/typescript/shared/components/create-boundary-component/hooks/use-deferred-measurement-trigger.d.ts.map +1 -0
  143. package/lib/typescript/shared/components/create-boundary-component/hooks/use-group-active-measurement.d.ts +2 -2
  144. package/lib/typescript/shared/components/create-boundary-component/hooks/use-group-active-measurement.d.ts.map +1 -1
  145. package/lib/typescript/shared/components/create-boundary-component/hooks/use-group-active-source-measurement.d.ts +11 -0
  146. package/lib/typescript/shared/components/create-boundary-component/hooks/use-group-active-source-measurement.d.ts.map +1 -0
  147. package/lib/typescript/shared/components/create-boundary-component/hooks/use-initial-layout-handler.d.ts.map +1 -1
  148. package/lib/typescript/shared/components/create-boundary-component/hooks/use-pending-destination-measurement.d.ts.map +1 -1
  149. package/lib/typescript/shared/components/create-boundary-component/hooks/use-pending-destination-retry-measurement.d.ts +3 -3
  150. package/lib/typescript/shared/components/create-boundary-component/hooks/use-pending-destination-retry-measurement.d.ts.map +1 -1
  151. package/lib/typescript/shared/components/create-boundary-component/hooks/use-scroll-settled-measurement.d.ts +2 -2
  152. package/lib/typescript/shared/components/create-boundary-component/hooks/use-scroll-settled-measurement.d.ts.map +1 -1
  153. package/lib/typescript/shared/components/create-boundary-component/index.d.ts +5 -3
  154. package/lib/typescript/shared/components/create-boundary-component/index.d.ts.map +1 -1
  155. package/lib/typescript/shared/components/create-boundary-component/types.d.ts +2 -4
  156. package/lib/typescript/shared/components/create-boundary-component/types.d.ts.map +1 -1
  157. package/lib/typescript/shared/components/create-transition-aware-component.d.ts +1 -0
  158. package/lib/typescript/shared/components/create-transition-aware-component.d.ts.map +1 -1
  159. package/lib/typescript/shared/components/native-screen-container.d.ts.map +1 -1
  160. package/lib/typescript/shared/components/native-screen.d.ts.map +1 -1
  161. package/lib/typescript/shared/components/screen-container/hooks/use-content-layout.d.ts +3 -0
  162. package/lib/typescript/shared/components/screen-container/hooks/use-content-layout.d.ts.map +1 -0
  163. package/lib/typescript/shared/components/screen-container/layers/content.d.ts.map +1 -1
  164. package/lib/typescript/shared/components/screen-container/layers/maybe-masked-navigation-container.d.ts +3 -1
  165. package/lib/typescript/shared/components/screen-container/layers/maybe-masked-navigation-container.d.ts.map +1 -1
  166. package/lib/typescript/shared/index.d.ts +0 -1
  167. package/lib/typescript/shared/index.d.ts.map +1 -1
  168. package/lib/typescript/shared/providers/gestures/handlers/use-handlers.d.ts +1 -1
  169. package/lib/typescript/shared/providers/gestures/handlers/use-handlers.d.ts.map +1 -1
  170. package/lib/typescript/shared/providers/gestures/helpers/gesture-activation.d.ts.map +1 -1
  171. package/lib/typescript/shared/providers/layout-anchor.provider.d.ts +1 -1
  172. package/lib/typescript/shared/providers/layout-anchor.provider.d.ts.map +1 -1
  173. package/lib/typescript/shared/providers/screen/animation/helpers/pipeline.d.ts.map +1 -1
  174. package/lib/typescript/shared/providers/stack/core.provider.d.ts +2 -0
  175. package/lib/typescript/shared/providers/stack/core.provider.d.ts.map +1 -1
  176. package/lib/typescript/shared/stores/animation.store.d.ts +5 -3
  177. package/lib/typescript/shared/stores/animation.store.d.ts.map +1 -1
  178. package/lib/typescript/shared/stores/bounds/internals/presence.d.ts.map +1 -1
  179. package/lib/typescript/shared/types/animation.types.d.ts +7 -0
  180. package/lib/typescript/shared/types/animation.types.d.ts.map +1 -1
  181. package/lib/typescript/shared/types/screen.types.d.ts +46 -22
  182. package/lib/typescript/shared/types/screen.types.d.ts.map +1 -1
  183. package/lib/typescript/shared/utils/bounds/helpers/compute-bounds-styles.d.ts.map +1 -1
  184. package/lib/typescript/shared/utils/bounds/helpers/resolve-bound-tag.d.ts.map +1 -1
  185. package/lib/typescript/shared/utils/bounds/index.d.ts +2 -2
  186. package/lib/typescript/shared/utils/bounds/index.d.ts.map +1 -1
  187. package/lib/typescript/shared/utils/bounds/types/frame-props.d.ts +5 -0
  188. package/lib/typescript/shared/utils/bounds/types/frame-props.d.ts.map +1 -0
  189. package/lib/typescript/shared/utils/bounds/zoom/accessor.d.ts +4 -4
  190. package/lib/typescript/shared/utils/bounds/zoom/accessor.d.ts.map +1 -1
  191. package/lib/typescript/shared/utils/bounds/zoom/build.d.ts.map +1 -1
  192. package/lib/typescript/shared/utils/bounds/zoom/types.d.ts +3 -3
  193. package/lib/typescript/shared/utils/bounds/zoom/types.d.ts.map +1 -1
  194. package/lib/typescript/shared/utils/resolve-screen-transition-options.d.ts +5 -0
  195. package/lib/typescript/shared/utils/resolve-screen-transition-options.d.ts.map +1 -0
  196. package/package.json +2 -1
  197. package/src/blank-stack/index.ts +1 -0
  198. package/src/blank-stack/navigators/create-blank-stack-navigator.tsx +138 -19
  199. package/src/blank-stack/types.ts +33 -5
  200. package/src/component-stack/navigators/create-component-stack-navigator.tsx +8 -0
  201. package/src/shared/components/create-boundary-component/hooks/helpers/measurement-rules.ts +258 -0
  202. package/src/shared/components/create-boundary-component/hooks/use-auto-source-measurement.ts +7 -17
  203. package/src/shared/components/create-boundary-component/hooks/use-boundary-measure-and-store.ts +38 -28
  204. package/src/shared/components/create-boundary-component/hooks/use-deferred-measurement-trigger.ts +58 -0
  205. package/src/shared/components/create-boundary-component/hooks/use-group-active-measurement.ts +41 -10
  206. package/src/shared/components/create-boundary-component/hooks/use-group-active-source-measurement.ts +82 -0
  207. package/src/shared/components/create-boundary-component/hooks/use-initial-layout-handler.ts +24 -12
  208. package/src/shared/components/create-boundary-component/hooks/use-pending-destination-measurement.ts +11 -9
  209. package/src/shared/components/create-boundary-component/hooks/use-pending-destination-retry-measurement.ts +29 -26
  210. package/src/shared/components/create-boundary-component/hooks/use-scroll-settled-measurement.ts +26 -17
  211. package/src/shared/components/create-boundary-component/index.tsx +25 -6
  212. package/src/shared/components/create-boundary-component/types.ts +8 -4
  213. package/src/shared/components/create-transition-aware-component.tsx +5 -2
  214. package/src/shared/components/native-screen-container.tsx +11 -3
  215. package/src/shared/components/native-screen.tsx +65 -20
  216. package/src/shared/components/screen-container/hooks/use-content-layout.ts +82 -0
  217. package/src/shared/components/screen-container/layers/content.tsx +11 -73
  218. package/src/shared/components/screen-container/layers/maybe-masked-navigation-container.tsx +24 -16
  219. package/src/shared/providers/gestures/handlers/use-handlers.ts +8 -5
  220. package/src/shared/providers/gestures/helpers/gesture-activation.ts +11 -6
  221. package/src/shared/providers/layout-anchor.provider.tsx +2 -5
  222. package/src/shared/providers/register-bounds.provider.tsx +1 -1
  223. package/src/shared/providers/screen/animation/helpers/pipeline.ts +24 -8
  224. package/src/shared/providers/stack/core.provider.tsx +27 -14
  225. package/src/shared/stores/animation.store.ts +11 -7
  226. package/src/shared/stores/bounds/internals/presence.ts +3 -1
  227. package/src/shared/types/animation.types.ts +7 -0
  228. package/src/shared/types/screen.types.ts +50 -22
  229. package/src/shared/utils/bounds/helpers/compute-bounds-styles.ts +14 -1
  230. package/src/shared/utils/bounds/helpers/resolve-bound-tag.ts +0 -6
  231. package/src/shared/utils/bounds/index.ts +16 -5
  232. package/src/shared/utils/bounds/types/frame-props.ts +5 -0
  233. package/src/shared/utils/bounds/zoom/accessor.ts +3 -3
  234. package/src/shared/utils/bounds/zoom/build.ts +32 -22
  235. package/src/shared/utils/bounds/zoom/types.ts +3 -3
  236. package/src/shared/utils/resolve-screen-transition-options.ts +37 -0
  237. package/lib/commonjs/shared/providers/viewport.provider.js +0 -33
  238. package/lib/commonjs/shared/providers/viewport.provider.js.map +0 -1
  239. package/lib/module/shared/providers/viewport.provider.js +0 -27
  240. package/lib/module/shared/providers/viewport.provider.js.map +0 -1
  241. package/lib/typescript/shared/providers/viewport.provider.d.ts +0 -13
  242. package/lib/typescript/shared/providers/viewport.provider.d.ts.map +0 -1
  243. package/src/shared/providers/viewport.provider.tsx +0 -39
package/README.md CHANGED
@@ -1,45 +1,14 @@
1
1
  # react-native-screen-transitions
2
2
 
3
- Customizable screen transitions for React Native. Build gesture-driven, shared element, and fully custom animations with a simple API.
3
+ Gesture-driven screen transitions, shared bounds, presets, and custom animation hooks for React Native and Expo.
4
4
 
5
- | iOS | Android |
6
- | --------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------- |
7
- | <video src="https://github.com/user-attachments/assets/c0d17b8f-7268-421c-9051-e242f8ddca76" width="300" height="600" controls></video> | <video src="https://github.com/user-attachments/assets/3f8d5fb1-96d2-4fe3-860d-62f6fb5a687e" width="300" controls></video> |
8
-
9
- ## Features
10
-
11
- - **Full Animation Control** – Define exactly how screens enter, exit, and respond to gestures
12
- - **Shared Elements** – Smooth transitions between screens using `Transition.Boundary` and the Bounds API
13
- - **Navigation Bounds** – SwiftUI-like zoom transitions with masked reveal effects via `bounds().navigation.zoom()`
14
- - **Gesture Support** – Swipe-to-dismiss with edge or full-screen activation, configurable velocity
15
- - **Animated Props** – Drive component-specific props (e.g., BlurView `intensity`) alongside styles
16
- - **Custom Layers** – `surfaceComponent` and `backdropComponent` with animated styles and props
17
- - **Stack Progress** – Track animation progress across the entire stack
18
- - **Ready-Made Presets** – Instagram, Apple Music, X (Twitter), zoom navigation style transitions included
19
-
20
- ## When to Use This Library
21
-
22
- | Use Case | This Library | Alternative |
23
- |----------|--------------|-------------|
24
- | Custom transitions (slide, zoom, fade variations) | Yes | `@react-navigation/stack` works too |
25
- | Shared element transitions | **Yes** | Limited options elsewhere |
26
- | Multi-stop sheets (bottom, top, side) with snap points | **Yes** | Dedicated sheet libraries |
27
- | Gesture-driven animations (drag to dismiss, elastic) | **Yes** | Requires custom implementation |
28
- | Instagram/Apple Music/Twitter-style transitions | **Yes** | Custom implementation |
29
- | Simple push/pop with platform defaults | Overkill | `@react-navigation/native-stack` |
30
- | Maximum raw performance on low-end devices | Not ideal | `@react-navigation/native-stack` |
31
-
32
- **Choose this library when** you need custom animations, shared elements, or gesture-driven transitions that go beyond platform defaults.
33
-
34
- **Choose native-stack when** you want platform-native transitions with zero configuration and maximum performance on low-end Android devices.
35
-
36
- ## Installation
5
+ ## Install
37
6
 
38
7
  ```bash
39
8
  npm install react-native-screen-transitions
40
9
  ```
41
10
 
42
- ### Peer Dependencies
11
+ Peer dependencies:
43
12
 
44
13
  ```bash
45
14
  npm install react-native-reanimated react-native-gesture-handler \
@@ -48,19 +17,15 @@ npm install react-native-reanimated react-native-gesture-handler \
48
17
  react-native-safe-area-context
49
18
  ```
50
19
 
51
- ---
52
-
53
- ## Quick Start
54
-
55
- ### 1. Create a Stack
20
+ ## Quickstart
56
21
 
57
22
  ```tsx
58
- import { createBlankStackNavigator } from "react-native-screen-transitions/blank-stack";
59
23
  import Transition from "react-native-screen-transitions";
24
+ import { createBlankStackNavigator } from "react-native-screen-transitions/blank-stack";
60
25
 
61
26
  const Stack = createBlankStackNavigator();
62
27
 
63
- function App() {
28
+ export function AppStack() {
64
29
  return (
65
30
  <Stack.Navigator>
66
31
  <Stack.Screen name="Home" component={HomeScreen} />
@@ -76,1072 +41,9 @@ function App() {
76
41
  }
77
42
  ```
78
43
 
79
- ### 2. With Expo Router
80
-
81
- ```tsx
82
- import { withLayoutContext } from "expo-router";
83
- import {
84
- createBlankStackNavigator,
85
- type BlankStackNavigationOptions,
86
- } from "react-native-screen-transitions/blank-stack";
87
-
88
- const { Navigator } = createBlankStackNavigator();
89
-
90
- export const Stack = withLayoutContext<
91
- BlankStackNavigationOptions,
92
- typeof Navigator
93
- >(Navigator);
94
- ```
95
-
96
- ---
97
-
98
- ## Presets
99
-
100
- Use built-in presets for common transitions:
101
-
102
- ```tsx
103
- <Stack.Screen
104
- name="Detail"
105
- options={{
106
- ...Transition.Presets.SlideFromBottom(),
107
- }}
108
- />
109
- ```
110
-
111
- | Preset | Description |
112
- | -------------------------------------- | --------------------------------------- |
113
- | `SlideFromTop()` | Slides in from top |
114
- | `SlideFromBottom()` | Slides in from bottom (modal-style) |
115
- | `ZoomIn()` | Scales in with fade |
116
- | `DraggableCard()` | Multi-directional drag with scaling |
117
- | `ElasticCard()` | Elastic drag with overlay |
118
- | `SharedIGImage({ sharedBoundTag })` | Instagram-style shared image |
119
- | `SharedAppleMusic({ sharedBoundTag })` | Apple Music-style shared element |
120
- | `SharedXImage({ sharedBoundTag })` | X (Twitter)-style image transition |
121
-
122
- ---
123
-
124
- ## Custom Animations
125
-
126
- ### The Basics
127
-
128
- Every screen has a `progress` value that goes from 0 → 1 → 2:
129
-
130
- ```
131
- 0 ─────────── 1 ─────────── 2
132
- entering visible exiting
133
- ```
134
-
135
- When navigating from A to B:
136
- - **Screen B**: progress goes `0 → 1` (entering)
137
- - **Screen A**: progress goes `1 → 2` (exiting)
138
-
139
- ### Simple Fade
140
-
141
- ```tsx
142
- options={{
143
- screenStyleInterpolator: ({ progress }) => {
144
- "worklet";
145
- return {
146
- content: {
147
- style: {
148
- opacity: interpolate(progress, [0, 1, 2], [0, 1, 0]),
149
- },
150
- },
151
- };
152
- },
153
- }}
154
- ```
155
-
156
- ### Slide from Right
157
-
158
- ```tsx
159
- options={{
160
- screenStyleInterpolator: ({ progress, layouts: { screen } }) => {
161
- "worklet";
162
- return {
163
- content: {
164
- style: {
165
- transform: [{
166
- translateX: interpolate(
167
- progress,
168
- [0, 1, 2],
169
- [screen.width, 0, -screen.width * 0.3]
170
- ),
171
- }],
172
- },
173
- },
174
- };
175
- },
176
- }}
177
- ```
178
-
179
- ### Slide from Bottom with Backdrop
180
-
181
- ```tsx
182
- options={{
183
- screenStyleInterpolator: ({ progress, layouts: { screen } }) => {
184
- "worklet";
185
- return {
186
- content: {
187
- style: {
188
- transform: [{
189
- translateY: interpolate(progress, [0, 1], [screen.height, 0]),
190
- }],
191
- },
192
- },
193
- backdrop: {
194
- style: {
195
- backgroundColor: "black",
196
- opacity: interpolate(progress, [0, 1], [0, 0.5]),
197
- },
198
- },
199
- };
200
- },
201
- }}
202
- ```
203
-
204
- ### Return Format
205
-
206
- Your interpolator returns a map of **slots**. The canonical format is explicit `{ style, props }`:
207
-
208
- ```tsx
209
- return {
210
- content: {
211
- style: { opacity: 1 },
212
- }, // Main screen content
213
- backdrop: {
214
- style: { opacity: 0.5 },
215
- props: { intensity: 80 }, // for components like BlurView
216
- }, // Backdrop layer between screens
217
- surface: {
218
- style: { transform: [{ scale: 0.98 }] },
219
- }, // Surface component layer
220
- ["hero-image"]: {
221
- style: { borderRadius: 24 },
222
- }, // Specific element via styleId
223
- };
224
- ```
225
-
226
- Shorthand styles are still supported and auto-wrapped as `{ style: value }`:
227
-
228
- ```tsx
229
- // Shorthand
230
- content: {
231
- opacity: 0.5,
232
- transform: [{ scale: 0.9 }],
233
- },
234
-
235
- // Explicit
236
- content: {
237
- style: { opacity: 0.5, transform: [{ scale: 0.9 }] },
238
- props: { intensity: 80 }, // for useAnimatedProps (e.g., BlurView)
239
- },
240
- ```
241
-
242
- > **Legacy format**: The flat `contentStyle`/`backdropStyle` format is still supported but deprecated. It will be auto-converted with a one-time warning in development.
243
-
244
- ### Animation Specs
245
-
246
- Control timing with spring configs:
247
-
248
- ```tsx
249
- options={{
250
- screenStyleInterpolator: myInterpolator,
251
- transitionSpec: {
252
- open: { stiffness: 1000, damping: 500, mass: 3 }, // Screen enters
253
- close: { stiffness: 1000, damping: 500, mass: 3 }, // Screen exits
254
- expand: { stiffness: 300, damping: 30 }, // Snap point increases
255
- collapse: { stiffness: 300, damping: 30 }, // Snap point decreases
256
- },
257
- }}
258
- ```
259
-
260
- ---
261
-
262
- ## Gestures
263
-
264
- Enable swipe-to-dismiss:
265
-
266
- ```tsx
267
- options={{
268
- gestureEnabled: true,
269
- gestureDirection: "vertical",
270
- ...Transition.Presets.SlideFromBottom(),
271
- }}
272
- ```
273
-
274
- ### Gesture Options
275
-
276
- | Option | Description |
277
- | ------------------------------- | ------------------------------------------------------------------------ |
278
- | `gestureEnabled` | Enable swipe-to-dismiss (snap sheets: `false` blocks dismiss-to-0 only) |
279
- | `gestureDirection` | Direction(s) for swipe gesture |
280
- | `gestureActivationArea` | Where gesture can start |
281
- | `gestureResponseDistance` | Pixel threshold for activation |
282
- | `gestureVelocityImpact` | How much velocity affects dismissal (default: 0.3) |
283
- | `gestureDrivesProgress` | Whether gesture controls animation progress (default: true) |
284
- | `snapVelocityImpact` | How much velocity affects snap targeting (default: 0.1, lower = iOS-like)|
285
- | `gestureReleaseVelocityScale` | Multiplier for post-release spring velocity (default: 1) |
286
- | `gestureReleaseVelocityMax` | Cap on post-release spring velocity (default: 3.2) |
287
- | `expandViaScrollView` | Allow expansion from ScrollView at boundary (default: true) |
288
- | `gestureSnapLocked` | Lock gesture-based snap movement to current snap point |
289
- | `backdropBehavior` | Touch handling for backdrop area |
290
- | `backdropComponent` | Custom backdrop component, driven by interpolator `backdrop` slot |
291
- | `surfaceComponent` | Custom surface component, driven by interpolator `surface` slot |
292
- | `maskEnabled` | Pre-mount masked view wrapper for navigation bounds masking |
293
-
294
- ### Gesture Direction
295
-
296
- ```tsx
297
- gestureDirection: "horizontal" // swipe left to dismiss
298
- gestureDirection: "horizontal-inverted" // swipe right to dismiss
299
- gestureDirection: "vertical" // swipe down to dismiss
300
- gestureDirection: "vertical-inverted" // swipe up to dismiss
301
- gestureDirection: "bidirectional" // any direction
302
-
303
- // Or combine multiple:
304
- gestureDirection: ["horizontal", "vertical"]
305
- ```
306
-
307
- ### Gesture Activation Area
308
-
309
- ```tsx
310
- // Simple - same for all edges
311
- gestureActivationArea: "edge" // only from screen edges
312
- gestureActivationArea: "screen" // anywhere on screen
313
-
314
- // Per-side configuration
315
- gestureActivationArea: {
316
- left: "edge",
317
- right: "screen",
318
- top: "edge",
319
- bottom: "screen",
320
- }
321
- ```
322
-
323
- ### With ScrollViews
324
-
325
- Use transition-aware scrollables so gestures work correctly:
326
-
327
- ```tsx
328
- <Transition.ScrollView>
329
- {/* content */}
330
- </Transition.ScrollView>
331
-
332
- <Transition.FlatList data={items} renderItem={...} />
333
- ```
334
-
335
- Gesture rules with scrollables:
336
- - **vertical** – only activates when scrolled to top
337
- - **vertical-inverted** – only activates when scrolled to bottom
338
- - **horizontal** – only activates at left/right scroll edges
339
-
340
- `Transition.ScrollView` and `Transition.FlatList` also emit a settled signal (on momentum end, or drag end with no momentum). Grouped boundaries listen for that signal and re-measure source bounds while idle, which keeps list/detail shared transitions accurate after focus-change auto-scrolling.
341
-
342
- ---
343
-
344
- ## Snap Points
345
-
346
- Create multi-stop sheets that snap to defined positions. Works with any gesture direction (bottom sheets, top sheets, side sheets):
347
-
348
- ### Basic Configuration
349
-
350
- ```tsx
351
- // Bottom sheet (most common)
352
- <Stack.Screen
353
- name="Sheet"
354
- options={{
355
- gestureEnabled: true,
356
- gestureDirection: "vertical",
357
- snapPoints: [0.5, 1], // 50% and 100% of screen
358
- initialSnapIndex: 0, // Start at 50%
359
- backdropBehavior: "dismiss", // Tap backdrop to dismiss
360
- ...Transition.Presets.SlideFromBottom(),
361
- }}
362
- />
363
-
364
- // Side sheet (same API, different direction)
365
- <Stack.Screen
366
- name="SidePanel"
367
- options={{
368
- gestureEnabled: true,
369
- gestureDirection: "horizontal",
370
- snapPoints: [0.3, 0.7, 1], // 30%, 70%, 100% of screen width
371
- initialSnapIndex: 1,
372
- // Add a horizontal screenStyleInterpolator for drawer-style motion
373
- }}
374
- />
375
- ```
376
-
377
- ### Options
378
-
379
- | Option | Description |
380
- | ------------------ | -------------------------------------------------------------------- |
381
- | `snapPoints` | Array of fractions (0-1) where sheet can rest |
382
- | `initialSnapIndex` | Index of initial snap point (default: 0) |
383
- | `gestureSnapLocked` | Locks gesture snapping to current point (programmatic `snapTo` still works) |
384
- | `backdropBehavior` | Touch handling: `"block"`, `"passthrough"`, `"dismiss"`, `"collapse"`|
385
- | `backdropComponent` | Custom backdrop component, driven by interpolator `backdrop` slot |
386
-
387
- #### backdropBehavior Values
388
-
389
- | Value | Description |
390
- | --------------- | ---------------------------------------------------------------- |
391
- | `"block"` | Backdrop catches all touches (default) |
392
- | `"passthrough"` | Touches pass through to content behind |
393
- | `"dismiss"` | Tapping backdrop dismisses the screen |
394
- | `"collapse"` | Tapping backdrop collapses to next lower snap point, then dismisses |
395
-
396
- #### Custom Backdrop Component
397
-
398
- Use `backdropComponent` to provide a custom component for the backdrop layer between screens (e.g., a `BlurView`).
399
-
400
- - The library wraps your component with `Animated.createAnimatedComponent` internally
401
- - Animated styles and props are driven by the `backdrop` slot in your interpolator
402
- - `backdropBehavior` still controls the wrapping `Pressable` for dismiss/collapse handling
403
-
404
- ```tsx
405
- import { BlurView } from "expo-blur";
406
-
407
- <Stack.Screen
408
- name="Sheet"
409
- options={{
410
- snapPoints: [0.5, 1],
411
- backdropBehavior: "dismiss",
412
- backdropComponent: BlurView,
413
- screenStyleInterpolator: ({ progress }) => {
414
- "worklet";
415
- return {
416
- backdrop: {
417
- style: { opacity: interpolate(progress, [0, 1], [0, 1]) },
418
- props: { intensity: interpolate(progress, [0, 1], [0, 80]) },
419
- },
420
- content: {
421
- style: {
422
- transform: [{ translateY: interpolate(progress, [0, 1], [800, 0]) }],
423
- },
424
- },
425
- };
426
- },
427
- }}
428
- />
429
- ```
430
-
431
- The `props` bucket is applied via `useAnimatedProps`, letting you animate component-specific properties like `BlurView`'s `intensity` or `SquircleView`'s `cornerRadius`.
432
-
433
- #### Custom Surface Component
434
-
435
- Use `surfaceComponent` to render a custom surface inside the animated content wrapper (e.g., a `SquircleView` for smooth rounded corners).
436
-
437
- - `content` drives container-level transitions (position/scale/opacity)
438
- - `surface` drives custom surface styles/props
439
- - Animated props are driven by the `surface` slot in your interpolator
440
- - When `maskEnabled: true` is active, the surface is rendered inside the masked navigation container so it stays clipped/transformed with zoom transitions
441
-
442
- ```tsx
443
- import { SquircleView } from "react-native-figma-squircle";
444
-
445
- <Stack.Screen
446
- name="Card"
447
- options={{
448
- surfaceComponent: SquircleView,
449
- screenStyleInterpolator: ({ progress }) => {
450
- "worklet";
451
- return {
452
- content: {
453
- style: {
454
- transform: [{ scale: interpolate(progress, [0, 1], [0.8, 1]) }],
455
- },
456
- },
457
- surface: {
458
- props: { cornerRadius: 24, cornerSmoothing: 0.7 },
459
- },
460
- };
461
- },
462
- }}
463
- />
464
- ```
465
-
466
- ### Programmatic Control
467
-
468
- Control snap points from anywhere in your app:
469
-
470
- ```tsx
471
- import { snapTo } from "react-native-screen-transitions";
472
-
473
- function BottomSheet() {
474
- // Expand to full height (index 1)
475
- const expand = () => snapTo(1);
476
-
477
- // Collapse to half height (index 0)
478
- const collapse = () => snapTo(0);
479
-
480
- return (
481
- <View>
482
- <Button title="Expand" onPress={expand} />
483
- <Button title="Collapse" onPress={collapse} />
484
- </View>
485
- );
486
- }
487
- ```
488
-
489
- The animated `snapIndex` is available in screen interpolators via `ScreenInterpolationProps`:
490
-
491
- ```tsx
492
- screenStyleInterpolator: ({ snapIndex }) => {
493
- // snapIndex interpolates between snap point indices
494
- // e.g., 0.5 means halfway between snap point 0 and 1
495
- return {
496
- content: {
497
- style: {
498
- opacity: interpolate(snapIndex, [0, 1], [0.5, 1]),
499
- },
500
- },
501
- };
502
- }
503
- ```
504
-
505
- ### ScrollView Behavior
506
-
507
- With `Transition.ScrollView` inside a snap-enabled sheet:
508
- - **`expandViaScrollView: true`**: At boundary, swipe up expands and swipe down collapses (or dismisses at min if enabled)
509
- - **`expandViaScrollView: false`**: Expand works only via deadspace; collapse/dismiss via scroll still works at boundary
510
- - **Scrolled into content**: Normal scroll behavior
511
-
512
- ### Snap Animation Specs
513
-
514
- Customize snap animations separately from enter/exit:
515
-
516
- ```tsx
517
- transitionSpec: {
518
- open: { stiffness: 1000, damping: 500, mass: 3 }, // Screen enter
519
- close: { stiffness: 1000, damping: 500, mass: 3 }, // Screen exit
520
- expand: { stiffness: 300, damping: 30 }, // Snap up
521
- collapse: { stiffness: 300, damping: 30 }, // Snap down
522
- }
523
- ```
524
-
525
- ---
526
-
527
- ## Shared Elements (Bounds API)
528
-
529
- Animate elements between screens by tagging them. There are two approaches: the `Transition.Boundary` namespace for declarative shared element transitions, and `sharedBoundTag` on `Transition.View`/`Transition.Pressable` for inline usage.
530
-
531
- ### Transition.Boundary
532
-
533
- The recommended setup. `Transition.Boundary` is a namespace with prebuilt variants:
534
- - `Transition.Boundary.Pressable` for source elements that trigger navigation
535
- - `Transition.Boundary.View` for passive source/destination elements
536
-
537
- ```tsx
538
- // Source screen — list item
539
- <Transition.Boundary.Pressable
540
- id="album-art"
541
- group="albums" // Optional: list/collection grouping
542
- onPress={() => router.push("/details")}
543
- >
544
- <Image source={album} style={{ width: 100, height: 100 }} />
545
- </Transition.Boundary.Pressable>
546
-
547
- // Destination screen
548
- <Transition.Boundary.View id="album-art">
549
- <Image source={album} style={{ width: 300, height: 300 }} />
550
- </Transition.Boundary.View>
551
- ```
552
-
553
- #### Boundary Props
554
-
555
- | Prop | Description |
556
- | ----------- | ------------------------------------------------------------------ |
557
- | `id` | Unique identifier for matching across screens |
558
- | `group` | Group name for list/collection scenarios (tag becomes `group:id`) |
559
- | `enabled` | Whether this boundary participates in matching (default: true) |
560
- | `method` | `"transform"` `"size"` `"content"` — how to animate |
561
- | `anchor` | Alignment anchor point |
562
- | `scaleMode` | `"match"` `"none"` `"uniform"` — aspect ratio handling |
563
- | `target` | Target for size calculations (for example `"fullscreen"`) |
564
-
565
- #### Groups
566
-
567
- For list/collection scenarios where multiple items share the same transition:
568
-
569
- ```tsx
570
- {items.map((item) => (
571
- <Transition.Boundary.Pressable
572
- key={item.id}
573
- id={item.id}
574
- group="photos"
575
- onPress={() => router.push(`/photo/${item.id}`)}
576
- >
577
- <Image source={item.src} />
578
- </Transition.Boundary.Pressable>
579
- ))}
580
- ```
581
-
582
- Only the tapped item transitions. The library tracks the active member for each group, and transition-aware scrollables emit settled signals so grouped boundaries can re-measure after focus-change auto-scrolling.
583
-
584
- ### Custom Boundary Components
585
-
586
- Use the boundary factory when you want a custom wrapped component (for example `Image`, `BlurView`, or design-system primitives):
587
-
588
- ```tsx
589
- import { Image } from "react-native";
590
- import Transition from "react-native-screen-transitions";
591
-
592
- const BoundaryImage = Transition.createBoundaryComponent(Image);
593
-
594
- <BoundaryImage id="cover-art" group="albums" source={cover} />
595
- ```
596
-
597
- ### Inline Shared Elements
598
-
599
- For simpler legacy cases, use `sharedBoundTag` directly on `Transition.View` or `Transition.Pressable`:
600
-
601
- ```tsx
602
- // Source
603
- <Transition.Pressable
604
- sharedBoundTag="avatar"
605
- onPress={() => navigation.navigate("Profile")}
606
- >
607
- <Image source={avatar} style={{ width: 50, height: 50 }} />
608
- </Transition.Pressable>
609
-
610
- // Destination
611
- <Transition.View sharedBoundTag="avatar">
612
- <Image source={avatar} style={{ width: 200, height: 200 }} />
613
- </Transition.View>
614
- ```
615
-
616
- > `sharedBoundTag` on `Transition.Pressable` is planned for deprecation in the next major version. Prefer `Transition.Boundary.Pressable` and `Transition.Boundary.View`.
617
-
618
- ### Using Bounds in Interpolators
619
-
620
- ```tsx
621
- screenStyleInterpolator: ({ bounds }) => {
622
- "worklet";
623
- return {
624
- "avatar": bounds({ id: "avatar", method: "transform" }),
625
- };
626
- };
627
- ```
628
-
629
- ### Navigation Bounds (Zoom Transitions)
630
-
631
- For SwiftUI-like navigation zoom transitions where content expands from a source element with a masked reveal:
632
-
633
- ```tsx
634
- <Stack.Screen
635
- name="Detail"
636
- options={{
637
- maskEnabled: true, // Required for masked reveal
638
- screenStyleInterpolator: ({ bounds, progress, focused }) => {
639
- "worklet";
640
- if (!focused) return {};
641
-
642
- return bounds({
643
- id: "album-art",
644
- }).navigation.zoom();
645
- },
646
- transitionSpec: {
647
- open: { stiffness: 1000, damping: 500, mass: 3, overshootClamping: true },
648
- close: { stiffness: 1000, damping: 500, mass: 3, overshootClamping: true },
649
- },
650
- }}
651
- />
652
- ```
653
-
654
- `bounds().navigation.zoom()` returns a complete interpolator result with content, mask, and container styles. Set `maskEnabled: true` to pre-mount the masked view wrapper so it's ready from the first frame.
655
-
656
- When using `surfaceComponent`, it participates in the same masked navigation container path under `maskEnabled: true`, so surface and children animate/clip together during zoom.
657
-
658
- `navigation.zoom(options?)` accepts optional zoom overrides for mask shape and drag feel.
659
-
660
- ```tsx
661
- screenStyleInterpolator: ({ bounds, focused }) => {
662
- "worklet";
663
- if (!focused) return {};
664
-
665
- return bounds({ id: "album-art" }).navigation.zoom({
666
- mask: {
667
- borderRadius: { from: 24, to: 0 },
668
- borderCurve: "continuous",
669
- outset: { bottom: 16 },
670
- },
671
- motion: {
672
- dragResistance: 0.32,
673
- dragDirectionalScaleMin: 0.2,
674
- },
675
- });
676
- };
677
- ```
678
-
679
- `navigation.zoom(options)` fields:
680
- - `anchor`, `scaleMode`, `target`: same meaning as `bounds({ ... })` options
681
- - `mask.borderRadius`: `number`, `"auto"`, or `{ from, to }`
682
- - `mask.borderTopLeftRadius`, `mask.borderTopRightRadius`, `mask.borderBottomLeftRadius`, `mask.borderBottomRightRadius`: per-corner overrides
683
- - `mask.borderCurve`: `"circular"` or `"continuous"` (where supported)
684
- - `mask.outset`: `number` or `{ top, right, bottom, left }` to expand mask bounds and avoid edge clipping
685
- - `motion.dragResistance`: drag translation resistance (default `0.4`)
686
- - `motion.dragDirectionalScaleMin`: directional drag minimum scale (default `0.25`)
687
- - `maskBorderRadius`: deprecated alias for `mask.borderRadius`
688
-
689
- Configuration guidance:
690
- - Preferred: define transition configuration on boundary components (`anchor`, `scaleMode`, `target`, `method`) via `Transition.Boundary.View` / `Transition.Boundary.Pressable`.
691
- - Supported but secondary: pass options through `bounds({ ... })` when needed.
692
-
693
- > **Note**: Navigation bounds masking requires `@react-native-masked-view/masked-view` to be installed.
694
-
695
- ### Bounds Options
696
-
697
- `bounds({ ... })` options are supported. For shared boundary flows, prefer setting configuration on boundary components and keep `bounds({ id })` minimal.
698
-
699
- | Option | Values | Description |
700
- | ----------- | ---------------------------------- | ----------------------------- |
701
- | `id` | string | The boundary id to match |
702
- | `method` | `"transform"` `"size"` `"content"` | How to animate |
703
- | `space` | `"relative"` `"absolute"` | Coordinate space |
704
- | `scaleMode` | `"match"` `"none"` `"uniform"` | Aspect ratio handling |
705
- | `anchor` | string | Alignment anchor point |
706
- | `target` | `"fullscreen"` etc. | Target for size calculations |
707
- | `raw` | boolean | Return raw values |
708
-
709
- ---
710
-
711
- ## Overlays
712
-
713
- Persistent UI that animates with the stack:
714
-
715
- ```tsx
716
- const TabBar = ({ focusedIndex, progress }) => {
717
- const style = useAnimatedStyle(() => ({
718
- transform: [{ translateY: interpolate(progress.value, [0, 1], [100, 0]) }],
719
- }));
720
- return <Animated.View style={[styles.tabBar, style]} />;
721
- };
722
-
723
- <Stack.Screen
724
- name="Home"
725
- options={{
726
- overlay: TabBar,
727
- overlayShown: true,
728
- }}
729
- />
730
- ```
731
-
732
- ### Overlay Props
733
-
734
- | Prop | Description |
735
- | -------------- | ------------------------------ |
736
- | `focusedRoute` | Currently focused route |
737
- | `focusedIndex` | Index of focused screen |
738
- | `routes` | All routes in the stack |
739
- | `progress` | Stack progress (derived value) |
740
- | `navigation` | Navigation prop |
741
- | `meta` | Custom metadata from options |
742
-
743
- ---
744
-
745
- ## Transition Components
746
-
747
- | Component | Description |
748
- | ------------------------------------------- | ------------------------------------------------------------------------------ |
749
- | `Transition.Boundary` | Namespace for shared-boundary helpers |
750
- | `Transition.Boundary.View` | Passive boundary wrapper for shared elements |
751
- | `Transition.Boundary.Pressable` | Pressable boundary wrapper with press-priority source measurement |
752
- | `Transition.createBoundaryComponent` | Factory for building boundary wrappers around custom components |
753
- | `Transition.View` | Animated view with `sharedBoundTag` or `styleId` |
754
- | `Transition.Pressable` | Pressable wrapper. `sharedBoundTag` usage is legacy and planned for next-major deprecation |
755
- | `Transition.ScrollView` | ScrollView with gesture coordination + scroll-settled signaling |
756
- | `Transition.FlatList` | FlatList with gesture coordination + scroll-settled signaling |
757
- | `Transition.MaskedView` | Deprecated legacy masking wrapper. Prefer `maskEnabled` on screen options |
758
-
759
- ---
760
-
761
- ## Hooks
762
-
763
- ### useScreenAnimation
764
-
765
- Access animation state inside a screen.
766
-
767
- By default, this returns the local screen animation values:
768
-
769
- ```tsx
770
- import { useScreenAnimation } from "react-native-screen-transitions";
771
-
772
- function DetailScreen() {
773
- const animation = useScreenAnimation();
774
-
775
- const style = useAnimatedStyle(() => ({
776
- opacity: animation.value.current.progress,
777
- }));
778
-
779
- return <Animated.View style={style}>...</Animated.View>;
780
- }
781
- ```
782
-
783
- You can also target ancestor animations:
784
-
785
- ```tsx
786
- const self = useScreenAnimation(); // local screen
787
- const parent = useScreenAnimation("parent"); // immediate parent
788
- const root = useScreenAnimation("root"); // highest ancestor
789
- const grandparent = useScreenAnimation({ ancestor: 2 }); // explicit depth
790
- ```
791
-
792
- If the requested target does not exist, the hook automatically falls back to local (`self`) values.
793
-
794
- Nested navigator example (`/_layout -> nested/_layout -> index`) where the leaf animates with the parent gesture:
795
-
796
- ```tsx
797
- import Animated, { useAnimatedStyle } from "react-native-reanimated";
798
- import { useScreenAnimation } from "react-native-screen-transitions";
799
-
800
- function NestedIndexScreen() {
801
- const parentAnimation = useScreenAnimation("parent");
802
-
803
- const staggeredStyle = useAnimatedStyle(() => ({
804
- opacity: parentAnimation.value.active.progress,
805
- transform: [{ translateY: (1 - parentAnimation.value.active.progress) * 16 }],
806
- }));
807
-
808
- return <Animated.View style={staggeredStyle}>{/* content */}</Animated.View>;
809
- }
810
- ```
811
-
812
- ### useScreenState
813
-
814
- Get navigation state without animation values:
815
-
816
- ```tsx
817
- import { useScreenState } from "react-native-screen-transitions";
818
-
819
- function DetailScreen() {
820
- const { index, focusedRoute, routes, navigation } = useScreenState();
821
- // ...
822
- }
823
- ```
824
-
825
- ### useHistory
826
-
827
- Access navigation history across the app:
828
-
829
- ```tsx
830
- import { useHistory } from "react-native-screen-transitions";
831
-
832
- function MyComponent() {
833
- const { getRecent, getPath } = useHistory();
834
-
835
- const recentScreens = getRecent(5); // Last 5 screens
836
- const path = getPath(fromKey, toKey); // Path between screens
837
- }
838
- ```
839
-
840
- ### useScreenGesture
841
-
842
- Coordinate your own pan gestures with the navigation gesture:
843
-
844
- ```tsx
845
- import { useScreenGesture } from "react-native-screen-transitions";
846
- import { Gesture, GestureDetector } from "react-native-gesture-handler";
847
-
848
- function MyScreen() {
849
- const screenGesture = useScreenGesture();
850
-
851
- const myPanGesture = Gesture.Pan()
852
- .simultaneousWithExternalGesture(screenGesture)
853
- .onUpdate((e) => {
854
- // Your gesture logic
855
- });
856
-
857
- return (
858
- <GestureDetector gesture={myPanGesture}>
859
- <View />
860
- </GestureDetector>
861
- );
862
- }
863
- ```
864
-
865
- Use this when you have custom pan gestures that need to work alongside screen dismiss gestures.
866
-
867
- ---
868
-
869
- ## Advanced Animation Props
870
-
871
- The full `screenStyleInterpolator` receives these props:
872
-
873
- | Prop | Description |
874
- | ---------------- | -------------------------------------------------------- |
875
- | `progress` | Combined progress (0-2) |
876
- | `stackProgress` | Accumulated progress across entire stack |
877
- | `snapIndex` | Animated snap point index (-1 if no snap points) |
878
- | `focused` | Whether this screen is the topmost in the stack |
879
- | `current` | Current screen state |
880
- | `previous` | Previous screen state |
881
- | `next` | Next screen state |
882
- | `active` | Screen driving the transition |
883
- | `inactive` | Screen NOT driving the transition |
884
- | `layouts.screen` | Screen dimensions |
885
- | `insets` | Safe area insets |
886
- | `bounds` | Shared element bounds function |
887
-
888
- ### Screen State Properties
889
-
890
- Each screen state (`current`, `previous`, `next`, `active`, `inactive`) contains:
891
-
892
- | Property | Description |
893
- | ----------- | ---------------------------------------- |
894
- | `progress` | Animation progress (0 or 1) |
895
- | `closing` | Whether closing (0 or 1) |
896
- | `entering` | Whether entering (0 or 1) |
897
- | `animating` | Whether animating (0 or 1) |
898
- | `gesture` | Gesture values (x, y, normalized values) |
899
- | `meta` | Custom metadata from options |
900
-
901
- ### Using `meta` for Conditional Logic
902
-
903
- Pass custom data between screens:
904
-
905
- ```tsx
906
- // Screen A
907
- options={{ meta: { hideTabBar: true } }}
908
-
909
- // Screen B reads it
910
- screenStyleInterpolator: (props) => {
911
- "worklet";
912
- const hideTabBar = props.inactive?.meta?.hideTabBar;
913
- // ...
914
- };
915
- ```
916
-
917
- ### Animate Individual Elements
918
-
919
- Use `styleId` to target specific elements:
920
-
921
- ```tsx
922
- // In options
923
- screenStyleInterpolator: ({ progress }) => {
924
- "worklet";
925
- return {
926
- "hero-image": {
927
- style: {
928
- opacity: interpolate(progress, [0, 1], [0, 1]),
929
- transform: [{ scale: interpolate(progress, [0, 1], [0.8, 1]) }],
930
- },
931
- },
932
- };
933
- };
934
-
935
- // In component
936
- <Transition.View styleId="hero-image">
937
- <Image source={...} />
938
- </Transition.View>
939
- ```
940
-
941
- ---
942
-
943
- ## Stack Types
944
-
945
- All three stacks share the same animation API. Choose based on your needs:
946
-
947
- | Stack | Best For |
948
- | ------------------- | --------------------------------------------------------- |
949
- | **Blank Stack** | Most apps. Full control, all features. |
950
- | **Native Stack** | When you need native screen primitives. |
951
- | **Component Stack** | Embedded flows, isolated from React Navigation. *(Experimental)* |
952
-
953
- ### Blank Stack
954
-
955
- The default choice. Uses `react-native-screens` for native screen containers, with animations powered by Reanimated worklets running on the UI thread (not the JS thread).
956
-
957
- ```tsx
958
- import { createBlankStackNavigator } from "react-native-screen-transitions/blank-stack";
959
- ```
960
-
961
- ### Native Stack
962
-
963
- Extends `@react-navigation/native-stack`. Requires `enableTransitions: true`.
964
-
965
- ```tsx
966
- import { createNativeStackNavigator } from "react-native-screen-transitions/native-stack";
967
-
968
- <Stack.Screen
969
- name="Detail"
970
- options={{
971
- enableTransitions: true,
972
- ...Transition.Presets.SlideFromBottom(),
973
- }}
974
- />
975
- ```
976
-
977
- ### Component Stack (Experimental)
978
-
979
- > **Note:** This API is experimental and may change based on community feedback.
980
-
981
- Standalone navigator, not connected to React Navigation. Ideal for embedded flows.
982
-
983
- ```tsx
984
- import { createComponentStackNavigator } from "react-native-screen-transitions/component-stack";
985
-
986
- const Stack = createComponentStackNavigator();
987
-
988
- <Stack.Navigator initialRouteName="step1">
989
- <Stack.Screen name="step1" component={Step1} />
990
- <Stack.Screen name="step2" component={Step2} />
991
- </Stack.Navigator>
992
- ```
993
-
994
- ---
995
-
996
- ## Caveats & Trade-offs
997
-
998
- ### Native Stack
999
-
1000
- The Native Stack uses transparent modal presentation to intercept transitions. This has trade-offs:
1001
-
1002
- - **Delayed touch events** – Exiting screens may have briefly delayed touch response
1003
- - **beforeRemove listeners** – Relies on navigation lifecycle events
1004
- - **Rapid navigation** – Some edge cases with very fast navigation sequences
1005
-
1006
- For most apps, Blank Stack avoids these issues entirely.
1007
-
1008
- ### Component Stack (Experimental)
1009
-
1010
- - **No deep linking** – Routes aren't part of your URL structure
1011
- - **Isolated state** – Doesn't affect parent navigation
1012
- - **Touch pass-through** – Uses `pointerEvents="box-none"` by default
1013
-
1014
- ---
1015
-
1016
- ## Experimental Features
1017
-
1018
- ### High Refresh Rate
1019
-
1020
- Force maximum refresh rate during transitions (for 90Hz/120Hz displays):
1021
-
1022
- ```tsx
1023
- options={{
1024
- experimental_enableHighRefreshRate: true,
1025
- }}
1026
- ```
1027
-
1028
- ---
1029
-
1030
- ## Masked View Setup (`maskEnabled` Recommended)
1031
-
1032
- Required for `SharedIGImage`, `SharedAppleMusic` presets, and `bounds().navigation.zoom()` transitions. For new code, prefer `maskEnabled: true` on screen options.
1033
-
1034
- > **Note**: Requires native code. Will not work in Expo Go.
1035
-
1036
- ### Installation
1037
-
1038
- ```bash
1039
- # Expo
1040
- npx expo install @react-native-masked-view/masked-view
1041
-
1042
- # Bare React Native
1043
- npm install @react-native-masked-view/masked-view
1044
- cd ios && pod install
1045
- ```
1046
-
1047
- ### Recommended Flow (`maskEnabled`)
1048
-
1049
- **1. Source Screen** – use a boundary pressable:
1050
-
1051
- ```tsx
1052
- // app/index.tsx
1053
- import { router } from "expo-router";
1054
- import Transition from "react-native-screen-transitions";
1055
-
1056
- export default function HomeScreen() {
1057
- return (
1058
- <Transition.Boundary.Pressable
1059
- id="album-art"
1060
- style={{
1061
- width: 200,
1062
- height: 200,
1063
- backgroundColor: "#1DB954",
1064
- borderRadius: 12,
1065
- }}
1066
- onPress={() => router.push("/details")}
1067
- />
1068
- );
1069
- }
1070
- ```
1071
-
1072
- **2. Destination Screen** – render the matching boundary:
1073
-
1074
- ```tsx
1075
- // app/details.tsx
1076
- import Transition from "react-native-screen-transitions";
1077
-
1078
- export default function DetailsScreen() {
1079
- return (
1080
- <Transition.Boundary.View
1081
- id="album-art"
1082
- style={{
1083
- backgroundColor: "#1DB954",
1084
- width: 400,
1085
- height: 400,
1086
- alignSelf: "center",
1087
- borderRadius: 12,
1088
- }}
1089
- />
1090
- );
1091
- }
1092
- ```
1093
-
1094
- **3. Layout** – enable `maskEnabled` and use `bounds().navigation.zoom()`:
1095
-
1096
- ```tsx
1097
- // app/_layout.tsx
1098
- import { Stack } from "./stack";
1099
-
1100
- export default function RootLayout() {
1101
- return (
1102
- <Stack>
1103
- <Stack.Screen name="index" />
1104
- <Stack.Screen
1105
- name="details"
1106
- options={{
1107
- maskEnabled: true,
1108
- screenStyleInterpolator: ({ bounds, focused }) => {
1109
- "worklet";
1110
- if (!focused) return {};
1111
- return bounds({ id: "album-art" }).navigation.zoom();
1112
- },
1113
- }}
1114
- />
1115
- </Stack>
1116
- );
1117
- }
1118
- ```
1119
-
1120
- ### Legacy Fallback (Deprecated): `Transition.MaskedView`
1121
-
1122
- `Transition.MaskedView` remains available for legacy/manual masking flows, but new implementations should use `maskEnabled`.
1123
-
1124
- ```tsx
1125
- <Transition.MaskedView style={{ flex: 1 }}>
1126
- <Transition.View sharedBoundTag="album-art" />
1127
- </Transition.MaskedView>
1128
- ```
1129
-
1130
- ### How It Works
1131
-
1132
- 1. `Transition.Boundary.Pressable` measures and stores source bounds (legacy fallback: `Transition.Pressable` with `sharedBoundTag`, planned for next-major deprecation).
1133
- 2. `Transition.Boundary.View` (or `Transition.View`) on the destination registers the matching target.
1134
- 3. `maskEnabled: true` pre-mounts the masked wrapper for zoom/reveal transitions (legacy fallback: `Transition.MaskedView`).
1135
- 4. The zoom preset interpolates position, size, and mask for a seamless expand/collapse effect.
1136
-
1137
- ---
1138
-
1139
- ## Support
1140
-
1141
- This package is developed in my spare time.
1142
-
1143
- If you'd like to fuel the next release, [buy me a coffee](https://buymeacoffee.com/trpfsu)
1144
-
1145
- ## License
44
+ ## Docs
1146
45
 
1147
- MIT
46
+ - Docs site: `https://eds2002.github.io/react-native-screen-transitions/`
47
+ - Stable docs line: `3.x`
48
+ - Unreleased docs line: `Next`
49
+ - Repository: `https://github.com/eds2002/react-native-screen-transitions`