From 8fb86d455016634ac41fc4f0198933c453397c3a Mon Sep 17 00:00:00 2001 From: Saad Najmi Date: Tue, 4 Nov 2025 17:23:07 -0800 Subject: [PATCH 1/6] feat: Add a dev menu to RCTSurfaceHostingView via a ContextContainer --- .../AppDelegate/RCTRootViewFactory.mm | 36 +++++++++++ .../RCTSurfaceHostingView+Private.h | 28 +++++++++ .../RCTSurfaceHostingView.h | 1 + .../RCTSurfaceHostingView.mm | 63 +++++++++++++++++++ 4 files changed, 128 insertions(+) create mode 100644 packages/react-native/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingView+Private.h diff --git a/packages/react-native/Libraries/AppDelegate/RCTRootViewFactory.mm b/packages/react-native/Libraries/AppDelegate/RCTRootViewFactory.mm index 8866b8a4bd7e24..536310ed30dc0c 100644 --- a/packages/react-native/Libraries/AppDelegate/RCTRootViewFactory.mm +++ b/packages/react-native/Libraries/AppDelegate/RCTRootViewFactory.mm @@ -25,13 +25,21 @@ #import #import #import +#import // [macOS] #import + +#if TARGET_OS_OSX && __has_include("RCTDevMenu.h") // [macOS] +#import "RCTDevMenu.h" +#endif // [macOS] #import #import #import #import #import #import +#import + +using namespace facebook::react; @implementation RCTRootViewFactoryConfiguration @@ -151,6 +159,18 @@ - (RCTPlatformView *)viewWithModuleName:(NSString *)moduleName // [macOS] #if !TARGET_OS_OSX // [macOS] surfaceHostingProxyRootView.backgroundColor = [UIColor systemBackgroundColor]; #endif // [macOS] + + [surfaceHostingProxyRootView setContextContainer:_contextContainer]; // [macOS] + +#if TARGET_OS_OSX && __has_include("RCTDevMenu.h") && RCT_DEV + // Insert dev menu for macOS context menu access in bridgeless mode + RCTDevMenu *devMenu = [self.reactHost.moduleRegistry moduleForClass:[RCTDevMenu class]]; + if (devMenu) { + _contextContainer->erase("RCTDevMenu"); + _contextContainer->insert("RCTDevMenu", wrapManagedObject(devMenu)); + } +#endif + if (_configuration.customizeRootView != nil) { _configuration.customizeRootView(surfaceHostingProxyRootView); } @@ -186,6 +206,12 @@ - (RCTPlatformView *)createRootViewWithBridge:(RCTBridge *)bridge #if !TARGET_OS_OSX // [macOS] rootView.backgroundColor = [UIColor systemBackgroundColor]; #endif // [macOS] + + // Set context container if this is a Fabric-enabled RCTSurfaceHostingView (or subclass) + if (enableFabric && [rootView isKindOfClass:[RCTSurfaceHostingView class]]) { + [(RCTSurfaceHostingView *)rootView setContextContainer:_contextContainer]; + } + return rootView; } @@ -202,6 +228,16 @@ - (RCTPlatformView *)createRootViewWithBridge:(RCTBridge *)bridge jsInvoker:callInvoker]; _contextContainer->erase("RuntimeScheduler"); _contextContainer->insert("RuntimeScheduler", _runtimeScheduler); + +#if TARGET_OS_OSX && __has_include("RCTDevMenu.h") && RCT_DEV + // Insert dev menu for macOS context menu access using proper moduleForClass pattern + RCTDevMenu *devMenu = [bridge moduleForClass:[RCTDevMenu class]]; + if (devMenu) { + _contextContainer->erase("RCTDevMenu"); + _contextContainer->insert("RCTDevMenu", wrapManagedObject(devMenu)); + } +#endif + return RCTAppSetupDefaultJsExecutorFactory(bridge, turboModuleManager, _runtimeScheduler); } else { return RCTAppSetupJsExecutorFactoryForOldArch(bridge, _runtimeScheduler); diff --git a/packages/react-native/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingView+Private.h b/packages/react-native/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingView+Private.h new file mode 100644 index 00000000000000..a5731a8da6cc4f --- /dev/null +++ b/packages/react-native/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingView+Private.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import "RCTSurfaceHostingView.h" + +#ifdef __cplusplus +#import +#endif + +NS_ASSUME_NONNULL_BEGIN + +@interface RCTSurfaceHostingView (Private) + +#ifdef __cplusplus +/** [macOS] + * Context container that provides access to the React Native runtime and TurboModule registry. + * This C++ interface is used internally by React Native for bridgeless mode. + */ +@property (nonatomic, assign, nullable) facebook::react::ContextContainer::Shared contextContainer; +#endif + +@end + +NS_ASSUME_NONNULL_END \ No newline at end of file diff --git a/packages/react-native/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingView.h b/packages/react-native/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingView.h index 5a348bb05ebe64..5035a417a50d5b 100644 --- a/packages/react-native/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingView.h +++ b/packages/react-native/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingView.h @@ -11,6 +11,7 @@ #import #import #import +// #import // [macOS] @class RCTBridge; @class RCTSurface; diff --git a/packages/react-native/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingView.mm b/packages/react-native/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingView.mm index 44d8390e2243f6..a0de5c82120ea9 100644 --- a/packages/react-native/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingView.mm +++ b/packages/react-native/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingView.mm @@ -6,6 +6,7 @@ */ #import "RCTSurfaceHostingView.h" +#import "RCTSurfaceHostingView+Private.h" // [macOS] #import "RCTConstants.h" #import "RCTDefines.h" #import "RCTSurface.h" @@ -13,6 +14,14 @@ #import "RCTSurfaceView.h" #import "RCTUtils.h" +#if TARGET_OS_OSX && __has_include("RCTDevMenu.h") // [macOS] +#import "RCTDevMenu.h" +#import "RCTBridgeProxy.h" +#import + +using namespace facebook::react; +#endif // [macOS] + @interface RCTSurfaceHostingView () @property (nonatomic, assign) BOOL isActivityIndicatorViewVisible; @@ -25,6 +34,7 @@ @implementation RCTSurfaceHostingView { RCTPlatformView *_Nullable _surfaceView; // [macOS] RCTSurfaceStage _stage; BOOL _autoHideDisabled; + facebook::react::ContextContainer::Shared _contextContainer; // [macOS] } RCT_NOT_IMPLEMENTED(-(instancetype)init) @@ -134,6 +144,19 @@ - (void)setSizeMeasureMode:(RCTSurfaceSizeMeasureMode)sizeMeasureMode _sizeMeasureMode = sizeMeasureMode; [self _invalidateLayout]; } + +// [macOS +- (facebook::react::ContextContainer::Shared)contextContainer +{ + return _contextContainer; +} + +- (void)setContextContainer:(facebook::react::ContextContainer::Shared)contextContainer +{ + _contextContainer = contextContainer; +} +// macOS] + - (void)disableActivityIndicatorAutoHide:(BOOL)disabled { _autoHideDisabled = disabled; @@ -278,4 +301,44 @@ - (void)surface:(__unused RCTSurface *)surface didChangeIntrinsicSize:(__unused }); } +#pragma mark - Context Menu + +#if TARGET_OS_OSX // [macOS] +- (NSMenu *)menuForEvent:(NSEvent *)event +{ + NSMenu *menu = nil; + +#if __has_include("RCTDevMenu.h") && RCT_DEV + // Try to get dev menu from context container + if (_contextContainer) { + auto devMenuOptional = _contextContainer->find>("RCTDevMenu"); + if (devMenuOptional.has_value()) { + RCTDevMenu *devMenu = unwrapManagedObject(*devMenuOptional); + if (devMenu && [devMenu respondsToSelector:@selector(menu)]) { + menu = [devMenu menu]; + } + } + } + + // Fallback: try legacy bridge access if surface has bridge + if (menu == nil && [_surface respondsToSelector:@selector(bridge)]) { + RCTBridge *bridge = [_surface performSelector:@selector(bridge)]; + if (bridge && [bridge respondsToSelector:@selector(devMenu)]) { + RCTDevMenu *devMenu = [bridge devMenu]; + if (devMenu && [devMenu respondsToSelector:@selector(menu)]) { + menu = [devMenu menu]; + } + } + } +#endif + + // Fall back to super's menu if no dev menu available + if (menu == nil) { + menu = [super menuForEvent:event]; + } + + return menu; +} +#endif // [macOS] + @end From d3a6e5375ca1fda14c0f020280a52a44e5c9fb0d Mon Sep 17 00:00:00 2001 From: Saad Najmi Date: Thu, 6 Nov 2025 11:07:42 -0800 Subject: [PATCH 2/6] formatting --- .../AppDelegate/RCTRootViewFactory.mm | 22 +++++++++---------- .../RCTSurfaceHostingView.h | 1 - .../RCTSurfaceHostingView.mm | 13 +++++------ 3 files changed, 16 insertions(+), 20 deletions(-) diff --git a/packages/react-native/Libraries/AppDelegate/RCTRootViewFactory.mm b/packages/react-native/Libraries/AppDelegate/RCTRootViewFactory.mm index 536310ed30dc0c..33ead2c90d6dc4 100644 --- a/packages/react-native/Libraries/AppDelegate/RCTRootViewFactory.mm +++ b/packages/react-native/Libraries/AppDelegate/RCTRootViewFactory.mm @@ -25,21 +25,20 @@ #import #import #import -#import // [macOS] #import -#if TARGET_OS_OSX && __has_include("RCTDevMenu.h") // [macOS] -#import "RCTDevMenu.h" -#endif // [macOS] #import #import #import #import #import #import -#import -using namespace facebook::react; +#if TARGET_OS_OSX && __has_include("RCTDevMenu.h") // [macOS +#import +#import +#import "RCTDevMenu.h" +#endif // macOS] @implementation RCTRootViewFactoryConfiguration @@ -160,15 +159,13 @@ - (RCTPlatformView *)viewWithModuleName:(NSString *)moduleName // [macOS] surfaceHostingProxyRootView.backgroundColor = [UIColor systemBackgroundColor]; #endif // [macOS] - [surfaceHostingProxyRootView setContextContainer:_contextContainer]; // [macOS] - #if TARGET_OS_OSX && __has_include("RCTDevMenu.h") && RCT_DEV - // Insert dev menu for macOS context menu access in bridgeless mode RCTDevMenu *devMenu = [self.reactHost.moduleRegistry moduleForClass:[RCTDevMenu class]]; if (devMenu) { _contextContainer->erase("RCTDevMenu"); _contextContainer->insert("RCTDevMenu", wrapManagedObject(devMenu)); } + [surfaceHostingProxyRootView setContextContainer:_contextContainer]; // [macOS] #endif if (_configuration.customizeRootView != nil) { @@ -207,11 +204,12 @@ - (RCTPlatformView *)createRootViewWithBridge:(RCTBridge *)bridge rootView.backgroundColor = [UIColor systemBackgroundColor]; #endif // [macOS] - // Set context container if this is a Fabric-enabled RCTSurfaceHostingView (or subclass) +#if TARGET_OS_OSX // [macOS if (enableFabric && [rootView isKindOfClass:[RCTSurfaceHostingView class]]) { [(RCTSurfaceHostingView *)rootView setContextContainer:_contextContainer]; } - +#endif // macOS] + return rootView; } @@ -363,4 +361,4 @@ - (NSURL *)bundleURL return self->_configuration.bundleURLBlock(); } -@end \ No newline at end of file +@end diff --git a/packages/react-native/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingView.h b/packages/react-native/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingView.h index 5035a417a50d5b..5a348bb05ebe64 100644 --- a/packages/react-native/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingView.h +++ b/packages/react-native/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingView.h @@ -11,7 +11,6 @@ #import #import #import -// #import // [macOS] @class RCTBridge; @class RCTSurface; diff --git a/packages/react-native/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingView.mm b/packages/react-native/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingView.mm index a0de5c82120ea9..d673498a46d657 100644 --- a/packages/react-native/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingView.mm +++ b/packages/react-native/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingView.mm @@ -14,13 +14,11 @@ #import "RCTSurfaceView.h" #import "RCTUtils.h" -#if TARGET_OS_OSX && __has_include("RCTDevMenu.h") // [macOS] +#if TARGET_OS_OSX && __has_include("RCTDevMenu.h") // [macOS #import "RCTDevMenu.h" #import "RCTBridgeProxy.h" #import - -using namespace facebook::react; -#endif // [macOS] +#endif // macOS] @interface RCTSurfaceHostingView () @@ -145,7 +143,7 @@ - (void)setSizeMeasureMode:(RCTSurfaceSizeMeasureMode)sizeMeasureMode [self _invalidateLayout]; } -// [macOS +#if TARGET_OS_OSX // [macOS - (facebook::react::ContextContainer::Shared)contextContainer { return _contextContainer; @@ -155,7 +153,7 @@ - (void)setContextContainer:(facebook::react::ContextContainer::Shared)contextCo { _contextContainer = contextContainer; } -// macOS] +#endif // macOS] - (void)disableActivityIndicatorAutoHide:(BOOL)disabled { @@ -301,9 +299,10 @@ - (void)surface:(__unused RCTSurface *)surface didChangeIntrinsicSize:(__unused }); } +#if TARGET_OS_OSX // [macOS] + #pragma mark - Context Menu -#if TARGET_OS_OSX // [macOS] - (NSMenu *)menuForEvent:(NSEvent *)event { NSMenu *menu = nil; From aeb41e06e229e8c5cc6ab507d603cd70dc760e34 Mon Sep 17 00:00:00 2001 From: Saad Najmi Date: Thu, 6 Nov 2025 11:35:27 -0800 Subject: [PATCH 3/6] fix stuff and simplify --- .../AppDelegate/RCTRootViewFactory.mm | 4 +-- .../RCTSurfaceHostingView.mm | 36 +++++-------------- 2 files changed, 10 insertions(+), 30 deletions(-) diff --git a/packages/react-native/Libraries/AppDelegate/RCTRootViewFactory.mm b/packages/react-native/Libraries/AppDelegate/RCTRootViewFactory.mm index 33ead2c90d6dc4..e9bd3e45c3b02b 100644 --- a/packages/react-native/Libraries/AppDelegate/RCTRootViewFactory.mm +++ b/packages/react-native/Libraries/AppDelegate/RCTRootViewFactory.mm @@ -163,7 +163,7 @@ - (RCTPlatformView *)viewWithModuleName:(NSString *)moduleName // [macOS] RCTDevMenu *devMenu = [self.reactHost.moduleRegistry moduleForClass:[RCTDevMenu class]]; if (devMenu) { _contextContainer->erase("RCTDevMenu"); - _contextContainer->insert("RCTDevMenu", wrapManagedObject(devMenu)); + _contextContainer->insert("RCTDevMenu", facebook::react::wrapManagedObject(devMenu)); } [surfaceHostingProxyRootView setContextContainer:_contextContainer]; // [macOS] #endif @@ -232,7 +232,7 @@ - (RCTPlatformView *)createRootViewWithBridge:(RCTBridge *)bridge RCTDevMenu *devMenu = [bridge moduleForClass:[RCTDevMenu class]]; if (devMenu) { _contextContainer->erase("RCTDevMenu"); - _contextContainer->insert("RCTDevMenu", wrapManagedObject(devMenu)); + _contextContainer->insert("RCTDevMenu", facebook::react::wrapManagedObject(devMenu)); } #endif diff --git a/packages/react-native/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingView.mm b/packages/react-native/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingView.mm index d673498a46d657..6f4d9d1a56efb3 100644 --- a/packages/react-native/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingView.mm +++ b/packages/react-native/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingView.mm @@ -16,7 +16,6 @@ #if TARGET_OS_OSX && __has_include("RCTDevMenu.h") // [macOS #import "RCTDevMenu.h" -#import "RCTBridgeProxy.h" #import #endif // macOS] @@ -299,45 +298,26 @@ - (void)surface:(__unused RCTSurface *)surface didChangeIntrinsicSize:(__unused }); } -#if TARGET_OS_OSX // [macOS] +#if TARGET_OS_OSX // [macOS #pragma mark - Context Menu - (NSMenu *)menuForEvent:(NSEvent *)event { - NSMenu *menu = nil; - -#if __has_include("RCTDevMenu.h") && RCT_DEV - // Try to get dev menu from context container +#if RCT_DEV_MENU && __has_include("RCTDevMenu.h") if (_contextContainer) { auto devMenuOptional = _contextContainer->find>("RCTDevMenu"); if (devMenuOptional.has_value()) { - RCTDevMenu *devMenu = unwrapManagedObject(*devMenuOptional); - if (devMenu && [devMenu respondsToSelector:@selector(menu)]) { - menu = [devMenu menu]; - } - } - } - - // Fallback: try legacy bridge access if surface has bridge - if (menu == nil && [_surface respondsToSelector:@selector(bridge)]) { - RCTBridge *bridge = [_surface performSelector:@selector(bridge)]; - if (bridge && [bridge respondsToSelector:@selector(devMenu)]) { - RCTDevMenu *devMenu = [bridge devMenu]; - if (devMenu && [devMenu respondsToSelector:@selector(menu)]) { - menu = [devMenu menu]; + RCTDevMenu *devMenu = facebook::react::unwrapManagedObject(*devMenuOptional); + if (devMenu) { + return [devMenu menu]; } } } #endif - - // Fall back to super's menu if no dev menu available - if (menu == nil) { - menu = [super menuForEvent:event]; - } - - return menu; + + return [super menuForEvent:event]; } -#endif // [macOS] +#endif // macOS] @end From 6190a6b36553e6cdde5ca18b1bf5694ae9b941a7 Mon Sep 17 00:00:00 2001 From: Saad Najmi Date: Thu, 6 Nov 2025 12:41:45 -0800 Subject: [PATCH 4/6] Why do we need context container at all? --- .../AppDelegate/RCTRootViewFactory.mm | 35 +++++++------------ .../RCTSurfaceHostingView+Private.h | 28 --------------- .../RCTSurfaceHostingView.h | 12 +++++++ .../RCTSurfaceHostingView.mm | 29 ++++----------- 4 files changed, 31 insertions(+), 73 deletions(-) delete mode 100644 packages/react-native/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingView+Private.h diff --git a/packages/react-native/Libraries/AppDelegate/RCTRootViewFactory.mm b/packages/react-native/Libraries/AppDelegate/RCTRootViewFactory.mm index e9bd3e45c3b02b..c54abac9e6dcca 100644 --- a/packages/react-native/Libraries/AppDelegate/RCTRootViewFactory.mm +++ b/packages/react-native/Libraries/AppDelegate/RCTRootViewFactory.mm @@ -34,9 +34,7 @@ #import #import -#if TARGET_OS_OSX && __has_include("RCTDevMenu.h") // [macOS -#import -#import +#if RCT_DEV_MENU // [macOS #import "RCTDevMenu.h" #endif // macOS] @@ -159,14 +157,12 @@ - (RCTPlatformView *)viewWithModuleName:(NSString *)moduleName // [macOS] surfaceHostingProxyRootView.backgroundColor = [UIColor systemBackgroundColor]; #endif // [macOS] -#if TARGET_OS_OSX && __has_include("RCTDevMenu.h") && RCT_DEV +#if RCT_DEV_MENU // [macOS RCTDevMenu *devMenu = [self.reactHost.moduleRegistry moduleForClass:[RCTDevMenu class]]; if (devMenu) { - _contextContainer->erase("RCTDevMenu"); - _contextContainer->insert("RCTDevMenu", facebook::react::wrapManagedObject(devMenu)); + surfaceHostingProxyRootView.devMenu = devMenu; } - [surfaceHostingProxyRootView setContextContainer:_contextContainer]; // [macOS] -#endif +#endif // macOS] if (_configuration.customizeRootView != nil) { _configuration.customizeRootView(surfaceHostingProxyRootView); @@ -200,15 +196,19 @@ - (RCTPlatformView *)createRootViewWithBridge:(RCTBridge *)bridge { BOOL enableFabric = _configuration.fabricEnabled; RCTPlatformView *rootView = RCTAppSetupDefaultRootView(bridge, moduleName, initProps, enableFabric); // [macOS] -#if !TARGET_OS_OSX // [macOS] - rootView.backgroundColor = [UIColor systemBackgroundColor]; -#endif // [macOS] -#if TARGET_OS_OSX // [macOS +#if RCT_DEV_MENU // [macOS if (enableFabric && [rootView isKindOfClass:[RCTSurfaceHostingView class]]) { - [(RCTSurfaceHostingView *)rootView setContextContainer:_contextContainer]; + RCTDevMenu *devMenu = [bridge moduleForClass:[RCTDevMenu class]]; + if (devMenu) { + [(RCTSurfaceHostingView *)rootView setDevMenu:devMenu]; + } } #endif // macOS] + +#if !TARGET_OS_OSX // [macOS] + rootView.backgroundColor = [UIColor systemBackgroundColor]; +#endif // [macOS] return rootView; } @@ -227,15 +227,6 @@ - (RCTPlatformView *)createRootViewWithBridge:(RCTBridge *)bridge _contextContainer->erase("RuntimeScheduler"); _contextContainer->insert("RuntimeScheduler", _runtimeScheduler); -#if TARGET_OS_OSX && __has_include("RCTDevMenu.h") && RCT_DEV - // Insert dev menu for macOS context menu access using proper moduleForClass pattern - RCTDevMenu *devMenu = [bridge moduleForClass:[RCTDevMenu class]]; - if (devMenu) { - _contextContainer->erase("RCTDevMenu"); - _contextContainer->insert("RCTDevMenu", facebook::react::wrapManagedObject(devMenu)); - } -#endif - return RCTAppSetupDefaultJsExecutorFactory(bridge, turboModuleManager, _runtimeScheduler); } else { return RCTAppSetupJsExecutorFactoryForOldArch(bridge, _runtimeScheduler); diff --git a/packages/react-native/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingView+Private.h b/packages/react-native/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingView+Private.h deleted file mode 100644 index a5731a8da6cc4f..00000000000000 --- a/packages/react-native/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingView+Private.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#import "RCTSurfaceHostingView.h" - -#ifdef __cplusplus -#import -#endif - -NS_ASSUME_NONNULL_BEGIN - -@interface RCTSurfaceHostingView (Private) - -#ifdef __cplusplus -/** [macOS] - * Context container that provides access to the React Native runtime and TurboModule registry. - * This C++ interface is used internally by React Native for bridgeless mode. - */ -@property (nonatomic, assign, nullable) facebook::react::ContextContainer::Shared contextContainer; -#endif - -@end - -NS_ASSUME_NONNULL_END \ No newline at end of file diff --git a/packages/react-native/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingView.h b/packages/react-native/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingView.h index 5a348bb05ebe64..06380914d46e40 100644 --- a/packages/react-native/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingView.h +++ b/packages/react-native/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingView.h @@ -15,6 +15,10 @@ @class RCTBridge; @class RCTSurface; +#if RCT_DEV_MENU// [macOS] +@class RCTDevMenu; +#endif // [macOS] + typedef RCTPlatformView *_Nullable (^RCTSurfaceHostingViewActivityIndicatorViewFactory)(void); // [macOS] NS_ASSUME_NONNULL_BEGIN @@ -63,6 +67,14 @@ NS_ASSUME_NONNULL_BEGIN * @param disabled if `YES`, the auto-hide is disabled. Otherwise the loading view will be hidden automatically */ - (void)disableActivityIndicatorAutoHide:(BOOL)disabled; + +#if RCT_DEV_MENU // [macOS +/** + * Dev menu for macOS context menu access. + */ +@property (nonatomic, strong, nullable) RCTDevMenu *devMenu; +#endif // macOS] + @end NS_ASSUME_NONNULL_END diff --git a/packages/react-native/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingView.mm b/packages/react-native/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingView.mm index 6f4d9d1a56efb3..1041901084356c 100644 --- a/packages/react-native/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingView.mm +++ b/packages/react-native/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingView.mm @@ -6,7 +6,6 @@ */ #import "RCTSurfaceHostingView.h" -#import "RCTSurfaceHostingView+Private.h" // [macOS] #import "RCTConstants.h" #import "RCTDefines.h" #import "RCTSurface.h" @@ -31,7 +30,6 @@ @implementation RCTSurfaceHostingView { RCTPlatformView *_Nullable _surfaceView; // [macOS] RCTSurfaceStage _stage; BOOL _autoHideDisabled; - facebook::react::ContextContainer::Shared _contextContainer; // [macOS] } RCT_NOT_IMPLEMENTED(-(instancetype)init) @@ -142,18 +140,6 @@ - (void)setSizeMeasureMode:(RCTSurfaceSizeMeasureMode)sizeMeasureMode [self _invalidateLayout]; } -#if TARGET_OS_OSX // [macOS -- (facebook::react::ContextContainer::Shared)contextContainer -{ - return _contextContainer; -} - -- (void)setContextContainer:(facebook::react::ContextContainer::Shared)contextContainer -{ - _contextContainer = contextContainer; -} -#endif // macOS] - - (void)disableActivityIndicatorAutoHide:(BOOL)disabled { _autoHideDisabled = disabled; @@ -304,16 +290,13 @@ - (void)surface:(__unused RCTSurface *)surface didChangeIntrinsicSize:(__unused - (NSMenu *)menuForEvent:(NSEvent *)event { -#if RCT_DEV_MENU && __has_include("RCTDevMenu.h") - if (_contextContainer) { - auto devMenuOptional = _contextContainer->find>("RCTDevMenu"); - if (devMenuOptional.has_value()) { - RCTDevMenu *devMenu = facebook::react::unwrapManagedObject(*devMenuOptional); - if (devMenu) { - return [devMenu menu]; - } - } +#if __has_include("RCTDevMenu.h") && RCT_DEV + // Try direct dev menu property first (simplest approach) + if (_devMenu) { + return [_devMenu menu]; } + + #endif return [super menuForEvent:event]; From 420994836509ee48cf0a3bf9543d0b6c7476547d Mon Sep 17 00:00:00 2001 From: Saad Najmi Date: Thu, 6 Nov 2025 17:00:36 -0800 Subject: [PATCH 5/6] formatting --- .../react-native/Libraries/AppDelegate/RCTRootViewFactory.mm | 5 +---- packages/react-native/React/Base/RCTRootView.m | 4 ++-- .../Base/Surface/SurfaceHostingView/RCTSurfaceHostingView.h | 5 ++--- .../Base/Surface/SurfaceHostingView/RCTSurfaceHostingView.mm | 3 +-- 4 files changed, 6 insertions(+), 11 deletions(-) diff --git a/packages/react-native/Libraries/AppDelegate/RCTRootViewFactory.mm b/packages/react-native/Libraries/AppDelegate/RCTRootViewFactory.mm index c54abac9e6dcca..1856406020d786 100644 --- a/packages/react-native/Libraries/AppDelegate/RCTRootViewFactory.mm +++ b/packages/react-native/Libraries/AppDelegate/RCTRootViewFactory.mm @@ -26,7 +26,6 @@ #import #import #import - #import #import #import @@ -51,7 +50,7 @@ - (instancetype)initWithBundleURL:(NSURL *)bundleURL newArchEnabled:(BOOL)newArc - (instancetype)initWithBundleURLBlock:(RCTBundleURLBlock)bundleURLBlock newArchEnabled:(BOOL)newArchEnabled { return [self initWithBundleURLBlock:bundleURLBlock - newArchEnabled:newArchEnabled + newArchEnabled:newArchEnabledx turboModuleEnabled:newArchEnabled bridgelessEnabled:newArchEnabled]; } @@ -209,7 +208,6 @@ - (RCTPlatformView *)createRootViewWithBridge:(RCTBridge *)bridge #if !TARGET_OS_OSX // [macOS] rootView.backgroundColor = [UIColor systemBackgroundColor]; #endif // [macOS] - return rootView; } @@ -226,7 +224,6 @@ - (RCTPlatformView *)createRootViewWithBridge:(RCTBridge *)bridge jsInvoker:callInvoker]; _contextContainer->erase("RuntimeScheduler"); _contextContainer->insert("RuntimeScheduler", _runtimeScheduler); - return RCTAppSetupDefaultJsExecutorFactory(bridge, turboModuleManager, _runtimeScheduler); } else { return RCTAppSetupJsExecutorFactoryForOldArch(bridge, _runtimeScheduler); diff --git a/packages/react-native/React/Base/RCTRootView.m b/packages/react-native/React/Base/RCTRootView.m index 9ac9afb245b84b..87d869f19ab918 100644 --- a/packages/react-native/React/Base/RCTRootView.m +++ b/packages/react-native/React/Base/RCTRootView.m @@ -494,9 +494,9 @@ - (void)containingWindowDidResignKey { - (NSMenu *)menuForEvent:(NSEvent *)event { NSMenu *menu = nil; -#if __has_include("RCTDevMenu.h") && RCT_DEV +#if RCT_DEV_MENU menu = [[_bridge devMenu] menu]; -#endif +#endif // RCT_DEV_MENU if (menu == nil) { menu = [super menuForEvent:event]; } diff --git a/packages/react-native/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingView.h b/packages/react-native/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingView.h index 06380914d46e40..a5f312c44a6ff5 100644 --- a/packages/react-native/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingView.h +++ b/packages/react-native/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingView.h @@ -14,10 +14,9 @@ @class RCTBridge; @class RCTSurface; - -#if RCT_DEV_MENU// [macOS] +#if RCT_DEV_MENU // [macOS @class RCTDevMenu; -#endif // [macOS] +#endif // macOS] typedef RCTPlatformView *_Nullable (^RCTSurfaceHostingViewActivityIndicatorViewFactory)(void); // [macOS] diff --git a/packages/react-native/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingView.mm b/packages/react-native/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingView.mm index 1041901084356c..b2b984b51bafe1 100644 --- a/packages/react-native/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingView.mm +++ b/packages/react-native/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingView.mm @@ -13,9 +13,8 @@ #import "RCTSurfaceView.h" #import "RCTUtils.h" -#if TARGET_OS_OSX && __has_include("RCTDevMenu.h") // [macOS +#if RCT_DEV_MENU // [macOS #import "RCTDevMenu.h" -#import #endif // macOS] @interface RCTSurfaceHostingView () From 550b49264ed4bed0aec685956105971caa00872b Mon Sep 17 00:00:00 2001 From: Saad Najmi Date: Fri, 7 Nov 2025 12:13:37 -0800 Subject: [PATCH 6/6] typo --- .../react-native/Libraries/AppDelegate/RCTRootViewFactory.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react-native/Libraries/AppDelegate/RCTRootViewFactory.mm b/packages/react-native/Libraries/AppDelegate/RCTRootViewFactory.mm index 1856406020d786..3b001dd6545855 100644 --- a/packages/react-native/Libraries/AppDelegate/RCTRootViewFactory.mm +++ b/packages/react-native/Libraries/AppDelegate/RCTRootViewFactory.mm @@ -50,7 +50,7 @@ - (instancetype)initWithBundleURL:(NSURL *)bundleURL newArchEnabled:(BOOL)newArc - (instancetype)initWithBundleURLBlock:(RCTBundleURLBlock)bundleURLBlock newArchEnabled:(BOOL)newArchEnabled { return [self initWithBundleURLBlock:bundleURLBlock - newArchEnabled:newArchEnabledx + newArchEnabled:newArchEnabled turboModuleEnabled:newArchEnabled bridgelessEnabled:newArchEnabled]; }