Skip to content

[pull] main from expo:main#861

Merged
pull[bot] merged 21 commits into
code:mainfrom
expo:main
May 13, 2026
Merged

[pull] main from expo:main#861
pull[bot] merged 21 commits into
code:mainfrom
expo:main

Conversation

@pull

@pull pull Bot commented May 13, 2026

Copy link
Copy Markdown

See Commits and Changes for more details.


Created by pull[bot] (v2.0.0-alpha.4)

Can you help keep this open source service alive? 💖 Please sponsor : )

TheSeydiCharyyev and others added 21 commits May 13, 2026 21:30
…on (#45716)

# Why

The "Hash support" section in
`docs/pages/router/reference/url-parameters.mdx` links to
`#local-versus-global-search-parameters`, but that anchor doesn't exist
on the page — the corresponding heading is `## Local versus global URL
parameters` (slug `local-versus-global-url-parameters`).

The anchor became stale after #29799 renamed the section from "search
parameters" to "URL parameters" to encompass both route and search
params. The cross-link in the Hash support section was missed during
that rename.

Result: clicking "search parameters" in the Hash support paragraph does
nothing.

# How

Updated the anchor in the "Hash support" section to match the current
heading slug.

### Diff

```diff
- It can be accessed and modified using the same hooks and APIs from [search parameters](#local-versus-global-search-parameters).
+ It can be accessed and modified using the same hooks and APIs from [search parameters](#local-versus-global-url-parameters).
```

# Test Plan

- Verified on http://localhost:3002/router/reference/url-parameters —
clicking the "search parameters" link in the Hash support section now
scrolls to the "Local versus global URL parameters" heading.
- Ran `pnpm lint` in `docs/` — all four checks pass (`oxfmt`, `oxlint`,
`tsc`, `eslint`).

# Checklist

- [ ] I added a `changelog.md` entry and rebuilt the package sources —
N/A (docs-only change)
- [ ] This diff will work correctly for `npx expo prebuild` & EAS Build
— N/A (docs-only change)
- [x] Conforms with the [Documentation Writing Style
Guide](https://github.com/expo/expo/blob/main/guides/Expo%20Documentation%20Writing%20Style%20Guide.md)
…45723)

# Why

Previously `pageFocused` event did fire, before screen render committed.
This caused incorrect metrics to be reported in `expo-observe`.

# How

1. Emit `pageFocused` in `useEffect` - after the render is finished

# Test Plan

1. Observe tester
2. CI

# Checklist

<!--
Please check the appropriate items below if they apply to your diff.
-->

- [ ] I added a `changelog.md` entry and rebuilt the package sources
according to [this short
guide](https://github.com/expo/expo/blob/main/CONTRIBUTING.md#-before-submitting)
- [ ] This diff will work correctly for `npx expo prebuild` & EAS Build
(eg: updated a module plugin).
- [ ] Conforms with the [Documentation Writing Style
Guide](https://github.com/expo/expo/blob/main/guides/Expo%20Documentation%20Writing%20Style%20Guide.md)

---------

Co-authored-by: Expo Bot <34669131+expo-bot@users.noreply.github.com>
# Why

Using custom param to signal that TTR is initial, is not optimal for
processing in Clickhouse.

# How

Change:
- `ttr` with `isInitial=true` to `cold_ttr`
- `ttr` with `isInitial=false` to `warm_ttr`

# Test Plan

1. Observe tester
2. CI

# Checklist

<!--
Please check the appropriate items below if they apply to your diff.
-->

- [ ] I added a `changelog.md` entry and rebuilt the package sources
according to [this short
guide](https://github.com/expo/expo/blob/main/CONTRIBUTING.md#-before-submitting)
- [ ] This diff will work correctly for `npx expo prebuild` & EAS Build
(eg: updated a module plugin).
- [ ] Conforms with the [Documentation Writing Style
Guide](https://github.com/expo/expo/blob/main/guides/Expo%20Documentation%20Writing%20Style%20Guide.md)
# Why

Handling the keyboard with native tabs, was simplified in
react-native-screens `4.25.0`. We can now expose it as a prop form
NativeTabs.

**Note**: Technically this is a breaking change on an unstable API, and
since we are in beta, I think we can add it to new features section
rather then the breaking changes

# How

Pass `tabBarRespectsIMEInsets` to screens

# Test Plan

1. Router e2e

`<NativeTabs>`

<img height="512" alt="Screenshot_1778660661"
src="https://github.com/user-attachments/assets/84c2f013-4891-4f97-ba44-ab9ca8c2a726"
/>

`<NativeTabs tabBarRespectsIMEInsets>`

<img height="512" alt="Screenshot_1778660676"
src="https://github.com/user-attachments/assets/00191c62-419c-45db-a049-645d0e5eb8dd"
/>


# Checklist

<!--
Please check the appropriate items below if they apply to your diff.
-->

- [ ] I added a `changelog.md` entry and rebuilt the package sources
according to [this short
guide](https://github.com/expo/expo/blob/main/CONTRIBUTING.md#-before-submitting)
- [ ] This diff will work correctly for `npx expo prebuild` & EAS Build
(eg: updated a module plugin).
- [ ] Conforms with the [Documentation Writing Style
Guide](https://github.com/expo/expo/blob/main/guides/Expo%20Documentation%20Writing%20Style%20Guide.md)
…eOrientations (#45733)

# Why

Fixes #45479.

`ScreenOrientationViewController.supportedInterfaceOrientations`
infinite-recurses and crashes release builds with `EXC_BAD_ACCESS`
(stack overflow) whenever `react-native-screens` per-screen orientation
is set on a screen below the root VC. The regression was introduced by
#44181 and ships in 55.0.14, 55.0.15, and current `main`.

In production (without `expo-dev-client`), `vcWithRNScreenOrientation()`
returns `self` because
`RNSScreenWindowTraits.shouldAskScreensForScreenOrientation(in: self)`
is true for the root VC. The override then evaluates
`vc.supportedInterfaceOrientations` on that same instance, which
dynamic-dispatches back into this override and never terminates. The
previous implementation called `super.supportedInterfaceOrientations` in
this branch, which is why 55.0.13 did not crash.

The crash fires once a `<Stack.Screen options={{ orientation: ... }}>`
mounts. The orientation value does not matter; the presence of the trait
on the active screen is what makes
`shouldAskScreensForScreenOrientation` return true. `expo-dev-client`
builds do not reproduce because `DevLauncherViewController` sits between
the window and `ScreenOrientationViewController`, so
`shouldAskScreensForScreenOrientation(in: self)` returns false for the
root VC and the child-search branch from #44181 takes over (returning a
non-self VC, which does not recurse). This is why the regression was not
caught when #44181 was tested.

# How

When `vcWithRNScreenOrientation()` returns `self`, fall through to
`super.supportedInterfaceOrientations` (UIKit's default resolution,
matching 55.0.13 behavior). When it returns a child VC (the
`expo-dev-client` case that #44181 was written for), keep the existing
call into the child's getter — that path was never recursive.

```swift
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
  if let vc = vcWithRNScreenOrientation() {
    if vc === self {
      return super.supportedInterfaceOrientations
    }
    return vc.supportedInterfaceOrientations
  }
  let mask = screenOrientationRegistry.requiredOrientationMask()
  return !mask.isEmpty ? mask : defaultOrientationMask
}
```

Three lines of behavioral change; the rest of the diff is a comment
update describing the new branch. Helper `vcWithRNScreenOrientation()`
is unchanged.

# Test Plan

Reproduction from #45479:
https://github.com/CacaoRick/expo-screen-orientation-55014-repro

1. `git clone
https://github.com/CacaoRick/expo-screen-orientation-55014-repro && cd
expo-screen-orientation-55014-repro`
2. Point `expo-screen-orientation` at this branch (or `yarn link` a
local build).
3. `yarn install && npx expo prebuild --clean && npx expo run:ios
--configuration Release -d`

Expected: app launches without crashing; the orientation-locked
`<Stack.Screen>` mounts and applies its orientation.

Also verified that the `expo-dev-client` path from #44181 still works:
when an intermediate VC blocks the single-level traversal,
`vcWithRNScreenOrientation()` returns a child VC (not `self`), the new
guard is skipped, and the existing call into
`child.supportedInterfaceOrientations` runs as before.

# Notes

- Regression was introduced when #44181 replaced `return
super.supportedInterfaceOrientations` with `return
vc.supportedInterfaceOrientations`. Restoring `super` for the `vc ===
self` branch is the minimal fix.
- Affects 55.0.14, 55.0.15, and `main` (any release that shipped
#44181). Maintainers may want to backport to the 55.x line.
- No CHANGELOG entry included; happy to add one in the requested format
if maintainers prefer.

# Checklist

- [x] I added a `changelog.md` entry and rebuilt the package sources
according to [this short
guide](https://github.com/expo/expo/blob/main/CONTRIBUTING.md#-before-submitting)
- Skipped pending maintainer guidance on which version section the entry
belongs in (55.x backport vs. unpublished 56.x). Will add on request.
- [ ] This diff will work correctly for `npx expo prebuild` & EAS Build
(eg: updated a module plugin).
- [ ] Conforms with the [Documentation Writing Style
Guide](https://github.com/expo/expo/blob/main/guides/Expo%20Documentation%20Writing%20Style%20Guide.md)

---------

Co-authored-by: Vojtech Novak <vonovak@gmail.com>
…45660)

# Why

`Updates.reloadAsync()` would not work on Android unless the
`Application` class implemented the deprecated `ReactApplication` class,
whici is the case for a lot of expo-brownfield users, where the host
activity belongs to the existing native app and the `Application` class
is whatever the consumer team already had (Compose, vanilla
`Application`, etc.).

# How

By using the `ReactNativeHostHandler.onDidCreateReactHost(context,
reactNativeHost)` callback from modules core, we can get a reference to
`reactNativeHost` and restart the app directly, this way skipping the
ReactApplication cast in apps that don't implement it.

# Test Plan

Manual test on Android using the existing brownfield fixtures in this
monorepo:

1. **Republish the brownfield AAR** from `apps/minimal-tester`:
   ```bash
   cd apps/minimal-tester
   npx expo-brownfield build:android --repository MavenLocal --release
   ``` 

2. **Build & launch the brownfield consumer** against the new AAR:
   ```bash
   cd apps/brownfield-tester/isolated/android
   ./gradlew installRelease
adb shell am start -n dev.expo.brownfieldintegratedtester/.MainActivity
adb logcat | grep -E
"expo.modules.updates|RelaunchProcedure|RecreateReactContext"
   ```
In the running app, exercise the fetch+reload flow (publish a no-op
update to the configured channel `u.expo.dev/ce96dd7b-…` first, then tap
the *Fetch update* + *Reload* buttons). Confirm:
- The string `"Could not reload application. Ensure you have passed the
correct instance of ReactApplication"` does **not** appear in logcat.
- Logs show `Restart from RelaunchProcedure` (or
`RecreateReactContextProcedure`).
- The brownfield activity reloads with the new JS bundle (visible UI /
state reset).

4. **Non-brownfield regression**: build any standard Expo app, call
`Updates.reloadAsync()`, and confirm reload still works. The helper
takes the legacy `ReactApplication`-cast branch first, so behavior on
existing apps is unchanged.

Automated tests for the procedures were considered but not added. I'll
follow up with a dedicated test PR later for iOS and Android.
 
 
# Checklist

<!--
Please check the appropriate items below if they apply to your diff.
-->

- [ ] I added a `changelog.md` entry and rebuilt the package sources
according to [this short
guide](https://github.com/expo/expo/blob/main/CONTRIBUTING.md#-before-submitting)
- [ ] This diff will work correctly for `npx expo prebuild` & EAS Build
(eg: updated a module plugin).
- [ ] Conforms with the [Documentation Writing Style
Guide](https://github.com/expo/expo/blob/main/guides/Expo%20Documentation%20Writing%20Style%20Guide.md)

---------

Co-authored-by: Kudo Chien <ckchien@gmail.com>
Co-authored-by: Kudo Chien <kudo@expo.dev>
# Why

<!--
Please describe the motivation for this PR, and link to relevant GitHub
issues, forums posts, or feature requests.
-->

The workspace had three `prettier` versions drifting across packages
(`3.5.3`, `3.6.2`, `3.8.3`). Running `pnpm dedupe` rehoisted the
resolution to `3.8.3`, and since 3.6 changed a few defaults, ESLint
started reporting formatting errors on every file.

# How

<!--
How did you build this feature or fix this bug and why?
-->

Aligned every workspace `prettier` devDependency on `^3.8.3` and
refreshed the lockfile (and run `pnpm dedupe`).

# Test Plan

<!--
Please describe how you tested this change and how a reviewer could
reproduce your test, especially if this PR does not include automated
tests! If possible, please also provide terminal output and/or
screenshots demonstrating your test/reproduction.
-->

- `pnpm-lock.yaml` now resolves a single `prettier@3.8.3`.
- `pnpm install` then `pnpm dedupe` produces no further changes.

# Checklist

<!--
Please check the appropriate items below if they apply to your diff.
-->

- [ ] I added a `changelog.md` entry and rebuilt the package sources
according to [this short
guide](https://github.com/expo/expo/blob/main/CONTRIBUTING.md#-before-submitting)
- [ ] This diff will work correctly for `npx expo prebuild` & EAS Build
(eg: updated a module plugin).
- [ ] Conforms with the [Documentation Writing Style
Guide](https://github.com/expo/expo/blob/main/guides/Expo%20Documentation%20Writing%20Style%20Guide.md)
# Why

Because `expo-observe` didn't know that route was preloaded it was
incorrectly reporting, the preloaded routes as `cold_ttr` instead of
warm one

# How

1. Expose `pagePreloaded` listener from router
2. When route is preloaded add it to rendered screens, but don't report
any metric

# Test Plan

1. CI
2. Observe tester

# Checklist

<!--
Please check the appropriate items below if they apply to your diff.
-->

- [ ] I added a `changelog.md` entry and rebuilt the package sources
according to [this short
guide](https://github.com/expo/expo/blob/main/CONTRIBUTING.md#-before-submitting)
- [ ] This diff will work correctly for `npx expo prebuild` & EAS Build
(eg: updated a module plugin).
- [ ] Conforms with the [Documentation Writing Style
Guide](https://github.com/expo/expo/blob/main/guides/Expo%20Documentation%20Writing%20Style%20Guide.md)
# Why

Add screen with examples for testing router integration

# How

<!--
How did you build this feature or fix this bug and why?
-->

# Test Plan

<!--
Please describe how you tested this change and how a reviewer could
reproduce your test, especially if this PR does not include automated
tests! If possible, please also provide terminal output and/or
screenshots demonstrating your test/reproduction.
-->

# Checklist

<!--
Please check the appropriate items below if they apply to your diff.
-->

- [ ] I added a `changelog.md` entry and rebuilt the package sources
according to [this short
guide](https://github.com/expo/expo/blob/main/CONTRIBUTING.md#-before-submitting)
- [ ] This diff will work correctly for `npx expo prebuild` & EAS Build
(eg: updated a module plugin).
- [ ] Conforms with the [Documentation Writing Style
Guide](https://github.com/expo/expo/blob/main/guides/Expo%20Documentation%20Writing%20Style%20Guide.md)
…g available in SDK 56 and later (#45736)

# Why

Fixes #45710

# How

Added warning callout under "Loading states with Suspense fallback"

# Test Plan

Docs-only change

# Checklist

- [ ] I added a `changelog.md` entry and rebuilt the package sources
according to [this short
guide](https://github.com/expo/expo/blob/main/CONTRIBUTING.md#-before-submitting)
- [x] This diff will work correctly for `npx expo prebuild` & EAS Build
(eg: updated a module plugin).
- [x] Conforms with the [Documentation Writing Style
Guide](https://github.com/expo/expo/blob/main/guides/Expo%20Documentation%20Writing%20Style%20Guide.md)
…gin-react-hooks@^7.0.0` (#43820)

# Why

Fixes #44237, #45036, #45603

React Compiler consolidated its ESLint rules into
`eslint-plugin-react-hooks@^7`. The standalone
`eslint-plugin-react-compiler` package is now considered deprecated ([as
it was last updated 10 months
ago](https://www.npmjs.com/package/eslint-plugin-react-compiler)),
however our ESLint configs (`eslint-config-expo` and
`eslint-config-universe`) still depend on
`eslint-plugin-react-hooks@^5`, which meant:

1. Users didn't get compiler lint rules out-of-the-box
2. Users who manually installed `eslint-plugin-react-hooks@^7` alongside
`eslint-config-expo` got "Cannot redefine plugin 'react-hooks'" errors
due to npm resolving two different major versions

# How

Bumped `eslint-plugin-react-hooks` from `^5.1.0` to `^7.0.0` in both
`eslint-config-expo` and `eslint-config-universe`.

# Test Plan

- CI
- Manual testing

# Checklist

- [x] I added a `changelog.md` entry and rebuilt the package sources
according to [this short
guide](https://github.com/expo/expo/blob/main/CONTRIBUTING.md#-before-submitting)
- [x] This diff will work correctly for `npx expo prebuild` & EAS Build
(eg: updated a module plugin).
- [ ] Conforms with the [Documentation Writing Style
Guide](https://github.com/expo/expo/blob/main/guides/Expo%20Documentation%20Writing%20Style%20Guide.md)

---------

Co-authored-by: Aman Mittal <amandeepmittal@live.com>
# Why
Parity with expo/eas-cli#3398 - we want to use
the new auth flow provided by website/www. This PR depends on
expo/universe#26792.

# How
Mirrored the OAuth 2.0 authorization code flow with PKCE from
[eas-cli#3542](expo/eas-cli#3542) into
`getSessionUsingBrowserAuthFlowAsync`:
- On login, generate `code_verifier`, `state`
`code_challenge`/`code_verifier` per OAuth2.1
  - Open the browser to `${websiteUrl}${sso ? '/sso-login' :
  '/login'}?<oauth-params>
- On the local callback, validate the returned `state` against the
generated one, then exchange the `code` for session secret
- `--browser` and `--sso` continue to share the same launcher — the only
difference is the website route (`/login` vs `/sso-login`).

Also updated `getExpoWebsiteBaseUrl()` to return `http://expo.test`
under `EXPO_LOCAL` (matching eas-cli), so the local Next.js dev server
can correctly serve its asset chunks under the expected `Host` header.

# Test Plan
Made sure --browser works for both regular users and sso users, both
when already logged in on website and not already logged in.

# Checklist

<!--
Please check the appropriate items below if they apply to your diff.
-->

- [ ] I added a `changelog.md` entry and rebuilt the package sources
according to [this short
guide](https://github.com/expo/expo/blob/main/CONTRIBUTING.md#-before-submitting)
- [ ] This diff will work correctly for `npx expo prebuild` & EAS Build
(eg: updated a module plugin).
- [ ] Conforms with the [Documentation Writing Style
Guide](https://github.com/expo/expo/blob/main/guides/Expo%20Documentation%20Writing%20Style%20Guide.md)
# Why

React Native is deprecating the `pointerEvents` component prop in favor
of the `pointerEvents` style property. This change migrates all usages
in the forked react-navigation views within expo-router to use the
style-based approach.

Also converts several `Platform.OS` checks to `process.env.EXPO_OS`
because it shakes with a bit less bundler complexity.

# How

- Moved all `pointerEvents` prop usages to the `style` prop across
Header, BottomTabBar, Card, CardStack, CardContent, CardA11yWrapper,
HeaderContainer, HeaderSearchBar, ResourceSavingView, and Screen
components.
- For static values, moved `pointerEvents` into `StyleSheet.create`
definitions.
- For dynamic values, inlined `pointerEvents` in the style array.
- Replaced `Platform.OS` with `process.env.EXPO_OS` where applicable.

# Test Plan

- Existing tests pass.
- Visual behavior should be unchanged since `pointerEvents` as a style
property is functionally equivalent to the component prop.

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@pull pull Bot locked and limited conversation to collaborators May 13, 2026
@pull pull Bot added the ⤵️ pull label May 13, 2026
@pull pull Bot merged commit 1182907 into code:main May 13, 2026
27 of 34 checks passed
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.