Skip to content

[pull] main from expo:main#953

Merged
pull[bot] merged 22 commits into
code:mainfrom
expo:main
Jun 10, 2026
Merged

[pull] main from expo:main#953
pull[bot] merged 22 commits into
code:mainfrom
expo:main

Conversation

@pull

@pull pull Bot commented Jun 10, 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 : )

lukmccall and others added 22 commits June 10, 2026 12:01
…e tab (#46445)

# Why

Even when tab is disabled, `tabPress` should be emitted, to allow for
custom actions

# How

Emit `tabPress` with `isPrevented: true`

# Test Plan

Router e2e


https://github.com/user-attachments/assets/0261a31e-a0ac-4a9c-8af1-bbc53beafb96

# 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>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Updates the Expo Skills install docs to use the official Claude Code
plugin from the claude-plugins-official marketplace.
- Adds Codex install instructions for the openai-curated Expo plugin
# Why

Our CI started failing on checkout with a 403 when cloning the
`react-native-lab/react-native` submodule. The cause is upstream:
`react-native` was transferred to the new `react` GitHub org, and that
repo (the root of the fork network) is currently disabled, so every fork
in the network, including ours, is blocked from git access. The
submodule clone fails before any job can run.

While investigating, it turned out most workflows don't actually need
the fork at all. Only Expo Go (and `eas-expo-go`) builds React Native
from the fork's source. Everything else builds against the published
`react-native` package from npm.

So those workflows were cloning a large submodule on every run for
nothing, and the upstream outage took them all down even though none of
them depend on the fork.

# How

- Removed `submodules: true` from the workflows that build against
published `react-native` (unit tests, test suites, xcframework/prebuild
jobs, native-component-list, lint).
- Moved the only Expo Go specific CI step (the Android `spotlessCheck`,
which configures the fork via Gradle `includeBuild`) into a new
`expo-go-android-lint` workflow that owns the submodule.
`android-unit-tests` no longer touches the fork.
- Removed the unused `hermes-engine-aar` cache from the `expo-caches`
action. No workflow set the input or read the output, and its only
consumer is an Expo Go source build that doesn't run in CI.

The result is that `react-native-lab` is referenced by Expo Go specific
workflows only, so an upstream fork outage can no longer break unrelated
jobs.

# Test Plan

CI is the test here. Since the fork is currently unreachable, any
workflow that still cloned it was failing at checkout, so the decoupled
workflows flipping back to green confirms they don't need it. Validated
each edited file parses as valid YAML and that `react-native-lab` /
`submodules: true` now appears only in the Expo Go workflow.

# 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)
- [ ] 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)
## Summary
- always generate `AGENTS.md` for create-expo projects
- generate `CLAUDE.md` and `.claude/settings.json` only when Claude Code
is detected
- cover global and project Claude Code detection signals in tests

## Test plan
- run `create-expo-app` without global Claude Code configuration ->
verify the `CLAUDE.md` and `.claude/settings.json` is not included in
the newly created app
## Summary

Upstreaming from Turborepo branch:
[`@kitten/chore/add-turborepo-3`](https://github.com/kitten-agent/expo/tree/%40kitten/chore/add-turborepo-3)
/
[`@kitten/chore/add-turborepo-2`](https://github.com/expo/expo/tree/%40kitten/chore/add-turborepo-2)

`@expo/log-box` missed some refactors that were already done on main
(e.g. obsolete `React` import, missing `type` annotations, etc) due to
it extending an incorrect `tsconfig.json` base, since it mixed Node and
non-Node source.

## Set of changes

- Add missing `type` export declarations
- Remove obsolete `React` imports
- Fix up `tsconfig.json` preset

## Checklist

**No user-facing changes**

<!--
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)
…ci & workerd) (#46728)

## Summary

Upstreaming from Turborepo branch:
[`@kitten/chore/add-turborepo-3`](https://github.com/kitten-agent/expo/tree/%40kitten/chore/add-turborepo-3)
/
[`@kitten/chore/add-turborepo-2`](https://github.com/expo/expo/tree/%40kitten/chore/add-turborepo-2)

Depending on how `expo-server` is accessed and built, `@types/node`,
`undici-types`, and `@cloudflare/workers-types` won't be added to add
declaration for some fetch-related types. We should explicitly mark
these to avoid any type errors on build (or in user declarations)

## Set of changes

- Add annotations where needed for one-off global fetch type declaration
merges

## Checklist

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

- [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)
- [ ] 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)
## Summary

Upstreaming from Turborepo branch:
[`@kitten/chore/add-turborepo-3`](https://github.com/kitten-agent/expo/tree/%40kitten/chore/add-turborepo-3)
/
[`@kitten/chore/add-turborepo-2`](https://github.com/expo/expo/tree/%40kitten/chore/add-turborepo-2)

Depending on the `tsconfig.json` and resolution of `expo-modules-core`
it won't be guaranteed to have `window` typings available to it, and
they shouldn't be treated as essential to `expo-modules-core`'s
behaviour either, so we can declare them as one-offs.

## Set of changes

- Add `declare const window` definitions

## Checklist

**No user-facing changes**

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

- [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)
- [ ] 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)
## Summary

Related to #46720

Upstreaming from Turborepo branch:
[`@kitten/chore/add-turborepo-3`](https://github.com/kitten-agent/expo/tree/%40kitten/chore/add-turborepo-3)
/
[`@kitten/chore/add-turborepo-2`](https://github.com/expo/expo/tree/%40kitten/chore/add-turborepo-2)

Depending on the `tsconfig.json` and resolution of `@expo/metro-runtime`
it won't be guaranteed to have `window` / `global` typings available to
it, and they shouldn't be treated as essential to
`@expo/metro-runtime`'s behaviour either, so we can declare them as
one-offs.

## Set of changes

- Add `declare const global` / `declare const window` definitions where
applicable
- Remove redundant `declare` from `react-native`'s `SyntheticError`
declaration (already in declare block)

## Checklist

**No user-facing changes**

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

- [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)
- [ ] 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


[Requested](https://discord.com/channels/695411232856997968/1504711019199467550/1509370597011099699)
by discord user petro.s. Adds the SwiftUI `minimumScaleFactor` view
modifier to `@expo/ui`, so text can scale down to fit the available
space before truncating.

# How

- Add `MinimumScaleFactorModifier` (a `ViewModifier`/`Record` wrapping
`content.minimumScaleFactor(factor)`) and register it under
`minimumScaleFactor` in `ViewModifierRegistry`.
- Add the `minimumScaleFactor(factor)` export in `swift-ui/modifiers`
with TSDoc mirroring the SwiftUI reference.
- Rebuild package declarations and regenerate the unversioned + SDK 56
docs API data.

# Test Plan

- `pnpm --filter @expo/ui build` and `pnpm --filter @expo/ui lint
--max-warnings 0` pass; docs API data regenerated for unversioned + SDK
56.
- Repro: apply `minimumScaleFactor(0.5)` with `lineLimit(1)` to a `Text`
whose content overflows, and confirm it scales down to fit instead of
truncating.

# 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)
- [ ] 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)
# Why

Speeds up our two slow CI workflows, based on recent run timings:

- **iOS Unit Tests** (~42 min): recompiles React Native C++ from scratch
every run with no compiler cache.
- **CLI** (~24 min): `playwright-ubuntu` ran the whole suite in one
unsharded job, and the slow Windows matrix ran on every PR.

# How

- **iOS Unit Tests:** enable ccache, mirroring the Test Suite setup
(`setup-ccache` + `ccache: 'true'` on `expo-caches`, with `ccache -s`
logging the hit rate).
- **CLI:** shard `playwright-ubuntu` into a 4-way matrix like the jest
jobs (report artifacts renamed `playwright-report-<os>-<shard>`, which
also fixes a latent `upload-artifact@v4` name collision).

# Test Plan

CI verifies it. The `ccache -s -v` step shows the iOS hit rate (cold on
the first run, hits on the next), the Playwright shards run in parallel
under the old single-job time, and Windows no longer runs on PRs.

# 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)
- [ ] 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


[Requested](https://discord.com/channels/695411232856997968/1504711019199467550/1509312192426676386)
on discord by `jsdev.robin`. Useful to get x, y, height, width of views.

# How

- **Android** — adds an `onGloballyPositioned` modifier wrapping
Compose's `Modifier.onGloballyPositioned`. It reports `{ x, y, width,
height }`, where `x`/`y` are the view's position in the window via
`positionInWindow()`. All values are in dp.
- **iOS** — extends the existing `onGeometryChange` modifier to also
report position. It now observes `frame(in: .global)` and reports `{ x,
y, width, height }` (previously size-only). The now-redundant
`#available(iOS 16.0)` guard was dropped, since the package's deployment
target is iOS 16.4.


### Alternative: imperative / on-demand reads

- Put a `ref` on `<Host>` and call `ref.current.measure(...)` /
`ref.current.measureInWindow((x, y, w, h) => …)`. `Host` is the real
bridged native view, so RN's measurement works on it directly.
- Or place a regular RN `<View>` inside the hosted tree via `RNHostView`
and call `measure` / `measureInWindow` on that view's ref.

A dedicated imperative `measure()` on the expo-ui primitives could be
added later if there's demand.

# Test Plan

- NCL → UI → **Modifiers** screen has a new section
(`onGloballyPositioned` on Android, `onGeometryChange (position + size)`
on iOS) that renders a box and shows its live window x/y and size.
- `pnpm build` and `pnpm lint --max-warnings 0` pass in
`packages/expo-ui`; the regenerated `build/` type declarations are
committed.



https://github.com/user-attachments/assets/480ac428-8a11-4cef-a425-c0561a96402a




# Checklist

- [x] Added a `CHANGELOG.md` entry.
- [x] Rebuilt the package's sources and committed `build/`.
- [ ] Documentation update (`et gdad`) — can follow up if wanted.
)

# Why

Resolves #46680

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

# How

Added `ignoresafearea=all` to Host of DateTimePicker, MenuView, Picker
and Slider.
<!--
How did you build this feature or fix this bug and why?
-->

# Test Plan

Tested in the repro.

<!--
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)
…6748)

# Why

GitHub Actions warn that several actions still run on the deprecated
Node.js 20 runtime:

> Node.js 20 actions are deprecated. […] Actions will be forced to run
with Node.js 24 by default starting June 16th, 2026. Node.js 20 will be
removed from the runner on September 16th, 2026.

The affected actions were `pnpm/action-setup`, `actions/setup-node`,
`actions/upload-artifact`, and `actions/download-artifact`.

# How

Bumped each deprecated action to the latest release that runs on the
Node.js 24 runtime, keeping the repo's existing convention of pinning to
a full commit SHA with a `# vN` comment:

| Action                      | Before | After          |
| --------------------------- | ------ | -------------- |
| `pnpm/action-setup`         | v4     | v6 (`0e279bb`) |
| `actions/setup-node`        | v4     | v6 (`48b55a0`) |
| `actions/upload-artifact`   | v4     | v5 (`330a01c`) |
| `actions/download-artifact` | v4     | v5 (`634f93c`) |

# Test Plan

These actions run only in CI, so they're exercised by the existing
workflow runs on this PR. After the change there should be no more
"Node.js 20 actions are deprecated" warnings in the workflow logs, and
the pnpm/Node setup, artifact upload, and artifact download steps
continue to pass.

# 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)
…y changes (#46747)

## Why

Prebuilt external (third-party) iOS XCFrameworks were only ever
regenerated by manually dispatching the workflow. When a supported
external package's pinned version or patch changed, someone had to
remember to run the prebuild and publish the new tarballs to GCS by
hand.

## How

Added `push` (main, sdk-*) and `pull_request` triggers. 

Path is pre-filtered to the files that can affect an external prebuild:
`apps/bare-expo/package.json`, patches/**, external SPM configs, and the
workflow itself.

Added a fast `detect` job that diffs the event base against HEAD and
emits the list of supported external packages whose SPM config, pnpm
patch, or pinned version actually changed.

The patch -> package map is derived at runtime from
pnpm-workspace.yaml's patchedDependencies, so adding a patched package
needs no edits here. `patches/**` is intentionally broad; detect ignores
patches that don't map to a supported package.

Gate `prebuild` on detect: it runs only when something relevant changed
and builds just those packages (via INPUT_PACKAGES) instead of all
externals. push runs publish to GCS automatically; pull_request
validates only (publish stays gated to push / manual dispatch with repo
== expo/expo). Manual workflow_dispatch behaves exactly as before.

Stop checking out submodules for the prebuild/detect jobs; the external
prebuild resolves sources from node_modules and doesn't need them.

## Test Plan

- Validated the workflow YAML parses and the shared `paths:` anchor
resolves identically for push and pull_request.
- Simulated the detect script against the repo: the patch map derived
from pnpm-workspace.yaml resolves all patched dependencies correctly
(scoped names and @Version suffixes handled), and every external config
dir maps to its expected patch (incl. react-native-gesture-handler for
when a config is added).
- Confirmed `et prebuild --external-only <name>` accepts the npm package
name detect emits (getExternalPackageByName resolves
external-configs/ios/<name>).
- Before merge, verify on a branch: (1) bump one external dep in
apps/bare-expo/package.json -> detect lists only that package and
prebuild runs scoped; (2) edit an unrelated patch -> detect reports
nothing and prebuild is skipped; (3) one workflow_dispatch run still
honors its inputs.
# Why

Widgets can render before the app has launched for the first time. In
that state, layouts registered at runtime with `createWidget` are not
available yet, so iOS will show a blank widget.

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

# How

- Add `ios.initialLayout`with a relative path for widget to `app.json`.
- Config plugin will create a layout registry with a paths to widgets.
- Evaluate the files on the build time with minimal metro runtime
(ignore all imports, we need only the createWidget and string function).

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

# Test Plan

Create new widget with initialLayout and do not open the app.

<!--
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.
-->

- [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).
- [x] Conforms with the [Documentation Writing Style
Guide](https://github.com/expo/expo/blob/main/guides/Expo%20Documentation%20Writing%20Style%20Guide.md)
# Why

To display widgets that require props _before the first app open_ we
need to provide initial properties for that widget.

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

# How

Add `initialProps` to layout registry. `createWidget` receives it as a
third argument.

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

# Test Plan

Create a widget that receives props and build iOS app, do not open the
app and add the widget.

<!--
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.
-->

- [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).
- [x] Conforms with the [Documentation Writing Style
Guide](https://github.com/expo/expo/blob/main/guides/Expo%20Documentation%20Writing%20Style%20Guide.md)
# Why

`FieldGroup` renders nothing on iOS inside `<Host matchContents>`. 

Fixes - #46203

# How

- Add a note to the `FieldGroup` docs (unversioned and v56.0.0): it
scrolls, has no intrinsic height, and needs a parent with a definite
size (`<Host style={{ flex: 1 }}>` or an explicit height), not
`matchContents`.

# Test Plan

Docs-only change.

# Checklist

- [x] Documentation is up to date to reflect these changes (eg:
https://docs.expo.dev and README.md).
- [x] This diff will work correctly for `npx expo prebuild` & EAS Build
(eg: updated a module plugin).
…a transition cross-fade (#46752)

# Why

Fixes [#46703](#46703).

On Android, an `<Image>` with a `transition` goes blank if its `source`
changes while the cross-fade is still running. `onLoad` fires and the
bitmap is in memory, but nothing shows.

# How

The cross-fade recycles the outgoing view in a `withEndAction`. Since
the wrapper reuses two views, a mid-transition source change can hand
the new image to that same view. Starting its fade-in cancels the old
animation, and `ViewPropertyAnimator` runs the end action on cancel, so
the stale recycle clears the view that now holds the new image.

Now we capture which target the outgoing view holds and only recycle it
if the view still holds that target, so a repurposed view is left alone.

# Test Plan

No native test harness for this package, so verified manually with the
repro from the issue (`transition={200}`, placeholder swapped for a
remote URI after a `setTimeout`):

- Before: image stays blank after the remote loads.
- After: remote image cross-fades in.

Also confirmed `transition={0}` and static sources still work.

# 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)
- [ ] 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>
@pull pull Bot locked and limited conversation to collaborators Jun 10, 2026
@pull pull Bot added the ⤵️ pull label Jun 10, 2026
@pull pull Bot merged commit 5a22445 into code:main Jun 10, 2026
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.

9 participants