Skip to content

feat(macos): port RedBox 2.0 to macOS (AppKit)#3027

Open
Saadnajmi wants to merge 118 commits into
microsoft:0.83-stablefrom
Saadnajmi:saadnajmi/0-83-saadnajmi-redbox2-macos
Open

feat(macos): port RedBox 2.0 to macOS (AppKit)#3027
Saadnajmi wants to merge 118 commits into
microsoft:0.83-stablefrom
Saadnajmi:saadnajmi/0-83-saadnajmi-redbox2-macos

Conversation

@Saadnajmi

Copy link
Copy Markdown
Collaborator

Summary

Ports upstream React Native 0.83.10's RedBox 2.0 refactor to macOS.

RedBox 2.0 is upstream's redesigned red error screen: RCTRedBox.mm becomes a thin coordinator that picks a controller based on the ReactNativeFeatureFlags::redBoxV2IOS() feature flag — the new RCTRedBox2Controller (redesigned UI with a header bar, parsed error title/category, syntax-highlighted code frame, a native HMR auto-reload client, and auto-retry) when the flag is on, or the classic RCTRedBoxController when off. The refactor also splits out helper classes: RCTRedBox2AnsiParser, RCTRedBox2ErrorParser, and RCTRedBoxHMRClient.

Files added (11) + coordinator

  • Verbatim (no UIKit): RCTRedBox2ErrorParser(+Internal.h/.mm), RCTRedBoxHMRClient(+Internal.h/.mm)
  • Import carve-out only: RCTRedBox+Internal.h
  • Import + RCTUIColor branch: RCTRedBox2AnsiParser(+Internal.h/.mm)
  • Interface-line branch (NSViewController/NSTableView): RCTRedBoxController+Internal.h, RCTRedBox2Controller+Internal.h
  • Mechanical port: RCTRedBoxController.mm — the classic controller. The macOS carve-outs were transferred from our existing, already-macOS-ported inline RCTRedBoxController in the old monolithic RCTRedBox.mm.
  • Genuinely new AppKit port: RCTRedBox2Controller.mm — the new RedBox 2.0 UI, which we have never shipped on macOS. Since AppKit NSTableView has no sections, the Message/Source/Call Stack sections are flattened into a single row list with lightweight header rows; footer uses NSButton with key equivalents; copy uses NSPasteboard; presentation uses a sheet.
  • RCTRedBox.mm: replaced our old monolith with upstream's ~383-line coordinator; the only macOS carve-out is a no-op loadExtraDataViewController (matching current fork behavior — RCTRedBoxExtraDataViewController presentation is iOS-only). RCTRedBox.h needed no change (already the coordinator header with a Foundation carve-out).

Carve-out approach

  • Additive #if !TARGET_OS_OSX // [macOS] ... #else // [macOS] ... #endif // macOS] clauses only; iOS branches are kept byte-identical to upstream (verified with unifdef -DTARGET_OS_OSX=0 against facebook/0.83-stable — the only diffs are sanctioned additive || TARGET_OS_OSX clauses and UIKit→<React/RCTUIKit.h> import swaps).
  • Uses the RCTUIKit compat layer: RCTUIColor/RCTPlatformView and the UIViewController/UIFont aliases.
  • Build wiring is automatic: both CocoaPods (React-CoreModules.podspec) and SwiftPM (Package.swift reactCoreModules) include React/CoreModules by glob, so simply adding the files compiles them.

Verification

  • cd packages/rn-tester && bundle exec pod install
  • xcodebuild -workspace RNTesterPods.xcworkspace -scheme RNTester-macOS -destination 'generic/platform=macOS' -configuration Debug buildBUILD SUCCEEDED (all 8 RedBox .mm/.m compiled on macOS).
  • redBoxV2IOS() still defaults to false, so the macOS RedBox2 UI is inactive by default (parity with iOS); the classic controller remains the active path until the flag is flipped.

huntie and others added 30 commits November 3, 2025 16:28
Summary:
Pull Request resolved: react#54385

Changelog: [Internal]

`test-release-local` shouldn't be changing the hermes version stored in `version.properties` as this script should be called on a cut branch with hermes already bumped.

Reviewed By: cipolleschi

Differential Revision: D86105703

fbshipit-source-id: 5a1edd9f7a6cd756521749c2b0023ea683dadf82
#publish-packages-to-npm&next
Summary:
Pull Request resolved: react#54419

Changelog: [Internal]

React Native uses `files` field in `package.json` to list everything that should end up in the apckage. `.hermesv1version` file was missing from that list, which is fixed by this diff.

Reviewed By: huntie, cipolleschi

Differential Revision: D86295805

fbshipit-source-id: 8a17191f26f9536884e4aaf09447121c020d1212
…eact#54421)

Summary:
OSS community shared with me that we have a circular dependency in React-utils.podspec that prevent them from building with JSC.
While fixing it, I realized that the dynamic framework build was broken. So I fixed them both.

## Changelog:
[iOS][Fixed] - Fixed build with dynamic frameworks

Pull Request resolved: react#54421

Test Plan: Build RNTester locally with USE_FRAMEWORKS=dynamic

Reviewed By: javache

Differential Revision: D86309592

Pulled By: cipolleschi

fbshipit-source-id: f2995332ae135ce951480b353df7d597ff8a85ec
Summary:
When RCT_SYMBOLICATE_PREBUILT_FRAMEWORKS is enabled, source file paths in dSYMs were incorrectly resolved with extra path segments:

double node_modules (e.g., /path/node_modules/node_modules/...)

The root cause was using File.expand_path(@react_native_path) without the correct base directory. The path was first expanded without a base (causing double node_modules), then fixed to use project_pods_root (ios/Pods/), which still resulted in incorrect paths with an extra ios/ folder.

Fixed by expanding the path relative to Pod::Config.instance.installation_root, which correctly points to the ios/ directory, allowing relative paths like ../node_modules/react-native to resolve properly to the project root's node_modules directory.

## Changelog:

[IOS] [FIXED] - Fix incorrect source path resolution in dSYM remapping in precompiled framework scripts

Pull Request resolved: react#54470

Test Plan:
```
rm -rf ./Pods
pod cache clean --all
RCT_USE_RN_DEP=1 RCT_USE_PREBUILT_RNCORE=1 RCT_SYMBOLICATE_PREBUILT_FRAMEWORKS=1 bundle exec pod install
```

✅ Tested with RN-Tester
✅ Tested in 0.83.rc0 project

Reviewed By: huntie

Differential Revision: D86667786

Pulled By: cipolleschi

fbshipit-source-id: cd6279d02d5ed7188e282e4491c05de35f17a8f1
Summary:
Pull Request resolved: react#54479

Fixes failing CI jobs on `0.83-stable`, e.g. https://github.com/facebook/react-native/actions/runs/19234912061/job/54982161510.

**Changes**

- Simplify main package `package.json` file read with existing `getWorkspaceRoot` util.
- Fix test by mocking `getWorkspaceRoot` (previously: read the real filesystem and caused test breakage outside `main`).
- Add additional `RC0 → RC1` test case.

Changelog: [Internal]

Reviewed By: cipolleschi

Differential Revision: D86674348

fbshipit-source-id: 0b8feb4cbf7b1ac7cf4cc560f066a0a10aec1b5f
Summary:
Pull Request resolved: react#54407

Introduces a new `InspectorSystemState` object and `ReactNativeApplication.systemStateChanged` CDP event, used to assert whether more than one React Native Host has been registered for the current app lifetime.

This will be used to disable the Performance and Network features in React Native DevTools when the debugger backend is in this currently unsupported state. We intend to implement host lifecycle correctness across all features soon.

Changelog: [Internal]

Reviewed By: cipolleschi

Differential Revision: D86201689

fbshipit-source-id: b8525359fc01eb7ae666879f2c0fd4c94f0af81a
…act#54408)

Summary:
Pull Request resolved: react#54408

Follows from the parent commit. This will prevent 3P CDP clients from using the `Tracing` or `Network` domains when we are in an unsupported multi React Native Host setup.

Changelog: [Internal]

Reviewed By: hoxyq

Differential Revision: D86201688

fbshipit-source-id: 052d563a371fd77c1a05ad8518e222d6bc1eb372
Local sync from 0.83-stable branch
#publish-packages-to-npm&next
Summary:
Pull Request resolved: react#54454

Changelog: [Internal] - Add feature flag around IntersectionObserver for canary

Reviewed By: rubennorte, cipolleschi

Differential Revision: D86547485

fbshipit-source-id: 0c6d84e276d1f6337a8da0bea141cc371010cd75
…0.83-stable branch.

Changelog: [General][Added] - React Native DevTools: Enable Network inspection features
#publish-packages-to-npm&next
#publish-packages-to-npm&next
rubennorte and others added 25 commits April 27, 2026 10:50
react#56597)

Summary:
Pull Request resolved: react#55919

Changelog: [internal]

Adds a new feature flag to enable the experimental and partial implementation of `MutationObserver`

Reviewed By: Abbondanzo, sammy-SC, javache

Differential Revision: D95223862

fbshipit-source-id: e19dd163e5f7fecd9ef28b79be61455f0993a3c4
#publish-packages-to-npm&0.83-stable
Summary:
Pull Request resolved: react#56211

The `removeClippedSubviews` prop toggle path in `RCTViewComponentView` did not
handle being turned off: children that were clipped (removed from superview)
remained invisible, and `_reactSubviews` became stale.

This diff:
- Adds `_updateRemoveClippedSubviewsState` helper that ensures consistent state
  when toggling. On toggle-off, re-mounts all children from `_reactSubviews` in
  the correct order and clears the tracking array.
- Makes the unmount path resilient by cleaning up `_reactSubviews` even when
  `removeClippedSubviews` is off.
- Splits the unmount assert into two distinct messages: "not mounted" vs
  "mounted inside a different view".
- Adds unit tests covering toggle-off re-mounting, ordering, cleanup, and
  unmount-after-toggle scenarios.

Changelog: [iOS][Fixed] Fixes crash when changing the value of `removeClippedSubviews`

Reviewed By: sbuggay

Differential Revision: D97971845

fbshipit-source-id: c5d0a99e632a23613cc5e05bcf00c2985c30d5b4
* Limit WebSocket queue size for packager connection (react#54300)

Summary:
Pull Request resolved: react#54300

Establishes a queue mechanism on top of the OkHttp's WebSocket implementation. This mechanism will control the queue size and guarantee that we don't have more than 16MB scheduled.

This prevents the scenario of when OkHttp forces WS disconnection because of this threshold.

Reviewed By: motiz88, alanleedev

Differential Revision: D85581509

fbshipit-source-id: ac3e830c935c1301b674739c96fcbe18446eaa71

* Bump chunk size for android (react#54301)

Summary:
Pull Request resolved: react#54301

# Changelog: [Internal]

Previously, we would read every single kilobyte and do Java -> C++ call with `jni`.

For big objects, like source maps, this means that we were doing at least 1024 calls for a single megabyte of incoming data. From my observations, some source maps on Twilight could reach 30Mb+.

There is a trade-off between how much of memory we want to allocate while reading a stream and a runtime. I didn't notice any differences while changing the chunk size from 8Kb to 1Mb and some values in between; in the end it purely depends on the OkHttp's or Okio's implementation of the stream, looks like it uses 8Kb as a chunk size by default:
{F1983042734}

Reviewed By: huntie

Differential Revision: D85652217

fbshipit-source-id: 68474f0b7eece13a0a1c8ea9e617b99a26d81ff9

* Increase the size of the chunk of ProfileChunk events (react#54352)

Summary:
Pull Request resolved: react#54352

# Changelog: [Internal]

Since we can now avoid disconnections, it should be safe to increase the chunk size.

This should improve the trace loading time.

Reviewed By: huntie

Differential Revision: D85937959

fbshipit-source-id: 4f0ef023a4d756217de0c756dbc1decbd99698d4

---------

Co-authored-by: Ruslan Lesiutin <hoxy@meta.com>
…nes (react#56994)

Summary:
Two sources of non-determinism cause `Podfile.lock` SPEC CHECKSUMS to differ between machines, breaking `pod install --deployment` in CI and creating unnecessary churn in PRs.

### Fix 1: Sort `Dir.glob` results in `Yoga.podspec`

`Dir.glob` returns files in filesystem-dependent order (varies across macOS APFS volumes, case sensitivity settings, and Linux ext4/xfs). Since CocoaPods evaluates the podspec at install time, the resulting array order differs between machines, producing different spec checksums.

```ruby
# Before
spec.private_header_files = Dir.glob(all_header_files) - Dir.glob(public_header_files)

# After
spec.private_header_files = Dir.glob(all_header_files).sort - Dir.glob(public_header_files).sort
```

### Fix 2: Use a Pods-relative path in `hermes-engine.podspec`

`require.resolve` with `__dir__` resolves to an absolute path containing the developer's home directory (e.g., `/Users/alice/project/node_modules/...`). This absolute path gets baked into `user_target_xcconfig`, which differs per machine.

Instead of hardcoding a relative path (which assumes a specific project layout), we dynamically compute the relative path from `Pod::Config.instance.sandbox.root` to the resolved `hermes-compiler` location. This supports any project layout (standard apps, monorepos, RNTester, etc.) while keeping the xcconfig deterministic.

```ruby
# Before — absolute path baked in
spec.user_target_xcconfig = {
  'HERMES_CLI_PATH' => "#{hermes_compiler_path}/hermesc/osx-bin/hermesc"
}

# After — dynamic relative path via $(PODS_ROOT)
pods_root = Pod::Config.instance.sandbox.root
relative_hermesc = Pathname.new(hermesc_path).relative_path_from(pods_root)

spec.user_target_xcconfig = {
  'HERMES_CLI_PATH' => "$(PODS_ROOT)/#{relative_hermesc}"
}
```
bypass-github-export-checks
## Changelog:

[IOS] [FIXED] - Make Podfile.lock SPEC CHECKSUMS deterministic across machines by sorting Dir.glob results in Yoga.podspec and using a dynamically computed Pods-relative path in hermes-engine.podspec

Pull Request resolved: react#56994

Test Plan:
1. Run `pod install` on machine A, record `Podfile.lock`
2. Run `pod install` on machine B (different username/home directory)
3. Verify SPEC CHECKSUMS are identical between both runs

We have verified this fix in our production app — after patching, running `pod install` consecutively produces zero diff in `Podfile.lock`.

Supersedes react#56977 (closed due to force-push history issue).
Fixes react#56975

Made with [Cursor](https://cursor.com)

Reviewed By: cortinico

Differential Revision: D107362027

Pulled By: cipolleschi

fbshipit-source-id: 8330b99bcd17098f0bcc337ef44372ee9a3e68be
react#57241)

* Expose cleanupContentsNodesRecursively for backport

Backport prerequisite: make cleanupContentsNodesRecursively externally
linkable and declare it in CalculateLayout.h so AbsoluteLayout.cpp can
call it. This mirrors the relevant slice of react#55876 (26cef64), which
is not present on this branch, and is required before applying react#56422
and react#57103.

* Fix node ownership when `display: contents` is used (react#56422)

Summary:
Pull Request resolved: react#56422

Changelog: [GENERAL][FIXED] Fixed Yoga node ownership when `display: contents` is used in absolutely positioned subtrees

Fixes an edge case where nodes with `display: contents` weren't cloned properly inside absolutely positioned subtrees.

Adds a test case covering this scenario.

X-link: react/yoga#1924

Reviewed By: NickGerleman

Differential Revision: D100581579

Pulled By: j-piasecki

fbshipit-source-id: e05e9a4076bd11a71be438ef910a262044659a9b

* Fix `display: contents` nodes having `hasNewLayout` set incorrectly (react#57103)

Summary:
Pull Request resolved: react#57103

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

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

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

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

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

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

X-link: react/yoga#1970

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

Reviewed By: javache

Differential Revision: D107854528

Pulled By: j-piasecki

fbshipit-source-id: cae5e889622296e8b6380a6428509b5ffea3e9ae
Summary:
Pull Request resolved: react#54784

This is a follow-up to D86201689 following user feedback on `0.83.0-rc.2`: react-native-community/discussions-and-proposals#954 (reply in thread).

The problem was that we were incorrectly attributing any and all `IInspector::addPage()` calls to represent a new React Native Host being registered. However, this API also remains common to the legacy Hermes `ConnectionDemux` runtime target setup (which does not represent a host target).

We now fork this code path internally based on `InspectorTargetCapabilities.prefersFuseboxFrontend`, in order to track `registeredHostsCount` accurately (i.e. **only** for HostTarget page registrations).

Changelog:
[General][Fixed] - React Native DevTools: Fix a bug where we would incorrectly flag apps using additonal Hermes runtimes (e.g. Reanimated) as being multi-host

Reviewed By: hoxyq

Differential Revision: D88386623

fbshipit-source-id: 49a82faa6c857de41e8e9a757f5fdd850f09c3dd
…. (react#55251)

Summary:
This fixes a regression introduced by b18cd58  by including the final, redirected to URL in the response object.

[ANDROID][FIXED] fetch() response URL is incorrect after redirect (react#55248)

Pull Request resolved: react#55251

Test Plan: Testing using the reproducer from issue react#55248.

Reviewed By: cortinico

Differential Revision: D91046809

Pulled By: javache

fbshipit-source-id: 314419304f18325e6273ae9ed6a828d32abd68ac
* Update React Native GitHub repo slug

* Fix repo slug test formatting

* Use available runner for Android build

* Use available Ubuntu runners in workflows
…act#57023)

* Make removeClippedSubviews toggle-resilient (react#56211)

Summary:
Pull Request resolved: react#56211

The `removeClippedSubviews` prop toggle path in `RCTViewComponentView` did not
handle being turned off: children that were clipped (removed from superview)
remained invisible, and `_reactSubviews` became stale.

This diff:
- Adds `_updateRemoveClippedSubviewsState` helper that ensures consistent state
  when toggling. On toggle-off, re-mounts all children from `_reactSubviews` in
  the correct order and clears the tracking array.
- Makes the unmount path resilient by cleaning up `_reactSubviews` even when
  `removeClippedSubviews` is off.
- Splits the unmount assert into two distinct messages: "not mounted" vs
  "mounted inside a different view".
- Adds unit tests covering toggle-off re-mounting, ordering, cleanup, and
  unmount-after-toggle scenarios.

Changelog: [iOS][Fixed] Fixes crash when changing the value of `removeClippedSubviews`

Reviewed By: sbuggay

Differential Revision: D97971845

fbshipit-source-id: c5d0a99e632a23613cc5e05bcf00c2985c30d5b4

* Update React Native GitHub repo slug

* Fix repo slug test formatting

* Use available runner for Android build

* Use available Ubuntu runners in workflows

---------

Co-authored-by: Pieter De Baets <pieterdb@meta.com>
…ve (react#56844)

* Cache prebuilt iOS binaries in ~/Library/Caches/ReactNative

Currently, Hermes, ReactNativeDependencies, and ReactNativeCore
tarballs are cached only inside the Pods/ directory. This means
every clean `pod install` (or deleting the Pods folder) triggers
a full re-download from Maven, even if the same version was already
downloaded before.

This adds a shared cache layer at ~/Library/Caches/ReactNative/.
On first download, tarballs are saved to the shared cache. On
subsequent pod installs, if the local Pods cache is empty but the
shared cache has the tarball, it is copied locally instead of
re-downloaded. This benefits:
- Clean installs after deleting Pods/
- Multiple projects using the same React Native version
- CI environments with a persistent home directory

Added descriptive log messages for each scenario (local hit,
shared cache hit, cache miss + download) to aid debugging.

* Update React Native GitHub repo slug

* Use available runner for Android build

* Use available Ubuntu runners in workflows

* Fix repo slug test formatting
#publish-packages-to-npm&0.83-stable
…mi/merge-0.83.10

# Conflicts:
#	.github/ISSUE_TEMPLATE.md
#	.gitignore
#	README.md
#	package.json
#	packages/assets/package.json
#	packages/babel-plugin-codegen/package.json
#	packages/community-cli-plugin/package.json
#	packages/core-cli-utils/package.json
#	packages/debugger-frontend/package.json
#	packages/dev-middleware/package.json
#	packages/eslint-config-react-native/package.json
#	packages/eslint-plugin-react-native/package.json
#	packages/eslint-plugin-specs/package.json
#	packages/gradle-plugin/package.json
#	packages/metro-config/package.json
#	packages/new-app-screen/package.json
#	packages/normalize-color/package.json
#	packages/polyfills/package.json
#	packages/react-native-babel-preset/package.json
#	packages/react-native-babel-transformer/package.json
#	packages/react-native-codegen/package.json
#	packages/react-native-compatibility-check/package.json
#	packages/react-native-popup-menu-android/package.json
#	packages/react-native/Package.swift
#	packages/react-native/React/CoreModules/RCTRedBox.mm
#	packages/react-native/React/CoreModules/RCTWebSocketModule.mm
#	packages/react-native/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm
#	packages/react-native/gradle/libs.versions.toml
#	packages/react-native/package.json
#	packages/react-native/sdks/.hermesv1version
#	packages/react-native/sdks/.hermesversion
#	packages/react-native/sdks/hermes-engine/version.properties
#	packages/react-native/third-party-podspecs/RCT-Folly.podspec
#	packages/react-native/third-party-podspecs/fmt.podspec
#	packages/rn-tester/Podfile.lock
#	packages/rn-tester/package.json
#	packages/typescript-config/package.json
#	packages/virtualized-lists/package.json
#	private/helloworld/package.json
#	private/react-native-codegen-typescript-test/package.json
#	scripts/releases/ios-prebuild/configuration.js
#	yarn.lock
First react-native-macos 0.83 release, syncing to upstream React Native
0.83.10.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Replace the nx version-plan with a Changesets entry (react-native-macos: minor),
matching the changesets release tooling this branch inherited from main (microsoft#2839).
This is the first 0.83 release of react-native-macos, syncing to RN 0.83.10.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- RCTFrameTimingsObserver: the new upstream screenshot observer uses UIKit-only
  APIs (UIScene/UIWindowScene/UIGraphicsImageRenderer/drawViewHierarchyInRect) and
  is only instantiated on iOS (RCTHost.mm, TARGET_OS_IPHONE). Compile a no-op stub
  on macOS so React-Core (static + SwiftPM prebuild) builds.
- yarn.lock: the merge deduped @typescript-eslint/eslint-plugin to 8.36.0 while
  @typescript-eslint/parser resolved to 8.38.0, breaking the transitive
  @typescript-eslint/types link under the pnpm nodeLinker (ESLint failed to load
  the plugin). Re-resolve both root ^8.36.0 deps to a consistent 8.63.0.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
export-versions.mts coerced dependencies['@react-native/codegen'], which is
'workspace:*' in the dev tree, producing the invalid 'workspace:*.0' passed to
the test-app integration's set-react-version. Read peerDependencies['react-native']
instead (the real upstream RN version, e.g. 0.83.10 -> 0.83), matching how the
react-native-macos init workflow derives its version.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The init and test-app integration gates (which only run on *-stable base
branches) pack react-native-macos and install it standalone, but its
@react-native-macos/virtualized-lists workspace dependency is not published at
the 1000.0.0 dev version, so the install failed to resolve it.

Pack virtualized-lists alongside react-native-macos and install/override it:
- init: npm install both tarballs together (npm satisfies the 1000.0.0 dep from
  the local tarball).
- test-app: add it to the set-react-version --overrides map.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@react-native/tester (the private RNTester app) is pinned to the upstream
snapshot version 0.83.0-main, which Changesets graduates to a phantom major
(1.0.0) bump in the release plan, tripping the 'no major bumps' guard in the
changesets check. It is never published, so add it to the changeset ignore list.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
RN 0.83.10 added a -dealloc that hid the loading window via UIWindow/.hidden.
Use the RCTPlatformWindow ivar type and hide via -orderOut: on macOS (NSWindow),
mirroring the existing #if !TARGET_OS_OSX carve-out in -hide.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
change.mts getBaseBranch() derived the git remote from package.json
repository.url, but the monorepo root package.json has no repository field, so
repoPath was empty and `(repoPath && ...) ?? 'origin'` evaluated to an empty
string (?? doesn't catch ''), yielding base ref '/0.83-stable'. changeset status
then failed to find the divergence point. Use || so an empty match falls back to
'origin' (=> origin/<base>).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
set-react-version --overrides only covers the direct react-native-macos dep, so
yarn still tried to fetch the unpublished @react-native-macos/virtualized-lists@1000.0.0
transitively. Add a root resolutions entry pointing at the packed tarball, using
the same mechanism as the @types/react pin.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Ports upstream RN 0.83.10's RedBox 2.0 refactor to macOS, completing the
deferral from the 0.83.10 merge (microsoft#3022) which kept the old monolithic macOS
RCTRedBox and omitted the 11 new iOS-only RedBox2 files.

- Adopts upstream's thin RCTRedBox.mm coordinator that selects a controller via
  ReactNativeFeatureFlags::redBoxV2IOS() (RCTRedBox2Controller when true, else
  RCTRedBoxController), plus the extracted AnsiParser/ErrorParser/HMRClient.
- RCTRedBoxController.mm: mechanical port — the carve-outs were transferred from
  our already-macOS-ported inline controller in the old RCTRedBox.mm.
- RCTRedBox2Controller.mm: genuinely new AppKit UI. NSTableView (no sections)
  flattens the Message/Source/CallStack sections into rows with header rows;
  NSButton footer with key equivalents; NSPasteboard copy; sheet presentation.
- Carve-outs follow fork convention: additive `#if !TARGET_OS_OSX // [macOS]`
  branches with RCTUIColor/RCTPlatformView compat types; iOS branches are
  byte-identical to upstream (verified via unifdef).
- Build wiring is automatic via the CoreModules glob (podspec + Package.swift).

Verified: RNTester-macOS Debug build = BUILD SUCCEEDED.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@Saadnajmi Saadnajmi requested a review from a team as a code owner July 14, 2026 21:59
…ease

The 'Test react-native-macos init' and 'react-native-test-app integration' gates
integration-test react-native-macos as a real project consumes it, which requires
the target minor to be published to npm: react-native-macos-init installs a
published react-native-macos (falling back to the previous published minor and
conflicting on the react-native peer), and react-native-test-app declares a
supported react-native-macos version range. Neither can be satisfied for the very
first release of a new minor, before anything is published.

Add a check-release-published gate that queries npm for the target minor and skips
both integration jobs when it is not yet published. They self-heal and run normally
for later patch releases once the minor is on npm. The failures occur at yarn/npm
install (before any bundling/pod/build), so this only skips the pre-publish window,
not real integration coverage.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@Saadnajmi Saadnajmi changed the title Port RedBox 2.0 to macOS (AppKit) feat(macos): port RedBox 2.0 to macOS (AppKit) Jul 15, 2026
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.