1562 Commits
Author SHA1 Message Date
Zeya PengandAlex Hunt 9a7b821a02 Fix TS exactOptionalPropertyTypes compatibility for generated types (#57628) (#57699)
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/57628

NOTE: Patches over a `flow-api-translator` bug, which I'll fix upstream later. We need to pick this to `0.87-stable` to resolve user integration issues.

**Context**

TypeScript's `exactOptionalPropertyTypes` flag (strict mode) creates a distinction between `foo?: T` and `foo?: T | undefined`.

```js
// Flow's semantics

interface Props {
  onRefresh?: () => void;
}
const a: Props = { onRefresh: undefined }; // ✅ ok
```
```ts
// TypeScript with exactOptionalPropertyTypes: true (i.e. strict mode)

interface Props {
  onRefresh?: () => void;
}
const a: Props = { onRefresh: undefined }; // ❌ error

interface PropsFixed {
  onRefresh?: (() => void) | undefined;
}
const b: PropsFixed = { onRefresh: undefined }; // ✅ ok
```

With this added strictness in TypeScript, our generated types via `flow-api-translator` could create downstream type incompatibility in apps.

**This diff**

Patches the above issue in React Native's Flow → TS `types_generated/` pipeline. We transform all instances to the wider `foo?: T | undefined` format, for maximum compatibility.

**Notes**

`foo?: T [| undefined]` **remains stripped** in the API snapshot (existing transform with the aim of a concise format). There is a net, nonfunctional snapshot diff around function members, which (as a positive result) are re-ordered.

Changelog:
[General][Fixed] - **Strict TypeScript API**: Optional property types are now widened to explicitly include `| undefined` for `exactOptionalPropertyTypes` compatibility

Reviewed By: cipolleschi

Differential Revision: D113030161

fbshipit-source-id: 3ab005edab6b80b18fbb9ae7125ba56e3bd94195

Co-authored-by: Alex Hunt <huntie@meta.com>
2026-07-27 09:35:50 -04:00
Christian Falch 330080c46b fix(iOS): make jsinspector-modern tracing state types move-only for Swift C++ interop (#57605)
Summary:
The nightly-tests job `[ios] react-native-unistyles` fails on Xcode 26.3 with:

```
error: no matching function for call to '__construct_at'
note: in instantiation of member function 'std::vector<...RuntimeSamplingProfile>::vector' requested here
note: in implicit copy constructor for 'facebook::react::jsinspector_modern::tracing::TraceRecordingState' first required here
```

while compiling the **Swift** files of the Unistyles pod. The same failure hits any library built with Swift C++ interop (`-cxx-interoperability-mode=default`) — in practice, every Nitro-based library — against the prebuilt React Native core.

### The error

`TraceRecordingState` and `HostTracingProfile` hold `std::vector`s of move-only types (`RuntimeSamplingProfile` and `FrameTimingSequence` explicitly delete their copy constructors). Here's the C++ subtlety: `std::vector<T>`'s copy constructor is **declared for every `T`** — it only becomes ill-formed when *instantiated*. So the implicit copy constructors of these two structs are not implicitly deleted; they exist as declared-but-broken constructors that hard-error the moment anything asks for a copy.

### Why React Native compiles fine today

Nothing in RN ever asks. Every usage passes these types by reference; the single constructions move. A pure C++ (or ObjC++) build never instantiates the implicit copy constructors, so this code has always compiled — and always would, no matter how much C++ CI you throw at it. The defect is unobservable from within C++.

### What fails, and why now

The prebuilt-core headers now ship as real clang modules. A Swift target with C++ interop imports them (directly or transitively — e.g. via a module member whose `#ifdef __cplusplus` body opens because interop builds modules with C++ enabled), and Swift's ClangImporter surfaces the C++ value types to Swift as copyable. When the consumer's generated interop code then uses such a type as a Swift value — for a Nitro-based library, the nitrogen-generated `*_cxx.swift` bridging does exactly this — the compiler **synthesizes a copy of the type, instantiating the ill-formed implicit copy constructor**. That is the "ask" that plain C++ never makes; on Xcode 26.3 it hard-errors the entire module import, killing every Swift file in the consumer. (Newer Swift toolchains treat such types as non-copyable instead of failing.)

Before the prebuilt-modules work there was no Swift-visible module containing these headers, so no interop consumer ever imported these types — which is why this surfaces now despite the C++ being unchanged.

We deliberately did **not** fix this by removing headers from the module maps: the guarded-C++-in-modules pattern is shared by ~30 legitimately modular headers and is benign in all but this one shape, and experiments showed the type is reachable through multiple independent module surfaces (removing one member just moved the error to the next path).

### The fix

Declare the truth: make both types explicitly move-only.

```cpp
TraceRecordingState(const TraceRecordingState &) = delete;
TraceRecordingState &operator=(const TraceRecordingState &) = delete;
TraceRecordingState(TraceRecordingState &&) = default;
TraceRecordingState &operator=(TraceRecordingState &&) = default;
```

With the copy constructor explicitly deleted, Swift's importer sees a non-copyable type and imports it as such instead of instantiating a broken copy. It is also simply more correct C++: these types were never copyable in practice, and the explicit deletion turns any future accidental copy into a clear compile error at the call site instead of a template backtrace.

Declaring special members makes `HostTracingProfile` a non-aggregate, so its one designated-initializer construction site (`HostTargetTraceRecording.cpp`) is converted to member-wise assignment.

A sweep of the affected header surface (`std::vector`/`std::map`/`std::deque` of move-only element types) found exactly these two types; a follow-up adds a `headers-verify.js` gate that imports the shipped modules under Swift C++ interop at prebuild time, so the next type with this shape fails RN's own CI instead of community nightlies.

## Changelog:

[IOS] [FIXED] - Fix Swift C++-interop build failure (implicit copy constructor of TraceRecordingState/HostTracingProfile) for libraries using cxx interop with prebuilt React Native core

Pull Request resolved: https://github.com/react/react-native/pull/57605

Test Plan:
On a fresh RN-nightly app with stock `react-native-unistyles@3.3.0` + `react-native-nitro-modules`, prebuilt core (`RCT_USE_RN_DEP=1 RCT_USE_PREBUILT_RNCORE=1`), Xcode 26.3:

- **Red**: stock headers reproduce the CI failure exactly (`__construct_at` → `TraceRecordingState`). Fixing only `TraceRecordingState` then surfaces the identical failure on `HostTracingProfile` — confirming the shape, not the type, is the bug.
- **Green**: with both headers fixed (stock module maps, nothing else changed): BUILD SUCCEEDED — zero `__construct_at`, zero `shadowNodeFromValue`, zero module errors.
- All RN-internal usages audited: references and moves only; no behavior change. Plain C++/ObjC++ compilation unaffected by construction.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Reviewed By: fabriziocucci

Differential Revision: D112802806

Pulled By: cipolleschi

fbshipit-source-id: d2ae201c1fbb4de040f51ebc88263c7347b5979b
2026-07-27 13:24:52 +00:00
Riccardo Cipolleschi 50bad79b42 Fix post-release workflow failures (#57627)
Summary:
Fixes the three post-release failures from the [0.87.0-rc.2 publish run](https://github.com/react/react-native/actions/runs/29775529785/):

- Keep Flow annotations in `verifyArtifactsAreOnMaven.js` as comments so `actions/github-script` can load the file with plain Node.
- Pin the Podfile lock workflow to `macos-15`, which provides the configured Xcode 16.4 version.
- Use the canonical `react/react-native` owner for release asset API operations so upload POST requests are not redirected from the former owner.

## Changelog:

[INTERNAL] [FIXED] - Fix post-release Maven verification, Podfile lock, and release asset jobs

Pull Request resolved: https://github.com/react/react-native/pull/57627

Test Plan:
```sh
node --check .github/workflow-scripts/verifyArtifactsAreOnMaven.js
node --check scripts/releases/upload-release-assets-for-dotslash.js
yarn jest .github/workflow-scripts/__tests__/verifyArtifactsAreOnMaven-test.js scripts/releases/__tests__/upload-release-assets-for-dotslash-test.js --runInBand
```

13 tests and 15 snapshots pass.

Reviewed By: zeyap

Differential Revision: D113032768

Pulled By: cipolleschi

fbshipit-source-id: df5f493603e6c25157fd7660b54aa409dcb742e7
2026-07-27 13:24:23 +00:00
Riccardo CipolleschiandChristian Falch 486df8d410 [0.87] Pick SwiftPM support chain (#57442, #57332, #57564) (#57578)
Co-authored-by: Christian Falch <christian.falch@gmail.com>
2026-07-16 15:56:54 +02:00
Christian Falch e325575445 feat(iOS): serve third-party deps from the prebuilt ReactNativeDependencies pod via dependency-only facades (#57440)
Summary:
Step 1 of making the prebuilt `ReactNativeDependencies` pod the **single header authority** for the third-party C/C++ deps (RCT-Folly, glog, boost, DoubleConversion, fmt, fast_float, SocketRocket) in prebuilt-deps mode.

Today the deps **binary** replaces the source pods' code, but the pod still `s.dependency`'s the real source pods and borrows their headers via `$(PODS_ROOT)/<pod>` search paths. That split header authority is the dual-copy bug class behind the 2026-07-03 SocketRocket regression (`duplicate interface` under `use_frameworks!` — SocketRocket's ObjC headers have no include guards).

Three commits:

1. **fix(cocoapods): harden prebuilt-deps header search paths and artifact handling** — `rndependencies.rb`'s `||= [] << path` only added the deps header search path when `HEADER_SEARCH_PATHS` was unset (silently dropped otherwise); normalize and always append, and point at the pod-local flattened `Headers/`. `ReactNativeDependencies.podspec` `prepare_command` now fails closed (`exit 1`) instead of silently producing a no-link pod. `reactNativeDependencies.js` no longer deletes + re-downloads a locally staged artifact that lacks a version marker.

2. **feat(cocoapods): dependency-only facades for third-party pods in prebuilt-deps mode** — in prebuilt-deps mode the real source pods are not declared, so a community podspec's hardcoded `s.dependency "RCT-Folly"` would resolve from trunk and compile from source next to the prebuilt binary. `RNDepsFacades` generates dependency-only local facade podspecs (no sources, no headers, a single dependency on `ReactNativeDependencies`); versions/subspecs are derived from the real podspecs in `third-party-podspecs/` (SocketRocket synthesized fail-closed from `socket_rocket_config`). Full contract documented in `scripts/cocoapods/__docs__/prebuilt-deps.md`.

3. **feat(ios-prebuild): SocketRocket privacy manifest + Xcode 26 header layout** — embed an RN-authored, accurate-empty `PrivacyInfo.xcprivacy` for SocketRocket (upstream ships none), and stage flat public headers into `include/` so Xcode 26's SwiftPM accepts the header layout.

Stacked on https://github.com/react/react-native/issues/57305 (base: `chrfalch/prebuilt-resources`); the SwiftPM preview (https://github.com/react/react-native/issues/57332) rebases on top of this. Follow-up (separate PR): headers-only `ReactNativeDependenciesHeaders.xcframework` sidecar so SPM auto-serves the deps namespaces and `ReactNativeHeaders` goes pure-RN.

## Changelog:

[IOS][CHANGED] - Prebuilt-deps mode: serve third-party headers from the ReactNativeDependencies pod itself and resolve community `s.dependency` on RCT-Folly/glog/boost/etc. via dependency-only facade pods

Pull Request resolved: https://github.com/react/react-native/pull/57440

Test Plan:
E2E matrix (2026-07-06, locally built deps artifact via `prepare-ios-prebuilds.js`):

- rn-tester, prebuilt core + prebuilt deps, static linkage — builds
- rn-tester, prebuilt core + prebuilt deps, `USE_FRAMEWORKS=dynamic` — builds (the SocketRocket-regression config)
- helloworld (private), prebuilt core + prebuilt deps, static — builds
- source-mode control: no facades generated, `Podfile.lock` identical to baseline

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Reviewed By: fabriziocucci

Differential Revision: D111449257

Pulled By: cipolleschi

fbshipit-source-id: ace5716868d126a08721200efd640e903b191658
2026-07-16 13:27:12 +00:00
Zeya Peng 3e14593b5c Fix local release testing: publish with --tag for prerelease versions (#57552)
Summary:
`scripts/e2e/init-project-e2e.js` publishes in-repo packages to the local Verdaccio proxy with `npm publish`, but omits `--tag`. **npm ≥ 11** (bundled with Node 24+) refuses to publish a prerelease version (e.g. `0.87.0-rc.0`) without an explicit tag:

```
npm error You must specify a tag using --tag when publishing a prerelease version.
```

This breaks `yarn test-release-local` immediately at the publish step on any machine using npm ≥ 11.

## Fix

Pass an explicit `--tag react-native-e2e`. This is a throwaway local registry and the install step pins the **exact** version, so the dist-tag value is not significant for resolution.

## Changelog

[Internal] - Fix `test-release-local` publishing on npm ≥ 11

Pull Request resolved: https://github.com/react/react-native/pull/57552

Test Plan: `yarn test-release-local -t RNTestProject -p iOS` now gets past the publish step on npm 11 (previously failed immediately at `npm publish`).

Reviewed By: christophpurrer

Differential Revision: D111995913

Pulled By: zeyap

fbshipit-source-id: 107a96d5c4317129228f783ad52bffe1578d1138
2026-07-15 07:40:45 +00:00
Alex Hunt d6baa433cb Enable Strict TS API by default (#57490)
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/57490

See [**RFC0894: Removing deep imports from react-native**](https://github.com/react-native-community/discussions-and-proposals/pull/894)

This is the **big switch** to enable the Strict TypeScript API (generated types + single index entry point) by default in React Native.

**Opt-in → opt-out**

After this change, the main `react-native` package resolves its `"types"` entry points only to `types_generated/index.d.ts` — with no other subpaths available.

The new `"react-native-legacy-deep-imports"` condition maps to legacy `types/` and `Libraries/*.d.ts` sources.

**Impact limitation**: For this stage of rollout, the `"default"` condition continues to resolve to source files. Only TypeScript is affected.

**How to opt out**

Opposite of today's opt-in, which we will update in [the docs](https://reactnative.dev/docs/strict-typescript-api). Again, the only impact area today is **TypeScript**.

```json5
// tsconfig.json
{
  "extends": "react-native/typescript-config",
  "compilerOptions": {
    ...
    "customConditions": ["react-native-legacy-deep-imports"]
  }
}
```

**Other changes**

- Drop `react-native/typescript-config/strict` entry point, update README.
- Update `__typetests__`.

**Rollout plan**

**Target release: 0.87**. This and the contributing stack will be cherry picked for RC1.

- We've conducted testing against 100+ real Expo codebases, giving us the confidence that we've reduced breaking changes enough that the vast majority of RN codebases can migrate.
- The Strict API includes a number of **intentional breaking changes**, and docs have been kept up to date.
- We're shipping a `/migrate-to-strict-api` skill to migrate via agents, see https://github.com/react-native-community/skills/pull/3.

**What's improved since 0.80?**

Since the initial opt-in launch of the Strict API in 0.80, we've been making continuous improvements over the last year to get our generated types into a widely launchable state.

Most notably:

- 21+ new/updated root APIs and fixes due to community feedback ([discussion](https://github.com/react-native-community/discussions-and-proposals/discussions/893), [PRs](https://github.com/react/react-native/pulls?q=is%3Apr%20label%3A%22JS%20API%20stabilization%20(1.0)%22%20is%3Aclosed)).
- Upstream encapsulation blocker in TypeScript, fixed in 6.0 (https://github.com/react/react-native/issues/53565).
- Tailwind/Uniwind compatibility (`interface` types for props).
- `*Instance` ref type exports for all built-in components (https://github.com/react-native-community/discussions-and-proposals/pull/1003).
- Fixes to previously mistyped, high impact APIs, such as `Appearance`.
- New subpath entry points for `asset-registry`, `setup-env`, and others.
- Refinements to doc comments/type translation build.

**Rollback plan**

Revert this diff.

IMPORTANT: We'll adopt a policy of **super-eager rollback**, if there are any unsolvable issues during the RC phase.

Changelog:
[General][Breaking] - React Native's default JavaScript API is now the [Strict TypeScript API](https://reactnative.dev/docs/strict-typescript-api). Use `customConditions: ["react-native-legacy-deep-imports"]` to opt out.

Reviewed By: cortinico

Differential Revision: D110458670

fbshipit-source-id: 4b0e0b458a5f895f783d6d936e7b11ccff2df076
2026-07-13 20:34:31 +01:00
Alex Hunt 6cfde8f296 Move AssetRegistry implementation into main package, expose as public API (#57369)
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/57369

**Problem**

The separate `react-native/assets-registry` package includes a longstanding ecosystem footgun.

`registry.js` holds asset state in a module-scoped variable, which makes the package a stateful singleton: exactly one instance must exist per JS runtime, or registration and lookup diverge.

We provide no guarantee that this singleton requirement holds:

- The install layout — how the package manager dedupes packages in `node_modules` — decides how many copies exist, and `react-native`'s exact-version pin means third-party ranges never dedupe against it.

Effects:

- **Consumers silently break**: `expo-asset` and `expo-image` can land on a second copy: assets register in one, resolve as `undefined` from the other. Expo neutralizes this with a shim in `expo/cli` that redirects every registry import to a single virtual module — bare React Native + Metro has no such protection.
- **This blocks 1.0**: The ecosystem can't move from exact-version lockstep to semver ranges until stateful packages like the asset registry are safe to duplicate. Today, relaxing the pin would turn a latent footgun into a common one.

**To solve this**, move towards (but not quite yet) deleting `react-native/assets-registry`, in favour of a replacement `AssetRegistry` API offered directly by `react-native`.

**Key changes**

NOTE: **Reviewer note**: Browsing file changes on GitHub may be more focused — https://github.com/react/react-native/pull/57369/changes

NOTE: Squash of https://github.com/react/react-native/pull/57233 (D108750302) and https://github.com/react/react-native/pull/57232 (D108750303)

`'react-native'`:
- Add new `AssetRegistry` API, along with the `PackagerAsset` and `AssetDestPathResolver` root type exports in `react-native`.
- Add a new `'react-native/asset-registry'` secondary entry point — intended for Metro's `transformer.assetRegistryPath` config contract.

`react-native/assets-registry`:
- Update to source from this relocated implementation — fixing the duplicate install layout bug (where apps/frameworks enforce a single copy of `react-native`).

**Impact**

- **✅ Fixed**: Imports from either `react-native` or `react-native/assets-registry` in RN 0.87+ will be durable to duplicate package installs — Expo can remove their virtual module shim.
- **✅ Fixed**: Deep import `'react-native/Libraries/Image/AssetRegistry'` dependency removed (migrated in `react-native/metro-config`).

Changelog:
- [General][Fixed] - **assets-registry**: `react-native/assets-registry` now shares state across duplicate installs, sourcing from a relocated implementation in the `react-native` package
- [General][Added] - Add `AssetRegistry` API (replaces `react-native/assets-registry/registry`)
- [General][Breaking] - `react-native/Libraries/Image/AssetRegistry` is removed. Please use the `AssetRegistry` API (apps/library code) and/or the `react-native/asset-registry` entrypoint (Metro/build configs).

Reviewed By: robhogan

Differential Revision: D109019622

fbshipit-source-id: 75599a94a9aba084a1266f2128c448379d1596cd
2026-07-06 10:32:14 -07:00
Pieter De Baets 07816cba56 Move ErrorUtils from cxxreact to jserrorhandler (#57236)
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/57236

Move `handleJSError` from `cxxreact/ErrorUtils.h` (header-inline) to `jserrorhandler/ErrorUtils.{h,cpp}` (declared + linked). Inverts the cyclic dep so `jserrorhandler` becomes a standalone leaf and `cxxreact:bridge` can be narrowed out of more consumers in follow-ups.

The old `<cxxreact/ErrorUtils.h>` include path continues to work via a deprecated `#warning` forwarder header that includes the new location. `cxxreact:bridge` now depends on `jserrorhandler:jserrorhandler` so existing consumers of the deprecated path still link cleanly. `jserrorhandler/BUCK` drops its `cxxreact:bridge` dep (and the matching `React-cxxreact` podspec entry).

Changelog:
[Internal]

Reviewed By: christophpurrer

Differential Revision: D108786498

fbshipit-source-id: 6a34ec47665558ac9c91343253e027ed1df70e93
2026-07-06 07:43:37 -07:00
Pieter De Baets c1d8ae970d Route enableCppPropsIteratorSetter through a copy ctor + RawProps::forEachItem (#57328)
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/57328

Today the iterator-setter path in `ConcreteComponentDescriptor::cloneProps` runs three sequential walks over the input — `RawProps::parse(parser)` (builds `keyIndexToValueIndex_` for `convertRawProp`), `static_cast<folly::dynamic>(rawProps)` (materializes a `folly::dynamic` via `jsi::dynamicFromValue` in JSI mode), and then `dynamic.items()` to dispatch `setProp`. Only the third is actually used: `convertRawProp` is never called on the iterator-setter branch, and the `folly::dynamic` materialization exists only as iteration scaffolding.

Restructure so the runtime flag picks one of two construction paths up front:

- **Iterator-setter** — copy-construct from `sourceProps` via the (re-enabled) `Props` copy ctor, then walk `rawProps` in-place via the new `RawProps::forEachItem` helper and route each entry through `setProp`. `parse()` is skipped entirely; the `folly::dynamic` materialization is skipped in `Mode::JSI`.
- **Classic** — unchanged: `parse()` + 3-arg `convertRawProp`-driven ctor.

`forEachItem` switches on `RawProps::Mode`:
- `Mode::JSI` — walks `value_.asObject(*runtime_).getPropertyNames(...)` and constructs `RawValue` from each `jsi::Value` directly, no `folly::dynamic` in between.
- `Mode::Dynamic` — iterates `dynamic_.items()` (same as today).
- `Mode::Empty` — no-op.

A new `HasIteratorSetterCtor<T>` concept (`std::copy_constructible<T>`) documents the contract and feeds a `static_assert` in `cloneProps`, so a future Props type that deletes its copy ctor fails at compile time rather than silently diverging at runtime between the two flag states.

The `RN_SERIALIZABLE_STATE` Props 2.0 accumulation branch keeps its existing dynamic-iteration shape — when `fallbackToDynamicRawPropsAccumulation` is true, `initializeDynamicProps` has already merged the source's rawProps with the input onto `shadowNodeProps->rawProps`, so we iterate that merged dynamic rather than the raw input.

The per-field `flag ? sourceProps.X : convertRawProp(...)` ternaries across every Props .cpp file become dead in the flag-on path (the copy ctor handles those fields) but are still functional in the flag-off path. They get removed in a follow-up cleanup; this diff is structurally non-breaking on either flag state.

Changelog:
[Internal]

Reviewed By: zeyap

Differential Revision: D109568749

fbshipit-source-id: eae20478418a7dbf7364c73d85d7694d99f1e8f1
2026-07-06 06:52:39 -07:00
Pieter De Baets 803456d699 Optimize MapBuffer representation (#57361)
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/57361

Broadens the former header-shrink change into a single representation-optimization commit for MapBuffer. It bundles three layout optimizations that were previously split: (1) the header is reduced to a single 2-byte `count` field; (2) multi-byte values are read via `memcpy` so unaligned access is well-defined on all platforms; (3) every dynamic-data entry (`String`, `Map`, `MapBufferList`, `IntBuffer`, `DoubleBuffer`) packs its `[offset][byteLength]` into the bucket's 8-byte value instead of writing an in-band length prefix into the dynamic data section.

Net effect: 4 fewer bytes per dynamic entry, one fewer indirection on read (the length is already in the bucket), and every dynamic entry becomes self-delimiting from its bucket alone. No public API change — only the internal serialized representation.

Changelog: [Internal]

landed-with-radar-review

Reviewed By: lenaic, zeyap

Differential Revision: D109848478

fbshipit-source-id: 30749aaa1c2d9fc9b1f8684a3b67815ef44632e8
2026-07-03 01:41:41 -07:00
Pieter De Baets 6a957746f6 Add MapBufferList entry type to MapBuffer (#57360)
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/57360

Introduces a dedicated `MapBufferList` `DataType` for an ordered array of nested MapBuffers, instead of overloading the `Map` type for lists. This makes a list of MapBuffers self-describing and distinguishable from a single nested `Map` (they were byte-distinct in payload but previously shared the `Map` type tag). Updates the C++ builder (`putMapBufferList`), the Kotlin `MapBuffer` interface, `ReadableMapBuffer`, and `WritableMapBuffer`, and adds cross-language JNI round-trip coverage in the serialization instrumentation test.

Changelog:
[Android][Added] - Add a dedicated `MapBufferList` type to `MapBuffer` for ordered lists of nested `MapBuffer`s

landed-with-radar-review

Reviewed By: zeyap

Differential Revision: D109848477

fbshipit-source-id: 7f590d5999d0cc4ee2d9d28cc34ae9220e442e18
2026-07-03 01:41:41 -07:00
Pieter De Baets e7cadaf9f3 Add IntBuffer and DoubleBuffer entry types to MapBuffer (#57359)
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/57359

Adds two new MapBuffer entry types, `IntBuffer` and `DoubleBuffer`, for storing homogeneous arrays of ints and doubles compactly in the dynamic data section. Unlike `Map` / map lists, these carry no per-element key/type overhead: a batch of N values costs ~N*elementSize bytes plus a single 4-byte count prefix instead of N 12-byte buckets. The bucket value holds the offset of the array within the dynamic data section.

Covers the full surface: the C++ reader (`MapBuffer::getIntBuffer` / `getDoubleBuffer`), the C++ builder (`MapBufferBuilder::putIntBuffer` / `putDoubleBuffer`), and the Kotlin reader API (`MapBuffer.getIntBuffer` / `getDoubleBuffer`, `Entry.intBufferValue` / `doubleBufferValue`). The `DataType` enum gains `IntBuffer = 6` and `DoubleBuffer = 7`, kept in sync across C++ and Kotlin.

Changelog:
[General][Added] - Add `IntBuffer` and `DoubleBuffer` entry types to MapBuffer for compact homogeneous int/double arrays

landed-with-radar-review

Reviewed By: zeyap

Differential Revision: D109848476

fbshipit-source-id: f9e86b7c094dea796d9a8b725e53eb948c1390ca
2026-07-03 01:41:41 -07:00
Mathieu Acthernoene 6b45e579d6 Remove StatusBar deprecated props / methods (#57392)
Summary:
Removes long-deprecated `StatusBar` APIs that no longer do anything:

- Android: `backgroundColor` / `translucent` props and `setBackgroundColor()` / `setTranslucent()` (no effect under edge-to-edge, deprecated since 0.76).
- iOS: `networkActivityIndicatorVisible` prop and `setNetworkActivityIndicatorVisible()` (unsupported since iOS 13, deprecated since 0.77).

Also removes the now-unused native backing (`setColor`/`setTranslucent` Android, `setNetworkActivityIndicatorVisible` iOS, Android `DEFAULT_BACKGROUND_COLOR`).

See https://github.com/react/react-native/issues/57384.

## Changelog:

[GENERAL] [BREAKING] - Remove deprecated `StatusBar` `backgroundColor` / `translucent` / `networkActivityIndicatorVisible` props and `setBackgroundColor` / `setTranslucent` / `setNetworkActivityIndicatorVisible` methods

Pull Request resolved: https://github.com/react/react-native/pull/57392

Test Plan:
- `yarn flow check` — passes
- `yarn jest StatusBar` — passes
- `yarn test-typescript` — passes

Reviewed By: Abbondanzo, javache

Differential Revision: D110304943

Pulled By: cortinico

fbshipit-source-id: f7383c6bbbf8fd40042195ef7064b32692940499
2026-07-02 05:41:55 -07:00
Alex Hunt 642273788b Improve preservation of doc comments during type translation (#57389)
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/57389

**Context**

Strict TypeScript API readiness: High quality inline docs should reach users via TypeScript in their IDEs.

**This diff**

Prior iterations of our Flow → TS translation stack dropped doc comments for default-exported values, and/or identifiers which change shape after type transformation (e.g. Flow `component` syntax), meaning many root APIs (`View`, `ScrollView`, `Pressable`, and others) showed no documentation on hover.

This diff extends the existing `reattachDocComments` transform to handle doc comment repositioning (suitable for the TS lang server) from a greater set of source positions:

- the exported declaration
- a `.displayName` assignment
- a HOC-wrapped inner component
- a renamed wrapper's public-named component
- a `declare const` / `declare export default typeof X` stub

**Impact**

(With the source code JSDoc improvements earlier in this stack.)

| Before (legacy types) | After (Strict API) |
| -- |
|  {F1991869487}  | {F1991869472}  |
| ⚠️ No inline docs for many symbols | ✅ New, detailed inline docs reach the TS server 🎉 |

Changelog:
[General][Fixed] - Preserve doc comments on root API symbols in the generated TypeScript types

Reviewed By: rubennorte

Differential Revision: D109316361

fbshipit-source-id: 8a83455fcf317f355bd7c5a67712d322248d8b00
2026-07-02 03:09:52 -07:00
Gang Zhao f482ab61d9 Implement IEventLoopControl in RuntimeScheduler (#57403)
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/57403

Make `RuntimeScheduler` implement `IEventLoopControl`.
Wire `ReactInstance` to register that scheduler on Hermes
runtimes that expose `ISetEventLoopControl`.
Clear the pointer during teardown before `RuntimeScheduler`
is destroyed.
Regenerate React Native C++ API snapshots for the public
header change.

Only the modern scheduler have the actual implementation, it's no-op
in the legacy scheduler.

Changelog: [Internal]

Reviewed By: javache

Differential Revision: D106744175

fbshipit-source-id: 90eb17ce8dbc929b5f2474e019de07ad28d9c21d
2026-07-01 16:39:48 -07:00
Bartlomiej Bloniarz 721b1cfcac Drive shared animation backend from Fabric frame callback (#57400)
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/57400

In this diff we drop the custom choreographer for the backend on Android and instead plug into the one in `FabricUIManager`. This reduces the area for possible mistakes, makes it clearer how Fabric interacts with animation on a per-frame basis, and simplifies the flow around invalidation and cleanup of the React instance.

The crash this is meant to avoid comes from having two separate frame callback lifecycles. The old `AnimationBackendChoreographer` owned a self-reposting callback that could keep driving `FabricUIManagerBinding.driveAnimationBackend` independently from Fabric's own lifecycle. During React instance teardown, `FabricUIManager.invalidate()` pauses Fabric's frame callback and then unregisters the native binding. If a separate backend callback survives that sequence, it can invoke the binding after the native side has been uninstalled.

The shared animation backend is now driven from Fabric's existing `DISPATCH_UI` frame callback after mount items are dispatched. The Android `AnimationChoreographer` implementation only owns backend pause/resume state and conditionally forwards active frames to the shared backend.

Threading-wise:
- If invalidation happens before a frame starts, `mDestroyed` makes the frame no-op.
- If invalidation races with an already-running frame, `ReactChoreographer.removeFrameCallback` is serialized with callback execution via the `callbackQueues` monitor, so `onHostPause()` waits for the current `DISPATCH_UI` callback to finish before `unregister()` tears down the native binding.
- If the frame reposts itself in `schedule()`, the blocked removal observes and removes that callback before teardown continues.

Changelog:
[Android][Fixed] - Drive the shared animation backend from Fabric's frame callback during React instance teardown

Reviewed By: javache, zeyap

Differential Revision: D110321362

fbshipit-source-id: 77c462ee30aeec2d3af0dcd48b8eed15846ae5da
2026-07-01 14:44:05 -07:00
OrfeasZ 923e7ddcaf Add guards around nativeProps usage to prevent race conditions (#52646)
Summary:
Some third-party libraries, like react-native-reanimated, can clone nodes in a different thread while react-native is calling `setNativeProps_DEPRECATED`. This results in a race condition, where a stale pointer to `nativeProps_DEPRECATED` can be accessed, resulting in a crash. This usually manifests as a `EXC_BAD_ACCESS` crash on iOS. On Android it seems more rare. We've added a lock around accesses to nativeProps_DEPRECATED, but alternative options of fixing this can be considered too.

For more information see https://github.com/software-mansion/react-native-reanimated/issues/7666

## Changelog:

[INTERNAL] [FIXED] - Fixed crashes caused by race conditions when third-party libraries clone the shadow dom from a different thread

Pull Request resolved: https://github.com/react/react-native/pull/52646

Test Plan:
Due to this being a race condition that only manifests in rare circumstances, it's very difficult to create a reliable reproduction case. The issue mentioned above contains ThreadSanitizer logs that demonstrate this issue. TSan no longer complains with this patch applied, and we've not seen any additional issues from it after deploying it in production over the past week.

Added unit test covering the `nativeProps_DEPRECATED` merge logic in `UIManager::cloneNode` and `ShadowNode::clone`:

```
buck2 test //xplat/js/react-native-github/packages/react-native/ReactCommon/react/renderer/uimanager:tests -- --regex FabricUIManagerTest
```

Reviewed By: zeyap

Differential Revision: D110169424

Pulled By: javache

fbshipit-source-id: 6139253dcc2c33348a0c1a3bd01e695d15aa83bc
2026-07-01 13:01:48 -07:00
Graham Campbell d1c5ee0388 Fix native animated mount flash (#57391)
Summary:
The C++ native animated backend (`cxxNativeAnimatedEnabled`) prevents the `useNativeDriver` first-frame flash by having `AnimatedMountingOverrideDelegate` re-merge a view's live animated props (`getManagedProps`) onto mount `Update` mutations, so a stale JS re-render can't reach the screen. There is a residual at connect time: `connectAnimatedNodeToView` registers the view (the override starts overriding it) but never runs the props node, so `getManagedProps()` returns an empty object until the next animation frame. If a Fabric mount transaction is pulled in that window the override has nothing to merge and the un-driven default value flashes for one frame, most visibly when a brand-new view is connected to an already mid-flight shared `Animated.Value`.

This seeds the props node with `node->update()` at the end of `connectAnimatedNodeToView` so `getManagedProps()` is live the instant the view becomes managed. No manager mutex is held at that point and `update()` takes only the node-local props mutex, so it is lock-safe; it is idempotent with the per-frame update and adds no extra Fabric commit because it only stages. It closes the connect-while-`Update`-in-flight case and mitigates the brand-new-view (`Insert`) first-paint case; the override only rewrites `Update`/`Delete` mutations today, so fully closing `Insert` is a follow-up. It also adds the missing unit coverage for the `getManagedProps` / `hasManagedProps` seam the override depends on.

## Changelog:

[INTERNAL] [FIXED] - Seed managed props when a view connects to the native animated backend so they are live before the first frame, shrinking the useNativeDriver mount flash

Pull Request resolved: https://github.com/react/react-native/pull/57391

Test Plan: Adds `ManagedPropsMountingOverrideTests.cpp` to the ReactCommon animated unit tests. `getManagedPropsReflectsLiveValueAcrossFrames`, `getManagedPropsNullForUnconnectedView`, `hasManagedPropsTracksConnectAndDisconnect` and `getManagedPropsIsolatedPerView` pin the seam and pass regardless of the change. `getManagedPropsLiveImmediatelyOnConnect` and `getManagedPropsLiveOnConnectWhileValueMidFlight` are the regression cases: they fail without the seed (empty props at connect) and pass with it. Run via the animated C++ unit test target. On-device verification (iOS and Android with `cxxNativeAnimatedEnabled` on, frame-stepped capture of a popover/menu open) is still recommended for the user-visible flash.

Reviewed By: sammy-SC

Differential Revision: D110323404

Pulled By: zeyap

fbshipit-source-id: 485e31e1c874548da1ee7339481164faa763b2d9
2026-07-01 12:53:55 -07:00
Rubén Norte 2bb7dbb499 Add an interactive REPL for Fantom (yarn fantom-cli) (#57387)
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/57387

Adds `yarn fantom-cli`, an interactive REPL that evaluates JavaScript against the same native tester binary and Hermes runtime that Fantom tests run in. State persists across lines, input goes through Metro/Babel (so `import`, JSX and Flow all work), and the environment is set up the same way tests set it up — `React`, `ReactNative` and the `Fantom` API are available globally, so you can render surfaces and drive them interactively from the prompt.

The native tester gains an `--interactive` mode that loads a warm-up bundle without running tests and then evaluates length-prefixed snippets read from stdin, reporting results, console output and errors back as newline-delimited JSON. A Node driver hosts a Metro server, builds the warm-up bundle, spawns the binary, and bridges each line of input into the live runtime (top-level declarations persist across evaluations).

Features:

- Console-style output: results are printed with an inspector similar to the Chrome DevTools / Node.js consoles (nested objects/arrays up to a depth limit, quoted strings, functions/classes, `Map`/`Set`/`RegExp`/`Date`/`Error`, class instances, circular references, multi-line wrapping), colorized by type when stdout is a terminal. Inspecting a property never aborts the result or leaks into later evaluations: a property whose getter fails renders as `[Thrown: <error>]`, including getters that fail asynchronously through the runtime's global error handler (e.g. accessing a `react-native` export backed by a TurboModule that isn't registered).
- Autocompletion: pressing Tab completes global identifiers, in-scope bindings and object properties (property names are listed without invoking getters).
- Node-like CLI: with no arguments it starts the REPL; `-e <code>` evaluates a snippet and exits; a filename runs that script and exits. In the non-interactive modes the value of a trailing expression is not printed (use `console.log`) and a thrown error exits with a non-zero status code.

Also documents the REPL in the Fantom README.

Changelog: [Internal]

Reviewed By: javache, sammy-SC

Differential Revision: D110187712

fbshipit-source-id: 3e76c498ae04b8b1ce9e0e27e5ce6b6a0cd11e09
2026-07-01 08:18:34 -07:00
Bartlomiej Bloniarz d9d2502b61 Fix AnimatedPropsRegistry surface-stop resurrection race (#57376)
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/57376

AnimatedPropsRegistry::update() runs on the UI thread every animation frame and
created a surface's entry via operator[]. clearOnSurfaceStop() (run on the JS
thread when a surface stops) erases that entry, but an in-flight animation frame
landing after the stop re-created it via operator[] -- and since the surface is
gone, nothing ever cleans it up again. The resurrected entry leaks its
PropsSnapshot and ShadowNodeFamily for the lifetime of the registry.

A surface's entry is legitimately created by getMap(), which
AnimationBackendCommitHook calls on every React commit. stopSurface drains
in-flight commits before unregistering the ShadowTree
(ShadowTreeRegistry::remove takes the registry's unique lock, which excludes the
shared-locked commit visits), so getMap() can never run for a stopped surface.
That leaves update()'s operator[] as the only thing that can resurrect one.

Fix: update() now only refines surfaces that already exist (find instead of
operator[]) and never creates an entry; getMap() remains the sole creator. A
stopped surface can no longer be resurrected, and there is no extra bookkeeping
that could grow over time.

Changelog: [General][Fixed] - Fix a surface-stop race in the C++ Animated shared backend that could permanently leak per-surface animated state

Reviewed By: javache

Differential Revision: D109156094

fbshipit-source-id: 4684ca51d372023e3b082427a225de7d84d14889
2026-07-01 07:13:13 -07:00
Pieter De Baets 2468e3c867 Remove unused ViewShadowNodeProps subclass (#57377)
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/57377

ViewShadowNodeProps was a thin subclass of ViewProps that only forwarded its constructor. After the feature flag propagation logic was removed, the subclass serves no purpose.

Changelog:
[Internal]

Reviewed By: lenaic

Differential Revision: D110095190

fbshipit-source-id: a2555c4ba455e51116c73be3b5c9a71788895ffd
2026-07-01 04:00:49 -07:00
SJLIM ca29d38537 fix(text): support start and end text alignment (#57201)
Summary:
Closes https://github.com/react/react-native/issues/45255.

Adds `textAlign: 'start' | 'end'` support for Text and TextInput across the JS types, Android, iOS, and Fabric text conversion paths.

- Android legacy Text and TextInput now accept logical `start`/`end` alignment values.
- Fabric preserves `start`/`end` as distinct `TextAlignment` values and resolves them against layout direction for iOS paragraph layout.
- Existing `left`/`right` behavior is left unchanged to avoid changing current RTL semantics.

This replaces https://github.com/react/react-native/issues/57007 because the original fork became locked and could not be updated after the upstream conflict.

## Changelog:

[GENERAL] [ADDED] - Add support for `textAlign: 'start'` and `textAlign: 'end'`.

Pull Request resolved: https://github.com/react/react-native/pull/57201

Test Plan:
- `yarn build-types`
- `yarn test-typescript`
- `yarn flow-check`
- `./node_modules/.bin/prettier --check packages/react-native/Libraries/Components/TextInput/TextInput.d.ts packages/react-native/Libraries/Components/TextInput/TextInput.flow.js packages/react-native/Libraries/StyleSheet/StyleSheetTypes.d.ts packages/react-native/Libraries/StyleSheet/StyleSheetTypes.js packages/react-native/types/__typetests__/index.tsx packages/react-native/ReactNativeApi.d.ts`
- `./gradlew ktfmtCheck -Preact.internal.useHermesStable=true --no-daemon`
- `./gradlew :packages:react-native:ReactAndroid:testDebugUnitTest --tests com.facebook.react.views.textinput.ReactTextInputPropertyTest.testTextAlign --tests com.facebook.react.views.text.TextAttributePropsTest -Preact.internal.useHermesStable=true --no-daemon`
- `./gradlew ':packages:react-native:ReactAndroid:buildCMakeDebug[arm64-v8a][hermestooling,jsi,etc]' -Preact.internal.useHermesStable=true --no-daemon`
- `git diff --check`

The Android unit test and CMake checks were run from an ASCII-only temporary worktree because Kotlin unit test compilation in my main checkout fails before running these tests when the workspace path contains non-ASCII characters.

Reviewed By: christophpurrer

Differential Revision: D108628602

Pulled By: javache

fbshipit-source-id: 28111d0553451d7de0424a07e956f71bda8787ca
2026-07-01 03:43:49 -07:00
Mathieu Acthernoene fd10410d51 Remove Modal animated prop (#57385)
Summary:
Removes the deprecated `animated` prop from `Modal`. It was a no-op everywhere. Use `animationType` instead.

See https://github.com/react/react-native/issues/57384

## Changelog:

[GENERAL] [REMOVED] - Remove deprecated `Modal` `animated` prop

Pull Request resolved: https://github.com/react/react-native/pull/57385

Test Plan:
- `yarn jest packages/react-native/Libraries/Modal`
- `yarn flow` and `tsc` pass with the prop removed from `Modal.js` / `Modal.d.ts`.

Reviewed By: huntie

Differential Revision: D110205204

Pulled By: cortinico

fbshipit-source-id: 8e5b4d7dc8811d7270de3776476e7f868eafddd5
2026-06-30 14:08:11 -07:00
Alex Hunt 3fcde34a36 Relocate __typetests__ directory, format (#57367)
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/57367

Places this one folder up, in a location that will be preserved when we later delete the manual `types/` dir. These tests already apply to both the `types/Libraries` dirs and the generated `types_generated/`.

Changelog: [Internal]

___

Differential Revision: D110055787

fbshipit-source-id: 5ff190d301628877c9bda57c92b1af1a2917f1ca
2026-06-29 08:06:24 -07:00
Pieter De Baets ce72288bfc Add back backwards compat for rawProps.at(x,y,z) (#57346)
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/57346

Restores a deprecated three-argument overload of `RawProps::at()` for backwards compatibility with existing callers (like Nitro modules) that pass prefix/suffix separately.

The new overload concatenates `prefix + name + suffix` when needed and delegates to the parser's `at(string_view)` method. When both prefix and suffix are null, it forwards directly to the single-argument version.

Changelog: [Internal]

Reviewed By: cortinico

Differential Revision: D109837388

fbshipit-source-id: c16188cee163ca786f4530d07475f561a53c51b6
2026-06-29 05:28:56 -07:00
Alex Hunt fa371d156d Add macOS 26 icon for RNDT (#57310)
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/57310

Add `AppIcon.icon` file (Icon Composer) for macOS 26 Tahoe. Also rename previous `.icns` file for consistency.

`electron/packager` is updated to `^20.0.0` (`.icon` support was added in `18.4.0`).

**Notes**

- This change ensures the Icon Composer source is part of the codebase (following above Electron packager support which came in March).

Changelog:
[General][Changed] - **React Native DevTools**: Add macOS 26/27 app icon

Reviewed By: robhogan

Differential Revision: D97292364

fbshipit-source-id: ba1c34175a95da8c2860142d9db0c4d98d3f6de0
2026-06-29 03:08:17 -07:00
Pieter De Baets eec26421ff Move remaining js1 build-* commands under the build namespace (#57348)
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/57348

Follow-up to the `js1 build-cxx-api` rename. Move `build-geo-screenshot-tests`, `build-js-api`, and `build-twui-screenshot-tests` under the `build` group so they sit next to their siblings (`js1 build assets`, `js1 build turbomodule`, etc.) instead of being top-level hyphenated outliers.

Each old top-level command stays as a hidden alias that prints a deprecation notice and delegates to the new module, so existing muscle memory and any out-of-tree scripts keep working.

Also updates the two places that emit the old command names into user-visible output: the TWUI template comment headers, and the JS API snapshot failure message.

Changelog:
[Internal]

Reviewed By: zeyap

Differential Revision: D109844649

fbshipit-source-id: 00623fa8b4d724e16a2dc62d196182c32a9fed64
2026-06-28 23:45:54 -07:00
Kamil Paradowski 54b88d9dea ArrayBuffer support to ObjC TurboModules
Summary:
Adds ArrayBuffer support to ObjC TurboModules, following the C++ ArrayBuffer PR ([`226ef2e`](https://github.com/facebook/react-native/commit/226ef2e7c5d1928d5696dc23efc1b8950ba00e37)).

- Codegen support for `ArrayBufferTypeAnnotation` in ObjC module specs (`NSMutableData *` params/returns, new `ArrayBufferKind`)
- JSI↔ObjC conversion wraps native-backed buffers zero-copy via `-[NSMutableData initWithBytesNoCopy:length:deallocator:]`; the deallocator retains the backing store so the bytes stay valid even if the `NSMutableData` escapes the call or the source ArrayBuffer is garbage-collected
- JS-backed buffers are copied, which is safe on both the synchronous and asynchronous paths

This PR is iOS-only; Android support follows in a separate PR.

## Changelog:

[IOS] [ADDED] - Add ArrayBuffer support to ObjC TurboModules

X-link: https://github.com/facebook/react-native/pull/56986

Reviewed By: javache

Differential Revision: D106846249

Pulled By: christophpurrer

fbshipit-source-id: 3393d5d6f31a1412f5d52328c90e51205aa6b153
2026-06-27 23:41:58 -07:00
Pieter De Baets 9052f0b427 Move nativeId parsing into the Props ctor initializer list (#57339)
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/57339

Every Props subclass parses its fields in its 3-arg ctor's initializer list, but `Props` was the odd one out — its 3-arg ctor had an empty initializer list and a body that called a separate `Props::initialize` method, which then assigned `nativeId` and (on Android) ran `initializeDynamicProps`.

Fold the `nativeId` parse back into the initializer list and inline the Android `initializeDynamicProps` call into the ctor body, matching the subclass pattern.

This removes the only remaining external caller of `Props::initialize`: `YogaStylableProps`'s ctor was constructing its `Props` subobject via `Props()` and then calling `initialize(...)` from its body. Replace with the standard `Props(ctx, sourceProps, rawProps, filterObjectKeys)` initializer-list chain. With both call sites gone, delete `Props::initialize` outright.

Behaviour is unchanged: the work that `initialize` did still runs on the same construction path, just via the ctor itself.

Changelog:
[Internal]

Reviewed By: christophpurrer

Differential Revision: D109691981

fbshipit-source-id: 835615191332239e90353da2e66fecc429365529
2026-06-25 12:45:38 -07:00
Pieter De Baets 67381e157f Remove RawPropsKey prefix and suffix
Summary:
X-link: https://github.com/facebook/react-native/pull/55763

RawPropsKey previously stored three `const char*` fields
(prefix, name, suffix) that were concatenated at runtime to form
property names.

This is pretty niche, used to make a few patterns simpler, but also can lead to confusing conflicts when the same property name can be represented in different ways (e.g. T174300106). Iterator style props parsing also completely avoids it.

Lets change the API to a flat name instead.

This change is breaking, but could only find a single user (Nitro module) effected, searching through `react-native-libraries`.

Changelog:
[General][Breaking]  - Remove RawPropsKey prefix and suffix

Reviewed By: christophpurrer

Differential Revision: D94367880

fbshipit-source-id: d865725c7be6f880760b6e8d1a567a1b12ac469a
2026-06-25 04:02:29 -07:00
Peter Abbondanzo fa8fad84d6 Fix helloworld e2e after core-cli-utils stopped publishing (#57308)
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/57308

`private/helloworld` depends on `react-native/core-cli-utils` (it imports `android`, `app`, and `apple` from it to build the app), but that package is no longer published to npm nor to the local Verdaccio proxy that the e2e build installs against. Since `private/helloworld` is excluded from the workspace, it installs standalone, so its `"*"` dependency on `react-native/core-cli-utils` could not resolve and `npm install` failed with `E404`.

Resolve `"*"`-pinned in-repo `react-native/*` dependencies to a local `file:` path in `_prepareHelloWorld()`, so helloworld consumes `core-cli-utils` directly from its in-repo reference implementation regardless of whether it is published. This mirrors how the `react-native` package itself is already wired up for the e2e build.

Changelog: [Internal]

Reviewed By: javache

Differential Revision: D109374920

fbshipit-source-id: b6668785387511fa54580ee75e81f13168782797
2026-06-23 05:52:17 -07:00
Rob Hogan 738839c0dd Apply prettier to .yml files + consistent quote style (#57286)
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/57286

We currently have a mix of quote styles in `.yml` files (AI summary below). This applies prettier and reformats everything to single quotes to align with defaults.

Also fixes a couple of cases of over-indentation.

```
Single-quotes only (0 double-quoted scalars):

analyze-pr.yml
 — 12 single, 0 double
api-changes.yml
 — 3 single, 0 double
check-for-reproducer.yml
 — 4 single, 0 double
retry-workflow.yml
 — 1 single, 0 double
Single-quote predominant > double:

autorebase.yml 2 vs 1
create-draft-release.yml 8 vs 2
generate-changelog.yml 3 vs 2
on-issue-labeled.yml 7 vs 2
prebuild-ios-core.yml 59 vs 17
prebuild-ios-dependencies.yml 39 vs 1
stale-bot.yml 18 vs 15
test-all.yml 70 vs 27
Double-quote predominant > single:

bump-podfile-lock.yml 1 vs 10
create-release.yml 3 vs 12
e2e-android-rntester.yml 2 vs 6
e2e-android-templateapp.yml 6 vs 13
e2e-ios-rntester.yml 2 vs 7
e2e-ios-templateapp.yml 2 vs 18
fantom-tests.yml 2 vs 7
monitor-new-issues.yml 3 vs 12
publish-npm.yml 42 vs 50
validate-cxx-api-snapshots.yml 2 vs 23
validate-dotslash-artifacts.yml 2 vs 5
Tie / 1-1:

cache-reaper.yml 1 vs 1
close-pr.yml 1 vs 1
needs-attention.yml 2 vs 2
All files contain single quotes somewhere, but only those 4 are single-quote-exclusive. Most CI-heavy workflows — bump, create-release, e2e-, fantom, monitor, publish-npm, validate- — lean double-quoted, while the pr/issue automation, prebuild ios, test-all, and stale-bot lean single-quoted.
```

Changelog: [Internal]

___

Differential Revision: D109151683

fbshipit-source-id: 24391e906c0dd92fe402224089dce8bb2068b4d9
2026-06-19 07:03:32 -07:00
Rubén Norte 2d491c0c75 Add deterministic timer mock to Fantom (#57274)
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/57274

Fantom could not deterministically fire delayed JS timers: the timer registry it used scheduled timers on a real background thread with real wall-clock delays, so `setTimeout(fn, 100)`/`setInterval` callbacks never fired within a synchronous test. This adds a mockable timer registry and a public Fantom API to control it from JS, similar to `installHighResTimeStampMock`.

- New `Fantom.installTimerMock()` returns a controller with `advanceTimersByTime(ms)`, `runAllTimers()`, `getPendingTimerCount()`, and `uninstall()` (jest fake-timer style). While installed, `setTimeout`/`setInterval` callbacks only fire when the virtual clock is advanced.
- New deterministic `FantomTimerRegistry` (no background thread) keyed off a virtual clock, injected via a new optional `platformTimerRegistryFactory` seam on `ReactInstanceConfig` (the default registry is unchanged for all other consumers).
- `PlatformTimerRegistry` gains a virtual `setTimerManager` (default no-op) so the registry can be wired polymorphically.
- Control flows from JS through new `NativeFantom` methods, the same way the high-res timestamp mock works.

Default (non-mock) behavior is preserved: zero-delay `setTimeout` still fires on the next work loop, and existing tests are unaffected.

Changelog: [Internal]

Reviewed By: christophpurrer

Differential Revision: D109017304

fbshipit-source-id: 8afe6fb2a39f470ae293038f6592c46535442dc2
2026-06-19 05:13:56 -07:00
Jakub Piasecki 45904c8668 Fix Fabric reusing nodes with a stale font scale (#57246)
Summary:
Fixes https://github.com/react/react-native/issues/52895

The original solution to this issue approached this by comparing the font scale used to lay out respective root nodes and re-cloning measurable nodes in the entire tree when it was different. This didn't work when a node within the tree was cloned from a node with an obsolete font scale stored (with root having the correct one). The new node would use the obsolete value in that pass.

This PR changes this approach - instead of comparing font scale in `SurfaceHandler::constraintLayout` (only when it changes), it moves the comparison to happen as part of `configureYogaTree`, similarly to `pointScaleFactor`. This way, nodes with an obsolete value stored get re-cloned using the correct one on each commit instead of only on the first one.

## Changelog:

[GENERAL][FIXED] - Fixed Fabric reusing nodes with a stale font scale

Pull Request resolved: https://github.com/react/react-native/pull/57246

Test Plan:
Issue reproducer

||Before|After|
|-|-|-|
|Android|<video src="https://github.com/user-attachments/assets/0b30ca95-76e9-4ce9-8d8f-418f9d827bea" />|<video src="https://github.com/user-attachments/assets/009be13c-c3b5-4af0-8be1-b44c94ac0496" />|
|iOS|<video src="https://github.com/user-attachments/assets/b861b622-a2ea-4cc4-a8db-0e3ad4cae5e7" />|<video src="https://github.com/user-attachments/assets/ec4d6f6e-7558-4430-813b-61a6e911c3b0" />|

Reviewed By: javache

Differential Revision: D108877387

Pulled By: j-piasecki

fbshipit-source-id: f4c5335dc691d30a50db7e6f66744fa9c7295fb2
2026-06-18 00:39:38 -07:00
Sam Zhou 9ab5dd857b Deploy 0.319.0 to xplat (#57256)
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/57256

[changelog](https://github.com/facebook/flow/blob/main/Changelog.md)
Changelog: [Internal]

Reviewed By: gkz

Differential Revision: D108885686

fbshipit-source-id: b31fc3f2987ddb08cbe52daa5e8eef437541c8df
2026-06-17 11:30:47 -07:00
Gijs Weterings bc20ec88eb Implement Page.addScriptToEvaluateOnNewDocument CDP handler (#57248)
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/57248

Implement the CDP `Page.addScriptToEvaluateOnNewDocument` and `Page.removeScriptToEvaluateOnNewDocument` methods in the modern JS inspector (`jsinspector-modern`). `Page.addScriptToEvaluateOnNewDocument` registers a JavaScript snippet that is evaluated in every new JS runtime created for the Host (for example, after a reload), before the application's main bundle runs, matching the standard Chrome DevTools Protocol semantics. This is useful for debugger frontends and tooling that need to install instrumentation ahead of application code.

The registered scripts are stored as session state (alongside `Runtime.addBinding` subscriptions in `SessionState`) and replayed onto each new runtime by `RuntimeAgent` via the runtime executor, so they run before any user code and survive reloads. Per CDP semantics the script does not run in the runtime that is current when it is registered; the client triggers `Page.reload` to apply it. `HostAgent` handles both methods, returning the generated script `identifier` from add and removing by `identifier` on remove.

Changelog:
[General][Added] - Implement the `Page.addScriptToEvaluateOnNewDocument` and `Page.removeScriptToEvaluateOnNewDocument` CDP methods in the modern inspector

Reviewed By: hoxyq

Differential Revision: D107084044

fbshipit-source-id: 7951028f81f89fbf36418cf8da8a03a7191d228a
2026-06-17 08:04:21 -07:00
Samuel Susla 79adce3942 Remove offscreen image request downgrading feature flag (#57226)
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/57226

This removes the experimental `enableImageRequestDowngradingForNonVisibleImages` feature flag and backs out the behavior it gated. When enabled, `ImageShadowNode` downgraded image requests to prefetch priority for images that layout determined did not intersect the viewport — threading an `ImageRequestPriority` through `ImageRequestParams` and the Apple image managers, and propagating per-node viewport frames during Yoga layout via `experimental_layoutOrigin`/`experimental_layoutFrame` on `LayoutContext`.

The flag defaulted to off and was never enabled in a release, and the gated behavior did not deliver the expected improvement, so the feature is removed entirely: `<Image>` once again always requests at immediate priority. This deletes the feature flag, the `ImageRequestPriority` enum and the `ImageRequestParams::priority` field, the priority parameter on `RCTImageManager`/`RCTSyncImageManager`/`RCTImageManagerProtocol`, the `experimental_layout*` `LayoutContext` fields and their Yoga propagation, the iOS request-priority debug overlay, and the associated Fantom test scaffolding. The generated feature-flag sources and the C++ API snapshots are regenerated accordingly.

Changelog: [Internal]

Reviewed By: javache

Differential Revision: D108411690

fbshipit-source-id: 1538ec699ed2857f3d3154d666fac43a1dc64cd1
2026-06-17 05:26:37 -07:00
Nathan Lanza dad85ba617 Remove getMapBuffer() from placeholder StateData (#57213)
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/57213

`StateData` is the placeholder data type for shadow nodes that have no state. It declared `getMapBuffer()` but never defined it, which breaks the build under clang-22.

`ConcreteState<DataT>::getMapBuffer()` calls `getData().getMapBuffer()` only when the `StateDataWithMapBuffer` concept is satisfied, and otherwise returns `MapBufferBuilder::EMPTY()`. Because `StateData` declared `getMapBuffer()`, it satisfied the concept, so `ConcreteState<StateData>::getMapBuffer()` referenced the undefined `StateData::getMapBuffer()`. Whether a class template's virtual members are implicitly instantiated is unspecified ([temp.inst]/11); clang-22 instantiates this override, turning the missing definition into an undefined-symbol link error.

Remove `getMapBuffer()` from `StateData` so the concept is no longer satisfied and the `EMPTY()` fallback is used — the same way `getJNIReference()` is already handled for this placeholder type. `getDynamic()` stays, since `ConcreteState` calls it unconditionally.

Changelog:
[Internal]

Reviewed By: javache

Differential Revision: D95506209

fbshipit-source-id: 71e767bb19dce5b6097d49654b3701896a783f5b
2026-06-15 19:06:49 -07:00
Zeya Peng dd5c383c21 Decide NativeAnimated backend per-instance instead of live flag (#57205)
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/57205

## Changelog:

[Internal][Fixed] - Fix EXC_BAD_ACCESS / KERN_INVALID_ADDRESS in C++ Animated when `useSharedAnimatedBackend()` flips across a reused runtime

C++ Animated chose between the legacy and shared-`AnimationBackend` code paths by reading `ReactNativeFeatureFlags::useSharedAnimatedBackend()` live, in many places. That flag is a process-global singleton (`ReactNativeFeatureFlags::accessor_`). On some app the global is reset and re-applied on every user switch (`FBReactModule setUpReactNativeFeatureFlags` -> `dangerouslyReset()`/`override()`), and the previous user's runtime is kept alive and reused. The shared `AnimationBackend` is attached only once, when an instance's `Scheduler` is constructed, gated on the flag at that moment. On a multi-account device the global flag could therefore read true on a reused instance whose backend was never attached, so `getOrCreate` took the shared path and dereferenced a null backend. It also let JS and C++ disagree, since JS caches the flag per runtime while C++ followed the mutated global.

Fix: make the per-instance decision once and use it everywhere instead of the live flag.

- `NativeAnimatedNodesManagerProvider::getOrCreate` selects the path by whether the shared `AnimationBackend` actually exists for this instance (`unstable_getAnimationBackend().lock() != nullptr`).
- `NativeAnimatedNodesManager` stores a `const bool useSharedAnimatedBackend_`, latched in its constructor (true for the shared-backend ctor, false for the legacy ctor), and exposes it via `useSharedAnimatedBackend()`. All internal reads now use the member.
- `PropsAnimatedNode` reads the decision through `manager_->useSharedAnimatedBackend()`.

The attach side (`Scheduler`) is intentionally unchanged: it remains the single construction-time read that latches the per-instance decision the rest of the code now follows. This keeps JS and C++ consistent across global flag flips and removes the null dereference.

Reviewed By: sbuggay

Differential Revision: D108428720

fbshipit-source-id: dff283cd3671866395d1b07b6c9c72e504aecea2
2026-06-15 09:55:11 -07:00
Samuel Susla 4eb7885faf Remove dead StartupLogger::getInitReactRuntimeEndTime getter
Summary:
X-link: https://github.com/facebook/react-native/pull/57140

`StartupLogger::getInitReactRuntimeEndTime()` was a public getter returning the `initReactRuntimeEndTime` member, but it had no callers. `NativePerformance` (the only consumer of `StartupLogger`) never reads it. This removes the dead getter; the backing member `initReactRuntimeEndTime` is kept because `logStartupEvent`/`reset` still write it.

Changelog: [Internal]

Reviewed By: mdvacca

Differential Revision: D108012904

fbshipit-source-id: 56a6710c485a926caf82ecb1cc08e845571b2dd8
2026-06-10 09:17:52 -07:00
Samuel Susla de57be51d0 Remove dead StartupLogger::getRunJSBundleEndTime getter
Summary:
X-link: https://github.com/facebook/react-native/pull/57142

`StartupLogger::getRunJSBundleEndTime()` was a public getter that returned the `runJSBundleEndTime` member, but it had no callers. `NativePerformance` is the only consumer of `StartupLogger` and reads the start-time getters plus `getAppStartupEndTime`, never this end-time getter. This removes the dead getter. The backing member `runJSBundleEndTime` is kept because `logStartupEvent`/`reset` still write it.

Changelog: [Internal]

Reviewed By: mdvacca

Differential Revision: D108012912

fbshipit-source-id: ac6348b8223fba8695843340e99d7e277bf4f60a
2026-06-10 09:17:52 -07:00
Samuel Susla bc7c757e9d Remove dead RAMBundleRegistry::multipleBundlesRegistry static factory
Summary:
X-link: https://github.com/facebook/react-native/pull/57137

`RAMBundleRegistry::multipleBundlesRegistry` was a static factory wrapping the public `RAMBundleRegistry` constructor (the one taking a main bundle plus a factory callback), but it had no callers anywhere. Registries are constructed via the public constructor directly. With the sibling `singleBundleRegistry` already removed, this deletes the last orphaned static factory; the constructor and the rest of the class remain intact.

Changelog: [Internal]

Reviewed By: mdvacca

Differential Revision: D108012906

fbshipit-source-id: 7bb403ff7660317f0f5b422dca140ac69e048dac
2026-06-10 09:17:52 -07:00
Samuel Susla b4de836f57 Remove dead RAMBundleRegistry::singleBundleRegistry factory
Summary:
X-link: https://github.com/facebook/react-native/pull/57143

`RAMBundleRegistry::singleBundleRegistry` was a static factory that wrapped the public `RAMBundleRegistry` constructor, but it had no callers anywhere. Objects are constructed via the public constructor directly. This removes the orphaned factory; the sibling `multipleBundlesRegistry`, the constructor, `MAIN_BUNDLE_ID`, `registerBundle`, `getModule`, and `getBundle` are all left intact.

Changelog: [Internal]

Reviewed By: mdvacca

Differential Revision: D108012903

fbshipit-source-id: 5d8f18ebce2bb19abd124dbb7c9eda60baa0f272
2026-06-10 09:17:52 -07:00
Samuel Susla 6d50defa28 Remove dead HostTargetController::installPerfIssuesBinding declaration
Summary:
X-link: https://github.com/facebook/react-native/pull/57145

`HostTargetController::installPerfIssuesBinding()` was declared in `jsinspector-modern/HostTarget.h` but had no definition anywhere and no callers. (`HostTargetController` is `final`, so the method is not an override.) A declared-but-never-defined non-virtual member cannot be invoked — any call would be a link error — so this is unreachable dead code. The unrelated, live `HostTarget::installPerfIssuesBinding` (a different class) is left intact.

Changelog: [Internal]

Reviewed By: mdvacca

Differential Revision: D108012907

fbshipit-source-id: 5c7f14a7956f67e3e884a32f95aa2e50fd0f3ea6
2026-06-10 09:17:52 -07:00
Samuel Susla a8d16b623e Remove dead JSIndexedRAMBundle from cxxreact
Summary:
X-link: https://github.com/facebook/react-native/pull/57133

`JSIndexedRAMBundle` was a deprecated legacy-architecture class (annotated `[[deprecated("This API will be removed along with the legacy architecture.")]]` and guarded by `#ifndef RCT_REMOVE_LEGACY_ARCH`) for parsing indexed RAM bundles. It was only ever instantiated by `Instance::loadRAMBundleFromString` and `Instance::loadRAMBundleFromFile`, and those two `Instance` methods have no callers anywhere in fbsource: the old Android entry point `CatalystInstanceImpl` that used to call them has been deleted, and the new architecture (`ReactInstance` / bridgeless) routes `loadScriptFromFile` through `loadJSBundleFromFile` in the new runtime, never touching the legacy `Instance`. The only remaining user was its own unit test.

This removes `JSIndexedRAMBundle` and the two dead `Instance` RAM-bundle loaders that referenced it:

- Delete `JSIndexedRAMBundle.cpp`, `JSIndexedRAMBundle.h`, and `JSIndexedRAMBundleTest.cpp`.
- Remove `loadRAMBundleFromString` / `loadRAMBundleFromFile` from `Instance.cpp` / `Instance.h` and drop the now-unused include.
- Drop `JSIndexedRAMBundle.h` from `CXXREACT_PUBLIC_HEADERS` in `cxxreact/BUCK`.
- Update the committed C++ API snapshots accordingly.

The broader legacy RAM-bundle machinery (`RAMBundleRegistry`, `JSModulesUnbundle`, `Instance::loadRAMBundle`, `JSIExecutor::setBundleRegistry`) is left in place; it belongs to the same `RCT_REMOVE_LEGACY_ARCH` legacy bridge and can be removed as a follow-up.

Changelog: [Internal]

Reviewed By: javache, mdvacca

Differential Revision: D108001933

fbshipit-source-id: 4b0f12258e8caff1991847a4bb211e94fbecefa8
2026-06-10 07:40:08 -07:00
Christoph Purrer d205267a5f Compile out RuntimeScheduler_Legacy under RCT_REMOVE_LEGACY_ARCH (#57116)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/57116

## Changelog:
[General][Breaking] Compile out RuntimeScheduler_Legacy under RCT_REMOVE_LEGACY_ARCH

Guard the legacy RuntimeScheduler implementation behind the `RCT_REMOVE_LEGACY_ARCH` macro instead of deleting it. `RuntimeScheduler_Legacy.h`/`.cpp` remain in the tree, but their contents — along with the feature-flag-based selection between the legacy and modern schedulers in `RuntimeScheduler.cpp`, `NativeMutationObserver.cpp`, and `Task.h` — are wrapped in `#ifndef RCT_REMOVE_LEGACY_ARCH`. When the macro is defined, the legacy code is compiled out and `RuntimeScheduler` unconditionally instantiates `RuntimeScheduler_Modern`; when it is not defined, behavior is unchanged.

The C++ API snapshots are updated to drop the `RuntimeScheduler_Legacy` symbols from the new-arch surface, and the parameterized scheduler test (`RuntimeSchedulerTest`) only runs the modern configuration when the legacy arch is compiled out.

Reviewed By: rubennorte

Differential Revision: D107777881

fbshipit-source-id: 2b50711ab3af182edc45a87fd232d96a0f879837
2026-06-09 09:29:10 -07:00
Hur Ali 40c90ada39 fix: allow escape interpretation for shells (#57114)
Summary:
This makes the shell to use escape interpretation by setting `echo -e "..."`. For zsh shell, this often works out of the box. For other shells like bash, we may need to set it explicitly.

## Changelog:

<!-- Help reviewers and the release process by writing your own changelog entry.

Pick one each for the category and type tags:

[ANDROID|GENERAL|IOS|INTERNAL] [BREAKING|ADDED|CHANGED|DEPRECATED|REMOVED|FIXED|SECURITY] - Message

For more details, see:
https://reactnative.dev/contributing/changelogs-in-pull-requests
-->
[INTERNAL] [FIXED] - allow escape interpretation for shells

Pull Request resolved: https://github.com/facebook/react-native/pull/57114

Test Plan:
- CI Passes
- Verified Locally on template app

https://github.com/user-attachments/assets/4c8c6bf7-1cf2-4bd8-b094-651c44578ae0

Reviewed By: cipolleschi

Differential Revision: D107904889

Pulled By: cortinico

fbshipit-source-id: 2222f589ecc149a82d5067e0a2198b9c1a17ffcb
2026-06-09 02:50:30 -07:00
Jakub Piasecki 2546ce4d82 Fix display: contents nodes having hasNewLayout set incorrectly (#57103)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/57103

Changelog: [General][Fixed] Fixed `display: contents` nodes having `hasNewLayout` set incorrectly

`cleanupContentsNodesRecursively` unconditionally sets `hasNewLayout=true` on `display: contents` children, including on code paths where their parent's layout was not actually performed in this pass. The stale flag can survive across layout passes and, in clone-on-write renderers (e.g. React Native Fabric), be observed by a subsequent pass whose parent was cloned but whose layout was served from cache, leaving the contents child's owner pointing at the previous parent revision.

There are two paths through which the cleanup could stamp a contents child whose parent's `hasNewLayout` would end up false:

1. Measure-phase visit. Inside `calculateLayoutImpl`, the cleanup ran with no knowledge of `performLayout`. When the parent's `calculateLayoutImpl` was invoked only with `performLayout=false` (cache miss on measure, cache hit on layout), the cleanup stamped contents children even though the parent itself never had its `hasNewLayout` set.

2. Absolute-layout walk. `layoutAbsoluteDescendants` walks every static layout descendant of the containing block - including ones whose own `calculateLayoutImpl` was skipped via the layout-phase cache. The cleanup invoked along that walk unconditionally stamped contents children, but the parent's `hasNewLayout` was only updated when the recursion actually found new layout downstream.

In both cases, the result is the same invariant violation: a contents node with `hasNewLayout=true` whose parent has `hasNewLayout=false`. A consumer iterating the tree via `hasNewLayout` skips the parent and never clears the stale flag.

X-link: https://github.com/facebook/yoga/pull/1970

Test Plan:
Added `YGContentsNodeHasNewLayoutTest.cpp` with regression tests:
- `contents_child_hasNewLayout_not_stamped_on_measure_only_visit` - pins the measure-phase fix
- `absolute_descendant_through_contents_is_reachable_via_hasNewLayout` - pins the positive case for absolute-layout path
- `absolute_phase_cleanup_does_not_stamp_when_parent_layout_skipped` - pins the negative case for absolute-layout path

Reviewed By: javache

Differential Revision: D107854528

Pulled By: j-piasecki

fbshipit-source-id: cae5e889622296e8b6380a6428509b5ffea3e9ae
2026-06-08 07:49:55 -07:00
Hur Ali b392035b10 fix: add line break to gradle.properties for template testing (#57107)
Summary:
This fixes the failing CI jobs on main for `template` testing. The job fails as they echo `react.internal.mavenLocalRepo=...` to the `gradle.properties` of template test project. As a result of which the `gradle.properties` look like below:

```properties
android.builtInKotlin=false
android.newDsl=falsereact.internal.mavenLocalRepo=...
```

To fix it we add a line break in the `echo` command.

## Changelog:

<!-- Help reviewers and the release process by writing your own changelog entry.

Pick one each for the category and type tags:

[ANDROID|GENERAL|IOS|INTERNAL] [BREAKING|ADDED|CHANGED|DEPRECATED|REMOVED|FIXED|SECURITY] - Message

For more details, see:
https://reactnative.dev/contributing/changelogs-in-pull-requests
-->

[INTERNAL] [FIXED] - add line break to gradle.properties for template testing

Pull Request resolved: https://github.com/facebook/react-native/pull/57107

Test Plan:
- CI Passing
- Verified Locally

Reviewed By: cortinico

Differential Revision: D107880136

Pulled By: cipolleschi

fbshipit-source-id: 81cf2fe53c1c2285f79db538aa5aa3cb745f796d
2026-06-08 07:05:56 -07:00