From 897057b75a03752636df956b9b93208d3c9eb9ce Mon Sep 17 00:00:00 2001 From: Saad Najmi Date: Tue, 4 Nov 2025 17:23:07 -0800 Subject: [PATCH 1/5] feat: Add a dev menu to RCTSurfaceHostingView via a ContextContainer --- .../AppDelegate/RCTRootViewFactory.mm | 30 +++++++++++++ .../RCTSurfaceHostingView+Private.h | 28 +++++++++++++ .../RCTSurfaceHostingView.mm | 42 +++++++++++++++++++ .../React/CoreModules/RCTDevMenu.h | 15 +++++++ .../React/CoreModules/RCTDevMenu.mm | 26 ++++++++++++ 5 files changed, 141 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 266d6bab211cdb..6aae3b7f52705d 100644 --- a/packages/react-native/Libraries/AppDelegate/RCTRootViewFactory.mm +++ b/packages/react-native/Libraries/AppDelegate/RCTRootViewFactory.mm @@ -26,6 +26,7 @@ #import #import #import + #import #import #import @@ -34,6 +35,12 @@ #import #import +#if RCT_DEV_MENU +#import +#import +#import "RCTDevMenu.h" +#endif // RCT_DEV_MENU + @implementation RCTRootViewFactoryConfiguration - (instancetype)initWithBundleURL:(NSURL *)bundleURL newArchEnabled:(BOOL)newArchEnabled @@ -190,6 +197,15 @@ - (UIView *)viewWithModuleName:(NSString *)moduleName RCTSurfaceHostingProxyRootView *surfaceHostingProxyRootView = [[RCTSurfaceHostingProxyRootView alloc] initWithSurface:surface]; +#if RCT_DEV_MENU + RCTDevMenu *devMenu = [self.reactHost.moduleRegistry moduleForClass:[RCTDevMenu class]]; + if (devMenu) { + _contextContainer->erase("RCTDevMenu"); + _contextContainer->insert("RCTDevMenu", facebook::react::wrapManagedObject(devMenu)); + } + [surfaceHostingProxyRootView setContextContainer:_contextContainer]; +#endif // RCT_DEV_MENU + surfaceHostingProxyRootView.backgroundColor = [UIColor systemBackgroundColor]; if (_configuration.customizeRootView != nil) { _configuration.customizeRootView(surfaceHostingProxyRootView); @@ -208,6 +224,13 @@ - (UIView *)createRootViewWithBridge:(RCTBridge *)bridge { UIView *rootView = RCTAppSetupDefaultRootView(bridge, moduleName, initProps, YES); rootView.backgroundColor = [UIColor systemBackgroundColor]; + +#if RCT_DEV_MENU + if ([rootView isKindOfClass:[RCTSurfaceHostingView class]]) { + [(RCTSurfaceHostingView *)rootView setContextContainer:_contextContainer]; + } +#endif // RCT_DEV_MENU + return rootView; } @@ -223,6 +246,13 @@ - (UIView *)createRootViewWithBridge:(RCTBridge *)bridge jsInvoker:callInvoker]; _contextContainer->erase(facebook::react::RuntimeSchedulerKey); _contextContainer->insert(facebook::react::RuntimeSchedulerKey, _runtimeScheduler); + + RCTDevMenu *devMenu = [bridge moduleForClass:[RCTDevMenu class]]; + if (devMenu) { + _contextContainer->erase("RCTDevMenu"); + _contextContainer->insert("RCTDevMenu", wrapManagedObject(devMenu)); + } + return RCTAppSetupDefaultJsExecutorFactory(bridge, turboModuleManager, _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..63354bfca1404b --- /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 +/** + * 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.mm b/packages/react-native/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingView.mm index 511e398a8bb78f..6ff53dcc26afc6 100644 --- a/packages/react-native/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingView.mm +++ b/packages/react-native/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingView.mm @@ -13,6 +13,12 @@ #import "RCTSurfaceView.h" #import "RCTUtils.h" +#if RCT_DEV_MENU +#import "RCTSurfaceHostingView+Private.h" +#import "RCTDevMenu.h" +#import +#endif // RCT_DEV_MENU + @interface RCTSurfaceHostingView () @property (nonatomic, assign) BOOL isActivityIndicatorViewVisible; @@ -25,6 +31,7 @@ @implementation RCTSurfaceHostingView { UIView *_Nullable _surfaceView; RCTSurfaceStage _stage; BOOL _autoHideDisabled; + facebook::react::ContextContainer::Shared _contextContainer; // [macOS] } RCT_NOT_IMPLEMENTED(-(instancetype)init) @@ -126,6 +133,17 @@ - (void)setSizeMeasureMode:(RCTSurfaceSizeMeasureMode)sizeMeasureMode _sizeMeasureMode = sizeMeasureMode; [self _invalidateLayout]; } + +- (facebook::react::ContextContainer::Shared)contextContainer +{ + return _contextContainer; +} + +- (void)setContextContainer:(facebook::react::ContextContainer::Shared)contextContainer +{ + _contextContainer = contextContainer; +} + - (void)disableActivityIndicatorAutoHide:(BOOL)disabled { _autoHideDisabled = disabled; @@ -249,4 +267,28 @@ - (void)surface:(__unused RCTSurface *)surface didChangeIntrinsicSize:(__unused }); } +#pragma mark - Dev Menu + +#if RCT_DEV_MENU // [macOS] +- (NSArray *)keyCommands +{ + if (_contextContainer) { + auto devMenuOptional = _contextContainer->find>("RCTDevMenu"); + if (devMenuOptional.has_value()) { + RCTDevMenu *devMenu = facebook::react::unwrapManagedObject(*devMenuOptional); + if (devMenu) { + return [devMenu keyCommands]; + } + } + } + + return @[]; +} + +- (BOOL)canBecomeFirstResponder +{ + return YES; +} +#endif // macOS] + @end diff --git a/packages/react-native/React/CoreModules/RCTDevMenu.h b/packages/react-native/React/CoreModules/RCTDevMenu.h index 976cb8c517b58e..9e6faadcd398ae 100644 --- a/packages/react-native/React/CoreModules/RCTDevMenu.h +++ b/packages/react-native/React/CoreModules/RCTDevMenu.h @@ -105,6 +105,21 @@ RCT_EXTERN NSString *const RCTShowDevMenuNotification; */ - (void)disableReloadCommand; +/** + * Get the key commands for the dev menu (Cmd+D, Cmd+I, Cmd+R). + */ +- (NSArray *)keyCommands; + +/** + * Toggle the element inspector (called by key command). + */ +- (void)toggleElementInspector; + +/** + * Reload from key command (called by key command). + */ +- (void)reloadFromKeyCommand; + @end typedef NSString * (^RCTDevMenuItemTitleBlock)(void); diff --git a/packages/react-native/React/CoreModules/RCTDevMenu.mm b/packages/react-native/React/CoreModules/RCTDevMenu.mm index 890c1596df74f7..2afc3663863200 100644 --- a/packages/react-native/React/CoreModules/RCTDevMenu.mm +++ b/packages/react-native/React/CoreModules/RCTDevMenu.mm @@ -544,6 +544,32 @@ - (void)disableReloadCommand } } +- (NSArray *)keyCommands +{ + return @[ + [UIKeyCommand keyCommandWithInput:@"d" + modifierFlags:UIKeyModifierCommand + action:@selector(toggle)], + [UIKeyCommand keyCommandWithInput:@"i" + modifierFlags:UIKeyModifierCommand + action:@selector(toggleElementInspector)], + [UIKeyCommand keyCommandWithInput:@"r" + modifierFlags:UIKeyModifierCommand + action:@selector(reloadFromKeyCommand)] + ]; +} + +- (void)toggleElementInspector +{ + RCTDevSettings *devSettings = [_moduleRegistry moduleForName:"DevSettings"]; + [devSettings toggleElementInspector]; +} + +- (void)reloadFromKeyCommand +{ + RCTTriggerReloadCommandListeners(@"Dev menu key command"); +} + - (std::shared_ptr)getTurboModule: (const facebook::react::ObjCTurboModule::InitParams &)params { From 2f01f2a5162b647ea051c383684605a65c59998e Mon Sep 17 00:00:00 2001 From: Saad Najmi Date: Thu, 6 Nov 2025 12:41:45 -0800 Subject: [PATCH 2/5] Why do we need context container at all? --- .../AppDelegate/RCTRootViewFactory.mm | 21 ++++---------- .../RCTSurfaceHostingView+Private.h | 28 ------------------- .../RCTSurfaceHostingView.h | 8 ++++++ .../RCTSurfaceHostingView.mm | 27 +++--------------- 4 files changed, 17 insertions(+), 67 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 6aae3b7f52705d..a29fe2c9c04f55 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 @@ -36,8 +35,6 @@ #import #if RCT_DEV_MENU -#import -#import #import "RCTDevMenu.h" #endif // RCT_DEV_MENU @@ -196,14 +193,11 @@ - (UIView *)viewWithModuleName:(NSString *)moduleName RCTSurfaceHostingProxyRootView *surfaceHostingProxyRootView = [[RCTSurfaceHostingProxyRootView alloc] initWithSurface:surface]; - #if RCT_DEV_MENU 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]; #endif // RCT_DEV_MENU surfaceHostingProxyRootView.backgroundColor = [UIColor systemBackgroundColor]; @@ -227,8 +221,10 @@ - (UIView *)createRootViewWithBridge:(RCTBridge *)bridge #if RCT_DEV_MENU if ([rootView isKindOfClass:[RCTSurfaceHostingView class]]) { - [(RCTSurfaceHostingView *)rootView setContextContainer:_contextContainer]; - } + RCTDevMenu *devMenu = [bridge moduleForClass:[RCTDevMenu class]]; + if (devMenu) { + [(RCTSurfaceHostingView *)rootView setDevMenu:devMenu]; + } #endif // RCT_DEV_MENU return rootView; @@ -246,13 +242,6 @@ - (UIView *)createRootViewWithBridge:(RCTBridge *)bridge jsInvoker:callInvoker]; _contextContainer->erase(facebook::react::RuntimeSchedulerKey); _contextContainer->insert(facebook::react::RuntimeSchedulerKey, _runtimeScheduler); - - RCTDevMenu *devMenu = [bridge moduleForClass:[RCTDevMenu class]]; - if (devMenu) { - _contextContainer->erase("RCTDevMenu"); - _contextContainer->insert("RCTDevMenu", wrapManagedObject(devMenu)); - } - return RCTAppSetupDefaultJsExecutorFactory(bridge, turboModuleManager, _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 63354bfca1404b..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 -/** - * 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 65accd5350665a..2b48a3592e39c2 100644 --- a/packages/react-native/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingView.h +++ b/packages/react-native/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingView.h @@ -63,6 +63,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 +/** + * Dev menu for macOS context menu access. + */ +@property (nonatomic, strong, nullable) RCTDevMenu *devMenu; +#endif + @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 6ff53dcc26afc6..c624679377cc87 100644 --- a/packages/react-native/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingView.mm +++ b/packages/react-native/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingView.mm @@ -14,9 +14,7 @@ #import "RCTUtils.h" #if RCT_DEV_MENU -#import "RCTSurfaceHostingView+Private.h" #import "RCTDevMenu.h" -#import #endif // RCT_DEV_MENU @interface RCTSurfaceHostingView () @@ -31,7 +29,6 @@ @implementation RCTSurfaceHostingView { UIView *_Nullable _surfaceView; RCTSurfaceStage _stage; BOOL _autoHideDisabled; - facebook::react::ContextContainer::Shared _contextContainer; // [macOS] } RCT_NOT_IMPLEMENTED(-(instancetype)init) @@ -134,16 +131,6 @@ - (void)setSizeMeasureMode:(RCTSurfaceSizeMeasureMode)sizeMeasureMode [self _invalidateLayout]; } -- (facebook::react::ContextContainer::Shared)contextContainer -{ - return _contextContainer; -} - -- (void)setContextContainer:(facebook::react::ContextContainer::Shared)contextContainer -{ - _contextContainer = contextContainer; -} - - (void)disableActivityIndicatorAutoHide:(BOOL)disabled { _autoHideDisabled = disabled; @@ -269,21 +256,15 @@ - (void)surface:(__unused RCTSurface *)surface didChangeIntrinsicSize:(__unused #pragma mark - Dev Menu -#if RCT_DEV_MENU // [macOS] +#if RCT_DEV_MENU - (NSArray *)keyCommands { - if (_contextContainer) { - auto devMenuOptional = _contextContainer->find>("RCTDevMenu"); - if (devMenuOptional.has_value()) { - RCTDevMenu *devMenu = facebook::react::unwrapManagedObject(*devMenuOptional); - if (devMenu) { - return [devMenu keyCommands]; - } - } + if (_devMenu) { + return [_devMenu keyCommands]; } - return @[]; } +#endif // RCT_DEV_MENU - (BOOL)canBecomeFirstResponder { From cb3fcb5e57b88da94b5d3cd5eaa54eac7b6eaf9c Mon Sep 17 00:00:00 2001 From: Saad Najmi Date: Thu, 6 Nov 2025 14:34:58 -0800 Subject: [PATCH 3/5] f --- .../react-native/Libraries/AppDelegate/RCTRootViewFactory.mm | 1 + .../Base/Surface/SurfaceHostingView/RCTSurfaceHostingView.h | 1 + 2 files changed, 2 insertions(+) diff --git a/packages/react-native/Libraries/AppDelegate/RCTRootViewFactory.mm b/packages/react-native/Libraries/AppDelegate/RCTRootViewFactory.mm index a29fe2c9c04f55..be213a7801101b 100644 --- a/packages/react-native/Libraries/AppDelegate/RCTRootViewFactory.mm +++ b/packages/react-native/Libraries/AppDelegate/RCTRootViewFactory.mm @@ -225,6 +225,7 @@ - (UIView *)createRootViewWithBridge:(RCTBridge *)bridge if (devMenu) { [(RCTSurfaceHostingView *)rootView setDevMenu:devMenu]; } + } #endif // RCT_DEV_MENU return rootView; diff --git a/packages/react-native/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingView.h b/packages/react-native/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingView.h index 2b48a3592e39c2..7f43dd54e03786 100644 --- a/packages/react-native/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingView.h +++ b/packages/react-native/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingView.h @@ -14,6 +14,7 @@ @class RCTBridge; @class RCTSurface; +@class RCTDevMenu; typedef UIView *_Nullable (^RCTSurfaceHostingViewActivityIndicatorViewFactory)(void); From b5c4e5be58da9547a3f3e3bf0a9125561739f2db Mon Sep 17 00:00:00 2001 From: Saad Najmi Date: Thu, 6 Nov 2025 14:58:22 -0800 Subject: [PATCH 4/5] remove old hotkeys and get new ones working --- .../Libraries/AppDelegate/RCTAppSetupUtils.mm | 10 --- .../RCTSurfaceHostingView.mm | 31 +++++--- .../React/CoreModules/RCTDevMenu.h | 7 +- .../React/CoreModules/RCTDevMenu.mm | 75 ------------------- .../platform/ios/ReactCommon/RCTInstance.mm | 10 --- 5 files changed, 28 insertions(+), 105 deletions(-) diff --git a/packages/react-native/Libraries/AppDelegate/RCTAppSetupUtils.mm b/packages/react-native/Libraries/AppDelegate/RCTAppSetupUtils.mm index fabfff326b854c..41bd41f44c4b60 100644 --- a/packages/react-native/Libraries/AppDelegate/RCTAppSetupUtils.mm +++ b/packages/react-native/Libraries/AppDelegate/RCTAppSetupUtils.mm @@ -124,16 +124,6 @@ void RCTAppSetupPrepareApp(UIApplication *application, BOOL turboModuleEnabled) // Necessary to allow NativeModules to lookup TurboModules [bridge setRCTTurboModuleRegistry:turboModuleManager]; -#if RCT_DEV - /** - * Instantiating DevMenu has the side-effect of registering - * shortcuts for CMD + d, CMD + i, and CMD + n via RCTDevMenu. - * Therefore, when TurboModules are enabled, we must manually create this - * NativeModule. - */ - [turboModuleManager moduleForName:"RCTDevMenu"]; -#endif // end RCT_DEV - auto runtimeInstallerLambda = [turboModuleManager, bridge, runtimeScheduler](facebook::jsi::Runtime &runtime) { if (!bridge || !turboModuleManager) { return; diff --git a/packages/react-native/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingView.mm b/packages/react-native/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingView.mm index c624679377cc87..5af1b5575499db 100644 --- a/packages/react-native/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingView.mm +++ b/packages/react-native/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingView.mm @@ -257,19 +257,32 @@ - (void)surface:(__unused RCTSurface *)surface didChangeIntrinsicSize:(__unused #pragma mark - Dev Menu #if RCT_DEV_MENU -- (NSArray *)keyCommands +- (BOOL)canBecomeFirstResponder { - if (_devMenu) { - return [_devMenu keyCommands]; - } - return @[]; + return YES; } -#endif // RCT_DEV_MENU -- (BOOL)canBecomeFirstResponder +- (NSArray *)keyCommands { - return YES; +// return [_devMenu keyCommands] ?: @[]; + + return @[ + [UIKeyCommand keyCommandWithInput:@"d" + modifierFlags:UIKeyModifierCommand + action:@selector(toggle)], + [UIKeyCommand keyCommandWithInput:@"i" + modifierFlags:UIKeyModifierCommand + action:@selector(toggleElementInspector)], + ]; +} + +- (void)toggle { + [_devMenu toggle]; } -#endif // macOS] + +- (void)toggleElementInspector { + [_devMenu toggleElementInspector]; +} +#endif // RCT_DEV_MENU @end diff --git a/packages/react-native/React/CoreModules/RCTDevMenu.h b/packages/react-native/React/CoreModules/RCTDevMenu.h index 9e6faadcd398ae..acdf490782800e 100644 --- a/packages/react-native/React/CoreModules/RCTDevMenu.h +++ b/packages/react-native/React/CoreModules/RCTDevMenu.h @@ -57,7 +57,7 @@ RCT_EXTERN NSString *const RCTShowDevMenuNotification; /** * Whether the hotkeys that toggles the developer menu is enabled. */ -@property (nonatomic, assign) BOOL hotkeysEnabled; +@property (nonatomic, assign) BOOL hotkeysEnabled DEPRECATED_ATTRIBUTE; /** * Whether the developer menu is enabled. @@ -84,6 +84,11 @@ RCT_EXTERN NSString *const RCTShowDevMenuNotification; */ - (void)show; +/** + * Manually toggle the dev menu + */ +- (void)toggle; + /** * Deprecated, use `RCTReloadCommand` instead. */ diff --git a/packages/react-native/React/CoreModules/RCTDevMenu.mm b/packages/react-native/React/CoreModules/RCTDevMenu.mm index 2afc3663863200..26816c3e60cc32 100644 --- a/packages/react-native/React/CoreModules/RCTDevMenu.mm +++ b/packages/react-native/React/CoreModules/RCTDevMenu.mm @@ -150,56 +150,10 @@ - (instancetype)init _keyboardShortcutsEnabled = true; _devMenuEnabled = true; - [self registerHotkeys]; } return self; } -- (void)registerHotkeys -{ -#if TARGET_OS_SIMULATOR || TARGET_OS_MACCATALYST - RCTKeyCommands *commands = [RCTKeyCommands sharedInstance]; - __weak __typeof(self) weakSelf = self; - - // Toggle debug menu - [commands registerKeyCommandWithInput:@"d" - modifierFlags:UIKeyModifierCommand - action:^(__unused UIKeyCommand *command) { - [weakSelf toggle]; - }]; - - // Toggle element inspector - [commands registerKeyCommandWithInput:@"i" - modifierFlags:UIKeyModifierCommand - action:^(__unused UIKeyCommand *command) { - [(RCTDevSettings *)[weakSelf.moduleRegistry moduleForName:"DevSettings"] - toggleElementInspector]; - }]; -#endif -} - -- (void)unregisterHotkeys -{ -#if TARGET_OS_SIMULATOR || TARGET_OS_MACCATALYST - RCTKeyCommands *commands = [RCTKeyCommands sharedInstance]; - - [commands unregisterKeyCommandWithInput:@"d" modifierFlags:UIKeyModifierCommand]; - [commands unregisterKeyCommandWithInput:@"i" modifierFlags:UIKeyModifierCommand]; -#endif -} - -- (BOOL)isHotkeysRegistered -{ -#if TARGET_OS_SIMULATOR || TARGET_OS_MACCATALYST - RCTKeyCommands *commands = [RCTKeyCommands sharedInstance]; - - return [commands isKeyCommandRegisteredForInput:@"d" modifierFlags:UIKeyModifierCommand] && - [commands isKeyCommandRegisteredForInput:@"i" modifierFlags:UIKeyModifierCommand]; -#else - return NO; -#endif -} - - (BOOL)isReloadCommandRegistered { #if TARGET_OS_SIMULATOR || TARGET_OS_MACCATALYST @@ -523,20 +477,6 @@ - (BOOL)hotLoadingEnabled return ((RCTDevSettings *)[_moduleRegistry moduleForName:"DevSettings"]).isHotLoadingEnabled; } -- (void)setHotkeysEnabled:(BOOL)enabled -{ - if (enabled) { - [self registerHotkeys]; - } else { - [self unregisterHotkeys]; - } -} - -- (BOOL)hotkeysEnabled -{ - return [self isHotkeysRegistered]; -} - - (void)disableReloadCommand { if ([self isReloadCommandRegistered]) { @@ -544,21 +484,6 @@ - (void)disableReloadCommand } } -- (NSArray *)keyCommands -{ - return @[ - [UIKeyCommand keyCommandWithInput:@"d" - modifierFlags:UIKeyModifierCommand - action:@selector(toggle)], - [UIKeyCommand keyCommandWithInput:@"i" - modifierFlags:UIKeyModifierCommand - action:@selector(toggleElementInspector)], - [UIKeyCommand keyCommandWithInput:@"r" - modifierFlags:UIKeyModifierCommand - action:@selector(reloadFromKeyCommand)] - ]; -} - - (void)toggleElementInspector { RCTDevSettings *devSettings = [_moduleRegistry moduleForName:"DevSettings"]; diff --git a/packages/react-native/ReactCommon/react/runtime/platform/ios/ReactCommon/RCTInstance.mm b/packages/react-native/ReactCommon/react/runtime/platform/ios/ReactCommon/RCTInstance.mm index d065b1b7943d0a..32c627ffbb5124 100644 --- a/packages/react-native/ReactCommon/react/runtime/platform/ios/ReactCommon/RCTInstance.mm +++ b/packages/react-native/ReactCommon/react/runtime/platform/ios/ReactCommon/RCTInstance.mm @@ -358,16 +358,6 @@ - (void)_start jsInvoker:jsCallInvoker devMenuConfigurationDecorator:_devMenuConfigurationDecorator]; -#if RCT_DEV - /** - * Instantiating DevMenu has the side-effect of registering - * shortcuts for CMD + d, CMD + i, and CMD + n via RCTDevMenu. - * Therefore, when TurboModules are enabled, we must manually create this - * NativeModule. - */ - [_turboModuleManager moduleForName:"RCTDevMenu"]; -#endif // end RCT_DEV - // Initialize RCTModuleRegistry so that TurboModules can require other TurboModules. [_bridgeModuleDecorator.moduleRegistry setTurboModuleRegistry:_turboModuleManager]; From 359815b02e63b943b1dd6f9b85cfe852bf768e07 Mon Sep 17 00:00:00 2001 From: Saad Najmi Date: Thu, 6 Nov 2025 15:10:12 -0800 Subject: [PATCH 5/5] f --- .../Base/Surface/SurfaceHostingView/RCTSurfaceHostingView.mm | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/react-native/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingView.mm b/packages/react-native/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingView.mm index 5af1b5575499db..246efba1a22e7b 100644 --- a/packages/react-native/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingView.mm +++ b/packages/react-native/React/Base/Surface/SurfaceHostingView/RCTSurfaceHostingView.mm @@ -264,8 +264,6 @@ - (BOOL)canBecomeFirstResponder - (NSArray *)keyCommands { -// return [_devMenu keyCommands] ?: @[]; - return @[ [UIKeyCommand keyCommandWithInput:@"d" modifierFlags:UIKeyModifierCommand