diff --git a/packages/react-native/Libraries/Components/TraceUpdateOverlay/TraceUpdateOverlay.js b/packages/react-native/Libraries/Components/TraceUpdateOverlay/TraceUpdateOverlay.js index 57c70fd5f28c75..97a4426e11fd42 100644 --- a/packages/react-native/Libraries/Components/TraceUpdateOverlay/TraceUpdateOverlay.js +++ b/packages/react-native/Libraries/Components/TraceUpdateOverlay/TraceUpdateOverlay.js @@ -17,7 +17,6 @@ import type {Overlay} from './TraceUpdateOverlayNativeComponent'; import UIManager from '../../ReactNative/UIManager'; import processColor from '../../StyleSheet/processColor'; import StyleSheet from '../../StyleSheet/StyleSheet'; -import Platform from '../../Utilities/Platform'; import View from '../View/View'; import TraceUpdateOverlayNativeComponent, { Commands, @@ -26,7 +25,6 @@ import * as React from 'react'; const {useEffect, useRef, useState} = React; const isNativeComponentReady = - Platform.OS === 'android' && UIManager.hasViewManagerConfig('TraceUpdateOverlay'); type Props = { @@ -39,13 +37,13 @@ export default function TraceUpdateOverlay({ const [overlayDisabled, setOverlayDisabled] = useState(false); useEffect(() => { - if (!isNativeComponentReady) { - return; - } - const drawTraceUpdates = ( nodesToDraw: Array<{node: InstanceFromReactDevTools, color: string}> = [], ) => { + if (!isNativeComponentReady) { + return; + } + // If overlay is disabled before, now it's enabled. setOverlayDisabled(false); diff --git a/packages/react-native/React/Fabric/Mounting/ComponentViews/RCTFabricComponentsPlugins.h b/packages/react-native/React/Fabric/Mounting/ComponentViews/RCTFabricComponentsPlugins.h index ca5f395c3141a8..51912e25dcd143 100644 --- a/packages/react-native/React/Fabric/Mounting/ComponentViews/RCTFabricComponentsPlugins.h +++ b/packages/react-native/React/Fabric/Mounting/ComponentViews/RCTFabricComponentsPlugins.h @@ -38,6 +38,7 @@ Class RCTSafeAreaViewCls(void) __attribute__((used)); Class RCTScrollViewCls(void) __attribute__((used)); Class RCTSwitchCls(void) __attribute__((used)); Class RCTTextInputCls(void) __attribute__((used)); +Class RCTTraceUpdateOverlayCls(void) __attribute__((used)); Class RCTUnimplementedNativeViewCls(void) __attribute__((used)); Class RCTViewCls(void) __attribute__((used)); Class RCTImageCls(void) __attribute__((used)); diff --git a/packages/react-native/React/Fabric/Mounting/ComponentViews/RCTFabricComponentsPlugins.mm b/packages/react-native/React/Fabric/Mounting/ComponentViews/RCTFabricComponentsPlugins.mm index 02d1dc1a125af7..dff4412f48ab38 100644 --- a/packages/react-native/React/Fabric/Mounting/ComponentViews/RCTFabricComponentsPlugins.mm +++ b/packages/react-native/React/Fabric/Mounting/ComponentViews/RCTFabricComponentsPlugins.mm @@ -26,6 +26,7 @@ {"ScrollView", RCTScrollViewCls}, {"Switch", RCTSwitchCls}, {"TextInput", RCTTextInputCls}, + {"TraceUpdateOverlay", RCTTraceUpdateOverlayCls}, {"UnimplementedNativeView", RCTUnimplementedNativeViewCls}, {"View", RCTViewCls}, {"Image", RCTImageCls}, diff --git a/packages/react-native/React/Fabric/Mounting/ComponentViews/TraceUpdateOverlay/RCTTraceUpdateOverlayComponentView.h b/packages/react-native/React/Fabric/Mounting/ComponentViews/TraceUpdateOverlay/RCTTraceUpdateOverlayComponentView.h new file mode 100644 index 00000000000000..d6aa304ef5725b --- /dev/null +++ b/packages/react-native/React/Fabric/Mounting/ComponentViews/TraceUpdateOverlay/RCTTraceUpdateOverlayComponentView.h @@ -0,0 +1,16 @@ +/* + * 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 + +#import + +#import + +@interface RCTTraceUpdateOverlayComponentView : RCTViewComponentView + +@end diff --git a/packages/react-native/React/Fabric/Mounting/ComponentViews/TraceUpdateOverlay/RCTTraceUpdateOverlayComponentView.mm b/packages/react-native/React/Fabric/Mounting/ComponentViews/TraceUpdateOverlay/RCTTraceUpdateOverlayComponentView.mm new file mode 100644 index 00000000000000..6bf68de14e15a8 --- /dev/null +++ b/packages/react-native/React/Fabric/Mounting/ComponentViews/TraceUpdateOverlay/RCTTraceUpdateOverlayComponentView.mm @@ -0,0 +1,65 @@ +/* + * 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 "RCTTraceUpdateOverlayComponentView.h" + +#import +#import +#import + +#import +#import +#import +#import + +#import "RCTFabricComponentsPlugins.h" + +using namespace facebook::react; + +@implementation RCTTraceUpdateOverlayComponentView { + RCTTraceUpdateOverlay *_overlay; +} + +- (instancetype)initWithFrame:(CGRect)frame +{ + if (self = [super initWithFrame:frame]) { + static const auto defaultProps = std::make_shared(); + _props = defaultProps; + + _overlay = [[RCTTraceUpdateOverlay alloc] initWithFrame:self.bounds]; + + self.contentView = _overlay; + } + + return self; +} + +#pragma mark - RCTComponentViewProtocol + ++ (ComponentDescriptorProvider)componentDescriptorProvider +{ + return concreteComponentDescriptorProvider(); +} + +#pragma mark - Native commands + +- (void)handleCommand:(const NSString *)commandName args:(const NSArray *)args +{ + RCTTraceUpdateOverlayHandleCommand(self, commandName, args); +} + +- (void)draw:(NSString *)overlays +{ + [_overlay draw:overlays]; +} + +@end + +Class RCTTraceUpdateOverlayCls(void) +{ + return RCTTraceUpdateOverlayComponentView.class; +} diff --git a/packages/react-native/React/Views/RCTTraceUpdateOverlay.h b/packages/react-native/React/Views/RCTTraceUpdateOverlay.h new file mode 100644 index 00000000000000..480883044d2e49 --- /dev/null +++ b/packages/react-native/React/Views/RCTTraceUpdateOverlay.h @@ -0,0 +1,16 @@ +/* + * 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 + +#import + +@interface RCTTraceUpdateOverlay : RCTView + +- (void)draw:(NSString *)serializedNodes; + +@end diff --git a/packages/react-native/React/Views/RCTTraceUpdateOverlay.m b/packages/react-native/React/Views/RCTTraceUpdateOverlay.m new file mode 100644 index 00000000000000..198f46b94429b6 --- /dev/null +++ b/packages/react-native/React/Views/RCTTraceUpdateOverlay.m @@ -0,0 +1,57 @@ +/* + * 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 "RCTTraceUpdateOverlay.h" + +#import +#import +#import + +@implementation RCTTraceUpdateOverlay + +- (void)draw:(NSString *)serializedNodes +{ + NSArray *subViewsToRemove = [self subviews]; + for (UIView *v in subViewsToRemove) { + [v removeFromSuperview]; + } + + NSError *error = nil; + id deserializedNodes = RCTJSONParse(serializedNodes, &error); + + if (error) { + RCTLogError(@"Failed to parse serialized nodes passed to RCTTraceUpdatesOverlay"); + return; + } + + if (![deserializedNodes isKindOfClass:[NSArray class]]) { + RCTLogError(@"Expected to receive nodes as an array, got %@", NSStringFromClass([deserializedNodes class])); + return; + } + + for (NSDictionary *node in deserializedNodes) { + NSDictionary *nodeRectangle = node[@"rect"]; + NSNumber *nodeColor = node[@"color"]; + + NSNumber *x = nodeRectangle[@"left"]; + NSNumber *y = nodeRectangle[@"top"]; + NSNumber *width = nodeRectangle[@"width"]; + NSNumber *height = nodeRectangle[@"height"]; + + CGRect rect = CGRectMake(x.doubleValue, y.doubleValue, width.doubleValue, height.doubleValue); + + UIView *box = [[UIView alloc] initWithFrame:rect]; + box.backgroundColor = [UIColor clearColor]; + + box.layer.borderWidth = 2.0f; + box.layer.borderColor = [RCTConvert UIColor:nodeColor].CGColor; + + [self addSubview:box]; + } +} + +@end diff --git a/packages/react-native/React/Views/RCTTraceUpdateOverlayManager.h b/packages/react-native/React/Views/RCTTraceUpdateOverlayManager.h new file mode 100644 index 00000000000000..f50680420dc332 --- /dev/null +++ b/packages/react-native/React/Views/RCTTraceUpdateOverlayManager.h @@ -0,0 +1,12 @@ +/* + * 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 + +@interface RCTTraceUpdateOverlayManager : RCTViewManager + +@end diff --git a/packages/react-native/React/Views/RCTTraceUpdateOverlayManager.m b/packages/react-native/React/Views/RCTTraceUpdateOverlayManager.m new file mode 100644 index 00000000000000..8386b94941d997 --- /dev/null +++ b/packages/react-native/React/Views/RCTTraceUpdateOverlayManager.m @@ -0,0 +1,38 @@ +/* + * 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 "RCTTraceUpdateOverlayManager.h" +#import "RCTTraceUpdateOverlay.h" + +#import +#import + +#import "RCTBridge.h" + +@implementation RCTTraceUpdateOverlayManager + +RCT_EXPORT_MODULE(TraceUpdateOverlay) + +- (UIView *)view +{ + return [RCTTraceUpdateOverlay new]; +} + +RCT_EXPORT_METHOD(draw : (nonnull NSNumber *)viewTag nodes : (NSString *)serializedNodes) +{ + [self.bridge.uiManager addUIBlock:^(RCTUIManager *uiManager, NSDictionary *viewRegistry) { + UIView *view = viewRegistry[viewTag]; + + if ([view isKindOfClass:[RCTTraceUpdateOverlay class]]) { + [(RCTTraceUpdateOverlay *)view draw:serializedNodes]; + } else { + RCTLogError(@"Expected view to be RCTTraceUpdateOverlay, got %@", NSStringFromClass([view class])); + } + }]; +} + +@end