react-native-screen-transitions 3.0.0-rc.5 → 3.1.0
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.
- package/README.md +360 -97
- package/lib/commonjs/blank-stack/components/overlay.js +1 -1
- package/lib/commonjs/blank-stack/components/overlay.js.map +1 -1
- package/lib/commonjs/shared/components/create-transition-aware-component.js +2 -0
- package/lib/commonjs/shared/components/create-transition-aware-component.js.map +1 -1
- package/lib/commonjs/shared/hooks/animation/use-screen-animation.js +9 -4
- package/lib/commonjs/shared/hooks/animation/use-screen-animation.js.map +1 -1
- package/lib/commonjs/shared/hooks/gestures/use-build-gestures.js +29 -5
- package/lib/commonjs/shared/hooks/gestures/use-build-gestures.js.map +1 -1
- package/lib/commonjs/shared/hooks/gestures/use-screen-gesture.js +26 -0
- package/lib/commonjs/shared/hooks/gestures/use-screen-gesture.js.map +1 -0
- package/lib/commonjs/shared/hooks/gestures/use-scroll-registry.js +32 -60
- package/lib/commonjs/shared/hooks/gestures/use-scroll-registry.js.map +1 -1
- package/lib/commonjs/shared/index.js +7 -0
- package/lib/commonjs/shared/index.js.map +1 -1
- package/lib/commonjs/shared/providers/gestures.provider.js +8 -18
- package/lib/commonjs/shared/providers/gestures.provider.js.map +1 -1
- package/lib/commonjs/shared/utils/animation/derivations.js +7 -0
- package/lib/commonjs/shared/utils/animation/derivations.js.map +1 -1
- package/lib/commonjs/shared/utils/bounds/helpers/interpolate-style.js +30 -0
- package/lib/commonjs/shared/utils/bounds/helpers/interpolate-style.js.map +1 -0
- package/lib/commonjs/shared/utils/bounds/index.js +29 -1
- package/lib/commonjs/shared/utils/bounds/index.js.map +1 -1
- package/lib/commonjs/shared/utils/create-provider.js +16 -0
- package/lib/commonjs/shared/utils/create-provider.js.map +1 -1
- package/lib/commonjs/shared/utils/gesture/check-gesture-activation.js +4 -0
- package/lib/commonjs/shared/utils/gesture/check-gesture-activation.js.map +1 -1
- package/lib/module/blank-stack/components/overlay.js +1 -1
- package/lib/module/blank-stack/components/overlay.js.map +1 -1
- package/lib/module/shared/components/create-transition-aware-component.js +2 -0
- package/lib/module/shared/components/create-transition-aware-component.js.map +1 -1
- package/lib/module/shared/hooks/animation/use-screen-animation.js +9 -4
- package/lib/module/shared/hooks/animation/use-screen-animation.js.map +1 -1
- package/lib/module/shared/hooks/gestures/use-build-gestures.js +30 -6
- package/lib/module/shared/hooks/gestures/use-build-gestures.js.map +1 -1
- package/lib/module/shared/hooks/gestures/use-screen-gesture.js +22 -0
- package/lib/module/shared/hooks/gestures/use-screen-gesture.js.map +1 -0
- package/lib/module/shared/hooks/gestures/use-scroll-registry.js +32 -60
- package/lib/module/shared/hooks/gestures/use-scroll-registry.js.map +1 -1
- package/lib/module/shared/index.js +1 -0
- package/lib/module/shared/index.js.map +1 -1
- package/lib/module/shared/providers/gestures.provider.js +9 -19
- package/lib/module/shared/providers/gestures.provider.js.map +1 -1
- package/lib/module/shared/utils/animation/derivations.js +7 -0
- package/lib/module/shared/utils/animation/derivations.js.map +1 -1
- package/lib/module/shared/utils/bounds/helpers/interpolate-style.js +26 -0
- package/lib/module/shared/utils/bounds/helpers/interpolate-style.js.map +1 -0
- package/lib/module/shared/utils/bounds/index.js +29 -1
- package/lib/module/shared/utils/bounds/index.js.map +1 -1
- package/lib/module/shared/utils/create-provider.js +17 -1
- package/lib/module/shared/utils/create-provider.js.map +1 -1
- package/lib/module/shared/utils/gesture/check-gesture-activation.js +4 -4
- package/lib/module/shared/utils/gesture/check-gesture-activation.js.map +1 -1
- package/lib/typescript/blank-stack/types.d.ts +2 -14
- package/lib/typescript/blank-stack/types.d.ts.map +1 -1
- package/lib/typescript/shared/components/create-transition-aware-component.d.ts +1 -0
- package/lib/typescript/shared/components/create-transition-aware-component.d.ts.map +1 -1
- package/lib/typescript/shared/hooks/animation/use-screen-animation.d.ts.map +1 -1
- package/lib/typescript/shared/hooks/gestures/use-build-gestures.d.ts +1 -0
- package/lib/typescript/shared/hooks/gestures/use-build-gestures.d.ts.map +1 -1
- package/lib/typescript/shared/hooks/gestures/use-screen-gesture.d.ts +15 -0
- package/lib/typescript/shared/hooks/gestures/use-screen-gesture.d.ts.map +1 -0
- package/lib/typescript/shared/hooks/gestures/use-scroll-registry.d.ts +1 -0
- package/lib/typescript/shared/hooks/gestures/use-scroll-registry.d.ts.map +1 -1
- package/lib/typescript/shared/index.d.ts +4 -2
- package/lib/typescript/shared/index.d.ts.map +1 -1
- package/lib/typescript/shared/providers/gestures.provider.d.ts +2 -6
- package/lib/typescript/shared/providers/gestures.provider.d.ts.map +1 -1
- package/lib/typescript/shared/types/animation.types.d.ts +51 -0
- package/lib/typescript/shared/types/animation.types.d.ts.map +1 -1
- package/lib/typescript/shared/types/bounds.types.d.ts +6 -0
- package/lib/typescript/shared/types/bounds.types.d.ts.map +1 -1
- package/lib/typescript/shared/types/core.types.d.ts +7 -0
- package/lib/typescript/shared/types/core.types.d.ts.map +1 -1
- package/lib/typescript/shared/utils/animation/derivations.d.ts +3 -1
- package/lib/typescript/shared/utils/animation/derivations.d.ts.map +1 -1
- package/lib/typescript/shared/utils/bounds/helpers/interpolate-style.d.ts +17 -0
- package/lib/typescript/shared/utils/bounds/helpers/interpolate-style.d.ts.map +1 -0
- package/lib/typescript/shared/utils/bounds/index.d.ts.map +1 -1
- package/lib/typescript/shared/utils/create-provider.d.ts +5 -1
- package/lib/typescript/shared/utils/create-provider.d.ts.map +1 -1
- package/lib/typescript/shared/utils/gesture/check-gesture-activation.d.ts +49 -1
- package/lib/typescript/shared/utils/gesture/check-gesture-activation.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/blank-stack/components/overlay.tsx +1 -1
- package/src/blank-stack/types.ts +2 -15
- package/src/shared/__tests__/derivations.test.ts +155 -0
- package/src/shared/__tests__/gesture-activation.test.ts +251 -0
- package/src/shared/components/create-transition-aware-component.tsx +2 -1
- package/src/shared/hooks/animation/use-screen-animation.tsx +9 -2
- package/src/shared/hooks/gestures/use-build-gestures.tsx +35 -8
- package/src/shared/hooks/gestures/use-screen-gesture.ts +19 -0
- package/src/shared/hooks/gestures/use-scroll-registry.tsx +39 -59
- package/src/shared/index.ts +2 -0
- package/src/shared/providers/gestures.provider.tsx +15 -27
- package/src/shared/types/animation.types.ts +57 -0
- package/src/shared/types/bounds.types.ts +11 -0
- package/src/shared/types/core.types.ts +8 -0
- package/src/shared/utils/animation/derivations.ts +8 -1
- package/src/shared/utils/bounds/helpers/interpolate-style.ts +38 -0
- package/src/shared/utils/bounds/index.ts +31 -1
- package/src/shared/utils/create-provider.tsx +31 -1
- package/src/shared/utils/gesture/check-gesture-activation.ts +4 -4
package/README.md
CHANGED
|
@@ -12,8 +12,8 @@ Customizable screen transitions for React Native. Build gesture-driven, shared e
|
|
|
12
12
|
- **Shared Elements** – Measure-driven transitions between screens using the Bounds API
|
|
13
13
|
- **Gesture Support** – Swipe-to-dismiss with edge or full-screen activation, works with ScrollViews
|
|
14
14
|
- **Two Stack Options** – Pure JS stack (recommended) or native stack integration
|
|
15
|
+
- **Stack Progress** – Track animation progress across the entire stack, not just adjacent screens
|
|
15
16
|
- **Ready-Made Presets** – Instagram, Apple Music, X (Twitter) style transitions included
|
|
16
|
-
- **TypeScript First** – Fully typed for better development experience
|
|
17
17
|
|
|
18
18
|
## Installation
|
|
19
19
|
|
|
@@ -36,10 +36,67 @@ npm install react-native-reanimated react-native-gesture-handler \
|
|
|
36
36
|
|
|
37
37
|
This package provides two stack navigators:
|
|
38
38
|
|
|
39
|
-
| Stack
|
|
40
|
-
|
|
41
|
-
| **Blank Stack** (recommended) | Pure JavaScript stack with full control over transitions, overlays, and gestures.
|
|
42
|
-
| **Native Stack**
|
|
39
|
+
| Stack | Description |
|
|
40
|
+
| ----------------------------- | --------------------------------------------------------------------------------- |
|
|
41
|
+
| **Blank Stack** (recommended) | Pure JavaScript stack with full control over transitions, overlays, and gestures. |
|
|
42
|
+
| **Native Stack** | Extends `@react-navigation/native-stack`. Fewer features but potentially faster. |
|
|
43
|
+
|
|
44
|
+
### Choosing a Stack
|
|
45
|
+
|
|
46
|
+
**Blank Stack** is feature-rich and recommended for most use cases:
|
|
47
|
+
|
|
48
|
+
- Full overlay system (float and screen modes)
|
|
49
|
+
- Stack progress tracking across the entire stack
|
|
50
|
+
- No delayed touch events on exiting screens
|
|
51
|
+
|
|
52
|
+
However, it's still a JavaScript implementation. While optimized to be as fast as possible (using `react-native-screens` under the hood, with animations and gesture logic running on the UI thread), heavy usage may not match native performance.
|
|
53
|
+
|
|
54
|
+
**Native Stack** has limitations but uses native navigation primitives:
|
|
55
|
+
|
|
56
|
+
- No overlay system
|
|
57
|
+
- Relies on `beforeRemove` listeners to intercept navigation
|
|
58
|
+
- Uses transparent modal presentation which can cause delayed touch events
|
|
59
|
+
- Some edge cases with rapid navigation
|
|
60
|
+
|
|
61
|
+
Choose Native Stack if you need maximum performance and can live without overlays.
|
|
62
|
+
|
|
63
|
+
### Blank Stack Philosophy
|
|
64
|
+
|
|
65
|
+
The Blank Stack is intentionally **blank** - transparent screens with no default animations. Unlike platform navigators that impose iOS or Android-style transitions, the Blank Stack gives you a clean slate.
|
|
66
|
+
|
|
67
|
+
**Why no defaults?**
|
|
68
|
+
|
|
69
|
+
- **Full creative control** – You define exactly how screens appear, not the OS
|
|
70
|
+
- **Consistency across platforms** – Same animation on iOS and Android
|
|
71
|
+
- **No fighting the framework** – No need to override or disable built-in behaviors
|
|
72
|
+
|
|
73
|
+
Every screen starts invisible and static. You bring it to life with your own `screenStyleInterpolator`. This encourages intentional, custom transitions rather than settling for platform defaults.
|
|
74
|
+
|
|
75
|
+
Under the hood, the Blank Stack uses `react-native-screens` for native-level performance. All animation and gesture logic runs on the UI thread via Reanimated worklets.
|
|
76
|
+
|
|
77
|
+
```tsx
|
|
78
|
+
// A screen with no options = invisible, no animation
|
|
79
|
+
<Stack.Screen name="Detail" component={DetailScreen} />
|
|
80
|
+
|
|
81
|
+
// Add your own transition
|
|
82
|
+
<Stack.Screen
|
|
83
|
+
name="Detail"
|
|
84
|
+
component={DetailScreen}
|
|
85
|
+
options={{
|
|
86
|
+
screenStyleInterpolator: ({ progress, layouts }) => {
|
|
87
|
+
"worklet";
|
|
88
|
+
return {
|
|
89
|
+
contentStyle: {
|
|
90
|
+
opacity: progress,
|
|
91
|
+
transform: [
|
|
92
|
+
{ translateY: interpolate(progress, [0, 1], [layouts.screen.height, 0]) }
|
|
93
|
+
],
|
|
94
|
+
},
|
|
95
|
+
};
|
|
96
|
+
},
|
|
97
|
+
}}
|
|
98
|
+
/>
|
|
99
|
+
```
|
|
43
100
|
|
|
44
101
|
### Blank Stack Setup
|
|
45
102
|
|
|
@@ -104,16 +161,16 @@ Built-in animation presets you can spread into screen options:
|
|
|
104
161
|
/>
|
|
105
162
|
```
|
|
106
163
|
|
|
107
|
-
| Preset
|
|
108
|
-
|
|
109
|
-
| `SlideFromTop()`
|
|
110
|
-
| `SlideFromBottom()`
|
|
111
|
-
| `ZoomIn()`
|
|
112
|
-
| `DraggableCard()`
|
|
113
|
-
| `ElasticCard()`
|
|
114
|
-
| `SharedIGImage({ sharedBoundTag })`
|
|
115
|
-
| `SharedAppleMusic({ sharedBoundTag })` | Apple Music-style shared element
|
|
116
|
-
| `SharedXImage({ sharedBoundTag })`
|
|
164
|
+
| Preset | Description |
|
|
165
|
+
| -------------------------------------- | ----------------------------------------------- |
|
|
166
|
+
| `SlideFromTop()` | Slides in from top, vertical gesture dismiss |
|
|
167
|
+
| `SlideFromBottom()` | Slides in from bottom, vertical gesture dismiss |
|
|
168
|
+
| `ZoomIn()` | Scales in with fade, no gesture |
|
|
169
|
+
| `DraggableCard()` | Multi-directional drag with card scaling |
|
|
170
|
+
| `ElasticCard()` | Elastic drag with overlay darkening |
|
|
171
|
+
| `SharedIGImage({ sharedBoundTag })` | Instagram-style shared image transition |
|
|
172
|
+
| `SharedAppleMusic({ sharedBoundTag })` | Apple Music-style shared element |
|
|
173
|
+
| `SharedXImage({ sharedBoundTag })` | X (Twitter)-style image transition |
|
|
117
174
|
|
|
118
175
|
---
|
|
119
176
|
|
|
@@ -154,19 +211,97 @@ import { interpolate } from "react-native-reanimated";
|
|
|
154
211
|
|
|
155
212
|
### Interpolator Props
|
|
156
213
|
|
|
157
|
-
| Prop
|
|
158
|
-
|
|
159
|
-
| `progress`
|
|
160
|
-
| `
|
|
161
|
-
| `
|
|
162
|
-
| `
|
|
163
|
-
| `
|
|
164
|
-
| `
|
|
165
|
-
| `
|
|
166
|
-
| `
|
|
167
|
-
| `
|
|
168
|
-
| `
|
|
169
|
-
| `bounds`
|
|
214
|
+
| Prop | Description |
|
|
215
|
+
| ---------------- | -------------------------------------------------------- |
|
|
216
|
+
| `progress` | Combined progress (0-2). 0=entering, 1=active, 2=exiting |
|
|
217
|
+
| `stackProgress` | Accumulated progress across entire stack (0, 1, 2, 3...) |
|
|
218
|
+
| `current` | Current screen state (progress, closing, gesture, meta) |
|
|
219
|
+
| `previous` | Previous screen state (may be undefined) |
|
|
220
|
+
| `next` | Next screen state (may be undefined) |
|
|
221
|
+
| `layouts.screen` | Screen dimensions `{ width, height }` |
|
|
222
|
+
| `insets` | Safe area insets `{ top, right, bottom, left }` |
|
|
223
|
+
| `focused` | Whether current screen is the topmost |
|
|
224
|
+
| `active` | The screen driving the transition |
|
|
225
|
+
| `inactive` | The screen NOT driving the transition |
|
|
226
|
+
| `bounds` | Function to access shared element positions |
|
|
227
|
+
|
|
228
|
+
### Screen State (`current`, `previous`, `next`, `active`, `inactive`)
|
|
229
|
+
|
|
230
|
+
Each screen state contains:
|
|
231
|
+
|
|
232
|
+
| Property | Description |
|
|
233
|
+
| ----------- | ----------------------------------------------------- |
|
|
234
|
+
| `progress` | Animation progress for this screen (0 or 1) |
|
|
235
|
+
| `closing` | Whether screen is closing (0 or 1) |
|
|
236
|
+
| `animating` | Whether screen is currently animating (0 or 1) |
|
|
237
|
+
| `gesture` | Gesture values (x, y, normalizedX, normalizedY, etc.) |
|
|
238
|
+
| `meta` | Custom metadata from screen options |
|
|
239
|
+
|
|
240
|
+
### Understanding `active` and `inactive`
|
|
241
|
+
|
|
242
|
+
The `active` and `inactive` props help you write cleaner conditional logic:
|
|
243
|
+
|
|
244
|
+
- **`active`** – The screen driving the transition. When focused, this is `current`. When not focused, this is `next`.
|
|
245
|
+
- **`inactive`** – The screen NOT driving the transition. When focused, this is `previous`. When not focused, this is `current`.
|
|
246
|
+
|
|
247
|
+
```tsx
|
|
248
|
+
// Check if the inactive screen wants to disable an animation
|
|
249
|
+
const disableTranslateY = props.inactive?.meta?.disableTranslateYAnimation;
|
|
250
|
+
|
|
251
|
+
// Check if the active screen is animating or closing
|
|
252
|
+
const isAnimating = props.active.animating;
|
|
253
|
+
const isClosing = props.active.closing;
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
### Using `meta` for Conditional Logic
|
|
257
|
+
|
|
258
|
+
Use `meta` to pass custom data for conditional animation logic. This is more robust than checking route names:
|
|
259
|
+
|
|
260
|
+
```tsx
|
|
261
|
+
// Screen A sets meta to affect how Screen B animates
|
|
262
|
+
<Stack.Screen
|
|
263
|
+
name="ScreenA"
|
|
264
|
+
options={{
|
|
265
|
+
meta: { disableTranslateYAnimation: true },
|
|
266
|
+
}}
|
|
267
|
+
/>
|
|
268
|
+
|
|
269
|
+
// Screen B checks inactive screen's meta
|
|
270
|
+
<Stack.Screen
|
|
271
|
+
name="ScreenB"
|
|
272
|
+
options={{
|
|
273
|
+
screenStyleInterpolator: (props) => {
|
|
274
|
+
"worklet";
|
|
275
|
+
|
|
276
|
+
// When entering from ScreenA, inactive = ScreenA (previous)
|
|
277
|
+
// When going back to ScreenA, inactive = ScreenB (current)
|
|
278
|
+
const disableY = props.inactive?.meta?.disableTranslateYAnimation;
|
|
279
|
+
|
|
280
|
+
return {
|
|
281
|
+
contentStyle: {
|
|
282
|
+
transform: [{ translateY: disableY ? 0 : translateY }],
|
|
283
|
+
},
|
|
284
|
+
};
|
|
285
|
+
},
|
|
286
|
+
}}
|
|
287
|
+
/>
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
You can also react to screen state changes within components:
|
|
291
|
+
|
|
292
|
+
```tsx
|
|
293
|
+
const animation = useScreenAnimation();
|
|
294
|
+
|
|
295
|
+
useAnimatedReaction(
|
|
296
|
+
() => animation.value,
|
|
297
|
+
(props) => {
|
|
298
|
+
// React to next screen's meta
|
|
299
|
+
if (props.next?.meta?.scalesOthers) {
|
|
300
|
+
scale.value = withTiming(0);
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
);
|
|
304
|
+
```
|
|
170
305
|
|
|
171
306
|
### Return Value
|
|
172
307
|
|
|
@@ -231,10 +366,10 @@ screenStyleInterpolator: ({ bounds }) => {
|
|
|
231
366
|
|
|
232
367
|
const avatarStyles = bounds({
|
|
233
368
|
id: "avatar",
|
|
234
|
-
method: "transform",
|
|
235
|
-
space: "relative",
|
|
236
|
-
scaleMode: "match",
|
|
237
|
-
anchor: "center",
|
|
369
|
+
method: "transform", // "transform" | "size" | "content"
|
|
370
|
+
space: "relative", // "relative" | "absolute"
|
|
371
|
+
scaleMode: "match", // "match" | "none" | "uniform"
|
|
372
|
+
anchor: "center", // positioning anchor
|
|
238
373
|
});
|
|
239
374
|
|
|
240
375
|
return {
|
|
@@ -245,15 +380,15 @@ screenStyleInterpolator: ({ bounds }) => {
|
|
|
245
380
|
|
|
246
381
|
### Bounds Options
|
|
247
382
|
|
|
248
|
-
| Option
|
|
249
|
-
|
|
250
|
-
| `id`
|
|
251
|
-
| `method`
|
|
252
|
-
| `space`
|
|
253
|
-
| `scaleMode` | `"match"` `"none"` `"uniform"`
|
|
254
|
-
| `anchor`
|
|
255
|
-
| `target`
|
|
256
|
-
| `raw`
|
|
383
|
+
| Option | Values | Description |
|
|
384
|
+
| ----------- | -------------------------------------- | -------------------------------------- |
|
|
385
|
+
| `id` | string | The `sharedBoundTag` to match |
|
|
386
|
+
| `method` | `"transform"` `"size"` `"content"` | How to animate (scale vs width/height) |
|
|
387
|
+
| `space` | `"relative"` `"absolute"` | Coordinate space |
|
|
388
|
+
| `scaleMode` | `"match"` `"none"` `"uniform"` | How to handle aspect ratio |
|
|
389
|
+
| `anchor` | `"center"` `"top"` `"topLeading"` etc. | Transform origin |
|
|
390
|
+
| `target` | `"bound"` `"fullscreen"` or custom | Destination target |
|
|
391
|
+
| `raw` | boolean | Return raw values instead of styles |
|
|
257
392
|
|
|
258
393
|
### Raw Values
|
|
259
394
|
|
|
@@ -262,6 +397,39 @@ const raw = bounds({ id: "avatar", method: "transform", raw: true });
|
|
|
262
397
|
// { translateX, translateY, scaleX, scaleY }
|
|
263
398
|
```
|
|
264
399
|
|
|
400
|
+
### Bounds Utilities
|
|
401
|
+
|
|
402
|
+
Access additional bounds data for custom animations:
|
|
403
|
+
|
|
404
|
+
```tsx
|
|
405
|
+
screenStyleInterpolator: ({ bounds, progress }) => {
|
|
406
|
+
"worklet";
|
|
407
|
+
|
|
408
|
+
// Get the active link between source and destination
|
|
409
|
+
const link = bounds.getLink("avatar");
|
|
410
|
+
// { source: { bounds, styles }, destination: { bounds, styles } }
|
|
411
|
+
|
|
412
|
+
// Interpolate a style property (e.g., borderRadius) between source and destination
|
|
413
|
+
const borderRadius = bounds.interpolateStyle("avatar", "borderRadius");
|
|
414
|
+
|
|
415
|
+
// Or access raw values for custom logic
|
|
416
|
+
const sourceBorderRadius = link?.source?.styles?.borderRadius ?? 0;
|
|
417
|
+
|
|
418
|
+
return {
|
|
419
|
+
avatar: {
|
|
420
|
+
...bounds({ id: "avatar" }),
|
|
421
|
+
borderRadius,
|
|
422
|
+
},
|
|
423
|
+
};
|
|
424
|
+
};
|
|
425
|
+
```
|
|
426
|
+
|
|
427
|
+
| Method | Description |
|
|
428
|
+
| ---------------------------------------------- | --------------------------------------------------- |
|
|
429
|
+
| `bounds.getLink(id)` | Get source/destination bounds and styles for a tag |
|
|
430
|
+
| `bounds.interpolateStyle(id, prop, fallback?)` | Interpolate a numeric style between source and dest |
|
|
431
|
+
| `bounds.getSnapshot(id, key)` | Manual lookup by specific screen key (edge cases) |
|
|
432
|
+
|
|
265
433
|
---
|
|
266
434
|
|
|
267
435
|
## Gestures
|
|
@@ -273,8 +441,8 @@ Enable swipe-to-dismiss on screens:
|
|
|
273
441
|
name="Detail"
|
|
274
442
|
options={{
|
|
275
443
|
gestureEnabled: true,
|
|
276
|
-
gestureDirection: "vertical",
|
|
277
|
-
gestureActivationArea: "edge",
|
|
444
|
+
gestureDirection: "vertical", // or "horizontal", ["vertical", "horizontal"]
|
|
445
|
+
gestureActivationArea: "edge", // or "screen", or { left: "edge", top: "screen" }
|
|
278
446
|
gestureResponseDistance: 50,
|
|
279
447
|
gestureVelocityImpact: 0.3,
|
|
280
448
|
}}
|
|
@@ -283,14 +451,14 @@ Enable swipe-to-dismiss on screens:
|
|
|
283
451
|
|
|
284
452
|
### Gesture Options
|
|
285
453
|
|
|
286
|
-
| Option
|
|
287
|
-
|
|
288
|
-
| `gestureEnabled`
|
|
289
|
-
| `gestureDirection`
|
|
290
|
-
| `gestureActivationArea`
|
|
291
|
-
| `gestureResponseDistance` | Distance threshold for gesture recognition
|
|
292
|
-
| `gestureVelocityImpact`
|
|
293
|
-
| `gestureDrivesProgress`
|
|
454
|
+
| Option | Description |
|
|
455
|
+
| ------------------------- | ---------------------------------------------------------------------------------- |
|
|
456
|
+
| `gestureEnabled` | Enable/disable gesture |
|
|
457
|
+
| `gestureDirection` | `"horizontal"` `"vertical"` `"horizontal-inverted"` `"vertical-inverted"` or array |
|
|
458
|
+
| `gestureActivationArea` | `"edge"` `"screen"` or per-side config |
|
|
459
|
+
| `gestureResponseDistance` | Distance threshold for gesture recognition |
|
|
460
|
+
| `gestureVelocityImpact` | How much velocity affects dismissal decision |
|
|
461
|
+
| `gestureDrivesProgress` | Whether gesture directly drives animation (default: true) |
|
|
294
462
|
|
|
295
463
|
### Gestures with ScrollViews
|
|
296
464
|
|
|
@@ -317,6 +485,7 @@ const TransitionFlashList = Transition.createTransitionAwareComponent(
|
|
|
317
485
|
```
|
|
318
486
|
|
|
319
487
|
Gesture rules with scrollables:
|
|
488
|
+
|
|
320
489
|
- **vertical** – only starts when scrolled to top
|
|
321
490
|
- **vertical-inverted** – only starts when scrolled to bottom
|
|
322
491
|
- **horizontal** – only starts at left/right edge
|
|
@@ -339,7 +508,9 @@ const FloatingHeader = ({ focusedIndex, routes, overlayAnimation }) => {
|
|
|
339
508
|
|
|
340
509
|
return (
|
|
341
510
|
<Animated.View style={[styles.header, style]}>
|
|
342
|
-
<Text>
|
|
511
|
+
<Text>
|
|
512
|
+
Screen {focusedIndex + 1} of {routes.length}
|
|
513
|
+
</Text>
|
|
343
514
|
</Animated.View>
|
|
344
515
|
);
|
|
345
516
|
};
|
|
@@ -351,7 +522,7 @@ const FloatingHeader = ({ focusedIndex, routes, overlayAnimation }) => {
|
|
|
351
522
|
overlayMode: "float",
|
|
352
523
|
overlayShown: true,
|
|
353
524
|
}}
|
|
354
|
-
|
|
525
|
+
/>;
|
|
355
526
|
```
|
|
356
527
|
|
|
357
528
|
### Screen Overlay
|
|
@@ -371,15 +542,15 @@ An overlay that moves with screen content:
|
|
|
371
542
|
|
|
372
543
|
### Overlay Props
|
|
373
544
|
|
|
374
|
-
| Prop
|
|
375
|
-
|
|
376
|
-
| `focusedRoute`
|
|
377
|
-
| `focusedIndex`
|
|
378
|
-
| `routes`
|
|
379
|
-
| `
|
|
380
|
-
| `navigation`
|
|
381
|
-
| `overlayAnimation` | Animation values
|
|
382
|
-
| `screenAnimation`
|
|
545
|
+
| Prop | Description |
|
|
546
|
+
| ------------------ | --------------------------------------------------------- |
|
|
547
|
+
| `focusedRoute` | Currently focused route |
|
|
548
|
+
| `focusedIndex` | Index of focused screen |
|
|
549
|
+
| `routes` | All routes in the stack |
|
|
550
|
+
| `meta` | Custom metadata passed from screen options |
|
|
551
|
+
| `navigation` | Navigation prop |
|
|
552
|
+
| `overlayAnimation` | Animation values with `progress` accumulated across stack |
|
|
553
|
+
| `screenAnimation` | Animation values for the current focused screen |
|
|
383
554
|
|
|
384
555
|
### Passing Custom Data
|
|
385
556
|
|
|
@@ -387,16 +558,16 @@ An overlay that moves with screen content:
|
|
|
387
558
|
<Stack.Screen
|
|
388
559
|
options={{
|
|
389
560
|
overlay: MyOverlay,
|
|
390
|
-
|
|
561
|
+
meta: {
|
|
391
562
|
title: "Step 1",
|
|
392
563
|
showProgress: true,
|
|
393
564
|
},
|
|
394
565
|
}}
|
|
395
|
-
|
|
566
|
+
/>;
|
|
396
567
|
|
|
397
568
|
// In overlay
|
|
398
|
-
const MyOverlay = ({
|
|
399
|
-
return <Text>{
|
|
569
|
+
const MyOverlay = ({ meta }) => {
|
|
570
|
+
return <Text>{meta?.title}</Text>;
|
|
400
571
|
};
|
|
401
572
|
```
|
|
402
573
|
|
|
@@ -404,13 +575,13 @@ const MyOverlay = ({ overlayOptions }) => {
|
|
|
404
575
|
|
|
405
576
|
## Transition Components
|
|
406
577
|
|
|
407
|
-
| Component
|
|
408
|
-
|
|
409
|
-
| `Transition.View`
|
|
410
|
-
| `Transition.Pressable`
|
|
411
|
-
| `Transition.ScrollView` | ScrollView with gesture coordination
|
|
412
|
-
| `Transition.FlatList`
|
|
413
|
-
| `Transition.MaskedView` | For clipping during shared element transitions
|
|
578
|
+
| Component | Description |
|
|
579
|
+
| ----------------------- | ------------------------------------------------------ |
|
|
580
|
+
| `Transition.View` | Animated view, supports `styleId` and `sharedBoundTag` |
|
|
581
|
+
| `Transition.Pressable` | Pressable with bounds measurement on press |
|
|
582
|
+
| `Transition.ScrollView` | ScrollView with gesture coordination |
|
|
583
|
+
| `Transition.FlatList` | FlatList with gesture coordination |
|
|
584
|
+
| `Transition.MaskedView` | For clipping during shared element transitions |
|
|
414
585
|
|
|
415
586
|
### Creating Custom Components
|
|
416
587
|
|
|
@@ -479,10 +650,12 @@ transitionSpec: {
|
|
|
479
650
|
|
|
480
651
|
## Masked View Setup
|
|
481
652
|
|
|
482
|
-
Required for `SharedIGImage` and `SharedAppleMusic` presets.
|
|
653
|
+
Required for `SharedIGImage` and `SharedAppleMusic` presets. The masked view creates the "reveal" effect where content appears to expand from the shared element.
|
|
483
654
|
|
|
484
655
|
> **Note**: Requires native code. Will not work in Expo Go.
|
|
485
656
|
|
|
657
|
+
### Installation
|
|
658
|
+
|
|
486
659
|
```bash
|
|
487
660
|
# Expo
|
|
488
661
|
npx expo install @react-native-masked-view/masked-view
|
|
@@ -492,18 +665,100 @@ npm install @react-native-masked-view/masked-view
|
|
|
492
665
|
cd ios && pod install
|
|
493
666
|
```
|
|
494
667
|
|
|
495
|
-
|
|
668
|
+
### Complete Example
|
|
669
|
+
|
|
670
|
+
Here's a full example showing how to set up an Apple Music-style shared element transition:
|
|
671
|
+
|
|
672
|
+
**1. Source Screen** – Tag pressable elements with `sharedBoundTag`:
|
|
496
673
|
|
|
497
674
|
```tsx
|
|
498
|
-
|
|
675
|
+
// app/index.tsx
|
|
676
|
+
import { router } from "expo-router";
|
|
677
|
+
import { View } from "react-native";
|
|
678
|
+
import Transition from "react-native-screen-transitions";
|
|
679
|
+
|
|
680
|
+
export default function HomeScreen() {
|
|
499
681
|
return (
|
|
500
|
-
<
|
|
501
|
-
|
|
682
|
+
<View style={{ flex: 1, alignItems: "center", justifyContent: "center" }}>
|
|
683
|
+
<Transition.Pressable
|
|
684
|
+
sharedBoundTag="album-art"
|
|
685
|
+
style={{
|
|
686
|
+
width: 200,
|
|
687
|
+
height: 200,
|
|
688
|
+
backgroundColor: "#1DB954",
|
|
689
|
+
borderRadius: 12,
|
|
690
|
+
}}
|
|
691
|
+
onPress={() => {
|
|
692
|
+
router.push({
|
|
693
|
+
pathname: "/details",
|
|
694
|
+
params: { sharedBoundTag: "album-art" },
|
|
695
|
+
});
|
|
696
|
+
}}
|
|
697
|
+
/>
|
|
698
|
+
</View>
|
|
699
|
+
);
|
|
700
|
+
}
|
|
701
|
+
```
|
|
702
|
+
|
|
703
|
+
**2. Destination Screen** – Wrap content with `MaskedView` and match the `sharedBoundTag`:
|
|
704
|
+
|
|
705
|
+
```tsx
|
|
706
|
+
// app/details.tsx
|
|
707
|
+
import { useLocalSearchParams } from "expo-router";
|
|
708
|
+
import Transition from "react-native-screen-transitions";
|
|
709
|
+
|
|
710
|
+
export default function DetailsScreen() {
|
|
711
|
+
const { sharedBoundTag } = useLocalSearchParams<{ sharedBoundTag: string }>();
|
|
712
|
+
|
|
713
|
+
return (
|
|
714
|
+
<Transition.MaskedView style={{ flex: 1, backgroundColor: "#121212" }}>
|
|
715
|
+
<Transition.View
|
|
716
|
+
sharedBoundTag={sharedBoundTag}
|
|
717
|
+
style={{
|
|
718
|
+
backgroundColor: "#1DB954",
|
|
719
|
+
width: 400,
|
|
720
|
+
height: 400,
|
|
721
|
+
alignSelf: "center",
|
|
722
|
+
borderRadius: 12,
|
|
723
|
+
}}
|
|
724
|
+
/>
|
|
725
|
+
{/* Additional screen content */}
|
|
502
726
|
</Transition.MaskedView>
|
|
503
727
|
);
|
|
504
728
|
}
|
|
505
729
|
```
|
|
506
730
|
|
|
731
|
+
**3. Layout** – Apply the shared element preset with dynamic `sharedBoundTag`:
|
|
732
|
+
|
|
733
|
+
```tsx
|
|
734
|
+
// app/_layout.tsx
|
|
735
|
+
import Transition from "react-native-screen-transitions";
|
|
736
|
+
import { Stack } from "./stack";
|
|
737
|
+
|
|
738
|
+
export default function RootLayout() {
|
|
739
|
+
return (
|
|
740
|
+
<Stack>
|
|
741
|
+
<Stack.Screen name="index" />
|
|
742
|
+
<Stack.Screen
|
|
743
|
+
name="details"
|
|
744
|
+
options={({ route }) => ({
|
|
745
|
+
...Transition.Presets.SharedAppleMusic({
|
|
746
|
+
sharedBoundTag: route.params?.sharedBoundTag ?? "",
|
|
747
|
+
}),
|
|
748
|
+
})}
|
|
749
|
+
/>
|
|
750
|
+
</Stack>
|
|
751
|
+
);
|
|
752
|
+
}
|
|
753
|
+
```
|
|
754
|
+
|
|
755
|
+
### How It Works
|
|
756
|
+
|
|
757
|
+
1. `Transition.Pressable` measures its bounds when pressed and stores them with the `sharedBoundTag`
|
|
758
|
+
2. `Transition.View` on the destination screen registers as the target for that tag
|
|
759
|
+
3. `Transition.MaskedView` clips the destination content to the animating shared element bounds
|
|
760
|
+
4. The preset interpolates position, size, and the mask to create the seamless expand/collapse effect
|
|
761
|
+
|
|
507
762
|
---
|
|
508
763
|
|
|
509
764
|
## Native Stack
|
|
@@ -522,10 +777,10 @@ const Stack = createNativeStackNavigator();
|
|
|
522
777
|
<Stack.Screen
|
|
523
778
|
name="Detail"
|
|
524
779
|
options={{
|
|
525
|
-
enableTransitions: true,
|
|
780
|
+
enableTransitions: true, // Required to enable custom transitions
|
|
526
781
|
...Transition.Presets.SlideFromBottom(),
|
|
527
782
|
}}
|
|
528
|
-
|
|
783
|
+
/>;
|
|
529
784
|
```
|
|
530
785
|
|
|
531
786
|
### Expo Router Setup
|
|
@@ -556,26 +811,27 @@ export const Stack = withLayoutContext<
|
|
|
556
811
|
|
|
557
812
|
All standard `@react-navigation/native-stack` options are available, plus:
|
|
558
813
|
|
|
559
|
-
| Option
|
|
560
|
-
|
|
561
|
-
| `enableTransitions`
|
|
562
|
-
| `screenStyleInterpolator` | `ScreenStyleInterpolator`
|
|
563
|
-
| `transitionSpec`
|
|
564
|
-
| `gestureEnabled`
|
|
565
|
-
| `gestureDirection`
|
|
566
|
-
| `gestureVelocityImpact`
|
|
567
|
-
| `gestureResponseDistance` | `number`
|
|
568
|
-
| `gestureDrivesProgress`
|
|
569
|
-
| `gestureActivationArea`
|
|
814
|
+
| Option | Type | Description |
|
|
815
|
+
| ------------------------- | ---------------------------------------- | ------------------------------------------------------------------ |
|
|
816
|
+
| `enableTransitions` | `boolean` | Enable custom transitions (sets presentation to transparent modal) |
|
|
817
|
+
| `screenStyleInterpolator` | `ScreenStyleInterpolator` | Function that returns animated styles |
|
|
818
|
+
| `transitionSpec` | `TransitionSpec` | Animation config for open/close |
|
|
819
|
+
| `gestureEnabled` | `boolean` | Whether swipe-to-dismiss is allowed |
|
|
820
|
+
| `gestureDirection` | `GestureDirection \| GestureDirection[]` | Allowed swipe directions |
|
|
821
|
+
| `gestureVelocityImpact` | `number` | How much velocity affects dismissal |
|
|
822
|
+
| `gestureResponseDistance` | `number` | Distance threshold for gesture |
|
|
823
|
+
| `gestureDrivesProgress` | `boolean` | Whether gesture drives animation |
|
|
824
|
+
| `gestureActivationArea` | `GestureActivationArea` | Where gesture can start |
|
|
825
|
+
| `meta` | `Record<string, unknown>` | Custom metadata for conditional animation logic |
|
|
570
826
|
|
|
571
827
|
### Renamed Native Options
|
|
572
828
|
|
|
573
829
|
To avoid collisions with custom gesture options, some native options are renamed:
|
|
574
830
|
|
|
575
|
-
| React Navigation
|
|
576
|
-
|
|
577
|
-
| `gestureDirection`
|
|
578
|
-
| `gestureEnabled`
|
|
831
|
+
| React Navigation | Renamed to |
|
|
832
|
+
| ------------------------- | ------------------------------- |
|
|
833
|
+
| `gestureDirection` | `nativeGestureDirection` |
|
|
834
|
+
| `gestureEnabled` | `nativeGestureEnabled` |
|
|
579
835
|
| `gestureResponseDistance` | `nativeGestureResponseDistance` |
|
|
580
836
|
|
|
581
837
|
### Limitations
|
|
@@ -587,9 +843,16 @@ To avoid collisions with custom gesture options, some native options are renamed
|
|
|
587
843
|
|
|
588
844
|
---
|
|
589
845
|
|
|
590
|
-
##
|
|
846
|
+
## Migrating from Earlier Versions
|
|
847
|
+
|
|
848
|
+
### Deprecated Props
|
|
849
|
+
|
|
850
|
+
The following props are deprecated and will be removed in a future version:
|
|
591
851
|
|
|
592
|
-
|
|
852
|
+
| Deprecated Prop | Use Instead |
|
|
853
|
+
| ----------------------- | ------------------ |
|
|
854
|
+
| `isActiveTransitioning` | `active.animating` |
|
|
855
|
+
| `isDismissing` | `active.closing` |
|
|
593
856
|
|
|
594
857
|
---
|
|
595
858
|
|
|
@@ -69,7 +69,7 @@ const OverlayHost = ({
|
|
|
69
69
|
screenAnimation,
|
|
70
70
|
focusedRoute: focusedScene.route,
|
|
71
71
|
focusedIndex: optimisticActiveIndex,
|
|
72
|
-
|
|
72
|
+
meta: focusedScene.descriptor.options.meta,
|
|
73
73
|
navigation: scene.descriptor.navigation
|
|
74
74
|
};
|
|
75
75
|
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Animated.View, {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["_native","require","_react","_reactNative","_useScreenAnimation","_keys","_transitionStyles","_useOverlayAnimation","_withStackNavigation","_jsxRuntime","getActiveFloatOverlay","scenes","index","length","startIndex","Math","max","i","scene","options","descriptor","overlayMode","overlayShown","overlayIndex","OverlayHost","isFloating","OverlayComponent","overlay","overlayAnimation","optimisticActiveIndex","useOverlayAnimation","routes","useStackNavigationContext","overlaySceneIndex","useMemo","findIndex","stackScene","route","key","focusedScene","maxOffset","normalizedIndex","min","screenAnimation","useScreenAnimation","overlayProps","focusedRoute","focusedIndex","
|
|
1
|
+
{"version":3,"names":["_native","require","_react","_reactNative","_useScreenAnimation","_keys","_transitionStyles","_useOverlayAnimation","_withStackNavigation","_jsxRuntime","getActiveFloatOverlay","scenes","index","length","startIndex","Math","max","i","scene","options","descriptor","overlayMode","overlayShown","overlayIndex","OverlayHost","isFloating","OverlayComponent","overlay","overlayAnimation","optimisticActiveIndex","useOverlayAnimation","routes","useStackNavigationContext","overlaySceneIndex","useMemo","findIndex","stackScene","route","key","focusedScene","maxOffset","normalizedIndex","min","screenAnimation","useScreenAnimation","overlayProps","focusedRoute","focusedIndex","meta","navigation","jsx","Animated","View","pointerEvents","style","styles","container","floating","zIndex","absolute","children","NavigationContext","Provider","value","NavigationRouteContext","FloatOverlay","activeOverlay","previous","current","next","KeysProvider","TransitionStylesProvider","ScreenOverlay","useKeys","Overlay","exports","Float","Screen","StyleSheet","create","absoluteFillObject","flex"],"sourceRoot":"../../../../src","sources":["blank-stack/components/overlay.tsx"],"mappings":"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","ignoreList":[]}
|