Skip to content

[pull] main from expo:main - #1190

Merged
pull[bot] merged 19 commits into
code:mainfrom
expo:main
Aug 27, 2026
Merged

[pull] main from expo:main#1190
pull[bot] merged 19 commits into
code:mainfrom
expo:main

Conversation

@pull

@pull pull Bot commented Aug 27, 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 : )

expo-bot and others added 19 commits August 27, 2026 12:02
…bars light (#49394)

> [!WARNING]
> **Agent-authored and NOT human-reviewed.** An automated `/verify
--fix` run for #49385 wrote this change and checked it in a sandbox; the
reasoning and evidence are in the outcome comment on that issue. Review
it as you would any external contribution.

Requested by @chrfalch · [investigation
run](https://github.com/expo/expo/actions/runs/32959146056) · refs
#49385

A `BottomSheet` with a custom background color turned the Android status
bar and navigation bar light, even in a dark app.
`ModalBottomSheetView.kt` resolves the content color with Material3's
`contentColorFor()`, which returns `LocalContentColor` for a container
color that is not a color-scheme role — and that is `Color.Black`.
Material3 themes the sheet window's system bars from the content color,
so a dark sheet asked for light system bars.

The default content color is now derived from the container color's
luminance when it matches no color-scheme role. An explicit
`contentColor`, a role color, and the theme's own container color all
resolve exactly as before. The content color also drives
`LocalContentColor` inside the sheet, so Compose content on a dark
custom background changes from black to white.

On a hosted Android emulator, a dark sheet made the status bar icons
turn black and vanish on the stock build; they stay white with this
change. The explicit-`contentColor`, light-background and theme-default
arms are identical on both builds.

<details><summary>Cause</summary>

expo-ui resolves the content color here:
https://github.com/expo/expo/blob/bde9b918e1614d69768c1f65a419f1c90a1272f5/packages/expo-ui/android/src/main/java/expo/modules/ui/ModalBottomSheetView.kt#L137-L138

The chain, in
`androidx.compose.material3:material3-android:1.5.0-alpha17` (the
version this package declares):

1. `contentColorFor(x)` is
`MaterialTheme.colorScheme.contentColorFor(x).takeOrElse {
LocalContentColor.current }`.
2. `ColorScheme.contentColorFor` returns `Color.Unspecified` for any
color that is not a color-scheme role.
3. `MaterialTheme` does not provide `LocalContentColor`. Its declared
default is `Color.Black`.
4. The sheet's own dialog window then sets `isAppearanceLightStatusBars`
and `isAppearanceLightNavigationBars` to `contentColor.isDark()`, where
`isDark()` is `luminance() <= 0.5`.

So any custom container color produced `Color.Black` and requested light
system bars. A custom container color reaches this code from
`backgroundStyle` on `@expo/ui/community/bottom-sheet`
(https://github.com/expo/expo/blob/bde9b918e1614d69768c1f65a419f1c90a1272f5/packages/expo-ui/src/community/bottom-sheet/BottomSheet.android.tsx#L75)
and from `containerColor` on the `jetpack-compose` `ModalBottomSheet`.

Sheets without a custom background were never affected:
`BottomSheetDefaults.ContainerColor` is `surfaceContainerLow`, which
maps to `onSurface` in both schemes.

The expression has resolved the content color this way since
`containerColor` and `contentColor` were added in
ff70cc3
(#43972), when the file was still named
`BottomSheetView.kt`.

</details>

<details><summary>Verification</summary>

Repro app: `create-expo-app` blank template with `userInterfaceStyle:
"dark"`, `expo@57.0.16`, `react-native@0.86.2`, `@expo/ui@57.0.13`. Two
EAS Android development builds of the same app, installed one after the
other on the same hosted emulator session; the second one carries this
change as a `patch-package` patch and compiles expo-ui from source.

The emulator draws no navigation bar — its accessibility tree has no
Back, Home or Recents node, and app content reaches the bottom edge — so
the measured quantity is the status bar icon color. Material3 sets
`isAppearanceLightStatusBars` and `isAppearanceLightNavigationBars` from
the same expression, so the status bar is a read-out of the same flag.
The white navigation bar in the linked report was not reproduced pixel
for pixel.

| arm | setup | stock build | build with this change |
| --- | --- | --- | --- |
| A | community `BottomSheet`, `backgroundStyle` `#101014` | black
icons, invisible | white icons, visible |
| B | `ModalBottomSheet`, `containerColor` `#101014` | black icons,
invisible | white icons, visible |
| C | `ModalBottomSheet`, `#101014` + `contentColor` `#FFFFFF` | white
icons, visible | white icons, visible |
| E | `ModalBottomSheet`, `containerColor` `#FFFFFF` | black icons,
correct | black icons, correct |
| F | `Host colorScheme="dark"`, theme default container color | white
icons, visible | white icons, visible |
| G | `Host colorScheme="light"`, theme default container color | black
icons, correct | black icons, correct |

Arm C isolates the mechanism: it differs from arm B only in the content
color. Arms C, E, F and G are the guards for this default change — an
explicit `contentColor`, a light custom background, and the theme's own
container color under both schemes — and they are identical on both
builds.

The device appearance setting changed between the two installs; no arm
depends on it, because A/B/C/E set their colors explicitly and F/G force
the scheme through `Host colorScheme`. An earlier arm that relied on the
emulator's own dark mode was dropped for that reason. No arm put Compose
content inside a sheet, so the `LocalContentColor` change described
above is reasoned from the code and not measured.

</details>

<details><summary>Checks run</summary>

In a checkout of this repository at
`bde9b918e1614d69768c1f65a419f1c90a1272f5` with the change applied, in
`packages/expo-ui`:

- `pnpm run typecheck` — exit 0
- `pnpm run lint` — 0 warnings, 0 errors over 345 files
- `pnpm test` — 31 suites, 174 tests, 17 snapshots, all passing

These are JavaScript checks and do not compile Kotlin. The Kotlin
compiles: the EAS Android build that carries this change builds expo-ui
from source and finished successfully.

</details>

<details><summary>Not covered</summary>

- No physical Samsung A55 and no One UI device, and the emulator draws
no navigation bar. How One UI paints a light navigation bar appearance
was not observed by this run.
- Android only. The iOS `BottomSheet` is a separate implementation and
is untouched.
- The `LocalContentColor` change inside the sheet was not measured on
device.

</details>

<!-- expo-bot:fix-options v1 -->
<details><summary>Options considered</summary>

1. **Add a `contentColor` prop to the community `BottomSheet` and
forward it, as the report proposes.** Touches
`src/community/bottom-sheet/types.ts` and `BottomSheet.android.tsx`, and
adds a prop that `@gorhom/bottom-sheet` does not have, so the component
stops mirroring the API it is compatible with. It also leaves the
default wrong, so every app with a dark `backgroundStyle` still has to
opt out. Rejected: it is an API addition that works around the defect
instead of fixing it, and `jetpack-compose`'s `ModalBottomSheet` already
accepts `contentColor` for anyone who wants to set it explicitly.
2. **Pass `isAppearanceLightStatusBars` /
`isAppearanceLightNavigationBars` through
`ModalBottomSheetProperties`.** Material3 accepts both, so the system
bars could be set directly. This needs two new record fields, two new JS
props and documentation for them, and it still needs a sensible default,
which is the same luminance decision made in a second place. Rejected:
more surface area for the same decision.
3. **Do nothing and document that a custom `backgroundStyle` needs a
matching `contentColor`.** No runtime risk. Rejected: the resulting
default is a black content color under a dark sheet, which is not a
defensible default in any theme, and it makes every app pay for a
library defect.
4. **Derive the default content color from the container color's
luminance when it matches no color-scheme role.** Chosen: it fixes the
cause in one expression, changes nothing for an explicit `contentColor`,
for a theme-role color, or for the default container color, and the four
guard arms above confirm that on device.

</details>
<!-- /expo-bot:fix-options -->

---------

Co-authored-by: expo-bot <expo-bot@users.noreply.github.com>
…entifier (#49429)

# Why

Part 1 of 2 for notification grouping via `threadIdentifier` (#28580).
This PR adds the iOS support;

`NotificationContentRecord` already declared and read back
`threadIdentifier`, but silently dropped it when building the native
notification — so the input never reached the system.

# How

- `NotificationContentRecord.toUNMutableNotificationContent` now sets
`threadIdentifier` on `UNMutableNotificationContent`, so scheduled local
notifications group natively in the notification center.
- `BackgroundEventTransformer` extracts `thread-id` from push payloads
and maps it to `threadIdentifier` in the emitted data, mirroring the
existing `categoryId` handling.

# Test Plan

- Swift Testing unit tests for the `thread-id` extraction in
`BackgroundEventTransformer`.
- Manual verification in `apps/notification-tester` on an iOS 27
simulator, driven by agent-device: scheduled 3 notifications each in
`chat-alice` and `chat-bob` threads plus one without a thread. The
notification center shows "Alice 3 notifications" and "Bob 3
notifications" stacks and one standalone notification;

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

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
# Why

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

Rounds the feedback dialog to 40px so it matches the EAS dashboard
modal, which is the same forked component at the same 500px width and
has been on `rounded-[40px]` while ours sat at 8px.

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

<img width="1106" height="1124" alt="CleanShot 2026-08-26 at 15 30
53@2x"
src="https://github.com/user-attachments/assets/50a69027-9d79-4253-bc7a-e2712f852340"
/>


# 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)
…x unloadAsync rule deletion (#49379)

# Why

Follow-up to #49266 (and closes the gap #49192 argued for). Tow issues:

1. `getFontFaceRulesMatchingResource` normalized quotes away from
**both** sides of the comparison. The left side of comparison comes from
the browsers and they report inconsistent results so we normalize it.
The right side is a literal family name, so we take it as the user
provides it.

2. `unloadAsync` deletes matching rules in ascending index order so with
more than one match it deletes wrong rules.

# How

- Normalize only the rule's side:
`normalizeFontFamilyName(rule.style.fontFamily) === fontFamilyName`.
- `unloadAsync` flip deletion order

# Test Plan

Extended `ExpoFontLoader-test.web.ts` 

# Checklist

- [ ] Documentation is up to date to reflect these changes (eg:
https://docs.expo.dev and README.md).
- [ ] Conforms with the [Documentation Writing Style
Guide](https://github.com/expo/expo/blob/main/guides/Expo%20Documentation%20Writing%20Style%20Guide.md)
- [x] This diff will work correctly for `npx expo prebuild` & EAS Build
(eg: updated a module plugin).
- [x] Added a `CHANGELOG.md` entry.

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
)

# Why

Followup to  #48087.

When navigating to a route with a loader, the loader will start to fetch
and React will suspend the route till it does. If the route is changed
before the loader settles (pressing back in the browser or swiping back
in a stack), there was no logic to clean up the in-flight request, the
request would complete and be incorrectly set in the suspense store to
be picked up by a future visit, serving potentially stale data.

# How

- `useLoaderData()` registers a "committed" subscription after a
suspended route commits
- Each fetch now has an `AbortController`. The controller aborts on
abandonment/teardown while the fetch is still in flight
- Every route now has a minimal lifecycle adapter above its Suspense
boundary. When that route's shell unmounts, it schedules abandonment of
its pending loader path

# Test Plan

- CI
- Manual testing with the `server-loader` fixture in `apps/router-e2e`:
navigate to `/slow` in a browser with DevTools open, press back before
it settles and see a cancelled network request. Navigate back to `/slow`
and ensure a new loader fetch request is triggered.

# 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)
…49056)

# Why

Fatal JavaScript errors during app startup on iOS do not show any UI at
all, instead just hanging on the splash screen at "Downloading 100%..."
or "Loading from Metro...".

| Before | After |
|---|---|
| <img width="456" height="972" alt="image"
src="https://github.com/user-attachments/assets/aedda8eb-32de-4d77-a9dc-7fb715597712"
/> | <img width="456" height="972" alt="image"
src="https://github.com/user-attachments/assets/07bb78b4-eb1d-49e7-8747-82b3b51d45da"
/> |

# How

This was due to two issues:

1. In the `RCTRedBox (WithExpoLogBox)` swizzle, we present the view
controller on the calling thread, whereas React Native's `RCTRedBox`
dispatches to the main queue. This resulted in UIKit throwing an
exception, and no sheet appearing onscreen. This was fixed by wrapping
the swizzled body in `dispatch_async(dispatch_get_main_queue(), ...)`.

2. After fixing the above, a sheet would render but without any content.
LogBox's JavaScript bundle would throw `TypeError: registerDOMComponent
is not a function` on startup. This happens because Metro skips
platform-extension resolution for `package.json`-declared `exports`, the
result of which was that web bundles would get the native `internal.ts`
where `registerDOMComponent` is `undefined`. This was fixed by changing
`dom.ts` and `internal.ts` to be barrel files re-exporting from the new
`dom/` and `internal/` subdirectories that hold the platform and
fallback logic, a similar approach as we took in #47870.

# Test Plan

Reproduced on the iOS simulator using `apps/router-e2e` with the
`server-loader` fixture and `experiments.noxcturnalTransformWorker:
true`.

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

Automated upstream sync of generated reference content.

| Generator | Status |
| --- | --- |
| App config schema | ➖ No changes |
| Expo Skills | ➖ No changes |
| EAS CLI reference | ✅ Synced |
| Android permissions | ➖ No changes |

## Files
- `docs/pages/eas/cli.mdx`
- `docs/ui/components/EASCLIReference/data/eas-cli-commands.json`

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

Resolves ENG-26210

We [added](#47108) memory warning logs
for iOS, which is published in SDK 57, but not documented.

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

# How

Document the memory warning event.

Additionally, clarify that events can be sent by `logEvent`, the SDK and
integrations.

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

# Test Plan

Review the new copy for correctness and style.

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

---------

Co-authored-by: Aman Mittal <amandeepmittal@live.com>
# Why

Add a cli tool for adding app intent scaffolding

# How

The tool introduces `npx expo-inline-modules init` command which adds
inline module scaffolding for app intents. It has a few examples:

- Minimal - minimal scaffolding with no examples
- Counter - The most basic example, good for understanding the basics
- Restaurant - Introduces shortcuts with parameters, shows how to pass
the data from JS to the Intents
- Journal - Shows app intent schemas

# Test Plan

Tested by running the cli tool in a fresh app located in `apps/`
directory

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
# Why

Adds the docs page (the API docs were added in the [1/n
commit](#47223)

# How

Add the docs

# Test Plan

Run `pnpm dev` in `docs/` directory

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
# Why

Adds AppIntents to BareExpo and NCL

# How

Add screens and appropriate native changes 

# Test Plan

Tested by running BareExpo on an iPhone 17 Pro

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
…#49441)

# Why

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

Fix ENG-26233

# How

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

Update `structured-data.ts` file

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

N/A

# 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

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

Fix ENG-26232

# How

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

Add a when-to-use section to llms.txt.

# 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.
-->
Run `pnpm generate-llms` locally and visit `/llms.txt` in a web browser.

**Preview**

<img width="3368" height="1260" alt="CleanShot 2026-08-27 at 17 39
11@2x"
src="https://github.com/user-attachments/assets/c487beac-f444-4dc9-b2a5-41be9e2905e8"
/>

# 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

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

Fix ENG-26185

# How

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

Add recommendation Software Mansion editors for rich text editing and
reorganize the guide. Also, remove outdated libraries mentions.

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

Proofread.

# 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: Kadi Kraman <hellokadi@gmail.com>
# Why

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

Follow-up #49373

# How

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

Takes the last floating surfaces off the old 6px radius, moving both
tooltip systems (Radix and the tippy code annotations) to 8px so they
finally match each other, and making the floating code copy chip a pill
like the rest of the buttons.

# 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.
-->
<img width="1336" height="500" alt="CleanShot 2026-08-26 at 15 22 20@2x"
src="https://github.com/user-attachments/assets/a665f3ad-e213-44b3-8af5-532c8108d4a9"
/>

<img width="868" height="338" alt="CleanShot 2026-08-26 at 15 22 23@2x"
src="https://github.com/user-attachments/assets/131f7ab8-9058-4769-896b-6bd1aa5485e2"
/>



# 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)
…49380)

# Why

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

Follow-up #49287

# How

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

Switches YouTube thumbnails from `maxresdefault` (1280x720) to
`sddefault` (640x480, cropped back to 16:9 by `object-cover`) and moves
the home `Talks` cards from a CSS `background-image` to a lazy `<img>`,
cutting each thumbnail from ~41 KB to ~19 KB.

On the home page that is ~350 KB and 8 fewer requests on initial load
(1573 KB → ~1220 KB, median of 5 local Lighthouse runs, CLS still 0).

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

Run docs app locally and note that thumbnails are loading.

# 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)
…49352)

# Why

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

Fix ENG-26180




https://github.com/user-attachments/assets/d74704fb-3e9b-49d4-aa22-be56783a1a3a



https://github.com/user-attachments/assets/21aeffcf-a9e4-4bcf-9c5f-b21bec8abc5f



Similar issue to #49347

# How

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

Pick the terminal package manager in CSS, not after hydration.

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


https://github.com/user-attachments/assets/cd92166f-2af6-4524-9fe5-29ffa05be0e9



https://github.com/user-attachments/assets/e6c4441b-25d8-4066-be74-811dfe34ac84



# 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)
…49371)

## Why

The `expo-splash-screen` config plugin always writes
`windowSplashScreenAnimatedIcon` as `@drawable/splashscreen_logo`, but
its image mod intentionally writes no logo resource when the plugin is
configured without an image. A valid background-only configuration
therefore fails Android resource linking.

A bounded seven-day EAS Build scan found this exact failure in 262
builds across 179 accounts and 173 apps. It occurs across Expo 57 patch
versions through 57.0.16.

[Sanitized Datadog
evidence](https://app.datadoghq.com/logs?query=service%3Aeas-build%20status%3Aerror%20sdk_version%3A57%2A%20%22resource%20drawable%2Fsplashscreen_logo%22%20%22not%20found%22&from_ts=1787119200000&to_ts=1787724000000&live=false)

## How

When no light splash image or custom drawable is configured, generate a
default `splashscreen_logo.xml` containing a transparent layer. This
preserves the existing theme reference and background-only behavior
while still allowing density-specific dark images to override the
fallback.

## Reproduction

The shared SDK 57 Build Watch harness configures the plugin with only:

```json
{
  "backgroundColor": "#123456"
}
```

- [baseline EAS
build](https://expo.dev/accounts/mustafaexpo/projects/build-watch-harness/builds/8448f84f-4d25-47e3-a154-1ecbb0c229ba)
fails during Android resource processing
- [validation EAS
build](https://expo.dev/accounts/mustafaexpo/projects/build-watch-harness/builds/ed875be9-3f84-49b0-8f18-796b88999a84)
completes successfully with the fallback

Locally, clean prebuild produced the dangling style reference with no
drawable before this change. The fixed output contains the referenced
transparent drawable. The complete regression record and classifier are
in [expo/build-watch#5](expo/build-watch#5).

## Validation

- `expo-splash-screen` Jest suite: 8 suites, 16 tests
- `expo-splash-screen` typecheck
- `expo-splash-screen` lint
- clean baseline/fixed prebuild output comparison
- EAS baseline/validation build pair


## Author

@AbbanMustafa

---------

Co-authored-by: expo-tuft[bot] <288127324+expo-tuft[bot]@users.noreply.github.com>
Co-authored-by: abbanmustafa <19319135+abbanmustafa@users.noreply.github.com>
Co-authored-by: Mathieu Acthernoene <zoontek@gmail.com>
@pull pull Bot locked and limited conversation to collaborators Aug 27, 2026
@pull pull Bot added the ⤵️ pull label Aug 27, 2026
@pull
pull Bot merged commit 589ee55 into code:main Aug 27, 2026
29 of 30 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.

7 participants