Summary:
Pull Request resolved: https://github.com/react/react-native/pull/58463
Add `yarn format-swift` and `yarn format-check-swift` using Apple swift-format, and compose them into the repository-wide commands. The wrapper selects a repository-provided formatter when available or uses swift-format 6.3 or newer from the Swift toolchain. Missing tools produce environment-specific setup guidance before Swift is skipped.
Changelog: [Internal]
Reviewed By: cipolleschi
Differential Revision: D119487615
fbshipit-source-id: 4da9939aa7ddf400e810cd17aeec12aa6118023b
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/58465
Add `yarn format-python` and `yarn format-check-python` using Ruff, and compose them into the repository-wide commands. The wrapper selects a repository-provided Ruff binary when available or bootstraps pinned Ruff through Python 3 and pip. Missing tools produce environment-specific setup guidance before Python is skipped.
Changelog: [Internal]
Reviewed By: javache
Differential Revision: D119487614
fbshipit-source-id: 4801ae3e565fcaa86a860cc5b8bb3b2d823d48df
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/58466
Add `yarn format-java` and `yarn format-check-java` using the npm `google-java-format` package, which bundles google-java-format 1.23.0. This removes the Gradle build dependency and adds the offline package mirror and workspace lock entries. The wrapper discovers a suitable JDK when available and otherwise prints environment-specific Java 17 setup guidance before skipping Java.
Changelog: [Internal]
Reviewed By: javache
Differential Revision: D119487613
fbshipit-source-id: e5ed299cc19f64bd5aceefd90c6160852be8ba37
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/58462
Add `yarn format-kotlin` and `yarn format-check-kotlin` using the npm `ktfmt` package and its bundled formatter jar. This adds the offline package mirror and workspace lock entry without changing existing Kotlin source formatting or Gradle configuration. The wrapper discovers a suitable JDK when available and otherwise prints environment-specific Java 17 setup guidance before skipping Kotlin.
allow-large-files: The npm package intentionally contains the upstream ktfmt executable jar so offline and public installs use the same formatter.
Changelog: [Internal]
Reviewed By: javache
Differential Revision: D119487612
fbshipit-source-id: cb699a1286cffbf461ef69ed66f694e3f69415d0
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/58461
Add npm-driven clang-format commands for exported C-family sources. Expose `yarn format-cpp` and `yarn format-check-cpp`, and compose them into the repository-wide commands. The wrapper automatically selects the repository-provided formatter for its environment.
Changelog: [Internal]
Reviewed By: javache
Differential Revision: D119487611
fbshipit-source-id: 9d2e4267ce0d80f2002c0d3648e62e53bd3284af
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/57904
The Old Architecture has been deleted from React Native iOS, which makes the
legacy `RCTNativeAnimatedModule` unreachable:
- Its JS spec only requests `'NativeAnimatedModule'` when
`shouldUseTurboAnimatedModule()` is false, but `ReactInstance.cpp` sets
`RN$Bridgeless = true` unconditionally on iOS, so that branch never runs.
- Its only entry points were `-setBridge:` and `RCTUIManagerObserver`, and
`RCTBridge` is now an all-nil stub with `RCTCxxBridge` deleted.
- Nothing referenced it by filename except a single `legacy = True` Buck
plugin provider.
iOS Animated is served by `RCTNativeAnimatedTurboModule` (bridgeless ObjC) and
by the C++ `facebook::react::AnimatedModule` behind `cxxNativeAnimatedEnabled()`.
With the last bridge-dependent Animated consumer gone, also stripped the dead
bridge plumbing it was the only reason for:
- `RCTNativeAnimatedNodesManager -initWithBridge:surfacePresenter:` loses
`bridge:`.
- `RCTPropsAnimatedNode -connectToView:viewName:bridge:surfacePresenter:` loses
`bridge:` and the `RCTUIManager` fallback in `-updateView`, which collapses to
the single `synchronouslyUpdateViewOnUIThread:props:` call.
- `viewName:` goes too, since it was only used to look up a legacy view
manager. The C++ (`connectAnimatedNodeToView(Tag, Tag)`) and Kotlin
(`connectAnimatedNodeToView(animatedNodeTag, viewTag)`) nodes managers already
take two arguments, and the sole remaining ObjC caller passed `nil`.
`RCTNativeAnimatedTurboModule` is deliberately NOT renamed back to
`RCTNativeAnimatedModule` — that is a much wider rename, best done separately.
Changelog: [iOS][BREAKING] Delete legacy RCTNativeAnimatedModule from RN iOS
Reviewed By: zeyap
Differential Revision: D115663619
fbshipit-source-id: d9c703171c2121e8456d923e4db58e624c9040f5
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/58416
Follow-up to the Android change in the previous diff, applying the same cleanup
to iOS.
Bridgeless is the only supported mode, so the `bridgelessEnabled` surface on
`RCTRootViewFactoryConfiguration` was already deprecated and hardcoded: the
property was assigned `YES` in every initializer, the two deprecated
initializers ignored the argument entirely, and
`RCTDefaultReactNativeFactoryDelegate` returned `YES` unconditionally. Nothing
read the value.
Changes:
- Removed the `bridgelessEnabled` property from
`RCTRootViewFactoryConfiguration`.
- Removed the two deprecated initializers
`initWithBundleURLBlock:newArchEnabled:turboModuleEnabled:bridgelessEnabled:`
and `initWithBundleURL:newArchEnabled:turboModuleEnabled:bridgelessEnabled:`.
Both were marked `__deprecated` and discarded all arguments except the bundle
URL, delegating to the designated initializer.
- Removed the `bridgelessEnabled` method from
`RCTDefaultReactNativeFactoryDelegate`. It was not declared in any header or
protocol.
- Updated the one caller in `RCTReactNativeFactory` to use
`initWithBundleURLBlock:newArchEnabled:`.
Behavior is unchanged: bridgeless remains unconditionally enabled. Callers of
the designated `initWithBundleURLBlock:newArchEnabled:` and
`initWithBundleURL:newArchEnabled:` initializers are unaffected.
Changelog:
[iOS][Breaking] - Remove the deprecated `bridgelessEnabled` property and the deprecated `initWithBundleURLBlock:newArchEnabled:turboModuleEnabled:bridgelessEnabled:` / `initWithBundleURL:newArchEnabled:turboModuleEnabled:bridgelessEnabled:` initializers from `RCTRootViewFactoryConfiguration`; bridgeless is always enabled
Reviewed By: rubennorte
Differential Revision: D116318829
fbshipit-source-id: 9a8c232f22a9435934f848a7a80401841c2e29a2
Summary:
Hit this using IntersectionObserver on a ScrollView with `rootMargin` to preload content below the fold. `rootBounds` grew by the margin, but `intersectionRatio` stayed 0 for anything past the clip.
We're clipping the target to the root's overflow (the ScrollView / `overflow: hidden` box) *before* intersecting with the margin-expanded rect. That's not what the spec does.
[Compute the intersection](https://w3c.github.io/IntersectionObserver/#calculate-intersection-rect-algo): walk containing blocks *while container is not root* and clip there, then intersect with the [root intersection rectangle](https://w3c.github.io/IntersectionObserver/#root-intersection-rectangle), which already includes `rootMargin`. The spec also calls out that `rootMargin` only applies to the root — clipping by any other ancestor is unchanged.
This stops overflow-clipping the observation root itself. Intermediate clippers stay as they are, so a viewport-rooted observer still can't see past a ScrollView. That's `scrollMargin`, which we don't implement.
--
Lots of words to say: This enables rootMargin to correctly extend the viewport of ScrollViews or any other view with overflow clipping when using that view as the root. This also gives users a path around missing scrollMargin.
## Changelog:
[GENERAL] [FIXED] - IntersectionObserver rootMargin now affects intersection against a clipping root
Pull Request resolved: https://github.com/react/react-native/pull/58177
Test Plan:
- existing "clipping root with rootMargin" test: 10px margin on a 100x100 overflow:hidden root should intersect 60px of a child sitting at y=50, not 50px
- new ScrollView + `rootMargin: 150px` + `threshold: [0.01]` — target fully below the fold reports intersecting
- new viewport-root control — same layout, still not intersecting (intermediate ScrollView still clips)
Reviewed By: rubennorte
Differential Revision: D117876568
Pulled By: christophpurrer
fbshipit-source-id: 381991048593959748c44e76c17a06fd8b5c0fb3
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/58403
Changelog: [General][Added] - Added `ReactNativeVersion.h` to public `react/utils` module.
Existing one inside private `cxxreact/bridge` module is now deprecated and still accessible when not opted in to `RN_STRICT_API`.
Reviewed By: javache
Differential Revision: D119163947
fbshipit-source-id: 692649c1afce8763f7e1d1f9d642d4a652f6d075
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/58351
Add `experimental_textWidthMode` as a Text style for sizing wrapped text to its widest rendered line on Android and iOS. The `auto` value preserves the existing constrained measurement behavior, while `longest-line` removes unused horizontal space without changing the line count.
Changelog:
[General][Added] - Add experimental longest-line width sizing for wrapped `Text`
Reviewed By: javache
Differential Revision: D118718410
fbshipit-source-id: aa132bf509a286ab569cc0720867eeedab215bd1
Summary:
fixes https://github.com/react/yoga/issues/2006
`distributeFreeSpaceFirstPass` decrements `totalFlexGrowFactors` /
`totalFlexShrinkScaledFactors` as it freezes items, but only reduces `remainingFreeSpace`
after the loop. Items after the first frozen one get an inflated fair share and freeze
spuriously. When the first item clamps, the whole line freezes and `remainingFreeSpace`
drains to 0, so the second pass has nothing to distribute and everything falls back to its
flex basis — a 540px row of three `flexGrow: 1` items with `maxWidth: 180` and minWidths
60/30/30 lays out as 60/30/30 instead of 180/180/180.
Snapshot both totals before the loop and divide by the snapshot. The first pass is then
iteration 1 of CSS Flexbox §9.7, and independent of child order.
Layout only changes for configs that opt in: this sits behind
`Errata::FlexFirstPassUsesRunningTotals`, which new configs set by default, so existing
geometry is untouched until a config clears the bit. Same shape as
`MinSizeUndefinedInsteadOfAuto`, which gates the CSS §4.5 auto-min floor.
Changelog:
[General][Fixed] - Fix a flex line collapsing to its minimum sizes when the first item clamps to its min or max main size, behind the new `FlexFirstPassUsesRunningTotals` errata (set by default)
X-link: https://github.com/react/yoga/pull/2021
Reviewed By: javache
Differential Revision: D119142409
Pulled By: pasqualeanatriello
fbshipit-source-id: 9e5ad19e2ca818a5cccdcac68cfb8905a6f40894
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/58404
Classifies `cxxreact:bridge` as a private target under the three-tier C++ stable API visibility model. Consumers that opt into `RN_STRICT_API` now get an error if they include its headers directly; without that flag the guards are inert, so no existing build changes behaviour. `ReactNativeVersion.h` is a generated file, so its guard also goes into `scripts/releases/templates/ReactNativeVersion.h-template.js`; without that the next version stamp would rewrite the header and silently drop the guard from every release and nightly artifact.
Changelog: [Internal]
Reviewed By: javache
Differential Revision: D119163927
fbshipit-source-id: 9d436770753079448173e3bcb8d4d5e9c13ae8e3
Summary:
Fixes https://github.com/react/react-native/issues/58085.
Android represents both an undefined color and explicit transparent black as ARGB `0`. `SharedColor` previously compared only that raw value, so Props 2.0 considered an explicitly supplied transparent color equal to an absent prop and omitted it from the mount diff.
This change tracks color presence separately from the platform value and includes it in equality, boolean conversion, and hashing. Platform parsers and the few call sites that intentionally produce an undefined color now preserve that state explicitly.
## Changelog:
[ANDROID] [FIXED] - Preserve explicitly transparent colors during Props 2.0 reconciliation.
Pull Request resolved: https://github.com/react/react-native/pull/58093
Test Plan:
- Added `ColorTest.testTransparentColorIsDistinctFromUndefined`.
- Compiled and ran a standalone regression harness against Android `Color.cpp`; it failed before this change and passes afterward.
- Built `ReactAndroid` CMake Debug for `arm64-v8a` successfully.
- Validated all 9 ReactCommon, ReactAndroid, and ReactApple C++ API snapshots against Doxygen 1.16.1.
- Ran targeted clang-format and `git diff --check`.
Reviewed By: javache
Differential Revision: D117292692
Pulled By: Abbondanzo
fbshipit-source-id: 08120b7eb805dbed06cd76b6bd14fe29a556d88e
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/58325
Follow-ups to the buffered CallInvoker, kept out of that diff so the behavioural
change stays reviewable on its own. No behaviour change intended here.
- `BufferedRuntimeExecutor` gains `asRuntimeExecutor()` and
`asWeakRuntimeExecutor()`. RuntimeExecutor is a std::function, so callers
cannot hand it the object and instead each hand-rolled the same capturing
lambda; the ownership question now has one answer per lifetime policy. The
weak form is what `getBufferedRuntimeExecutor` needs, which must not keep the
instance alive.
- `BufferedWork` becomes private. It was only ever an implementation detail, and
being public put its fields in the C++ API snapshot.
- The buffer holds a `std::vector` sorted once at flush rather than a
`std::priority_queue`. Indices are handed out before the lock, so arrival
order can differ from submission order and something has to restore it — but a
heap is the expensive way. `std::priority_queue::top()` returns a const
reference, so every flushed item copied its `std::function` on the way out;
that copy is now a move, and nothing sifts on the way in.
- `runtimeExecutorThatGoesThroughRuntimeScheduler` was a second copy of
`getUnbufferedRuntimeExecutor()`; it now calls it.
- `RuntimeSchedulerCallInvoker` is marked deprecated. Its remaining users are
migrated: `ReactCxxPlatform` holds a `ReactInstance` and can use
`createJSCallInvoker()`, and four other files only `#include`d it without ever
constructing one. The single remaining use is the flag-off branch, which is
suppressed locally and goes when the flag is cleaned up.
- Drops a null check on `bufferedRuntimeExecutor_` in `callFunctionOnModule`
that the constructor makes unreachable.
Changelog:
[Internal]
Reviewed By: christophpurrer
Differential Revision: D118616045
fbshipit-source-id: 884179f2c8a1f61185d44216a505fc75e5d103eb
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/58313
In bridgeless, native reaches JS by two routes that end in the same
`RuntimeScheduler` queue but get there differently. `callFunctionOnModule` goes
through the instance's `BufferedRuntimeExecutor`; the `CallInvoker` goes
straight to `scheduleTask`. The CallInvoker therefore skips the buffer entirely
and can reach the runtime while a module call issued earlier is still parked,
unflushed, because the bundle is mid-evaluation. Native code that issues both
cannot rely on the order it issued them in, and `Task` is a min-heap on
`now() + timeout(priority)` with no insertion tiebreak, so equal priorities do
not settle it either.
Gives the two channels the same buffering. `BufferedRuntimeExecutor` gains a
priority-carrying `execute`, so work routed through it keeps the scheduler
priority it was submitted with instead of collapsing to the executor default,
and buffered work from both overloads stays in one submission-ordered stream.
`BufferedCallInvoker` sits on that executor and becomes the bridgeless
`jsCallInvoker` on Android, iOS and macOS.
`invokeSync` deliberately keeps going straight to the scheduler: a synchronous
call cannot wait for a flush that only happens once the bundle has run.
Behind `enableBufferedCallInvoker`, default true. `ReactInstance` picks between
the buffered invoker and the existing `RuntimeSchedulerCallInvoker` in one
place, so the platform call sites are identical either way and the change is
revertible at runtime — it moves when native-issued async work first reaches JS
during startup, which is the intended contract but affects every native module.
One lifetime hazard this surfaces, worth knowing about beyond this diff:
`BufferedRuntimeExecutor` reaches the scheduler through a raw pointer captured
at construction, which is safe only while the owning instance is alive. A
CallInvoker is routinely held across instance teardown, so `BufferedCallInvoker`
guards every async dispatch on a weak reference to the scheduler and drops the
work when it has expired — the same contract `RuntimeSchedulerCallInvoker` has.
Without that guard this reliably segfaults on a reload.
Changelog:
[General][Changed] - Async `CallInvoker` work is now buffered alongside callable module calls, so it no longer runs before the JS bundle has finished evaluating
Reviewed By: rubennorte
Differential Revision: D118456662
fbshipit-source-id: 7c6ccb595d69595721092eeb84b4724809140496
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/57724
Upgrade the legacy native module spec files from `flow` to `flow strict-local` to enforce stricter local type checking. Loose `Object` types were replaced with the codegen-equivalent `UnsafeObject`, and `Array<any>` parameters with `Array<unknown>`, both of which are codegen-identical so the generated native interfaces are unchanged.
Changelog: [Internal]
Reviewed By: javache
Differential Revision: D113763785
fbshipit-source-id: 085a0a570246eeda27b3c22a56a2696b04821fd5
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/58311
# Why
Currently, grid style properties are stored in yoga style (`gridTemplateRows_`, `gridAutoColumns_` etc). These properties increase the size of style object from `152` bytes to `280` bytes (84% increase). The cost is added even when a node is not a grid container or a grid item.
# How
Move grid style properties behind a pointer that is lazily allocated, on the first grid property set. A node that doesn't use grid only adds the cost of this pointer (8 bytes). So style now costs 160 bytes (5% increase). The public API remains unchanged.
# Tests
A test is added to catch the style size regression and `tests/GridStyleTest.cpp` includes additional cases to assert unset style, copy and move behaviour.
Changelog: [Internal]
X-link: https://github.com/react/yoga/pull/2018
Reviewed By: rubennorte
Differential Revision: D118628661
Pulled By: javache
fbshipit-source-id: 185370e93bcf5b277b48c436ba3d06dada5a66fe
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/58274
`ReadableNativeMap` materialization copied keys and created temporary JNI references for every imported type. Cache pointers to the stable native values and reuse global `ReadableType` references so importing maps and arrays does less allocation and lookup work.
Writable maps can continue mutating after materialization because `folly::dynamic` stores object entries in reference-stable `F14NodeMap` nodes.
Changelog: [Internal]
Reviewed By: christophpurrer, rubennorte
Differential Revision: D118277119
fbshipit-source-id: 955a60ef7f1eb4cb7549d64caa1238416e90b223
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/57984
`hash_combine` mixes each field into the previous seed, so it forms a dependency chain the CPU
cannot overlap and an unset optional still costs a full link. `hash_combine_optionals` folds a run
of optionals into one presence-mask link plus the engaged values, so a further optional costs a bit
in the mask rather than a link. The mask is what keeps it collision-free: skipping disengaged
fields alone would make the same value in two different slots hash identically.
Equality moves from `std::tie` to a short-circuit chain ordered cheapest first, with the string and
vector fields last, because the dominant caller is a successful cache lookup where the keys are
equal and every field has to be examined.
Changelog: [Internal]
Reviewed By: javache
Differential Revision: D115621401
fbshipit-source-id: f164c24f6b085ef8d32cafbeb2b61636eec3d0cf
Summary:
Replace the immediate template-app startup assertion with `extendedWaitUntil` and a 60-second timeout.
The Android ARM64 debug app occasionally becomes accessibility-visible just after the existing assertion times out under native translation. This failed all three attempts in [run 33609361836](https://github.com/react/react-native/actions/runs/33609361836/job/100196578829) and [run 33540863593](https://github.com/react/react-native/actions/runs/33540863593/job/99984608541). In the captured failure artifact, both the screenshot and XML hierarchy contain `Welcome to React Native`, indicating a startup/accessibility timing race rather than an app failure.
Release runs remain fast because `extendedWaitUntil` returns as soon as the element is visible.
## Changelog:
[INTERNAL] [FIXED] - Wait for the template app to become visible in Maestro E2E tests.
Pull Request resolved: https://github.com/react/react-native/pull/58289
Test Plan:
- `MAESTRO_CLI_NO_ANALYTICS=1 maestro check-syntax scripts/e2e/.maestro/start.yml` — passed (`OK`)
- `./node_modules/.bin/prettier --check scripts/e2e/.maestro/start.yml` — passed
- `git diff --check` — passed
- Inspected the failing Android debug artifact: the expected text is present in both the final screenshot and accessibility hierarchy.
Reviewed By: christophpurrer
Differential Revision: D118457123
Pulled By: cortinico
fbshipit-source-id: d2f5232482933e1decb13a9b2dac7911b205db4f
Summary:
**Motivation**
Minimum infra fix to enable subsequently landing https://github.com/react/react-native/pull/57940.
Referencing `ReactNativeFeatureFlags` on the existing `react-native/react-private-interface` boundary is blocked by a gap in the `build-types` pipeline and a type translation error, addressed here.
**Changes**
- `simpleResolve.js`: Explicitly support `react-native/react-private-interface` as a special case, fixing resolution.
- `ReactNativeFeatureFlagsBase.js`: Tweak the `OverridesFor` type here to fix TypeScript translation compatibility, where the unconstrained `T` type param is now narrowed.
**Impact**
No change to the API snapshot (the `ReactNativeFeatureFlags` import is ultimately tree-shaken!), and no effect on generated types until https://github.com/react/react-native/issues/57940 lands.
Changelog: [Internal]
Pull Request resolved: https://github.com/react/react-native/pull/58075
Test Plan:
- `yarn build-types`
- Applied https://github.com/react/react-native/issues/57940 patch on top; both stayed green, no `types_generated/**/featureflags/**`
Reviewed By: GijsWeterings
Differential Revision: D117513265
Pulled By: cortinico
fbshipit-source-id: 348e8de3d622081fe0062ef939ce14c21af587a8
Summary:
Build only the `arm64-v8a` Android ABI for dry-run CI artifacts and run the ARM64 RNTester and template-app APKs on an API 35 `google_apis` x86_64 emulator using the system images built-in NDK translation support.
This also makes the Maestro emulator API level and target configurable, logs the device ABI/native-bridge configuration, and updates local RNTester artifact selection to use the ARM64 split.
Release and nightly publication builds continue to build all supported Android ABIs.
## Changelog:
[INTERNAL] [CHANGED] - Run Android E2E tests with ARM64 APKs through NDK translation.
Pull Request resolved: https://github.com/react/react-native/pull/58092
Test Plan:
- `node --check .github/workflow-scripts/maestro-android.js` — passed.
- `node --check scripts/release-testing/test-release-local.js` — passed.
- Parsed all modified YAML files with the `yaml` Node package — passed.
- `./node_modules/.bin/prettier --check <modified files>` — passed.
- `git diff --check HEAD~3..HEAD` — passed.
- `actionlint` reported only existing repository metadata warnings for the custom `4-core-ubuntu` label and the missing description in the local `yarn-install` action.
- `yarn test .github/workflow-scripts/__tests__/maestro-android-test.js --runInBand` could not start because the local dependency tree is missing `flow-parser`; restoring dependencies was blocked by HTTP 503 responses from the npm registry.
- The draft CI run should validate ARM64 APK installation, Hermes startup, and the complete Maestro suites through `libndk_translation.so`.
Reviewed By: Abbondanzo
Differential Revision: D117195078
Pulled By: cortinico
fbshipit-source-id: a78f2127f04e80c3b5ca4c95d2024dffb92ff122
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/58001
The existing npm `clang-format` wrapper bundles LLVM 15, causing `yarn clang-format` to disagree with the formatting of checked-in headers.
Replace it with checksum-pinned DotSlash artifacts for `clang-format` 21.1.2 across Linux, macOS, and Windows. Add a chunked formatting runner and remove the obsolete npm dependency. The runner skips generated sources and ignores dirsynchronized or vendored subtrees that maintain their own formatting.
Changelog: [Internal]
Reviewed By: christophpurrer
Differential Revision: D116500359
fbshipit-source-id: 2141bee22ed2b712aae1637a1f052db23535bbb0
Summary:
> Stack 3/3 — parent: `feat/LayoutEventEmitter`. Review the two parents first.
Implements the [`ResizeObserver`](https://drafts.csswg.org/resize-observer/) Web API for the New Architecture, behind the `enableResizeObserverByDefault` flag (off by default).
The motivation is Web compatibility, and it's more capable than `onLayout`: callers pick which box to observe (`content-box`, `border-box`, `device-pixel-content-box`) and the sizes for those boxes are delivered in the notification.
The design is as follows: JS `ResizeObserver`/`ResizeObserverEntry`/`ResizeObserverSize` on top of a manager singleton and the `NativeResizeObserver` TurboModule, using the same notify + `takeRecords` pull model. In C++, `ResizeObserverManager` collects observed targets whose layout changed at commit time (via `shadowTreeDidCommit`) and then computes and delivers observations in the event loop's "update the rendering" step (`RuntimeSchedulerResizeObserverDelegate::runResizeObservations`), as the spec requires. Requires bridgeless + the modern event loop; the legacy scheduler gets a no-op delegate.
`runResizeObservations` implements the spec's depth-increasing gather/broadcast loop: each round gathers observations deeper than the shallowest target delivered in the previous round, so a callback that synchronously resizes or observes a shallower node is still delivered within the same tick.
Known deviations from the spec (each pinned by a test):
- Resizes triggered from a callback via a React state update are delivered on the next tick rather than within the current loop, because RN has no synchronous re-layout. Callbacks that resize or `observe()` synchronously do run further rounds in the same tick, and report `ResizeObserver loop completed with undelivered notifications` when an observation is left undelivered.
- The loop carries a hard cap of 100 iterations on top of the spec's depth rule. Reaching the cap reports the loop error and stops, so a pathological callback degrades to a log line instead of a frozen app.
- Re-observing a target with the same box is a no-op and does not re-deliver. This matches browsers, not the literal `observe()` algorithm.
- Callback order across observers follows first-`observe()` order rather than construction order.
## Changelog:
[INTERNAL] [ADDED] - Add the `ResizeObserver` API, behind the `enableResizeObserverByDefault` feature flag
Pull Request resolved: https://github.com/react/react-native/pull/57723
Test Plan:
- Fantom `ResizeObserver-itest.js` covers many test scenarios.
- rn-tester has `ResizeObserver` examples (box sizes, text, visibility); verified initial, resize, and animation-driven delivery there.
- `RuntimeSchedulerTest.cpp` new test scenarios for update rendering loop.
Reviewed By: christophpurrer
Differential Revision: D114045415
Pulled By: javache
fbshipit-source-id: a561d5321ba45adb35f46ffb0cf26ad78eb3bae6
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/57997
`scripts/debugger-frontend/sync-and-build` with `--create-diff` only worked under fbsource, making commit creation (in particular the generated changes table) inconvenient outside of Meta.
This diff lifts commit creation functionality to both Git and Mercurial (`sl`), and makes writing a local commit the default behaviour.
**Changes**
- Synced `debugger-frontend` artifacts are now always committed, regardless of version control backend. Internal Mercurial behaviour is forked to a `fbsource-backend.fb.js` script.
- `--create-diff` is narrowed to draft Phabricator diff submission (fbsource only).
- The script now aborts if there are any working copy changes.
Changelog: [Internal]
Reviewed By: vzaidman
Differential Revision: D116031207
fbshipit-source-id: 8ef3ed465b91d8f71ffa44fd1cba16f28860e3a9
Summary:
iOS TurboModules mapped a JS `ArrayBuffer` to `NSData` on arguments and `NSMutableData` on returns, so every crossing copied — and `NSMutableData` cannot alias foreign memory, so there was no way to express "these bytes live somewhere else".
This adds `RCTArrayBuffer` (`packages/react-native/React/Base/`) as the ObjC representation of an `ArrayBuffer`. It carries an `isOwningBytes` flag: an owning buffer can be stored and read from any thread, a non-owning one aliases bytes valid only for the synchronous call that produced it.
Codegen now emits `RCTArrayBuffer *` for `ArrayBufferTypeAnnotation` params (was `NSData *`) and returns (was `NSMutableData *`).
## Changelog:
[IOS] [BREAKING] - Add `RCTArrayBuffer`, the ObjC representation of a JS `ArrayBuffer` for TurboModules, with an explicit byte-ownership contract
Pull Request resolved: https://github.com/react/react-native/pull/57879
Test Plan:
- `RCTTurboModuleArrayBufferTests` — 9 tests over the sync in-place path, `isOwningBytes` on a sync argument, returning one's own argument, the void/Promise copy paths, nesting, and a zero-length round trip.
- `RCTTurboModuleTests.mm` adds `testNativeBackedArrayBufferIsAliasedAndKeepsBackingStoreAlive`.
- `RCTSampleTurboModule` doubles its argument in place and returns the same buffer, covering the path end to end.
- Codegen and C++ API snapshots regenerated.
Reviewed By: cipolleschi
Differential Revision: D115629409
Pulled By: christophpurrer
fbshipit-source-id: a7ee6eadf99fd5f9f82fd2a95b0d3ff1369f4ddf
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/57982
Changelog: [ANDROID][FIXED] Enforce the ArrayBuffer borrow contract for Java TurboModules
Follow-up hardening for the Android `ArrayBuffer` TurboModule type. Three problems:
**1. Borrowed JS-heap bytes outlived the call that lent them.** For a synchronous
method, `convertJSIArgsToJNIArgs` hands the module a `ByteBuffer` aliasing the JS
`ArrayBuffer`'s bytes without copying. Nothing stopped a module from stashing that
`ArrayBuffer` in a field and reading it later, after the JS heap may have moved,
freed, or reused the memory — a use-after-free that reads as intermittent data
corruption rather than a crash.
The borrow is now explicitly scoped to the call frame. `JNIArgs` records every
borrowed `ArrayBuffer` and revokes it in its destructor — including when the call
throws — via the new `JArrayBuffer::invalidate`, which drops the C++ side's
reference to the bytes. `ArrayBuffer.bytes` and `ArrayBuffer.size` then throw,
with a message pointing at `ArrayBuffer.arrayBufferWithCopiedBytes`, and
`JArrayBuffer::toJSBuffer` throws rather than aliasing revoked memory. Modules
that need the bytes past the call copy them; modules that don't keep the
zero-copy fast path.
Revocation lives entirely on the C++ side: the peer is the single source of
truth, and Kotlin asks it through `isBytesValid`. The destructor runs while the
stack unwinds, possibly with a Java exception pending, so it resolves each peer
pointer at borrow time — the `global_ref` alongside it keeps the Java object, and
therefore the peer, alive — and calls only the `noexcept`
`JArrayBuffer::invalidate`. No JNI calls are made from the destructor, which is
what lets it stay `noexcept` honestly.
**2. Argument conversion aborted under runtimes that refuse `tryGetMutableBuffer`.**
`jsi::Runtime::tryGetMutableBuffer` and `detached` are not universally
implemented: tracing and replay runtimes throw from `tryGetMutableBuffer`, and
`detached` throws a `JSINativeException` if the JS-side property isn't a bool.
`ArrayBuffer` argument conversion is not wrapped in a try/catch, so either throw
propagated out of a JNI frame. Both calls now go through exception-tolerant
helpers in `react/bridging/ArrayBuffer.h`; a runtime that refuses to answer is
treated as "no native buffer available", which selects the copy path. Routing
`AsyncArrayBuffer::acquire` and `::borrow` through the same helper fixes the
identical latent bug on the shared C++/ObjC path.
**3. A wrong return type from a module crashed instead of raising a JS error.**
The `ArrayBufferKind` return path cast the returned `jobject` to `JArrayBuffer`
unconditionally. A module returning any other object type produced undefined
behavior. The cast is now guarded by an `isInstanceOf` check that throws a
`jsi::JSError` naming the offending module and method.
Also in this change:
- `JByteBufferMutableBuffer::data()` reports null for a zero-capacity direct
buffer instead of calling `getDirectBytes()`, which throws for one. That made
`createArrayBuffer` throw for an empty `ArrayBuffer`.
- Dropped two dead zero-size branches in `JArrayBuffer`: `JByteBuffer::wrapBytes`
already routes `size == 0` to an empty buffer.
- `JArrayBuffer.cpp` reuses the shared `detail::OwnedBytesBuffer` from
`react/bridging/ArrayBuffer.h` instead of a second local copy.
- `ArrayBuffer.kt` KDoc corrected: the returned JS `ArrayBuffer` is a new object
over the same bytes rather than the identical one, `size` is the capacity and
not a view's remaining bytes, and `arrayBufferWithOwnedBytes` documents the
caller's lifetime obligation.
- `ArrayBuffer.kt` moves from the `bridge` target to `native-types`, alongside the
other JNI-backed bridge types.
Changelog:
[Android][Breaking] - TurboModule methods taking or returning an `ArrayBuffer`
now use `com.facebook.react.bridge.ArrayBuffer` instead of
`java.nio.ByteBuffer`, and an `ArrayBuffer` argument must not be retained past
the method that receives it unless its bytes are copied with
`ArrayBuffer.arrayBufferWithCopiedBytes()`.
Reviewed By: javache
Differential Revision: D115794808
fbshipit-source-id: 26f5d863469cc14a3f1bffc2cbc3302f3e983ecb
Summary:
Android TurboModules mapped a JS `ArrayBuffer` to `java.nio.ByteBuffer`, copying every argument into a direct buffer — and `ByteBuffer` carries no ownership contract, so there was no way to express aliased or borrowed bytes for synchronous in-place access.
This adds `ArrayBuffer` (`packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/ArrayBuffer.kt`) as the Java representation of an `ArrayBuffer`. It carries an `isOwningBytes` flag: an owning buffer can be stored and returned to JS, a non-owning one aliases bytes valid only for the synchronous call that produced it.
Codegen now emits `ArrayBuffer` for `ArrayBufferTypeAnnotation` params (was `ByteBuffer`) and returns (was `ByteBuffer`).
## Changelog:
[ANDROID] [ADDED] - Add `ArrayBuffer`, the Java representation of a JS `ArrayBuffer` for TurboModules, with an explicit byte-ownership contract
Pull Request resolved: https://github.com/react/react-native/pull/57897
Test Plan:
- Codegen Java spec and JNI C++ snapshot tests updated for `ArrayBuffer` param/return signatures.
- `SampleTurboModule` doubles its sync argument in place and returns the same buffer, covering the zero-copy path end to end; `createNativeBuffer` allocates via `ArrayBuffer`.
- C++ API snapshots regenerated.
Reviewed By: javache
Differential Revision: D115755247
Pulled By: christophpurrer
fbshipit-source-id: de067789ad145b7202da721a02f838358c82f4d8
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/57975
`HighResDuration::fromDOMHighResTimeStamp` and `HighResTimeStamp::fromDOMHighResTimeStamp` converted milliseconds back to nanoseconds with `static_cast<int64_t>(units * 1e6)`, which truncates toward zero.
`toDOMHighResTimeStamp()` divides the nanosecond count by 1e6 (one rounding) and multiplying back by 1e6 rounds again, so the product frequently lands a hair below the original integer (e.g. `537648854729249.97`). Truncation then chops off a whole nanosecond, so `fromDOMHighResTimeStamp(toDOMHighResTimeStamp(x)) != x` for roughly 2% of random `now()` values.
That is the source of an intermittent `BridgingTest/highResTimeStampTest` failure, which reported:
```
Expected equality of these values:
timestamp
Which is: 8-byte object <22-02 00-21 FD-E8 01-00>
bridging::fromJs<HighResTimeStamp>( rt, bridging::toJs(rt, timestamp), invoker)
Which is: 8-byte object <21-02 00-21 FD-E8 01-00>
```
Round to the nearest nanosecond instead of truncating. Nanosecond values below 2^53 are exactly representable in a double, so the round trip is now exact for every value below 2.25e15 ns (26 days of monotonic clock); beyond that the double's ULP exceeds 0.5 ns and residual error is at most 2 ns, which is a floor of the DOM representation itself.
Rounding is also the correct semantic independently of the round trip — truncation gives a systematic downward bias and is asymmetric across zero, which affects the other callers (`RCTHighResTimeStampFromSeconds` for touch timestamps, `RuntimeTargetConsole` `console.timeStamp`, and `PerformanceTracer`).
The rounding is `std::llround`, which costs both overloads their `constexpr`: `<cmath>` rounding functions do not become usable in a constant expression until C++23 (P0533), and this header is compiled as C++20 everywhere (`-std=c++20` in `rn_defs.bzl`, `react-native-flags.cmake`, the podspecs and `Package.swift`). Both carry a `TODO` to restore `constexpr` once the C++23 rollout reaches them.
Dropping it is safe here. All 14 call sites are plain runtime calls — none is in a constant-expression context, none assigns to a `constexpr` variable or feeds a `static_assert` — and both functions are defined inside the class body, so they stay implicitly `inline` and neither linkage nor ABI changes. `fromDOMHighResTimeStamp` converts a `double` arriving from JS, so constant-evaluating it was never meaningful in the first place.
This does narrow the published API surface, so the C++ API snapshots are regenerated: the only change across all nine `.api` files is the `constexpr` keyword dropping off these two declarations, 18 lines in total.
`HighResTimeStamp::fromDOMHighResTimeStamp` now delegates to `HighResDuration`'s so there is a single implementation.
`highResTimeStampTest` previously asserted on `HighResTimeStamp::now()`, whose magnitude is host-uptime-dependent, so it only tripped the bug on about 2% of runs. It now round-trips five fixed nanosecond values (including the exact value from the failing run), which exercises the bug on every run. No test was skipped, disabled, or loosened.
Changelog:
[General][Fixed] - Round instead of truncate when converting a `DOMHighResTimeStamp` back to nanoseconds, so `HighResTimeStamp` and `HighResDuration` round trips are exact
Reviewed By: javache
Differential Revision: D116286868
fbshipit-source-id: 1adafd1b57b1185f51f08fa4dc55d96b88c176cd
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/57952
Implement Idle frame spans in React Native DevTools, by emitting synthetic `NeedsBeginFrameChanged` + `BeginFrame` events.
**Definition**
An idle frame is emitted whenever the gap between two consecutive frames exceeds one vsync interval, derived from the display's refresh rate (`CADisplayLink.duration` on iOS, `Display.refreshRate` on Android, falling back to 60 Hz).
```
frame N gap > 1 vsync frame N+1
+------------+ +--------------------------------+ +------------+
| BeginFrame | | NeedsBeginFrameChanged | | BeginFrame |
| DrawFrame | | BeginFrame (no DrawFrame) | | DrawFrame |
+------------+ +--------------------------------+ +------------+
rendered as an "Idle frame"
```
**Implementation notes**
- Drop frames that begin before the recording start — Android `FrameMetrics` can deliver frames from app startup, and the first iOS `CADisplayLink` callback reports the previous vsync.
- Sort frames by begin timestamp before serializing, since async screenshot encoding can deliver them out of order and break gap detection.
- iOS: skip the frame event when the screenshot is unchanged, letting the gap render as an idle frame.
Changelog: [Internal]
Reviewed By: hoxyq
Differential Revision: D97502569
fbshipit-source-id: 7cb19e0a462ad878f0b44b66f6b5de3f76426ffe
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/57851
The flow-* packages have support for all latest syntax and is better maintained.
Changelog: [Internal]
Reviewed By: huntie
Differential Revision: D115064040
fbshipit-source-id: 7265eb722910a460c76d0dbde0603cf962fe4e4e
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/57815
Apply the existing `fontVariationSettings` text style prop when Fabric
constructs fonts on iOS. Parse CSS-compatible axis settings into CoreText
variation dictionaries while preserving absent, explicit-clear, and invalid
value semantics for nested text.
The parser supports quoted four-character OpenType tags and finite numeric
values, rejects malformed settings as a complete unit, and applies normalized
variations after the base font and feature settings are resolved. This shared
attributed-text path covers Fabric `Text` and `TextInput`.
Changelog:
[iOS][Added] - Add `fontVariationSettings` support for Fabric text
Reviewed By: Abbondanzo, christophpurrer
Differential Revision: D114121940
fbshipit-source-id: d2b2fffd4fe723c5205e5279a466a125aa7edd38
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/57804
Add a `fontVariationSettings` text style prop and carry it through Fabric text attributes into Android text rendering. Android now deserializes the prop for `<Text>`, applies it to `Paint`, and includes it in text measurement cache identity because variable axes can affect layout.
Preserve the distinction between an absent setting and an explicitly empty setting so nested text can inherit or clear the parent variation axes. Apply high-level font properties before low-level variation settings so explicit axes take precedence, matching CSS font realization order.
Settings syntax is intentionally forwarded unchanged through common text attributes and validated only by the Android font variation parser. This avoids narrowing the grammar Android accepts. As a result, malformed child settings are outside the supported inheritance contract: they replace an inherited value before Android validation and are not guaranteed to fall back to the parent settings. Android also accepts `normal` and the React Native empty-string convention as explicit resets.
Changelog:
[Android][Added] - Add `fontVariationSettings` support for `<Text>`
Reviewed By: Abbondanzo, huntie
Differential Revision: D113580491
fbshipit-source-id: 46cea13ef5f06b33ed9f9d0b28b5c16f84193ea6
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/57813
`SurfaceHandler` already takes a throwaway snapshot of its `Parameters` under `parametersMutex_` before handing them to the `UIManager`, but `UIManager::startSurface` and `UIManager::setSurfaceProps` took `moduleName` and `props` by const reference and then copy-captured them into the lambda posted to the `RuntimeExecutor`. That forced a second deep copy of the props tree — which for a real surface holds the initial route params and deep link data — on every surface start, prop update, and display mode change.
Take both by value and move them into the lambda, and move at the `SurfaceHandler` call sites, so the snapshot is handed off instead of duplicated. The snapshot is a local that is dead after the call, so there is nothing left to observe the moved-from state.
Changelog:
[General][Changed] - `UIManager::startSurface` and `UIManager::setSurfaceProps` now take `moduleName` and `props` by value
Reviewed By: zeyap, christophpurrer
Differential Revision: D114730310
fbshipit-source-id: 7891f6ac61abda43ff0da5f4336741af6c329ed2
Summary:
On Android, in development, the JS bundle is downloaded and saved as a file - this is done to avoid passing it through JNI, but iOS could use similar approach for uniform behavior.
This allows libraries to be able to obtain the bundle from the file without re-downloading it from Metro.
It would impact iOS boot slightly, but only in development, so it should be negligible.
## Changelog:
[IOS] [CHANGED] - make iOS preserve dev bundle as a temp file on par with Android implementation
Pull Request resolved: https://github.com/react/react-native/pull/57751
Test Plan: rn-tester iOS dev works with this change
Reviewed By: cortinico, christophpurrer
Differential Revision: D114346244
Pulled By: coado
fbshipit-source-id: ebb4264fe8949cd766e71ca0363aa209a61370f7
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/57806
Changelog: [INTERNAL]
Remove the dead `NativeModalManager` TurboModule spec and all its dependents — 13 files, 192 deletions across JS spec, Modal.js usage, native registration, CXX API snapshots, blocklist entries, and test mocks. The spec was never implemented and the Modal component no longer needs the event subscription pattern since transitioning to the new renderer.
Reviewed By: cortinico
Differential Revision: D114652881
fbshipit-source-id: af939c002d4d58c662bacb840c805d2dd4f42eb4
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/57668
When enabling the props 2.0 feature flags I noticed that for an `<Image source={...} style={{ tintColor: 'transparent' }} />` the image is actually still showing, instead of becoming transparent.
### The underlying issue
All color props are defined as `SharedColor`, where a `SharedColor` has a default value of `0`:
https://github.com/facebook/react-native/blob/f3678f51d9873cb19602d7e36a4d8ed71562b9d0/packages/react-native/ReactCommon/react/renderer/graphics/platform/android/react/renderer/graphics/HostPlatformColor.h#L15-L18https://github.com/facebook/react-native/blob/f3678f51d9873cb19602d7e36a4d8ed71562b9d0/packages/react-native/ReactCommon/react/renderer/graphics/Color.h#L30-L32
> [!NOTE]
> This is a bit confusing to me. `0` is not really an "undefined" color, but its actually "transparent". What we are really saying this way is that all color props have a default value of "transparent". The naming makes me unsure whether this has been intentional.
For other use cases, this seems to make sense. Ie. a user expects their text to have a background color of transparent/"nothing". However, we do not expect our image's tint color to have a default color of "transparent". This would hide all our images.
With props 2.0 we use the `getDiffProp` function, and when we pass `tintColor: 'transparent'` it will be passed to native as `tintColor: 0`. When we then compare the passed prop's value vs the default value here, it will not include the `tintColor`:
https://github.com/facebook/react-native/blob/f3678f51d9873cb19602d7e36a4d8ed71562b9d0/packages/react-native/ReactCommon/react/renderer/components/image/ImageProps.cpp#L249-L251
`tintColor` really is an optional color prop, and should be treated as such. The best fix I found was therefor making it really an `std::optional`. Let me know if you think otherwise!
## 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
-->
[ANDROID] [CHANGED] - ImageProps make `tintColor` an `std::optional` to support color `transparent` (`0`) with props 2.0
X-link: https://github.com/facebook/react-native/pull/55535
Test Plan:
- In the RNTester app change one of the Tint Color image examples to use tintColor of "transparent"
- The image should be invisible now as all visible pixels turned transparent
- Enable the props 2.0 feature flags
- Run the same example, notice that the tintColor has not been applied
Reviewed By: lenaic
Differential Revision: D93140534
Pulled By: coado
fbshipit-source-id: 0d8abf3583d87ad840b3f72603b4c29c775671ca
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/57752
## Rationale
Flow lib defs that declare global types (available anywhere, without an `import`) must be referenced in `.flowconfig` and can't be maintained incrementally. That's not too bad for very stable APIs and it's necessary for environment/runtime globals, but for 3P libraries it makes the lib defs much more difficult to maintain for little benefit (we have to import the runtime APIs anyway). Secondarily, it's a problem for generating TypeScript types, as TS doesn't declare any 3P library globally.
Babel is one of few cases where a library declares Flow globals - every one has an importable equivalent.
## This diff
Replaces usages of Babel global types across xplat/js with their `babel/types` equivalents
Changelog: [Internal]
Reviewed By: javache
Differential Revision: D113574665
fbshipit-source-id: be668d968345a60e76a3515d19d8eaa002d53274
Summary:
> Stack 2/3 — parent: `feat/shadowTreeDidCommit`. Review that first.
`onLayout` events are emitted inline from `ShadowTree::emitLayoutEvents`, which forces `ShadowTree` to depend on `ViewProps` and `BaseViewEventEmitter`.
This moves that logic into a standalone `LayoutEventEmitter` that consumes the `shadowTreeDidCommit` hook (added in the parent PR) and is registered as a commit hook by `Scheduler`. Same filter (nodes with an `onLayout` prop), same timing (during commit), same `BaseViewEventEmitter::onLayout` call — behavior is unchanged.
After this, `ShadowTree` no longer references view props or event emitters, and the per-commit layout-change signal is shared with `ResizeObserver` instead of being duplicated.
## Changelog:
[INTERNAL] [CHANGED] - Emit `onLayout` from a `LayoutEventEmitter` commit hook instead of inline in `ShadowTree`
Pull Request resolved: https://github.com/react/react-native/pull/57722
Test Plan: Behavior-preserving refactor. Existing `onLayout` tests pass and `ShadowTree` no longer includes `ViewShadowNode`/`ViewProps`. Verified in rn-tester that `onLayout` still fires on mount and on size changes.
Reviewed By: christophpurrer
Differential Revision: D114045065
Pulled By: javache
fbshipit-source-id: 5b887537ad3e947f3a352fb9dd10b7d124f669df
Summary:
> Stack 1/3 — parent: `main`. Followed by `LayoutEventEmitter` → `ResizeObserver`.
`ShadowTree` already computes the set of nodes whose layout changed on every commit (`affectedLayoutableNodes`), but today it's only consumed internally by `ShadowTree::emitLayoutEvents`.
This adds a `shadowTreeDidCommit(shadowTree, rootShadowNode, affectedLayoutableNodes)` method to `ShadowTreeDelegate` and `UIManagerCommitHook` so other systems can react to layout changes after a commit. `ShadowTree` calls it once the new revision is installed, and `UIManager` forwards it to the registered commit hooks.
Both declarations have no-op defaults, so nothing observes the hook yet — this is inert on its own. It's the shared signal the next two PRs build on (extracting `onLayout` emission, and `ResizeObserver`), so neither has to re-derive which nodes changed layout.
## Changelog:
[INTERNAL] [ADDED] - Add `shadowTreeDidCommit` commit hook exposing the nodes with layout changes after each commit
Pull Request resolved: https://github.com/react/react-native/pull/57721
Test Plan: No behavior change: the hook has no-op defaults and no consumer in this PR. Existing Fabric commit/mounting tests pass.
Reviewed By: mdvacca
Differential Revision: D114044722
Pulled By: javache
fbshipit-source-id: 2a556006f7b66a967aea5559cf10273c61aabcbe
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/57579
Makes `enableMountingCoordinatorPullModelAndroid` functional. With the flag on, the commit thread only signals transaction availability and the UI thread pulls and applies at mount time (matching iOS/macOS); with the flag off (default), behavior is byte-for-byte identical.
- `schedulerShouldRenderTransactions`: notifies via JNI (`FabricMountingManager::onTransactionAvailable`) instead of pulling and building the batch.
- `schedulerDidFinishTransaction`: no-op under the pull model.
- `FabricUIManagerBinding::pullAndExecuteTransaction` (new JNI method): pulls the surface's transaction on the UI thread and runs `executeMount`.
- `FabricMountingManager::executeMount`: gains a `synchronous` mode that executes the batch directly on the UI thread.
- The accumulation sites remain gated on `enableAccumulatedUpdatesInRawPropsAndroid`; the pull model requires that flag to be co-enabled, since a pull may collapse several commits into one diff and therefore needs complete accumulated rawProps.
## Changelog:
[Android] [Added] - Wire the pull-model mounting path in C++ behind `enableMountingCoordinatorPullModelAndroid`
Reviewed By: christophpurrer
Differential Revision: D112309053
fbshipit-source-id: 6e3ca5b8fbc8db647356ac555890c2e465890100
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/57655
An implementation for the RFC in https://github.com/react-native-community/discussions-and-proposals/pull/1008
Wires up the Android native color resolver (Fabric) to honor the lazy `{fallback}` carried by `PlatformColor(...)`. A later diff adds the JS argument that emits it, so on its own this change is a no-op for existing call sites.
To tell a genuine miss apart from a token that resolves to transparent black (ARGB 0):
- `FabricUIManager.getColor` now returns a boxed `Nullable Integer` — `null` means no resource path resolved. The Fabric C++ `PlatformColorParser.h` reads that boxed result over JNI, caches the explicit-miss signal, and on a miss parses the raw fallback string with the shared CSS color parser (`parseCSSProperty<CSSColor>`), matching the iOS Fabric path. The color object is now read as a `map<string, RawValue>` because it mixes an array (`resource_paths`) with an optional string (`fallback`).
- `NativeDrawable` carries an optional `colorFallback` alongside `resource_paths` so ripple drawables degrade to the fallback too.
Generated files (`ReactAndroid.api` and the `ReactAndroid*Cxx.api` snapshots) are regenerated to match the new public signatures.
Changelog:
[Internal] - PlatformColor: Android native support for a lazy raw-color fallback
Reviewed By: mdvacca, javache
Differential Revision: D113329136
fbshipit-source-id: ee15aea8dfed66364e99d427825e1b9ebcbdc483
Summary:
Pull Request resolved: https://github.com/react/react-native/pull/57656
Changelog: [Internal]
View event handlers can run synchronously before NativeAnimated nodes created on the async path have been flushed into the active graph. Flush pending async-created nodes on the render thread before evaluating view-driven animation events, so focus-driven animations can resolve their value nodes on the first native focus event instead of needing another runloop/event.
Reviewed By: zeyap
Differential Revision: D111257551
fbshipit-source-id: d5b7322cfce90b820ccf06422f1c830255bea3b3
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