Skip to content

feat(macos): merge RN through RedBox 2.0 cutoff and port RedBox 2.0 to AppKit - #3054

Draft
Saadnajmi wants to merge 566 commits into
microsoft:0.85-mergefrom
Saadnajmi:saadnajmi/0-85-redbox2-merge-appkit
Draft

feat(macos): merge RN through RedBox 2.0 cutoff and port RedBox 2.0 to AppKit#3054
Saadnajmi wants to merge 566 commits into
microsoft:0.85-mergefrom
Saadnajmi:saadnajmi/0-85-redbox2-merge-appkit

Conversation

@Saadnajmi

Copy link
Copy Markdown
Collaborator

Summary

This draft genuinely merges React Native through 78a740d40aa2f9284b4568cb14307628e0f1d3f1 (react#56585, the complete RedBox 2.0 introduction), preserves React Native macOS adaptations, regenerates broad-merge artifacts, and ports RedBox 2.0 to AppKit.

This replacement supersedes #3047 without modifying or closing it: #3047 uses cherry-pick topology, while this draft preserves the real upstream two-parent merge and its provenance. #3047 remains open and unmodified.

Topology

Role Commit Tree Parent(s)
Microsoft 0.85-merge base dcd3d60324c220393aae7729bb538235f3c70416
Upstream cutoff 78a740d40aa2f9284b4568cb14307628e0f1d3f1
Mechanical merge c1798b51c75f09c2b8585bd6ceb8ccc2dee31dc7 56c1f7c25cb4e86c322dc55d48102816508b1315 dcd3d603… then 78a740d4…
Aggregate correction e3351d0afc5432314e586f4fd6fd8d516e51355f 127f67ee477700dabf536454e9a1f389fe344848 c1798b51…
AppKit port c616cd7a66125ca03c04d30c8dd44c2738ef1780 50b97dd5df97a82b5605e2cdfaab6667dccb6ccf e3351d0a…
Reachability fix / PR head c499d672e6a43bcb5ba7c00b5ecde6112905f9f9 778136a143540a71a21ed42406ccd8590458cbe6 c616cd7a…
0.85-merge (dcd3d603) ──┐
                        ├─► c1798b51  genuine ordered two-parent merge
78a740d4 (#56585) ──────┘
                            │
                            ▼
                        e3351d0a  50-path correction layer
                            │
                            ▼
                        c616cd7a  four-file AppKit port
                            │
                            ▼
                        c499d672  RCTRedBox.mm reachability fix

The first-parent count from Microsoft 0.85-merge to the PR head is exactly four. No commit was rebased, squashed, reworded, or regenerated.

Merge scope

git rev-list --count dcd3d60324c220393aae7729bb538235f3c70416..78a740d40aa2f9284b4568cb14307628e0f1d3f1 returns 561.

The deterministic path-scoped query

git log --oneline \
  dcd3d60324c220393aae7729bb538235f3c70416..78a740d40aa2f9284b4568cb14307628e0f1d3f1 \
  -- 'packages/react-native/React/CoreModules/RCTRedBox*'

returns 10 of 561 commits that touch RCTRedBox*; 551 do not. The cutoff commit 78a740d4 (react#56585, Add redbox subspec to React-debug pod) is within those 551 because it does not touch that pathspec.

The fetched React Native 0.86 fork point is d1cdce24cca2224f8d37873d24a49523a8271a0a, derived by git merge-base origin/0.86-merge facebook/0.86-stable. The cutoff is its ancestor, and:

git rev-list --count 78a740d40aa2f9284b4568cb14307628e0f1d3f1..d1cdce24cca2224f8d37873d24a49523a8271a0a
21

Conflict and correction decisions

A fresh-clone-only git merge-tree --write-tree dcd3d603… 78a740d4… re-derived 49 conflict paths: 46 content and 3 modify/delete, with 144 stage records. The generated merge tree contains 100 conflict blocks / 300 exact marker terms.

The 50-path correction layer is exact-set checked against the finished merge diff:

Category Paths Decision
Workflow cleanup 1 Remove inherited upstream blank EOF for first-parent diff-check
Dependency ownership 2 Align Hermes tooling and declare Fantom's direct import
Generated feature flags 3 Canonical yarn featureflags --update output
Generated JavaScript API 1 Canonical yarn build-types snapshot
Generated C++ API 6 Pinned Doxygen 1.16.1 output
Generated Babel fixtures 12 Canonical Jest update output under Node 22/Yarn 4
Generated LogBox snapshot 1 Canonical Jest output after the broad View adaptation
Yarn/CocoaPods locks 2 Public npm and CocoaPods 1.15.2 regeneration
RNM native/SwiftPM forward-port 22 Bounded platform/ownership adaptations

22 RNM native/SwiftPM adaptations

Exact path list
packages/react-native/Libraries/Text/TextInput/RCTBackedTextInputDelegateAdapter.mm
packages/react-native/Package.swift
packages/react-native/React/CoreModules/RCTDevLoadingView.mm
packages/react-native/React/CoreModules/RCTRedBox+Internal.h
packages/react-native/React/CoreModules/RCTRedBox.mm
packages/react-native/React/CoreModules/RCTRedBox2AnsiParser+Internal.h
packages/react-native/React/CoreModules/RCTRedBox2AnsiParser.mm
packages/react-native/React/CoreModules/RCTRedBox2Controller+Internal.h
packages/react-native/React/CoreModules/RCTRedBox2Controller.mm
packages/react-native/React/CoreModules/RCTRedBoxController+Internal.h
packages/react-native/React/CoreModules/RCTRedBoxController.mm
packages/react-native/React/DevSupport/RCTFrameTimingsObserver.mm
packages/react-native/ReactCommon/React-Fabric.podspec
packages/react-native/ReactCommon/react/renderer/components/legacyviewmanagerinterop/platform/ios/react/renderer/components/legacyviewmanagerinterop/RCTLegacyViewManagerInteropCoordinator.mm
packages/react-native/ReactCommon/react/renderer/components/view/HostPlatformTouch.h
packages/react-native/ReactCommon/react/renderer/components/view/HostPlatformViewEventEmitter.h
packages/react-native/ReactCommon/react/renderer/components/view/HostPlatformViewProps.h
packages/react-native/ReactCommon/react/renderer/components/view/HostPlatformViewTraitsInitializer.h
packages/react-native/ReactCommon/react/renderer/components/view/KeyEvent.h
packages/react-native/ReactCommon/react/renderer/components/view/MouseEvent.h
packages/react-native/ReactCommon/react/renderer/components/view/platform/macos/react/renderer/components/view/HostPlatformViewEventEmitter.cpp
packages/react-native/ReactCommon/react/renderer/components/view/platform/macos/react/renderer/components/view/HostPlatformViewProps.cpp

Full correction inventory

All 50 paths, categories, and provenance
status	category	path	provenance
M	workflow_cleanup	.github/workflows/test-all.yml	Inherited upstream blank EOF removed for first-parent diff-check
M	dependency_ownership	package.json	Align root hermes-estree with cutoff Hermes 0.35 toolchain
M	generated_babel_fixture	packages/react-native-babel-preset/src/__tests__/__fixtures__/output/default-dev.js	Canonical Jest -u output under Node 22/Yarn 4 cutoff toolchain
M	generated_babel_fixture	packages/react-native-babel-preset/src/__tests__/__fixtures__/output/default-prod.js	Canonical Jest -u output under Node 22/Yarn 4 cutoff toolchain
M	generated_babel_fixture	packages/react-native-babel-preset/src/__tests__/__fixtures__/output/hermes-canary-dev.js	Canonical Jest -u output under Node 22/Yarn 4 cutoff toolchain
M	generated_babel_fixture	packages/react-native-babel-preset/src/__tests__/__fixtures__/output/hermes-canary-prod.js	Canonical Jest -u output under Node 22/Yarn 4 cutoff toolchain
M	generated_babel_fixture	packages/react-native-babel-preset/src/__tests__/__fixtures__/output/hermes-stable-dev-preserve-async.js	Canonical Jest -u output under Node 22/Yarn 4 cutoff toolchain
M	generated_babel_fixture	packages/react-native-babel-preset/src/__tests__/__fixtures__/output/hermes-stable-dev-preserve-class-private.js	Canonical Jest -u output under Node 22/Yarn 4 cutoff toolchain
M	generated_babel_fixture	packages/react-native-babel-preset/src/__tests__/__fixtures__/output/hermes-stable-dev.js	Canonical Jest -u output under Node 22/Yarn 4 cutoff toolchain
M	generated_babel_fixture	packages/react-native-babel-preset/src/__tests__/__fixtures__/output/hermes-stable-prod-no-import-export-transform.js	Canonical Jest -u output under Node 22/Yarn 4 cutoff toolchain
M	generated_babel_fixture	packages/react-native-babel-preset/src/__tests__/__fixtures__/output/hermes-stable-prod.js	Canonical Jest -u output under Node 22/Yarn 4 cutoff toolchain
M	generated_babel_fixture	packages/react-native-babel-preset/src/__tests__/__fixtures__/output/no-babel-runtime.js	Canonical Jest -u output under Node 22/Yarn 4 cutoff toolchain
M	generated_babel_fixture	packages/react-native-babel-preset/src/__tests__/__fixtures__/output/no-import-export-transform.js	Canonical Jest -u output under Node 22/Yarn 4 cutoff toolchain
M	generated_babel_fixture	packages/react-native-babel-preset/src/__tests__/__fixtures__/output/with-babel-runtime-version.js	Canonical Jest -u output under Node 22/Yarn 4 cutoff toolchain
M	generated_logbox_snapshot	packages/react-native/Libraries/LogBox/UI/__tests__/__snapshots__/LogBoxInspectorStackFrames-test.js.snap	Canonical Jest -u output after broad View adaptation
M	rnm_native_adaptation	packages/react-native/Libraries/Text/TextInput/RCTBackedTextInputDelegateAdapter.mm	Restore macOS text-input delegate implementation; preserves existing first-parent whitespace byte
M	rnm_native_adaptation	packages/react-native/Package.swift	Bounded 4014f771..db92dc83 RNM platform/SwiftPM adaptation; cutoff upstream bytes preserved
M	rnm_native_adaptation	packages/react-native/React/CoreModules/RCTDevLoadingView.mm	Bounded 4014f771..db92dc83 RNM platform/SwiftPM adaptation; cutoff upstream bytes preserved
M	rnm_native_adaptation	packages/react-native/React/CoreModules/RCTRedBox+Internal.h	Bounded 4014f771..db92dc83 RNM platform/SwiftPM adaptation; cutoff upstream bytes preserved
M	rnm_native_adaptation	packages/react-native/React/CoreModules/RCTRedBox.mm	Apply 0.86 macOS RedBox2 exclusion; five-file AppKit child intentionally reverses this gate
M	rnm_native_adaptation	packages/react-native/React/CoreModules/RCTRedBox2AnsiParser+Internal.h	Bounded 4014f771..db92dc83 RNM platform/SwiftPM adaptation; cutoff upstream bytes preserved
M	rnm_native_adaptation	packages/react-native/React/CoreModules/RCTRedBox2AnsiParser.mm	Bounded 4014f771..db92dc83 RNM platform/SwiftPM adaptation; cutoff upstream bytes preserved
M	rnm_native_adaptation	packages/react-native/React/CoreModules/RCTRedBox2Controller+Internal.h	Bounded 4014f771..db92dc83 RNM platform/SwiftPM adaptation; cutoff upstream bytes preserved
M	rnm_native_adaptation	packages/react-native/React/CoreModules/RCTRedBox2Controller.mm	Bounded 4014f771..db92dc83 RNM platform/SwiftPM adaptation; cutoff upstream bytes preserved
M	rnm_native_adaptation	packages/react-native/React/CoreModules/RCTRedBoxController+Internal.h	Bounded 4014f771..db92dc83 RNM platform/SwiftPM adaptation; cutoff upstream bytes preserved
M	rnm_native_adaptation	packages/react-native/React/CoreModules/RCTRedBoxController.mm	Forward-port legacy AppKit RedBox controller ownership and behavior
M	rnm_native_adaptation	packages/react-native/React/DevSupport/RCTFrameTimingsObserver.mm	Bounded 4014f771..db92dc83 RNM platform/SwiftPM adaptation; cutoff upstream bytes preserved
M	generated_featureflags	packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsDefaults.kt	Canonical yarn featureflags --update output
M	rnm_native_adaptation	packages/react-native/ReactCommon/React-Fabric.podspec	Bounded 4014f771..db92dc83 RNM platform/SwiftPM adaptation; cutoff upstream bytes preserved
M	generated_featureflags	packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h	Canonical yarn featureflags --update output
M	rnm_native_adaptation	packages/react-native/ReactCommon/react/renderer/components/legacyviewmanagerinterop/platform/ios/react/renderer/components/legacyviewmanagerinterop/RCTLegacyViewManagerInteropCoordinator.mm	Bounded 4014f771..db92dc83 RNM platform/SwiftPM adaptation; cutoff upstream bytes preserved
A	rnm_native_adaptation	packages/react-native/ReactCommon/react/renderer/components/view/HostPlatformTouch.h	Bounded 4014f771..db92dc83 RNM platform/SwiftPM adaptation; cutoff upstream bytes preserved
A	rnm_native_adaptation	packages/react-native/ReactCommon/react/renderer/components/view/HostPlatformViewEventEmitter.h	Bounded 4014f771..db92dc83 RNM platform/SwiftPM adaptation; cutoff upstream bytes preserved
A	rnm_native_adaptation	packages/react-native/ReactCommon/react/renderer/components/view/HostPlatformViewProps.h	Bounded 4014f771..db92dc83 RNM platform/SwiftPM adaptation; cutoff upstream bytes preserved
A	rnm_native_adaptation	packages/react-native/ReactCommon/react/renderer/components/view/HostPlatformViewTraitsInitializer.h	Bounded 4014f771..db92dc83 RNM platform/SwiftPM adaptation; cutoff upstream bytes preserved
A	rnm_native_adaptation	packages/react-native/ReactCommon/react/renderer/components/view/KeyEvent.h	Bounded 4014f771..db92dc83 RNM platform/SwiftPM adaptation; cutoff upstream bytes preserved
A	rnm_native_adaptation	packages/react-native/ReactCommon/react/renderer/components/view/MouseEvent.h	Bounded 4014f771..db92dc83 RNM platform/SwiftPM adaptation; cutoff upstream bytes preserved
M	rnm_native_adaptation	packages/react-native/ReactCommon/react/renderer/components/view/platform/macos/react/renderer/components/view/HostPlatformViewEventEmitter.cpp	Bounded 4014f771..db92dc83 RNM platform/SwiftPM adaptation; cutoff upstream bytes preserved
M	rnm_native_adaptation	packages/react-native/ReactCommon/react/renderer/components/view/platform/macos/react/renderer/components/view/HostPlatformViewProps.cpp	Bounded 4014f771..db92dc83 RNM platform/SwiftPM adaptation; cutoff upstream bytes preserved
M	generated_js_api	packages/react-native/ReactNativeApi.d.ts	Canonical yarn build-types API snapshot
M	generated_featureflags	packages/react-native/src/private/featureflags/ReactNativeFeatureFlags.js	Canonical yarn featureflags --update output
M	lockfile	packages/rn-tester/Podfile.lock	CocoaPods 1.15.2 Hermes/native adaptation regeneration
M	dependency_ownership	private/react-native-fantom/package.json	Declare direct istanbul-lib-coverage import exposed by Yarn pnpm linker isolation
M	generated_cxx_api	scripts/cxx-api/api-snapshots/ReactAndroidDebugCxx.api	Pinned Doxygen 1.16.1 validator output
M	generated_cxx_api	scripts/cxx-api/api-snapshots/ReactAndroidReleaseCxx.api	Pinned Doxygen 1.16.1 validator output
M	generated_cxx_api	scripts/cxx-api/api-snapshots/ReactAppleDebugCxx.api	Pinned Doxygen 1.16.1 validator output
M	generated_cxx_api	scripts/cxx-api/api-snapshots/ReactAppleReleaseCxx.api	Pinned Doxygen 1.16.1 validator output
M	generated_cxx_api	scripts/cxx-api/api-snapshots/ReactCommonDebugCxx.api	Pinned Doxygen 1.16.1 validator output
M	generated_cxx_api	scripts/cxx-api/api-snapshots/ReactCommonReleaseCxx.api	Pinned Doxygen 1.16.1 validator output
M	lockfile	yarn.lock	Public npm Node 22/Yarn 4.12 canonical regeneration

Hermes, Fantom, and generated-artifact rationale

  • Hermes: root hermes-estree is realigned to the cutoff's Hermes 0.35 toolchain. CocoaPods' hermes-engine checksum embeds an absolute HERMES_CLI_PATH, so the two checksum lines are checkout-path-dependent—not a dependency change. The corrected Pod gate also hides Git from podspec evaluation, preventing 74 podspecs from injecting the ephemeral PR-head SHA into portable checksums.
  • Fantom: @react-native/fantom declares its direct istanbul-lib-coverage import, required by Yarn's strict pnpm linker.
  • Generated artifacts: 23 paths across feature flags (3), JavaScript API (1), C++ API (6), Babel fixtures (12), and the LogBox snapshot (1) were regenerated by their canonical tools and not hand-edited. Their exact provenance is in the inline inventory above.

The tracked JavaScript API snapshots at e3351d0a and c499d672 are byte-identical (SHA-256 a95b55e7c1ef4185d8bf82edf8e93d6a16ad9a4621ae101bba6d7db1c2691127), so the five-file AppKit delta has no JS API change. The repository's diff tool still emits its known historical nine-item BREAKING classification when given those identical inputs; that exact output is retained in gate evidence rather than misrepresented as an AppKit delta.

Five-file AppKit delta

The post-correction AppKit delta is exactly five modified files under packages/react-native/React/CoreModules/: 579 insertions / 15 deletions.

[macOS] tags File
5 RCTRedBox.mm
2 RCTRedBox2AnsiParser+Internal.h
2 RCTRedBox2AnsiParser.mm
1 RCTRedBox2Controller+Internal.h
22 RCTRedBox2Controller.mm

c616cd7a is the four-file AppKit implementation. c499d672 is the separately reviewable reachability fix: it removes the transplanted 0.86 macOS exclusion so flag ON instantiates RCTRedBox2Controller, while flag OFF retains RCTRedBoxController.

 #import "CoreModulesPlugins.h"
 #import "RCTRedBox+Internal.h"
-#if !TARGET_OS_OSX // [macOS]
 #import "RCTRedBox2Controller+Internal.h"
-#endif // [macOS]
 #import "RCTRedBoxController+Internal.h"

@@
     if (self->_controller == nullptr) {
-      if (!TARGET_OS_OSX && facebook::react::ReactNativeFeatureFlags::redBoxV2IOS()) { // [macOS]
-#if !TARGET_OS_OSX // [macOS]
+      if (facebook::react::ReactNativeFeatureFlags::redBoxV2IOS()) {
         self->_controller = [[RCTRedBox2Controller alloc] initWithCustomButtonTitles:self->_customButtonTitles
                                                                 customButtonHandlers:self->_customButtonHandlers];
-#endif // [macOS]
       } else {
         self->_controller = [[RCTRedBoxController alloc] initWithCustomButtonTitles:self->_customButtonTitles
                                                                customButtonHandlers:self->_customButtonHandlers];

Commands and gates

All dependency and JavaScript commands used a tracked-only archive of tree 778136a1…, Node 22.6.0, checked-in Yarn 4.12.0, an isolated HOME/XDG/config/cache environment, no auth variables, and effective npm/Yarn registry https://registry.npmjs.org. The public-registry host was saads-macbook-pro; no Office/private registry was loaded.

Gate Command / protocol Result
Identity exact SHA/tree/ordered-parent/path assertion script PASS
Registry effective npm + Yarn registry checks, auth-variable scan, public ping PASS
Install yarn install --immutable PASS
Generated/JS feature flags, Flow, lint, format, TypeScript, generated TypeScript, JS API validation/diff PASS
Focused Jest FeatureFlags; jest packages/react-native/Libraries/LogBox --runInBand PASS: 11 tests; 20 suites / 190 tests / 62 snapshots
Full Jest yarn test-ci PASS: 278 suites / 5,647 passed / 2 skipped / 1,797 snapshots
Pods/codegen GIT_DIR=<nonexistent> RCT_SKIP_CODEGEN=0 bundle _2.5.16_ exec pod install PASS: 89 dependencies / 88 pods; only two Hermes checksum lines; zero podspec commit keys; path-only project lines restored
macOS xcodebuild … -sdk macosx -scheme RNTester-macOS -destination generic/platform=macOS … build PASS: 1,712 compile / 16 RedBox / 0 RedBox diagnostics
iOS Simulator xcodebuild … -sdk iphonesimulator -scheme RNTester -destination id=0A9B… … build PASS: 853 / 8 / 0
visionOS Simulator xcodebuild … -sdk xrsimulator -scheme RNTester-visionOS -destination id=320E… … build PASS: 853 / 8 / 0
C++ API pinned official Doxygen 1.16.1; python -m scripts.cxx-api.parser --validate PASS: 6/6 snapshots
SwiftPM swift package dump-package in packages/react-native PASS: package React, 71 targets, zero dependencies
Structural first-parent/AppKit git diff --check, exact conflict-marker scan, tag counts, iOS projection PASS
GUI hash-checked exact-tree prior harness PARTIAL_PASS_BLOCKED, draft-only

The correction-only git diff --check c1798b51… e3351d0a… exits 2 on one four-space line in RCTBackedTextInputDelegateAdapter.mm. Byte evidence shows the identical four spaces already exist in first parent dcd3d603, so the first-parent PR diff and five-file AppKit diff both pass.

GUI evidence — PARTIAL, not a full release smoke

The disposable harness used tree 778136a143540a71a21ed42406ccd8590458cbe6, exactly the PR-head tree.

Observed Blocked
Flag ON selected RCTRedBox2Controller Stack expand/collapse: minimal throw had no frames
Flag OFF selected RCTRedBoxController Custom buttons: not configured by the minimal harness
AppKit and legacy surfaces were visibly presented HMR auto-clear: no measurable update was established
ANSI sequences were stripped Resize and runtime Accessibility: login session was locked
⌥⌘C copied the AppKit error text
Escape dismissed the AppKit sheet
⌘R caused a new Metro bundle request
  • ON AppKit screenshot SHA-256: 5c3f2d0baf1afb011febbfd1e9da07f113bb6ad2209955bc2b9894bfd693202a
  • OFF legacy screenshot SHA-256: d9c455accc54cb0a287601fd7130fb33294121606ae70806be68b17a32ada74f

This is partial evidence, not a full release smoke. The residual GUI checklist remains a declared blocker, which is why this PR must remain a draft.

Evidence availability

The correction disclosure is fully inline above. No gist, upload, attachment comment, or follow-up publication action is required. Durable local evidence is at:

/Users/sanajmi/.copilot/workspaces/74e17dbb-43b3-48d8-a94f-542180acd3c9/artifacts/redbox2-canonical-pr

That local artifact tree is not available on GitHub. Its exact SHA-256 manifest is supplied to the independent judge before publication.

Supersession

#3047 remains open and unmodified. Close it manually only after this replacement draft is reviewed.

Review checklist

  • Ordered merge parents are genuine (dcd3d603 then 78a740d4)
  • Correction layer: 50 paths / 9 categories match the inline inventory
  • 22 RNM native/SwiftPM adaptations reviewed
  • Five-file AppKit delta is the only source change after the correction
  • c499d672 reachability fix reviewed (ON=RedBox2 AppKit, OFF=legacy)
  • macOS / iOS / visionOS RNTester Debug all green
  • Full Jest + LogBox + Flow + lint + TS + JS API evidence reviewed
  • Remaining GUI checklist items completed in an unlocked interactive session
  • feat(macos): port RedBox 2.0 to AppKit #3047 closed manually after this PR supersedes it

coado and others added 30 commits March 31, 2026 08:32
Summary:
Pull Request resolved: react#56042

Adds CI workflow for validating whether the current C++ API snapshot is equivalent with the generated one.

Changelog:
[Internal]

Reviewed By: cortinico

Differential Revision: D95963515

fbshipit-source-id: 4629999e2d09dbdcfb9fd3e6308a9254dd4f0237
Summary:
Pull Request resolved: react#56173

Removes leaked test code from the snapshot.

Changelog:
[Internal]

Reviewed By: cortinico

Differential Revision: D97457090

fbshipit-source-id: ac6aedfa9f4fda8c7f7371fc29a91ce813916777
Summary:
Pull Request resolved: react#56248

Refactor and add global exclude patterns to the C++ stable API snapshot config. This enables better modularization of shared exclude patterns coming from the assumption that ReactAndroid and ReactApple consists of ReactCommon in their inputs and some paths should not be processed on each platform.

Changelog:
[Internal]

Reviewed By: cortinico

Differential Revision: D97465431

fbshipit-source-id: e71daef90853dad8003a0f41b1ea78b8c56bee02
…56247)

Summary:
Pull Request resolved: react#56247

Removes fantom test specific methods, namely:
- NativeFantomTestSpecificMethods,
- FantomForcedCloneCommitHook

from the C++ API snapshot.

Changelog:
[Internal]

Reviewed By: cortinico

Differential Revision: D97466201

fbshipit-source-id: b8464ddd242056a1e21db409b738414814550b30
Summary:
Pull Request resolved: react#56252

Removes stubs from the snapshot which should be irrelevant in context of the public surface.

Changelog:
[Internal]

Reviewed By: cortinico

Differential Revision: D97478132

fbshipit-source-id: da95c86a02b056e9ece0fbdcbbbced2300c9fbae
…#56238)

Summary:
Pull Request resolved: react#56238

Currently, all xml artifacts generated by doxygen are stored in the tmp dir and deleted at the end of the snapshot generation. For debugging reasons, this diff adds `--xml` flag to persist generated artifacts, so that they can be analyzed.

Changelog:
[Internal]

Reviewed By: cipolleschi

Differential Revision: D98289956

fbshipit-source-id: 73eb0185f7112389e589d3e8f8a2004efe325e8d
…zations (react#56239)

Summary:
Pull Request resolved: react#56239

Doxygen incorrectly merges base classes from primary templates into their partial specializations. In C++, a specialization's inheritance list completely replaces the primary template's, but Doxygen combines both into a single basecompoundref list.

- **Contradictory type traits** — is_optional<std::optional<T>> and is_variant_of_data_types<std::variant<Ts...>> showed inheritance from both std::false_type (primary) and std::true_type (specialization)

- **Duplicate base classes** — Converter<jsi::Object> listed ConverterBase<jsi::Object> twice (once from the primary template after substitution, once from the specialization)

This diff fixes both issues with two complementary mechanisms:

- **Dedup-by-name (Extendable._deduplicate_base_classes)**: removes exact duplicate base classes, keeping the last occurrence. Handles cases where Doxygen's template argument substitution produces identical names.
- **Primary template base subtraction (StructLikeScopeKind._remove_merged_primary_bases)**: for partial specializations, looks up the primary template among sibling scopes and performs count-based subtraction of its bases. Count-based (rather than set-based) subtraction correctly preserves bases that a specialization explicitly re-inherits from the same class as the primary.

Changelog:
[Internal]

Reviewed By: cipolleschi

Differential Revision: D98291360

fbshipit-source-id: 82b34969b13c7df8babf2c5efc222b29979d6361
Summary:
Pull Request resolved: react#56246

Fixes return type to receive correct generic types.

Before:
```
static std::pair<T1, T1>
  fromJs(facebook::jsi::Runtime &rt, const jsi::Array &array, const std::shared_ptr<CallInvoker> &jsInvoker)
```

After:
```
static std::pair<T1, T2>
  fromJs(facebook::jsi::Runtime &rt, const jsi::Array &array, const std::shared_ptr<CallInvoker> &jsInvoker)
```

Changelog:
[Internal]

Reviewed By: cipolleschi

Differential Revision: D98292820

fbshipit-source-id: bb7791ace2391240dd50ece55b2a2ce905a51115
Summary:
Pull Request resolved: react#56240

There are cases in which we want to strip particular symbols from the snapshot. This diff adds `exclude_symbols` to the parser config to enable definitions of symbol patterns that should be excluded from the snapshot.

Changelog:
[Internal]

Reviewed By: cipolleschi

Differential Revision: D98295409

fbshipit-source-id: 47414c1e5060a01dce76d1fc4fdd8ea355bb8d37
Summary:
Pull Request resolved: react#56241

Strips remaining Fantom symbols from the public API snapshots generated by codegen.

Changelog:
[Internal]

Reviewed By: cipolleschi

Differential Revision: D98295521

fbshipit-source-id: 24568b825b2aaa062e2b11dc77a018e403c68ddd
…56243)

Summary:
Pull Request resolved: react#56243

Modifies C++ API parser config to accept `exclude_symbols` at the platform level and sets `Android` symbols to be excluded from the ReactApple snapshot.

Changelog:
[Internal]

Reviewed By: cipolleschi

Differential Revision: D98298766

fbshipit-source-id: 70b39fe4935e6791701c173e7c9e12532c2817a5
Summary:
Pull Request resolved: react#56245

Removes feature flags from the C++ public API snapshots as they are considered private. This greatly reduces snapshots size.

Changelog:
[Internal]

Reviewed By: cipolleschi

Differential Revision: D98312529

fbshipit-source-id: e6aad9d930c7c77300329c25668dc2fc3a4686f2
Summary:
Pull Request resolved: react#56242

Excluded symbols that contain "UnstableLegacy" from public stable C++ API snapshot, that is `UnstableLegacyViewManagerAutomaticComponentDescriptor` and `UnstableLegacyViewManagerInteropComponentDescriptor`.

Changelog:
[Internal]

Reviewed By: cipolleschi

Differential Revision: D98317003

fbshipit-source-id: deb4631a26ecb138007cf4958dbabb57ef3739cc
…56244)

Summary:
Pull Request resolved: react#56244

Excludes symbols marked as Experimental from the C++ public API snapshots. Types with the "Experimental" prefix are explicitly not stable API — they represent features still under active development and are subject to change or removal without notice.

Changelog:
[Internal]

Reviewed By: cipolleschi

Differential Revision: D98454721

fbshipit-source-id: 7f7488fab6bc94c52b94a3ae2d9a7a7914815d63
…react#56249)

Summary:
Pull Request resolved: react#56249

Prevents iOS Switch component leaking into the ReactAndroid snapshot by adding `*/components/switch/iosswitch/*` path to the `exclude_patterns` in the parser config.

Changelog:
[Internal]

Reviewed By: cipolleschi

Differential Revision: D98473064

fbshipit-source-id: de25c4cbe839f8a065b8465e48a2b8c2a5ba81d7
…ot (react#56251)

Summary:
Pull Request resolved: react#56251

Excludes InputAccessory which is an iOS-only component with no Android support at any layer. In the `InputAccessoryView.js` there is explicit iOS guard which logs warning on Android.

Changelog:
[Internal]

Reviewed By: cipolleschi

Differential Revision: D98478125

fbshipit-source-id: 871923e001024971167a7bb2eb900ca3867983a4
…eact#56250)

Summary:
Pull Request resolved: react#56250

Excludes iOS-specific symbols from the ReactAndroid C++ API snapshot. The snapshot contains iOS native modules CxxSpec templates, their data structs, and bridging structs that have no relevance on Android. These symbols leaked because the Android codegen generates CxxSpec templates for ALL JavaScript module specs regardless of platform.

Changelog:
[Internal]

Reviewed By: cipolleschi

Differential Revision: D98480080

fbshipit-source-id: a5990c4769456ab756095129851eb4e8dbeda912
…#56253)

Summary:
Pull Request resolved: react#56253

Renames flag for verifying that the C++ public API snapshot is with sync with the actual public API surface to match the JS API command.

Changelog:
[Internal]

Reviewed By: huntie

Differential Revision: D98484129

fbshipit-source-id: ec806353f263b00e5060d9e7f0333bcf4cced148
Summary:
Pull Request resolved: react#56286

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

Reviewed By: gkz

Differential Revision: D98860515

fbshipit-source-id: 196ffafcee417ac2949822848fe7752070a2c30a
Summary:
Pull Request resolved: react#56207

Changelog: [Internal]

Reviewed By: cipolleschi

Differential Revision: D96101927

fbshipit-source-id: 06c6dd11c145be44bcdd97f14683a222c66c96c6
Summary:
Add Changelog for 0.85.0-rc.7

## Changelog:
[Internal] - Add Changelog for 0.85.0-rc.7

Pull Request resolved: react#56276

Test Plan: N/A

Reviewed By: cipolleschi

Differential Revision: D98792883

Pulled By: alanleedev

fbshipit-source-id: c21c189e35d3eca3a013e2e924c87725cec86153
Summary:
Adds missing `mixBlendMode: 'plus-lighter'` which has full support on CSS across all browsers (as opposed to, for example, `plus-darker`)

iOS: ended up using linear dodge blend mode which should be identical, I tried using `@"addition"` which should've used `CIAdditionCompositing` but that didn't work, although I did confirm `maximum` does work and apply  `CIMaximumCompositing`, funny stuff, can't wait for SwiftUI layer to take this over

Android works as expected with its `BlendMode.PLUS`

## Changelog:

[GENERAL] [ADDED] - Add mixBlendMode plus-lighter

Pull Request resolved: react#56278

Test Plan: <img width="726" height="822" alt="image" src="https://github.com/user-attachments/assets/6f8a235c-f79b-4739-9d6c-90c989bad5f5" />

Reviewed By: javache, jorge-cab

Differential Revision: D98842036

Pulled By: NickGerleman

fbshipit-source-id: 3f4bf83918276579c48c784479d2a20bf2a2ba4c
Summary:
Pull Request resolved: react#56282

Fixes react#56185
Fixes react#56186
Fixes react#56187

Delete the `fixTextClippingAndroid15useBoundsForWidth()` feature flag and all code gated behind it. This flag was never shipped, and the new code path has been implicated in several bugs.

The change removes:
- The feature flag definition and all generated plumbing (C++, JNI, Kotlin, JS)
- The visual-bounds-based width measurement path in `TextLayoutManager.kt`
- The `setUseBoundsForWidth(true)` call in `buildLayout()`
- The MobileConfig parameter (`react_fabric.fix_text_clipping_android_15_use_bounds_for_width`)
- The Facebook Android and OSS Experimental overrides

The old advance-based width logic is retained as the sole code path.

Changelog: [Internal]

Reviewed By: cortinico

Differential Revision: D98427218

fbshipit-source-id: 7c322353d9c0a0548386a486ecd4280b73a66872
…fined with props 2.0 (react#56288)

Summary:
When Android props 2.0 diffs a `View` where `zIndex` changes from a value to `undefined`, `HostPlatformViewProps::getDiffProps` calls `zIndex.value()` and throws `bad_optional_access`:

https://github.com/user-attachments/assets/89752243-ff48-42c7-a584-b47a091b4a4d

This change emits `folly::dynamic(nullptr)` when `zIndex` is cleared instead.

## Changelog:

[ANDROID] [FIXED] - Fixed a crash when clearing `zIndex` with props 2.0 enabled

Pull Request resolved: react#56288

Test Plan:
Use the repro in `packages/rn-tester/js/examples/Playground/RNTesterPlayground.js`:

```js
function Playground() {
  const [toggle, setToggle] = React.useState(false);

  return (
    <View style={styles.container}>
      <Button title="Toggle" onPress={() => setToggle(t => !t)} />
      <View
        style={{
          backgroundColor: toggle ? 'blue' : 'red',
          height: 100,
          width: 100,
          position: 'absolute',
          zIndex: toggle ? undefined : 1,
        }}
      />
    </View>
  );
}
```

1. Enable Android props 2.0:

```
  override fun enableAccumulatedUpdatesInRawPropsAndroid(): Boolean = true
  override fun enableExclusivePropsUpdateAndroid(): Boolean = true
  override fun enablePropsUpdateReconciliationAndroid(): Boolean = true
```

2. run RNTester Playground on Android, and press `Toggle` to switch `zIndex` between `1` and `undefined`.

This is with the issue fixed:

https://github.com/user-attachments/assets/11253c23-b235-4e70-89a3-0d7bd07937f5

Reviewed By: javache

Differential Revision: D98960669

Pulled By: NickGerleman

fbshipit-source-id: d4a98434c599d2298c5cfc8c6895988ed0743af6
Summary:
Pull Request resolved: react#56293

Changelog: [Internal]

Reviewed By: mdvacca

Differential Revision: D98942266

fbshipit-source-id: b6df078e4e10191b464b3aebc70d55cca5f12fa2
Summary:
Pull Request resolved: react#56300

Changelog: [Internal]

Reviewed By: marcoww6

Differential Revision: D99004126

fbshipit-source-id: dfedc13c867cb768777e2ba65256a2c40ffb1d08
Summary:
Pull Request resolved: react#56289

Changelog: [GENERAL][FIXED] Link VirtualView component

I saw D98039999 and I wanted to check how the new components are working in OSS, and currently they don't. VirtualView component isn't correctly linked in OSS. This diff addresses that.

Note that VirtualView in OSS requires `babel-plugin-transform-flow-enums` which is not part of the default template.

Reviewed By: CalixTang

Differential Revision: D98887952

fbshipit-source-id: f06ec9d4581c6fa3f2185641cb4b9f7acb8f557e
…56292)

Summary:
Pull Request resolved: react#56292

The TinyMap is a helper class under internal directory, not referenced anywhere in the snapshot, and considered unsafe (from the comment). It is not part of any module, so it is better to remove that from the snapshot.

The `packAnimatedProps` method is used in `AnimationBackend` for translation from `AnimatedProps` to `folly::dynamic` and should not be used outside of React Native.

Changelog:
[Internal]

Reviewed By: cipolleschi

Differential Revision: D98907855

fbshipit-source-id: e3a371cc088000a23f1ce1121fda808494979140
…EY (react#56304)

Summary:
Pull Request resolved: react#56304

Add support for specifying a custom `timeStamp` in the `Event` constructor options via a private symbol key (`EVENT_INIT_TIMESTAMP_KEY`) defined in `EventInternals`. This is for internal construction of events using a custom timestamp (instead of event object creation), for use cases like dispatching events from the host platform using the original timestamps.

- Added `EVENT_INIT_TIMESTAMP_KEY` symbol to `EventInternals`
- Added `setEventInitTimeStamp(eventInit, timeStamp)` helper function in `EventInternals` that validates the type and sets the symbol-keyed property on the event init object
- Updated the `Event` constructor to read the custom timestamp from options if present, falling back to `performance.now()`
- Added Fantom tests for custom timestamp and zero as a valid timestamp

Changelog: [Internal]

Reviewed By: huntie

Differential Revision: D99076591

fbshipit-source-id: 2ea00394de885a5f338c1b3fe4792d5b4768cd7b
Summary:
Pull Request resolved: react#56295

Changelog: [Android][Added] - Pass event object to `BackHandler` `hardwareBackPress` events to access timeStamp from native event.

BackHandler on Android emits the `hardwareBackPress` event with a `null`
payload — no timestamp or event data. This means there is no way for
handlers to know when the user actually pressed the back button, which
prevents accurate performance tracing for back navigations.

This diff:
- Sends `SystemClock.uptimeMillis()` as `timestamp` in the native
  `DeviceEventManagerModule.emitHardwareBackPressed()` event payload
- Creates a new `HardwareBackPressEvent` class extending the DOM `Event`
  class, which overrides the `timeStamp` getter to return the native
  timestamp (falling back to `performance.now()` if unavailable)
- Makes the public constructor throw `TypeError("Illegal constructor")`
  following the `PerformanceEntry` pattern
- Updates all BackHandler platform files (Android, iOS, macOS, Windows)
  and type definitions (Flow, TypeScript) to create and pass the event
  to handlers
- Updates the BackHandler mock to pass events in `mockPressBack`
- Adds Fantom integration tests for both `HardwareBackPressEvent` and
  `BackHandler`

Reviewed By: huntie

Differential Revision: D98941079

fbshipit-source-id: baca35947cd7e8f598e9e040059579fb6e19553e
alanleedev and others added 30 commits April 24, 2026 10:55
Summary:
Pull Request resolved: react#56486

Follow-up to react#55855 (D100437445), which replaced the legacy height-based IME detector in `ReactRootView.CustomGlobalLayoutListener` with a visibility-only detector (`WindowInsetsCompat.Type.ime()`).

The legacy code also re-emitted `keyboardDidShow` whenever the IME *height* changed while still visible (e.g., user toggles the emoji panel or predictive bar). Removing that left these JS consumers reading stale `endCoordinates`:
- `KeyboardAvoidingView` — caches `_keyboardEvent`, no longer resizes on IME height changes.
- `ScrollView` — caches `_keyboardMetrics`; focused `TextInput` auto-scroll uses stale `screenY`/`height`.
- `Keyboard.metrics()` — public API returning the cached payload from the last `keyboardDidShow`.

Fix: track the last reported IME height and re-emit `keyboardDidShow` when the keyboard is visible AND (it just appeared OR the height changed), restoring pre-D100437445 semantics. The hide branch is gated on `mKeyboardIsVisible` so it still fires exactly once per cycle.

Changelog: [Android][Fixed] KeyboardAvoidingView and TextInput auto-scroll not responding to IME height changes (e.g., when toggling emoji panel or predictive bar)

Reviewed By: mdvacca, javache

Differential Revision: D101385688

fbshipit-source-id: 071707bc6fb9e7173e491135b27a66dc177c14c5
…eact#56604)

Summary:
Pull Request resolved: react#56604

## Changelog:

[Internal] [Fixed] - keep old snapshot node position updated at applyViewTransitionName

`createViewTransitionInstance` is only called once in a shadowNode's lifecycle but `applyViewTransitionName` will be called multiple times at each transition for the same shadowNode.

Reviewed By: christophpurrer

Differential Revision: D102226352

fbshipit-source-id: ac1ba1fe53dce199d6a2ff7e83a22e5249336a01
…orking) (react#56602)

Summary:
Pull Request resolved: react#56602

Changelog:

[iOS][Fixed] - Removing unused ivars

Reviewed By: Murf-o

Differential Revision: D102315121

fbshipit-source-id: 51075b1460fda1d7d044f6788fc0b2d390bed778
Summary:
Pull Request resolved: react#56603

Upgrade transitive dependency lodash from 4.17.21 to 4.18.1 to remediate CVE-2026-4800 (Improper Control of Generation of Code / Code Injection).

- Added `"lodash": "4.18.1"` to `resolutions` in package.json to force all lodash ranges (including `~4.17.15`) to resolve to 4.18.1
- Updated yarn.lock entry to resolve all lodash ranges to 4.18.1

Without the resolution override, the `~4.17.15` range would stay at 4.17.21 (vulnerable) since `~` only allows patch-level updates and 4.18.1 is a minor bump.

Changelog: [Internal]

Reviewed By: christophpurrer

Differential Revision: D102273666

fbshipit-source-id: d3a17ba480b5d44c048b2b1d814bc3989abcd06a
… dispatch + fix unsigned retainCount_ underflow (react#56537)

Summary:
**1) `EventQueueProcessor::flushEvents` — release on every exit path.** `flushEvents` retains every `EventTarget` in the batch, then for each event calls `eventPipe_` (which dispatches into JS via `UIManagerBinding::dispatchEventToJS` and can throw `jsi::JSError`), then `eventPipeConclusion_`, and finally runs a trailing loop that calls `event.eventTarget->release(runtime)`. If either pipe call throws, stack unwinding skips the release loop, leaving `strongInstanceHandle_` (a `jsi::Value` strong reference to the JS event-target object) pinned and `retainCount_` desynchronised.

This change replaces the trailing release loop with a folly `SCOPE_EXIT` block immediately after the retain pass, so every retained target is released on every exit path — normal return, `eventPipe_` throw, or `eventPipeConclusion_` throw. (Earlier revisions used a hand-rolled RAII class; switched to `SCOPE_EXIT` per reviewer feedback. `folly/ScopeGuard.h` is already in the OSS RN folly subset — `RCT-Folly.podspec`, `ReactAndroid/.../folly/CMakeLists.txt`, `react-native-fantom/.../folly/CMakeLists.txt` — and is a transitive dep of `//xplat/folly:dynamic`, so no new build edges.)

Behaviour-preserving on the happy path: same release ordering (after `eventPipeConclusion_`), same no-`DispatchMutex` policy for release (the `events` vector still holds the strong `shared_ptr`s), zero added allocation.

**2) `EventTarget::release` — guard the unsigned decrement.** `retainCount_` is `size_t`. `retain()` early-returns when the target is disabled, but the matching `release()` always runs, so `release()` can be entered with `retainCount_ == 0`; the unconditional `--retainCount_` then wraps to `SIZE_MAX`, the `== 0` check never fires again, and `strongInstanceHandle_` is never cleared. The trailing `react_native_assert(retainCount_ >= 0)` is a tautology on an unsigned type and is removed. This change guards the decrement (`if (retainCount_ > 0) --retainCount_;`) and drops the dead assert and the now-unused `react_native_assert.h` include.

Adds `EventQueueProcessorTest.releasesEventTargetsWhenDispatchThrows` (proves the strong handle is released during unwind when `eventPipe_` throws; fails on the pre-fix trailing-loop code) and `EventTargetTests.releaseWhileDisabledDoesNotCorruptRetainCount` (retain/release while disabled, then enable+retain must still acquire the handle; fails on the pre-fix unconditional decrement).

Changelog: [Internal]

Pull Request resolved: react#56537

Reviewed By: javache

Differential Revision: D100280132

fbshipit-source-id: 8c7128082d8c967a150952434a7791b62586659f
Summary:
Add Changelog for 0.83.8

## Changelog:
[Internal] - Add Changelog for 0.83.8

Pull Request resolved: react#56596

Test Plan: N/A

Reviewed By: christophpurrer

Differential Revision: D102339274

Pulled By: motiz88

fbshipit-source-id: c83710b74ad615cd389d33b5ee6c519de72cb32d
Summary:
- Adds retry jobs (up to 2 retries) for all 4 E2E test jobs on PRs to handle flakiness
- Original E2E jobs use `continue-on-error` on PRs so failures don't block the workflow; on `main`, behavior is unchanged and the existing `rerun-failed-jobs` mechanism continues to work
- Each retry runs on a fresh runner (addressing environment-level flakes) and is triggered via step-level outcome captured as a job output
- Added `overwrite: true` to artifact uploads in maestro composite actions so retry jobs don't conflict on artifact names

### How it works
- **On PRs:** E2E job fails → `retry_1` triggers → if that fails → `retry_2` triggers. All have `continue-on-error` so the workflow stays green.
- **On `main`:** `continue-on-error` is `false`, retry jobs are skipped (PR-only), and `rerun-failed-jobs` handles retries as before.

### Known limitation
Since these are matrix jobs (Debug/Release), the job output uses the last-to-complete matrix combination's value. If only one flavor fails and the passing one finishes last, the retry may not trigger. In the common flakiness pattern (environment-level issues), both flavors tend to be affected, so this works well in practice.

## Changelog:
[Internal] - Add E2E test retry jobs for PRs

Pull Request resolved: react#56581

Test Plan:
- CI will validate the workflow syntax
- On a PR where E2E tests pass: retry jobs should be skipped
- On a PR where E2E tests fail due to flakiness: retry jobs should trigger and (ideally) pass on a fresh runner
- On pushes to `main`: existing `rerun-failed-jobs` behavior is preserved (retry jobs are skipped)

Reviewed By: cortinico

Differential Revision: D102327900

Pulled By: cipolleschi

fbshipit-source-id: e257e012357fdba442c302085ceed0667355272e
…gn null checks and error message code style (react#56150)

Summary:
This PR continue the work I'm doing to improve the `AccessibilityInfo` module (react#56066 and connected PRs).

In this new PR I added the missing tests for all the Promise based methods in the `AccessibilityInfo`, to prevent regressions similar to those fixed in the previous PRs.

This PR also includes a couple of small code style consistency improvement:
- aligned the null check in `getRecommendedTimeoutMillis` to the other ones already present in the file
- aligned the error messages returned from `isGrayscaleEnabled`, `isInvertColorsEnabled` and `isReduceMotionEnabled` to the other ones
- added the docs links where was missing (related to the PR I opened on the react-native doc repo)

## Changelog:

[GENERAL] [ADDED] - AccessibilityInfo: added missing tests for Promise based methods, align null checks and error message code style

Pull Request resolved: react#56150

Test Plan: I run the tests that I added to verify their correctness. Some of them were failing because of the change of the error messages, and I made them green by changing the message in the production code. For this others, I verified their correctness by breaking the production code to see if they were failing.

Reviewed By: cipolleschi

Differential Revision: D102190403

Pulled By: cortinico

fbshipit-source-id: f5fe5cacfe0136b25a93d05f3b136c2bc49bd0e2
Summary:
Pull Request resolved: react#56623

Fix the return types of toJSON() methods in PerformanceEntry, PerformanceServerTiming, and Performance to return an object representation ({[string]: unknown}) instead of a string, per the WebIDL spec ([Default] object toJSON()).

Changelog: [internal]

Reviewed By: fabriziocucci

Differential Revision: D102597516

fbshipit-source-id: 9f063d16693e1b44f89a298c08f25548f8a05c76
…eact#56624)

Summary:
Pull Request resolved: react#56624

Adds Flow type definitions for `MutationObserver` (and its related types `MutationRecord` and `MutationObserverInit`) and `IntersectionObserver` (and its related types `IntersectionObserverEntry`, `IntersectionObserverCallback` and `IntersectionObserverOptions`) to React Native's library definitions, reflecting the features supported by the React Native implementations.

Changelog: [internal]

Reviewed By: fabriziocucci

Differential Revision: D102597515

fbshipit-source-id: 86ff8d90aeb26f7f950a968b93596808da834951
…flag) (react#56622)

Summary:
Pull Request resolved: react#56622

Changelog: [internal]

Adds examples for MutationObserver if the API is available (which isn't normally as it's gated).

Reviewed By: fabriziocucci

Differential Revision: D102593725

fbshipit-source-id: cdcfe613b485bf9b015a342cb51003ce43455096
Summary:
Add a new feature flag to gate overriding getClipBounds on Android views to return
the padding box when overflow is hidden. This communicates the view's clipping
region to the Android framework for correct getGlobalVisibleRect calculations
(T253147322, T263753590).

Changelog: [Internal]

Reviewed By: twasilczyk

Differential Revision: D102353841

fbshipit-source-id: d5f9c5428c342061c0d45bfcc000db356048f930
…eact#56606)

Summary:
Pull Request resolved: react#56606

Override `getClipBounds()` on ReactViewGroup to return the padding box rect when
`overflow` is hidden or scroll, gated behind the `syncAndroidClipBoundsWithOverflow`
feature flag.

This exposes the view's clipping behavior to the Android framework via the standard
`View.getClipBounds()` API:
- `getClipBounds(Rect): Boolean` returns `true` and populates the rect with the
  padding box when overflow is hidden/scroll, or `false` when overflow is visible
- `getClipBounds(): Rect?` returns the padding box rect or `null` respectively

This allows framework-level systems to inspect a view and determine whether it clips
its children by checking `getClipBounds() != null`, and to obtain the actual clipping
region for `getGlobalVisibleRect()` calculations.

## Why not `setClipBounds()`?

An alternative approach would be to call `View.setClipBounds(Rect)` which sets the
`mClipBounds` field directly. This has the advantage of being picked up by AOSP's
`ViewGroup.getChildVisibleRect()` (which reads `mClipBounds` via direct field access
rather than calling `getClipBounds()`). However, `setClipBounds()` also propagates
the clip rect to the RenderNode via `mRenderNode.setClipRect()`, which clips the
view's own rendering — including its borders. It also requires maintaining a Rect
that must be kept in sync across size changes, border width changes, and overflow
changes.

For now, the `getClipBounds()` override is sufficient because harvesting systems
query the method rather than the field. If we find that AOSP's field-based path is
also needed, we can switch to `setClipBounds()` in the future.

Adds `BackgroundStyleApplicator.getPaddingBoxRect()` (internal via buck friend_paths)
which computes the padding box (view bounds minus border insets) reusing the same
border inset resolution logic as `clipToPaddingBox()`.

Changelog: [Internal]

Reviewed By: twasilczyk, javache

Differential Revision: D102353840

fbshipit-source-id: fe1d52e3c000ba1b5e2d21eac75928be24a86645
…s out of `react-native`" (react#56621)

Summary:
Pull Request resolved: react#56621

Changelog: [General][Deprecated] Deprecated second argument for hook function passed to AppRegistry.setComponentProviderInstrumentationHook as it's not usable by apps. Passed stub that warns when used.

Re-applying react#56580 that was reverted.

Reviewed By: javache

Differential Revision: D102593753

fbshipit-source-id: 7714260a494a62d55880f10887cd440d217a4672
Summary:
Pull Request resolved: react#56608

## Changelog:

[Internal] [Fixed] - Fix PixelCopy snapshot for partially off-screen

PixelCopy captures only the visible portion of the window surface.
When a view is partially off-screen, the capture rect extends beyond
the window bounds, resulting in a bitmap where only the visible
region has content. This partial bitmap then gets stretched to fill
the full-size pseudo-element, causing visual distortion.

Fix by clamping the PixelCopy rect to the window bounds and
compositing the clamped capture into a full-size bitmap at the
correct offset. The off-screen portions remain transparent instead
of being stretched.

If the view is entirely off-screen, skip capture entirely — the
pseudo-element will have no snapshot applied (didMountItems skips
tags without a captured bitmap).

Reviewed By: javache

Differential Revision: D102360642

fbshipit-source-id: 6da9ddce0eef4bac011f25494a6d916c8311058e
Summary:
Pull Request resolved: react#56601

`ACTION_SCROLL` events (mouse wheel, trackpad, joystick) were not participating in FPS performance logging. Touch-driven scrolls already called `enableFpsListener`/`disableFpsListener` through `handlePostTouchScrolling`, which uses a stable-frames heuristic to detect when scrolling has settled (3 consecutive frames with no position change). ACTION_SCROLL events bypassed this entirely.

This adds FPS listener support to the `ACTION_SCROLL` path by calling `enableFpsListener` when a scroll event arrives, then delegating to `handlePostTouchScrolling` for lifecycle management:

- **Snapping ScrollViews (`ReactScrollView`, `ReactHorizontalScrollView`):** The existing debounce runnable calls `flingAndSnap` to animate to a snap point. After the snap, `handlePostTouchScrolling` monitors the animation via the stable-frames mechanism and disables the FPS listener once settled.
- **Non-snapping ScrollViews (`ReactScrollView`):** `handlePostTouchScrolling` is called directly. Its re-entry guard (`mPostTouchRunnable != null`) naturally deduplicates across rapid scroll events, while `onScrollChanged` keeps the monitor alive by setting `mActivelyScrolling`.

Also nulls `mPostTouchRunnable` before reassignment in the debounce cancel path to avoid stale references.

Changelog:
[Android][Fixed] - Dispatch FPS performance events for mouse wheel and trackpad scroll interactions in ScrollView

Reviewed By: javache, jehartzog

Differential Revision: D102347043

fbshipit-source-id: aab91858404db54b1c44146d4d071193baaae7a1
Summary:
This PR (initially created for edge-to-edge opt-in support, rebased multiple times) fixes the `Dimensions` API `window` values on Android < 15, when edge-to-edge is enabled.

Currently the window height doesn't include the status and navigation bar heights (but it does on Android >= 15):

<img width="300" alt="Screenshot 2025-06-27 at 16 23 02" src="https://github.com/user-attachments/assets/c7d11334-9298-4f7f-a75c-590df8cc2d8a" />

Using `WindowMetricsCalculator` from AndroidX:

<img width="300" alt="Screenshot 2025-06-27 at 16 34 01" src="https://github.com/user-attachments/assets/7a4e3dc7-a83b-421b-8f6d-fd1344f5fe81" />

Fixes react#47080

## Changelog:

[Android] [Fixed] Fix `Dimensions` `window` values on Android < 15 when edge-to-edge is enabled

Pull Request resolved: react#53254

Test Plan: Run the example app on an Android < 15 device.

Reviewed By: javache

Differential Revision: D80237818

Pulled By: alanleedev

fbshipit-source-id: f05e546cd38c7bd539b86d30fe7b663715a34a99
…() (react#56627)

Summary:
Pull Request resolved: react#56627

## Changelog:

[Android] [Fixed] - make sure view width and height are non 0 before calling createBitmap()

Reviewed By: Abbondanzo

Differential Revision: D102657602

fbshipit-source-id: 5e93e110af0e5a795e23c0006a9833934c5e5985
…t#56630)

Summary:
Pull Request resolved: react#56630

Catch `OutOfMemoryError` in the `onResponse` callback's response processing try-catch block in `NetworkingModule.kt`. Previously, only `IOException` was caught — `OutOfMemoryError` (which extends `Error`, not `Exception`) would propagate uncaught and crash the app.

When the Java heap is near its limit (e.g., 256MB with <1% free), any allocation during response processing (buffer creation in `readWithProgress`, `responseBody.bytes()`, `responseBody.string()`) can trigger OOM. The fix converts this to a network request error event sent to JS, allowing the app to handle the failure gracefully (retry, show error message) instead of crashing.

**Crash:** `android_crash:java.lang.OutOfMemoryError:com.oculus.igvr`
**MID:** `024a57cfb70eef9a61af42d845c981a1` — 246 crashes in 7 days
**Task:** T212267841

Logview link: [024a57cfb70eef9a61af42d845c981a1](https://www.internalfb.com/logview/system_vros_crashes/024a57cfb70eef9a61af42d845c981a1)
Changelog: [Android][Fixed] - Catch OutOfMemoryError in NetworkingModule response processing to prevent app crashes

Reviewed By: cortinico

Differential Revision: D102236869

fbshipit-source-id: de6624640b3f2343ca8e516fe7677eecae23a932
…0) (react#56586)

Summary:
Fixes react#50797. A view with a non-invertible transform (e.g. `transform: [{scaleY: 0}]` or `{scaleX: 0}`) still received touches on both Android and iOS. On Android the view appeared to "inherit" a hit region from another view in the hierarchy; on iOS the view registered taps along the collapsed axis. Both symptoms collapse to the same native behaviour: when a transform can't be inverted, the platform APIs silently fall back to stale or degenerate data during hit testing.

### Root cause

**Android.** `TouchTargetHelper.getChildPoint` calls `Matrix.invert(inverseMatrix)` without checking its return value. `Matrix.invert` returns `false` for a non-invertible matrix and **leaves its destination unchanged**. `inverseMatrix` is a class-level field reused across every child-point conversion, so on failure we apply *the previous view's* inverse to the current view's touch point: the exact "inherits from another view" behavior. It is also why shrinking a view from `scaleY: 0.9` to `0.0` leaves a 90 % hit region: the 0.9 frame populated the cache.

**iOS.** `CGAffineTransformInvert` is documented to return the original matrix when it can't invert. `-[UIView convertPoint:fromView:]` uses that "inverse" during hit testing, so the touch point gets collapsed onto the degenerate axis (e.g. y = 0 for `scaleY: 0`) and the inherited `pointInside:` still reports a hit against a visually invisible view.

### Fix

- **Android** (`TouchTargetHelper.kt`): `getChildPoint` now returns `Boolean`. It returns `false` when `Matrix.invert` fails; the child iteration loop skips such children. One behaviour change, no epsilon tuning, no shared state leaks. Resolves both symptom variants via the same code path.
- **iOS** (`RCTViewComponentView.mm`, Fabric): add a small `RCTLayerTransformCollapsesAxis` helper that tests the determinant of the 2 × 2 XY projection of `layer.transform` and return `NO` from the existing `pointInside:` override when it collapses.
- **Tests.** `TouchTargetHelperTest` (new, Robolectric): initial `scaleX`/`scaleY: 0`, zero-scale parent, the "inherits from sibling" regression, the 0.9 to 0.0 transition, and the touch-path accumulator. `RCTViewComponentViewTests` gets four parallel iOS cases. All pass locally.
- **RNTester.** New Transforms entry "Zero-scale hit test (regression for react#50797)". Reproduces both variants and exposes a scale input so you can step through the transition interactively.

### Why not react#53769?

PR react#53769 solved the Android side with a `hasZeroScale(view)` early-return plus an epsilon comparison on individual matrix entries, and handled the `invert` failure in `getChildPoint` by *falling back to untransformed coordinates*. That still lets the degenerate view be hit with its pre-transform bounds; the early-return then has to catch the miss. This branch fixes the root cause once: if the matrix can't be inverted we don't descend into the child. The iOS fix is the matching change on the Fabric side.

## Changelog:

[GENERAL] [FIXED] - Views with a non-invertible transform (e.g. `scaleX: 0` or `scaleY: 0`) no longer receive touches on Android or iOS.

Pull Request resolved: react#56586

Test Plan:
### Unit tests

- `./gradlew :packages:react-native:ReactAndroid:testDebugUnitTest --tests 'com.facebook.react.uimanager.TouchTargetHelperTest*'`: 7/7 pass.
- iOS build-for-testing of `RNTesterUnitTests` scheme succeeds; the four new `RCTViewComponentViewTests` cases live next to the existing cases in `React/Tests/Mounting/`.
- `./gradlew ktfmtCheck`, `clang-format --dry-run -Werror`, `prettier --check`, `flow`, and `eslint` all pass.

### Manual verification (Android)

RNTester → Components → Transforms → "Zero-scale hit test (regression for react#50797)".

**Variant 1: tap the `scaleY: 0` row directly.** "Last tapped:" must stay `(none)`.

| Before | After |
| --- | --- |
| <img src="https://raw.githubusercontent.com/qflen/react-native/6f3799dbb597630a91f43e460437d636796dbbe7/assets/50797/before-tap-zero-scale.png" width="260"> | <img src="https://raw.githubusercontent.com/qflen/react-native/6f3799dbb597630a91f43e460437d636796dbbe7/assets/50797/after-tap-zero-scale.png" width="260"> |
| `Last tapped: zero-scale` (bug) | `Last tapped: (none)` |

**Variant 2: tap the `scaleY: 0.5` row (①), then tap the `scaleY: 0` row (②).** Without the fix, the shared `inverseMatrix` cache populated by tap ① leaks into the zero-scale hit test on tap ②. After the fix, tap ② is correctly ignored and "Last tapped" still reflects tap ①.

| Before | After |
| --- | --- |
| <img src="https://raw.githubusercontent.com/qflen/react-native/6f3799dbb597630a91f43e460437d636796dbbe7/assets/50797/before-tap-zero-after-05.png" width="260"> | <img src="https://raw.githubusercontent.com/qflen/react-native/6f3799dbb597630a91f43e460437d636796dbbe7/assets/50797/after-tap-zero-after-05.png" width="260"> |
| `Last tapped: zero-scale` (stale cache) | `Last tapped: variable (scaleY=0.5)` |

iOS behaves similarly. I tried the example on iPhone 17 Pro (Simulator, iOS 26.1) and the zero-scale pressable is correctly untouchable; driving synthetic taps on the simulator wasn't scripted here, so the iOS signal is the four XCTest cases plus manual verification.

Reviewed By: fabriziocucci

Differential Revision: D102590386

Pulled By: javache

fbshipit-source-id: 863a653f17db72ff85135fd8eb344ccd1528eda7
…ent (react#56633)

Summary:
Pull Request resolved: react#56633

Changelog: [internal]

TSIA

Reviewed By: javache

Differential Revision: D102604056

fbshipit-source-id: 4d965a04b7f3d99a15bf11c8fa9f448425f63e6d
Summary:
Pull Request resolved: react#56636

General typing improvements to the `renderApplication` module:

- Refactors `renderApplication` to take a single options object instead
  of positional arguments, and removes the unused `fabric` and `_unused`
  parameters. The `fabric` parameter was already always treated as
  `true` internally, and the `_unused` slot was a reserved positional
  placeholder for a removed `scopedPerformanceLogger` argument.
- Migrates the file to `flow strict-local`.
- Types `RootComponent` and `WrapperComponent` using component syntax
  instead of `React.ComponentType`.
- Replaces `rootTag: any` with `number | RootTag`, normalizing via the
  existing `createRootTag` helper for `<AppContainer>` and `Number()`
  for `Renderer.renderElement`.
- Simplifies `ActivityType` (drops the unnecessary spread) and tightens
  null/boolean checks (`debugName != null`, `useOffscreen === true`).

Exports a new `RenderApplicationOptions<Props>` type and updates all
internal callers accordingly.

Changelog:
[Internal]

Reviewed By: javache

Differential Revision: D102325691

fbshipit-source-id: 9b4f0b16d8508f6eee33c2e6cb8d5b7157c0742a
Summary:
Pull Request resolved: react#56628

This test file contains a single `it.skip` test guarded by the comment "Enable once synchronous C++ state updates are re-introduced." That feature was deleted entirely (not just disabled) since 2025-07-15, with the reason: *"The current design of enableSynchronousStateUpdates is not correct and breaks `<Modal />` on Android. let's delete it.

Findings: A scan of `packages/react-native/src/private/featureflags`, `scripts/featureflags`, and `ReactCommon/react/featureflags` returns no replacement flag for synchronous C++ state updates. The `enableSynchronousStateUpdates` flag was removed from every layer (JS config, C++, Android Kotlin/JNI, iOS overrides, MC schemas) and the guarded code path in `EventQueue.cpp` was deleted as well.

Empirical confirmation: Removed the `it.skip` and ran the test 10x via stress runs. All 10 runs failed deterministically. The test is asserting the *presence* of the bug — i.e., that an intermediate state mutation leaks through when a UI-thread commit pulls transactions from an in-flight JS commit. Without the synchronous-state-updates codepath, that leak no longer occurs, so the test's expected log never matches the actual output:

  Expected: [Update ScrollView, Update intermediate-state-should-not-be-visible, Update view]
  Actual:   [Update view, Update ScrollView]

The test cannot be un-skipped (the bug it documents is no longer reproducible), and rewriting the assertion would defeat the purpose of the test. Deleting it.

Changelog: [Internal]

Reviewed By: pixelfreak

Differential Revision: D102661539

fbshipit-source-id: fca5d552a80cad572ac43047ff6709403de294f1
…eact#56609)

Summary:
Pull Request resolved: react#56609

`mFpsListener` is injected via `ReactHorizontalScrollView`'s constructor and should live for the lifetime of the view. However, it was declared as a mutable field and nulled in `initView()`, which is called both during construction and when the view is recycled in a virtualized list. After recycling, `isScrollPerfLoggingEnabled()` returned false because `mFpsListener` was null, silently disabling FPS performance tracking for the rest of that view instance's lifecycle.

The fix moves `mFpsListener` to a `final` field initialized in the constructor, and removes the `mFpsListener = null` assignment from `initView()`. Applied to `ReactScrollView`, `ReactHorizontalScrollView`, and `ReactNestedScrollView`.

This is a safe change because both view managers are instantiated with a single instance of FPS listener, so recycled view instances will always reference the same FPS listener instance.

Changelog:
[Android][Fixed] - Fix FPS performance listener being cleared on ScrollView recycle

Reviewed By: jehartzog

Differential Revision: D102359747

fbshipit-source-id: 2707e2d853620ff6980c68edaf9d11354b0825be
Summary:
Same fix as react#56584 (targeting 0.83-stable), applied to main.

Add a `redbox` subspec to `React-debug.podspec` with its own `header_dir`, following the same pattern `React-Fabric` uses for its subdirectories.

Without this, static library builds (without `USE_FRAMEWORKS`) flatten all headers into the top-level `header_dir` (`react/debug`), so imports like `<react/debug/redbox/RedBoxErrorParser.h>` fail because the `redbox/` subdirectory is lost.

On main this is currently masked because `test_e2e_ios_templateapp` uses prebuilt `React.framework`, but it would break any from-source static library build that includes `React-CoreModules`.

Changelog: [Internal]

Pull Request resolved: react#56585

Test Plan: CI

Reviewed By: cortinico

Differential Revision: D102809818

Pulled By: motiz88

fbshipit-source-id: 9871706a8e028c27f64f4d0dd9942d7c408c6b3b
Set RCT_HERMES_V1_ENABLED=1 on the resolve-hermes job so the resolver reads
HERMES_V1_VERSION_NAME (250829098.0.12) instead of HERMES_VERSION_NAME
(1000.0.0), which 404s and falls back to a stale hermes-v0.14.0 engine lacking
the facebook::jsi IRuntime ABI. Align the build-from-source fallback tag in
.hermesv1version to the same version.

Fixes the missing IRuntime symbol link failures in Prebuild macOS Core.

Co-authored-by: Copilot <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.