diff --git a/packages/react-native/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingView.mm b/packages/react-native/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingView.mm index 44d8390e2243f6..1d94f1b411debd 100644 --- a/packages/react-native/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingView.mm +++ b/packages/react-native/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingView.mm @@ -13,6 +13,13 @@ #import "RCTSurfaceView.h" #import "RCTUtils.h" +#if __has_include() && RCT_DEV +#import +#import +#import +#import +#endif + @interface RCTSurfaceHostingView () @property (nonatomic, assign) BOOL isActivityIndicatorViewVisible; @@ -278,4 +285,42 @@ - (void)surface:(__unused RCTSurface *)surface didChangeIntrinsicSize:(__unused }); } +#if TARGET_OS_OSX // [macOS +- (NSMenu *)menuForEvent:(NSEvent *)event +{ + NSMenu *menu = nil; +#if __has_include() && RCT_DEV + // Try to get DevMenu from the contextContainer via the surface presenter + // This works in Fabric architecture where DevMenu is stored in contextContainer + if ([self.surface respondsToSelector:@selector(surfacePresenter)]) { + RCTSurfacePresenter *surfacePresenter = [self.surface performSelector:@selector(surfacePresenter)]; + if (surfacePresenter) { + auto contextContainer = surfacePresenter.contextContainer; + if (contextContainer) { + auto optionalDevMenu = contextContainer->find>("RCTDevMenu"); + if (optionalDevMenu) { + RCTDevMenu *devMenu = facebook::react::unwrapManagedObject(optionalDevMenu.value()); + if (devMenu) { + menu = [devMenu menu]; + } + } + } + } + } + + // Fall back to notification-based approach if contextContainer access fails + if (menu == nil) { + [[NSNotificationCenter defaultCenter] postNotificationName:RCTShowDevMenuNotification object:nil]; + // Return nil as the menu will be shown programmatically via notification + return nil; + } +#endif + + if (menu == nil) { + menu = [super menuForEvent:event]; + } + return menu; +} +#endif // macOS] + @end diff --git a/packages/react-native/React/Fabric/RCTSurfacePresenterBridgeAdapter.mm b/packages/react-native/React/Fabric/RCTSurfacePresenterBridgeAdapter.mm index d3dcaf5bc5dab0..41618f435e119c 100644 --- a/packages/react-native/React/Fabric/RCTSurfacePresenterBridgeAdapter.mm +++ b/packages/react-native/React/Fabric/RCTSurfacePresenterBridgeAdapter.mm @@ -18,6 +18,10 @@ #import #import +#if __has_include() && RCT_DEV +#import +#endif + #import #import #import @@ -39,6 +43,15 @@ - (void)invokeAsync:(std::function &&)func; contextContainer->insert("Bridge", wrapManagedObjectWeakly(bridge)); contextContainer->insert("RCTImageLoader", wrapManagedObject((id)imageLoader)); + +#if __has_include() && RCT_DEV + // Add DevMenu to contextContainer for Fabric views to access + RCTDevMenu *devMenu = [bridge devMenu]; + if (devMenu) { + contextContainer->insert("RCTDevMenu", wrapManagedObject(devMenu)); + } +#endif + return contextContainer; }