diff --git a/Libraries/FBReactNativeSpec/FBReactNativeSpec/FBReactNativeSpec-generated.mm b/Libraries/FBReactNativeSpec/FBReactNativeSpec/FBReactNativeSpec-generated.mm index 087773c2434..bce1dea35f5 100644 --- a/Libraries/FBReactNativeSpec/FBReactNativeSpec/FBReactNativeSpec-generated.mm +++ b/Libraries/FBReactNativeSpec/FBReactNativeSpec/FBReactNativeSpec-generated.mm @@ -1671,6 +1671,33 @@ namespace facebook { + } + + } // namespace react +} // namespace facebook +namespace facebook { + namespace react { + + + static facebook::jsi::Value __hostFunction_NativeLogBoxSpecJSI_show(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + return static_cast(turboModule).invokeObjCMethod(rt, VoidKind, "show", @selector(show), args, count); + } + + static facebook::jsi::Value __hostFunction_NativeLogBoxSpecJSI_hide(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + return static_cast(turboModule).invokeObjCMethod(rt, VoidKind, "hide", @selector(hide), args, count); + } + + + NativeLogBoxSpecJSI::NativeLogBoxSpecJSI(id instance, std::shared_ptr jsInvoker) + : ObjCTurboModule("LogBox", instance, jsInvoker) { + + methodMap_["show"] = MethodMetadata {0, __hostFunction_NativeLogBoxSpecJSI_show}; + + + methodMap_["hide"] = MethodMetadata {0, __hostFunction_NativeLogBoxSpecJSI_hide}; + + + } } // namespace react diff --git a/Libraries/FBReactNativeSpec/FBReactNativeSpec/FBReactNativeSpec.h b/Libraries/FBReactNativeSpec/FBReactNativeSpec/FBReactNativeSpec.h index 0d39cefcab4..bb1c8d2d99a 100644 --- a/Libraries/FBReactNativeSpec/FBReactNativeSpec/FBReactNativeSpec.h +++ b/Libraries/FBReactNativeSpec/FBReactNativeSpec/FBReactNativeSpec.h @@ -1771,6 +1771,25 @@ namespace facebook { }; } // namespace react } // namespace facebook +@protocol NativeLogBoxSpec + +- (void)show; +- (void)hide; + +@end +namespace facebook { + namespace react { + /** + * ObjC++ class for module 'LogBox' + */ + + class JSI_EXPORT NativeLogBoxSpecJSI : public ObjCTurboModule { + public: + NativeLogBoxSpecJSI(id instance, std::shared_ptr jsInvoker); + + }; + } // namespace react +} // namespace facebook @protocol NativeModalManagerSpec - (void)addListener:(NSString *)eventName; diff --git a/Libraries/NativeModules/specs/NativeLogBox.js b/Libraries/NativeModules/specs/NativeLogBox.js new file mode 100644 index 00000000000..6d89481c390 --- /dev/null +++ b/Libraries/NativeModules/specs/NativeLogBox.js @@ -0,0 +1,21 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow + * @format + */ + +'use strict'; + +import type {TurboModule} from 'react-native/Libraries/TurboModule/RCTExport'; +import * as TurboModuleRegistry from 'react-native/Libraries/TurboModule/TurboModuleRegistry'; + +export interface Spec extends TurboModule { + +show: () => void; + +hide: () => void; +} + +export default (TurboModuleRegistry.get('LogBox'): ?Spec); diff --git a/React/CoreModules/BUCK b/React/CoreModules/BUCK index 21bd66f4258..f42fcca46f2 100644 --- a/React/CoreModules/BUCK +++ b/React/CoreModules/BUCK @@ -96,6 +96,9 @@ rn_apple_library( ) + react_module_plugin_providers( name = "RedBox", native_class_func = "RCTRedBoxCls", + ) + react_module_plugin_providers( + name = "LogBox", + native_class_func = "RCTLogBoxCls", ) + react_module_plugin_providers( name = "TVNavigationEventEmitter", native_class_func = "RCTTVNavigationEventEmitterCls", diff --git a/React/CoreModules/CoreModulesPlugins.h b/React/CoreModules/CoreModulesPlugins.h index 660c86a281d..b158cb2aa32 100644 --- a/React/CoreModules/CoreModulesPlugins.h +++ b/React/CoreModules/CoreModulesPlugins.h @@ -48,6 +48,7 @@ Class RCTPerfMonitorCls(void) __attribute__((used)); Class RCTDevMenuCls(void) __attribute__((used)); Class RCTDevSettingsCls(void) __attribute__((used)); Class RCTRedBoxCls(void) __attribute__((used)); +Class RCTLogBoxCls(void) __attribute__((used)); Class RCTTVNavigationEventEmitterCls(void) __attribute__((used)); Class RCTWebSocketExecutorCls(void) __attribute__((used)); Class RCTWebSocketModuleCls(void) __attribute__((used)); diff --git a/React/CoreModules/CoreModulesPlugins.mm b/React/CoreModules/CoreModulesPlugins.mm index d1a69375116..dfd937c5389 100644 --- a/React/CoreModules/CoreModulesPlugins.mm +++ b/React/CoreModules/CoreModulesPlugins.mm @@ -37,6 +37,7 @@ Class RCTCoreModulesClassProvider(const char *name) { {"DevMenu", RCTDevMenuCls}, {"DevSettings", RCTDevSettingsCls}, {"RedBox", RCTRedBoxCls}, + {"LogBox", RCTLogBoxCls}, {"TVNavigationEventEmitter", RCTTVNavigationEventEmitterCls}, {"WebSocketExecutor", RCTWebSocketExecutorCls}, {"WebSocketModule", RCTWebSocketModuleCls}, diff --git a/React/CoreModules/RCTLogBox.h b/React/CoreModules/RCTLogBox.h new file mode 100644 index 00000000000..ec2a4861e31 --- /dev/null +++ b/React/CoreModules/RCTLogBox.h @@ -0,0 +1,21 @@ +/* + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import + +#import +#import +#import + +@class RCTJSStackFrame; + +@interface RCTLogBox : NSObject + +- (void)show; +- (void)hide; + +@end diff --git a/React/CoreModules/RCTLogBox.mm b/React/CoreModules/RCTLogBox.mm new file mode 100644 index 00000000000..cda46ca31f7 --- /dev/null +++ b/React/CoreModules/RCTLogBox.mm @@ -0,0 +1,162 @@ +/* + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import "RCTLogBox.h" + +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import + +#import + +#import "CoreModulesPlugins.h" + +#if RCT_DEV_MENU + +@class RCTLogBoxWindow; + +@protocol RCTLogBoxWindowActionDelegate + +- (void)logBoxWindow:(RCTLogBoxWindow *)logBoxWindow openStackFrameInEditor:(RCTJSStackFrame *)stackFrame; +- (void)reloadFromlogBoxWindow:(RCTLogBoxWindow *)logBoxWindow; +- (void)loadExtraDataViewController; + +@end + +@interface RCTLogBoxWindow : UIWindow +@property (nonatomic, weak) id actionDelegate; +@end + +@implementation RCTLogBoxWindow +{ + UITableView *_stackTraceTableView; + NSString *_lastErrorMessage; + NSArray *_lastStackTrace; + int _lastErrorCookie; +} + +- (instancetype)initWithFrame:(CGRect)frame bridge:(RCTBridge *)bridge +{ + _lastErrorCookie = -1; + if ((self = [super initWithFrame:frame])) { +#if TARGET_OS_TV + self.windowLevel = UIWindowLevelAlert + 1000; +#else + self.windowLevel = UIWindowLevelStatusBar - 1; +#endif + self.backgroundColor = [UIColor clearColor]; + self.hidden = YES; + + RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge moduleName:@"LogBox" initialProperties:nil]; + + UIViewController *rootViewController = [UIViewController new]; + rootViewController.view = rootView; + self.rootViewController = rootViewController; + } + return self; +} + + +- (void)show +{ + [self becomeFirstResponder]; + [self makeKeyAndVisible]; +} + +- (void)dismiss +{ + self.hidden = YES; + [self resignFirstResponder]; + [RCTSharedApplication().delegate.window makeKeyWindow]; +} + +@end + +@interface RCTLogBox () +@end + +@implementation RCTLogBox +{ + RCTLogBoxWindow *_window; +} + +@synthesize bridge = _bridge; + +RCT_EXPORT_MODULE() + ++ (BOOL)requiresMainQueueSetup +{ + return YES; +} + +- (void)setBridge:(RCTBridge *)bridge +{ + _bridge = bridge; + dispatch_async(dispatch_get_main_queue(), ^{ + self->_window = [[RCTLogBoxWindow alloc] initWithFrame:[UIScreen mainScreen].bounds bridge: self->_bridge]; + }); +} + +RCT_EXPORT_METHOD(show) +{ + dispatch_async(dispatch_get_main_queue(), ^{ + [self->_window show]; + }); +} + +RCT_EXPORT_METHOD(hide) +{ + dispatch_async(dispatch_get_main_queue(), ^{ + [self->_window dismiss]; + }); +} + +- (std::shared_ptr)getTurboModuleWithJsInvoker:(std::shared_ptr)jsInvoker +{ + return std::make_shared(self, jsInvoker); +} + +@end + +#else // Disabled + +@interface RCTLogBox() +@end + +@implementation RCTLogBox + ++ (NSString *)moduleName +{ + return nil; +} + +- (void)show { + // noop +} + +- (void)hide { + // noop +} + +- (std::shared_ptr)getTurboModuleWithJsInvoker:(std::shared_ptr)jsInvoker +{ + return std::make_shared(self, jsInvoker); +} +@end + +#endif + +Class RCTLogBoxCls(void) { + return RCTLogBox.class; +} diff --git a/ReactAndroid/src/main/java/com/facebook/fbreact/specs/NativeLogBoxSpec.java b/ReactAndroid/src/main/java/com/facebook/fbreact/specs/NativeLogBoxSpec.java new file mode 100644 index 00000000000..085f0559be5 --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/fbreact/specs/NativeLogBoxSpec.java @@ -0,0 +1,31 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + *

This source code is licensed under the MIT license found in the LICENSE file in the root + * directory of this source tree. + * + *

Generated by an internal genrule from Flow types. + * + * @generated + * @nolint + */ + +package com.facebook.fbreact.specs; + +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.bridge.ReactContextBaseJavaModule; +import com.facebook.react.bridge.ReactMethod; +import com.facebook.react.bridge.ReactModuleWithSpec; +import com.facebook.react.turbomodule.core.interfaces.TurboModule; + +public abstract class NativeLogBoxSpec extends ReactContextBaseJavaModule implements ReactModuleWithSpec, TurboModule { + public NativeLogBoxSpec(ReactApplicationContext reactContext) { + super(reactContext); + } + + @ReactMethod + public abstract void hide(); + + @ReactMethod + public abstract void show(); +}