Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,21 @@
#import <React/RCTComponentViewProtocol.h>
#import <React/RCTFabricSurface.h>
#import <React/RCTSurfaceHostingProxyRootView.h>
#import <React/RCTSurfaceHostingView+Private.h> // [macOS]
#import <React/RCTSurfacePresenter.h>

#if TARGET_OS_OSX && __has_include("RCTDevMenu.h") // [macOS]
#import "RCTDevMenu.h"
#endif // [macOS]
#import <ReactCommon/RCTHost+Internal.h>
#import <ReactCommon/RCTHost.h>
#import <ReactCommon/RCTTurboModuleManager.h>
#import <react/renderer/runtimescheduler/RuntimeScheduler.h>
#import <react/renderer/runtimescheduler/RuntimeSchedulerCallInvoker.h>
#import <react/runtime/JSRuntimeFactory.h>
#import <react/utils/ManagedObjectWrapper.h>

using namespace facebook::react;

@implementation RCTRootViewFactoryConfiguration

Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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;
}

Expand All @@ -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);
Expand Down
Original file line number Diff line number Diff line change
@@ -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 <react/utils/ContextContainer.h>
#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
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#import <React/RCTSurfaceProtocol.h>
#import <React/RCTSurfaceSizeMeasureMode.h>
#import <React/RCTSurfaceStage.h>
// #import <react/utils/ContextContainer.h> // [macOS]

@class RCTBridge;
@class RCTSurface;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,22 @@
*/

#import "RCTSurfaceHostingView.h"
#import "RCTSurfaceHostingView+Private.h" // [macOS]
#import "RCTConstants.h"
#import "RCTDefines.h"
#import "RCTSurface.h"
#import "RCTSurfaceDelegate.h"
#import "RCTSurfaceView.h"
#import "RCTUtils.h"

#if TARGET_OS_OSX && __has_include("RCTDevMenu.h") // [macOS]
#import "RCTDevMenu.h"
#import "RCTBridgeProxy.h"
#import <react/utils/ManagedObjectWrapper.h>

using namespace facebook::react;
#endif // [macOS]

@interface RCTSurfaceHostingView ()

@property (nonatomic, assign) BOOL isActivityIndicatorViewVisible;
Expand All @@ -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)
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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<std::shared_ptr<void>>("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
Loading