Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ expo-env.d.ts

#Bun
node_modules/
/starters/*/bun.lock

# OS-specific
.DS_Store
Expand Down
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,18 @@ Customizable screen transitions for React Native. Build gesture-driven, shared e
- Blank stack, native stack, and Expo Router integration.
- Written in TypeScript.

## Navigation Compatibility

This README documents the stable v3 release.

| Navigation setup | v3 status | Integration |
| ---------------- | --------- | ----------- |
| React Navigation 6 or 7 | Supported | Use the v3 blank stack or native-stack adapter APIs. |
| Expo Router on Expo SDK 55 or earlier | Supported | Wrap the v3 blank stack with `withLayoutContext()`. |
| Expo Router on Expo SDK 56 or later | Not supported by v3 | Use the [v4 alpha Expo Router integration](https://screen-transitions.esjr.org/v4-experimental/getting-started). |

Expo SDK 55 is the last Expo Router release that uses the React Navigation-backed integration documented for v3. Expo Router forked the navigation packages it builds upon in SDK 56, so the v3 and SDK 56+ navigator internals cannot be mixed. See Expo's [SDK 55 to 56 migration guide](https://docs.expo.dev/router/migrate/sdk-55-to-56/) for the upstream change.

## Getting Started

Install the package:
Expand All @@ -35,6 +47,8 @@ npm install react-native-reanimated react-native-gesture-handler \

See [the documentation site](https://screen-transitions.esjr.org).

For complete runnable projects, start with the [v3 Expo Router starter](https://github.com/eds2002/react-native-screen-transitions/tree/main/starters/expo-router), which pins the final supported Expo Router environment on Expo SDK 55, or the [v3 React Navigation starter](https://github.com/eds2002/react-native-screen-transitions/tree/main/starters/react-navigation).

## Support

v3 (current) supports Reanimated v3, Reanimated v4, and React Native Gesture Handler v2.
Expand Down
6 changes: 3 additions & 3 deletions apps/e2e/app.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
"orientation": "portrait",
"scheme": "e2e",
"userInterfaceStyle": "automatic",
"newArchEnabled": true,
"ios": {
"supportsTablet": true,
"bundleIdentifier": "com.eds2002.e2e",
Expand All @@ -16,7 +15,6 @@
"adaptiveIcon": {
"backgroundColor": "#E6F4FE"
},
"edgeToEdgeEnabled": true,
"predictiveBackGestureEnabled": false,
"package": "com.eds2002.e2e"
},
Expand All @@ -26,7 +24,9 @@
"plugins": [
"expo-router",
"expo-video",
"expo-web-browser"
"expo-web-browser",
"expo-font",
"expo-image"
],
"experiments": {
"typedRoutes": true,
Expand Down
48 changes: 24 additions & 24 deletions apps/e2e/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,39 +22,39 @@
"@react-navigation/elements": "^2.6.3",
"@react-navigation/native": "^7.1.8",
"@react-navigation/stack": "^7.4.10",
"expo": "~54.0.34",
"expo-blur": "~15.0.8",
"expo-constants": "~18.0.10",
"expo-font": "~14.0.9",
"expo-haptics": "~15.0.7",
"expo-image": "~3.0.10",
"expo-linking": "~8.0.12",
"expo-router": "~6.0.14",
"expo-splash-screen": "~31.0.10",
"expo-status-bar": "~3.0.8",
"expo-symbols": "~1.0.7",
"expo-system-ui": "~6.0.8",
"expo-video": "~3.0.16",
"expo-web-browser": "~15.0.11",
"react": "19.1.0",
"react-dom": "19.1.0",
"react-native": "0.81.5",
"expo": "^55.0.0",
"expo-blur": "~55.0.16",
"expo-constants": "~55.0.17",
"expo-font": "~55.0.8",
"expo-haptics": "~55.0.16",
"expo-image": "~55.0.11",
"expo-linking": "~55.0.16",
"expo-router": "~55.0.17",
"expo-splash-screen": "~55.0.23",
"expo-status-bar": "~55.0.6",
"expo-symbols": "~55.0.9",
"expo-system-ui": "~55.0.20",
"expo-video": "~55.0.19",
"expo-web-browser": "~55.0.18",
"react": "19.2.0",
"react-dom": "19.2.0",
"react-native": "0.83.10",
"react-native-fast-squircle": "^1.1.1",
"react-native-gesture-handler": "~2.28.0",
"react-native-reanimated": "~4.1.1",
"react-native-gesture-handler": "~2.30.0",
"react-native-reanimated": "4.2.1",
"react-native-safe-area-context": "~5.6.0",
"react-native-screen-transitions": "workspace:*",
"react-native-screens": "~4.16.0",
"react-native-screens": "~4.23.0",
"react-native-teleport": "1.1.10",
"react-native-web": "~0.21.0",
"react-native-worklets": "0.5.1",
"react-native-worklets": "0.7.4",
"zustand": "^5.0.11"
},
"devDependencies": {
"@types/react": "~19.1.0",
"typescript": "~5.9.2",
"@types/react": "~19.2.10",
"eslint": "^9.25.0",
"eslint-config-expo": "~10.0.0"
"eslint-config-expo": "~55.0.1",
"typescript": "~5.9.2"
},
"private": true
}
530 changes: 227 additions & 303 deletions bun.lock

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions packages/docs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,15 @@
"@resvg/resvg-js": "^2.6.2",
"@tanstack/react-router": "1.170.18",
"@tanstack/react-start": "1.168.32",
"react": "19.2.3",
"react-dom": "19.2.3"
"react": "19.2.0",
"react-dom": "19.2.0"
},
"devDependencies": {
"@mdx-js/rollup": "^3.1.1",
"@netlify/vite-plugin-tanstack-start": "1.3.17",
"@tailwindcss/vite": "^4.3.0",
"@types/node": "^25.9.0",
"@types/react": "~19.2.0",
"@types/react": "~19.2.10",
"@types/react-dom": "~19.2.0",
"@vitejs/plugin-react": "^6.0.2",
"geist": "^1.7.1",
Expand Down
2 changes: 1 addition & 1 deletion packages/docs/src/content/docs/adapters.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ const Stack = withScreenTransitions(NativeStack);
For Expo Router, wrap the adapted native stack with `withLayoutContext()`:

<Note>
Expo SDK 56 changes Expo Router's navigator internals. This package does not currently support SDK 56 without replacing the internal React Navigation imports with Expo Router imports.
This v3 adapter supports Expo Router through Expo SDK 55. Expo Router forked its navigation internals in SDK 56, so SDK 56+ apps must use the separate [v4 alpha Expo Router integration](/v4-experimental/getting-started).
</Note>

```tsx
Expand Down
2 changes: 1 addition & 1 deletion packages/docs/src/content/docs/custom-animations.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ Custom animations are created inside `screenStyleInterpolator`, where each scree

```tsx
import { interpolate } from "react-native-reanimated";
import { createBlankStackNavigator } from "react-native-screen-transitions/react-navigation";
import { createBlankStackNavigator } from "react-native-screen-transitions/blank-stack";

const Stack = createBlankStackNavigator();

Expand Down
18 changes: 10 additions & 8 deletions packages/docs/src/content/docs/expo-router.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,19 @@ to: /expo-router

## Overview

In v3, Expo Router integration wraps `createBlankStackNavigator()` with Expo Router's `withLayoutContext()`.
The stable v3 Expo Router integration supports Expo SDK 55 and earlier. It wraps `createBlankStackNavigator()` with Expo Router's `withLayoutContext()`, using the React Navigation-backed navigator internals available in those SDKs.

<Note>
Looking for Expo SDK 55+ support? See the [v4 documentation](/v4-experimental/getting-started).
Expo SDK 55 is the final SDK supported by this v3 integration. Expo Router forked the navigation packages it builds upon in SDK 56. For Expo SDK 56 or later, use the separate [v4 alpha Expo Router integration](/v4-experimental/getting-started).
</Note>

The SDK 56 boundary applies to Expo Router, not to Expo projects generally. An Expo app using React Navigation directly can continue to use v3. See Expo's [SDK 55 to 56 migration guide](https://docs.expo.dev/router/migrate/sdk-55-to-56/) for details about the upstream import and runtime changes.

If you want a complete reference app before integrating this into an existing project, use the [v3 Expo Router starter](https://github.com/eds2002/react-native-screen-transitions/tree/main/starters/expo-router). It pins Expo SDK 55, the final Expo Router environment supported by the v3 integration and the version used by the v3 e2e app.

## Blank Stack Layout

This is the pattern from the e2e app:
This is the v3 integration pattern used by the e2e app and starter:

```tsx
// layouts/blank-stack.tsx
Expand All @@ -39,7 +43,7 @@ import {
const { Navigator } = createBlankStackNavigator();

function BlankStackNavigator(props: ComponentProps<typeof Navigator>) {
return <Navigator {...props} nativeScreens={false} />;
return <Navigator {...props} />;
}

export const BlankStack = withLayoutContext<
Expand All @@ -50,9 +54,7 @@ export const BlankStack = withLayoutContext<
>(BlankStackNavigator);
```

The local wrapper lets your screens use screen options like `screenStyleInterpolator`, `gestureEnabled`, `snapPoints`, and `overlay`.

The blank-stack navigator itself also accepts navigator props like `independent` and `nativeScreens`. The e2e wrapper above pins `nativeScreens={false}`; remove that fixed prop if route layouts should choose the value themselves.
The local wrapper provides a stable TypeScript boundary for `withLayoutContext()` while forwarding navigator props unchanged. Native screens remain enabled by default.

## Using It In Route Layouts

Expand Down Expand Up @@ -97,7 +99,7 @@ The destination can use a matching passive `Transition.Boundary`, `Transition.Bo
## Embedded Flows

```tsx
<BlankStack independent enableNativeScreens={false}>
<BlankStack independent nativeScreens={false}>
<BlankStack.Screen name="index" />
</BlankStack>
```
Expand Down
2 changes: 1 addition & 1 deletion packages/docs/src/content/docs/gesture-ownership.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ If no screen in the current ownership chain claims that direction, the scroll vi
This is the cleanest setup: the parent owns one direction, the child screen owns another.

```tsx
import { createBlankStackNavigator } from "react-native-screen-transitions/react-navigation";
import { createBlankStackNavigator } from "react-native-screen-transitions/blank-stack";

const RootStack = createBlankStackNavigator();
const DetailsStack = createBlankStackNavigator();
Expand Down
4 changes: 2 additions & 2 deletions packages/docs/src/content/docs/independent-stacks.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ They solve different problems.
Use it when the stack lives inside another screen, sheet, host app surface, or any embedded flow that should not join the parent React Navigation tree.

```tsx
import { createBlankStackNavigator } from "react-native-screen-transitions/react-navigation";
import { createBlankStackNavigator } from "react-native-screen-transitions/blank-stack";

const Stack = createBlankStackNavigator();

Expand Down Expand Up @@ -121,7 +121,7 @@ This is usually the most predictable setup for nested flows, custom containers,
The same options are available in the static factory form:

```tsx
import { createBlankStackNavigator } from "react-native-screen-transitions/react-navigation";
import { createBlankStackNavigator } from "react-native-screen-transitions/blank-stack";

const Stack = createBlankStackNavigator({
independent: true,
Expand Down
25 changes: 24 additions & 1 deletion packages/docs/src/content/docs/installation.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,20 @@ order: 2
to: /installation
---

## Choose Your Navigation Setup

This page installs the stable v3 release.

| Navigation setup | v3 status | Next step |
| --- | --- | --- |
| React Navigation 6 or 7 | Supported | Follow this page, then [Quick Start](/quick-start). |
| Expo Router on Expo SDK 55 or earlier | Supported | Follow this page, then [Expo Router](/expo-router). |
| Expo Router on Expo SDK 56 or later | Not supported by v3 | Use the [v4 alpha installation](/v4-experimental/installation). |

<Note>
Expo SDK 55 is the final SDK supported by the v3 Expo Router integration. Expo Router changed navigation internals in SDK 56; do not combine an SDK 56+ Expo Router app with the v3 setup below.
</Note>

## 1. Install The Package

<CodeBlock
Expand Down Expand Up @@ -152,7 +166,7 @@ If this renders and navigates without Reanimated or Gesture Handler errors, the

```tsx
import Transition from "react-native-screen-transitions";
import { createBlankStackNavigator } from "react-native-screen-transitions/react-navigation";
import { createBlankStackNavigator } from "react-native-screen-transitions/blank-stack";

const Stack = createBlankStackNavigator();

Expand All @@ -173,3 +187,12 @@ export function RootNavigator() {
```

Then continue to [Quick Start](/quick-start).

## Start From A Complete App

If you are creating a new project, these starters keep the two supported v3 navigation setups separate:

- [v3 Expo Router starter](https://github.com/eds2002/react-native-screen-transitions/tree/main/starters/expo-router) — an Expo SDK 55 app exercising the final Router environment supported by the v3 `withLayoutContext()` integration.
- [v3 React Navigation starter](https://github.com/eds2002/react-native-screen-transitions/tree/main/starters/react-navigation) — upstream React Navigation with the v3 blank stack.

Both starters show the same detail transition, snap-point sheet, and paired-boundary remote-media zoom, so the only meaningful difference is the navigation host.
2 changes: 1 addition & 1 deletion packages/docs/src/content/docs/migrating-to-3-4.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ options={{
If you previously used component stack for embedded or independent flows, move that work to blank stack:

```tsx
import { createBlankStackNavigator } from "react-native-screen-transitions/react-navigation";
import { createBlankStackNavigator } from "react-native-screen-transitions/blank-stack";

const Stack = createBlankStackNavigator();

Expand Down
16 changes: 16 additions & 0 deletions packages/docs/src/content/docs/overview.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,22 @@ React Native can support smooth, 60 fps transition work across Android and iOS.

Screen Transitions is a customizable package for building transitions that used to feel out of reach in React Native.

## Navigation Compatibility

These are the supported navigation paths for the stable v3 release:

| Navigation setup | v3 status | Integration |
| --- | --- | --- |
| React Navigation 6 or 7 | Supported | Use `react-native-screen-transitions/blank-stack` or the native-stack adapter. |
| Expo Router on Expo SDK 55 or earlier | Supported | Wrap the v3 blank stack with `withLayoutContext()`. |
| Expo Router on Expo SDK 56 or later | Not supported by v3 | Use the [v4 alpha Expo Router integration](/v4-experimental/getting-started). |

<Note>
Expo SDK 55 is the last Expo Router release that uses the React Navigation-backed integration documented for v3. Expo Router forked the navigation packages it builds upon in SDK 56. See Expo's [SDK 55 to 56 migration guide](https://docs.expo.dev/router/migrate/sdk-55-to-56/) for the upstream change.
</Note>

Using React Navigation directly is still supported, including inside an Expo app. The SDK 56 boundary applies specifically to Expo Router.

## Choose A Stack

### Blank Stack
Expand Down
2 changes: 1 addition & 1 deletion packages/docs/src/content/docs/quick-start.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ to: /quick-start
>
<CodeBlock
code={`import Transition from "react-native-screen-transitions";
import { createBlankStackNavigator } from "react-native-screen-transitions/react-navigation";
import { createBlankStackNavigator } from "react-native-screen-transitions/blank-stack";

const Stack = createBlankStackNavigator();

Expand Down
2 changes: 1 addition & 1 deletion packages/docs/src/content/docs/transition-components.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import Transition, {
type ScreenTransitionConfig,
} from "react-native-screen-transitions";

import { createBlankStackNavigator } from "react-native-screen-transitions/react-navigation";
import { createBlankStackNavigator } from "react-native-screen-transitions/blank-stack";
```

Use the blank-stack subpath export to build the recommended navigator. Use `withScreenTransitions()` to adapt existing native-stack navigators. Use `Transition` for transition-aware primitives, boundary components, presets, and specs.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ order: 3
to: /getting-started
---

This page covers only the Screen Transitions navigator setup. It assumes your app already has Expo Router or React Navigation configured.
This page covers only the v4 alpha Screen Transitions navigator setup. It assumes your app already has Expo Router on Expo SDK 56 or later, or upstream React Navigation, configured.

## Expo Router

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ order: 2
to: /installation
---

<Note>
This installs the v4 alpha. Use this line for Expo Router on Expo SDK 56 or later, or to test the new Standard Navigator integration with React Navigation. Stable v3 remains the supported path for Expo Router on SDK 55 and earlier.
</Note>

## Install the package

<CodeBlock
Expand Down
6 changes: 3 additions & 3 deletions packages/docs/src/content/docs/v4-experimental/overview.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@ Use it to build custom push and dismiss animations, gesture-driven screens, snap

## One navigator, two hosts

v4's Blank Stack is a [Standard Navigator](https://reactnavigation.org/docs/standard-navigator/). The same transition navigator integrates with both React Navigation and Expo Router through host-specific package entry points.
v4's Blank Stack is a [Standard Navigator](https://reactnavigation.org/docs/standard-navigator/). The same transition navigator integrates with both upstream React Navigation and the forked Expo Router navigation runtime through host-specific package entry points.

Blank Stack is the default choice when Screen Transitions should drive the stack. `withScreenTransitions` remains available as an adapter for one-off animations inside an existing native stack.

<Note>
v4 is experimental. Its navigation and bounds APIs may change before the stable release.
v4 is alpha software. Its navigation and bounds APIs may change before the stable release. The Expo Router entry point uses Expo's alpha Standard Navigator integration, which is available in Expo SDK 56 and later.
</Note>

Continue to [Installation](/v4-experimental/installation), then connect your navigator in [Getting Started](/v4-experimental/getting-started).
Expand All @@ -42,7 +42,7 @@ export default function RootLayout() {
<BlankStack.Screen name="index" />
<BlankStack.Screen
name="detail"
options={Transition.Presets.SlideFromBottom}
options={Transition.Presets.SlideFromBottom()}
/>
</BlankStack>
</GestureHandlerRootView>
Expand Down
2 changes: 1 addition & 1 deletion packages/docs/src/lib/docs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ export const docVersions = [
{
basePath: "/v4-experimental",
id: "v4-experimental",
label: "v4 (next)",
label: "v4 (alpha)",
},
] as const satisfies ReadonlyArray<DocVersion>;

Expand Down
Loading
Loading