Skip to content

Commit fda2587

Browse files
authored
feat: Add a dev menu to RCTSurfaceHostingView (2/2) (#2749)
## Summary: You can launch the dev menu 3 ways: 1. Via the hot key Cmd+D (not supported on macOS at time of writing) 2. Via a right click (which wasn't enabled in Fabric yet) 3. By pressing "d" in metro. This had a couple of problems: We don't want to register hotkeys on the window, as a window may have multiple instances of RN running. We _could_ register it on the root view. That may be hard to discover as keyboard focus is rarely in the root view for Mac apps... it's usually just on the window or applicatin. The right click context menu wasn't available in Fabric, so this PR adds that. It involves a non trivial amount of code to add a contextContainer to RCTSurfaceHostingView and have RCTRootViewFactory set it. The other issue is that when the menu is presented from metro, it's odd for it to be a context menu off the window or (if it can't find the window) at coordiantes 0,0 (bottom left of the screen for macOS). To match other platforms, I think it would be better to make the deve menu an NSAlert. Let's also preserve the right click context menu for now, since we don't have a way to get the dev menu from the app without metro otherwise. ## Test Plan: Dev menu on Fabric: <img width="627" height="896" alt="image" src="https://github.com/user-attachments/assets/50a25f80-db10-4ca3-bbcf-44165d2f4ce8" />
1 parent b3aad0b commit fda2587

File tree

4 files changed

+60
-3
lines changed

4 files changed

+60
-3
lines changed

packages/react-native/Libraries/AppDelegate/RCTRootViewFactory.mm

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@
3333
#import <react/renderer/runtimescheduler/RuntimeSchedulerCallInvoker.h>
3434
#import <react/runtime/JSRuntimeFactory.h>
3535

36+
#if RCT_DEV_MENU // [macOS
37+
#import "RCTDevMenu.h"
38+
#endif // macOS]
39+
3640
@implementation RCTRootViewFactoryConfiguration
3741

3842
- (instancetype)initWithBundleURL:(NSURL *)bundleURL newArchEnabled:(BOOL)newArchEnabled
@@ -151,6 +155,14 @@ - (RCTPlatformView *)viewWithModuleName:(NSString *)moduleName // [macOS]
151155
#if !TARGET_OS_OSX // [macOS]
152156
surfaceHostingProxyRootView.backgroundColor = [UIColor systemBackgroundColor];
153157
#endif // [macOS]
158+
159+
#if RCT_DEV_MENU // [macOS
160+
RCTDevMenu *devMenu = [self.reactHost.moduleRegistry moduleForClass:[RCTDevMenu class]];
161+
if (devMenu) {
162+
surfaceHostingProxyRootView.devMenu = devMenu;
163+
}
164+
#endif // macOS]
165+
154166
if (_configuration.customizeRootView != nil) {
155167
_configuration.customizeRootView(surfaceHostingProxyRootView);
156168
}
@@ -183,6 +195,16 @@ - (RCTPlatformView *)createRootViewWithBridge:(RCTBridge *)bridge
183195
{
184196
BOOL enableFabric = _configuration.fabricEnabled;
185197
RCTPlatformView *rootView = RCTAppSetupDefaultRootView(bridge, moduleName, initProps, enableFabric); // [macOS]
198+
199+
#if RCT_DEV_MENU // [macOS
200+
if (enableFabric && [rootView isKindOfClass:[RCTSurfaceHostingView class]]) {
201+
RCTDevMenu *devMenu = [bridge moduleForClass:[RCTDevMenu class]];
202+
if (devMenu) {
203+
[(RCTSurfaceHostingView *)rootView setDevMenu:devMenu];
204+
}
205+
}
206+
#endif // macOS]
207+
186208
#if !TARGET_OS_OSX // [macOS]
187209
rootView.backgroundColor = [UIColor systemBackgroundColor];
188210
#endif // [macOS]
@@ -327,4 +349,4 @@ - (NSURL *)bundleURL
327349
return self->_configuration.bundleURLBlock();
328350
}
329351

330-
@end
352+
@end

packages/react-native/React/Base/RCTRootView.m

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -494,9 +494,9 @@ - (void)containingWindowDidResignKey {
494494
- (NSMenu *)menuForEvent:(NSEvent *)event
495495
{
496496
NSMenu *menu = nil;
497-
#if __has_include("RCTDevMenu.h") && RCT_DEV
497+
#if RCT_DEV_MENU
498498
menu = [[_bridge devMenu] menu];
499-
#endif
499+
#endif // RCT_DEV_MENU
500500
if (menu == nil) {
501501
menu = [super menuForEvent:event];
502502
}

packages/react-native/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingView.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@
1414

1515
@class RCTBridge;
1616
@class RCTSurface;
17+
#if RCT_DEV_MENU // [macOS
18+
@class RCTDevMenu;
19+
#endif // macOS]
1720

1821
typedef RCTPlatformView *_Nullable (^RCTSurfaceHostingViewActivityIndicatorViewFactory)(void); // [macOS]
1922

@@ -63,6 +66,14 @@ NS_ASSUME_NONNULL_BEGIN
6366
* @param disabled if `YES`, the auto-hide is disabled. Otherwise the loading view will be hidden automatically
6467
*/
6568
- (void)disableActivityIndicatorAutoHide:(BOOL)disabled;
69+
70+
#if RCT_DEV_MENU // [macOS
71+
/**
72+
* Dev menu for macOS context menu access.
73+
*/
74+
@property (nonatomic, strong, nullable) RCTDevMenu *devMenu;
75+
#endif // macOS]
76+
6677
@end
6778

6879
NS_ASSUME_NONNULL_END

packages/react-native/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingView.mm

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@
1313
#import "RCTSurfaceView.h"
1414
#import "RCTUtils.h"
1515

16+
#if RCT_DEV_MENU // [macOS
17+
#import "RCTDevMenu.h"
18+
#endif // macOS]
19+
1620
@interface RCTSurfaceHostingView ()
1721

1822
@property (nonatomic, assign) BOOL isActivityIndicatorViewVisible;
@@ -134,6 +138,7 @@ - (void)setSizeMeasureMode:(RCTSurfaceSizeMeasureMode)sizeMeasureMode
134138
_sizeMeasureMode = sizeMeasureMode;
135139
[self _invalidateLayout];
136140
}
141+
137142
- (void)disableActivityIndicatorAutoHide:(BOOL)disabled
138143
{
139144
_autoHideDisabled = disabled;
@@ -278,4 +283,23 @@ - (void)surface:(__unused RCTSurface *)surface didChangeIntrinsicSize:(__unused
278283
});
279284
}
280285

286+
#if TARGET_OS_OSX // [macOS
287+
288+
#pragma mark - Context Menu
289+
290+
- (NSMenu *)menuForEvent:(NSEvent *)event
291+
{
292+
#if __has_include("RCTDevMenu.h") && RCT_DEV
293+
// Try direct dev menu property first (simplest approach)
294+
if (_devMenu) {
295+
return [_devMenu menu];
296+
}
297+
298+
299+
#endif
300+
301+
return [super menuForEvent:event];
302+
}
303+
#endif // macOS]
304+
281305
@end

0 commit comments

Comments
 (0)