react-native 0.85.2 → 0.85.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (108) hide show
  1. package/Libraries/Core/ReactNativeVersion.js +1 -1
  2. package/Libraries/Utilities/HMRClient.js +28 -1
  3. package/React/Base/RCTVersion.m +1 -1
  4. package/React/CoreModules/RCTJscSafeUrl+Internal.h +23 -0
  5. package/React/CoreModules/RCTJscSafeUrl.mm +38 -0
  6. package/React/CoreModules/RCTRedBox+Internal.h +42 -0
  7. package/React/CoreModules/RCTRedBox.mm +30 -454
  8. package/React/CoreModules/RCTRedBox2AnsiParser+Internal.h +22 -0
  9. package/React/CoreModules/RCTRedBox2AnsiParser.mm +55 -0
  10. package/React/CoreModules/RCTRedBox2Controller+Internal.h +34 -0
  11. package/React/CoreModules/RCTRedBox2Controller.mm +764 -0
  12. package/React/CoreModules/RCTRedBox2ErrorParser+Internal.h +46 -0
  13. package/React/CoreModules/RCTRedBox2ErrorParser.mm +57 -0
  14. package/React/CoreModules/RCTRedBoxController+Internal.h +31 -0
  15. package/React/CoreModules/RCTRedBoxController.mm +447 -0
  16. package/React/CoreModules/RCTRedBoxHMRClient+Internal.h +26 -0
  17. package/React/CoreModules/RCTRedBoxHMRClient.mm +125 -0
  18. package/React/CoreModules/React-CoreModules.podspec +1 -0
  19. package/React/DevSupport/RCTFrameTimingsObserver.h +24 -0
  20. package/React/DevSupport/RCTFrameTimingsObserver.mm +298 -0
  21. package/React/FBReactNativeSpec/FBReactNativeSpecJSI.h +40 -0
  22. package/ReactAndroid/gradle.properties +1 -1
  23. package/ReactAndroid/src/main/java/com/facebook/react/devsupport/InspectorFlags.kt +4 -0
  24. package/ReactAndroid/src/main/java/com/facebook/react/devsupport/inspector/FrameTimingSequence.kt +1 -1
  25. package/ReactAndroid/src/main/java/com/facebook/react/devsupport/inspector/FrameTimingsObserver.kt +127 -26
  26. package/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlags.kt +31 -1
  27. package/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxAccessor.kt +51 -1
  28. package/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxInterop.kt +11 -1
  29. package/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsDefaults.kt +11 -1
  30. package/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsLocalAccessor.kt +56 -1
  31. package/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsProvider.kt +11 -1
  32. package/ReactAndroid/src/main/java/com/facebook/react/internal/tracing/PerformanceTracer.kt +39 -0
  33. package/ReactAndroid/src/main/java/com/facebook/react/modules/systeminfo/ReactNativeVersion.kt +1 -1
  34. package/ReactAndroid/src/main/java/com/facebook/react/runtime/ReactHostImpl.kt +50 -10
  35. package/ReactAndroid/src/main/jni/CMakeLists.txt +7 -0
  36. package/ReactAndroid/src/main/jni/react/devsupport/JInspectorFlags.cpp +22 -0
  37. package/ReactAndroid/src/main/jni/react/devsupport/JInspectorFlags.h +2 -0
  38. package/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.cpp +71 -1
  39. package/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.h +16 -1
  40. package/ReactAndroid/src/main/jni/react/runtime/jni/JReactHostInspectorTarget.cpp +14 -0
  41. package/ReactAndroid/src/main/jni/react/runtime/jni/JReactHostInspectorTarget.h +18 -4
  42. package/ReactCommon/React-Fabric.podspec +6 -0
  43. package/ReactCommon/cxxreact/ReactNativeVersion.h +2 -2
  44. package/ReactCommon/jsinspector-modern/HostAgent.cpp +36 -0
  45. package/ReactCommon/jsinspector-modern/HostTarget.cpp +7 -1
  46. package/ReactCommon/jsinspector-modern/HostTarget.h +25 -0
  47. package/ReactCommon/jsinspector-modern/HostTargetTracing.cpp +1 -1
  48. package/ReactCommon/jsinspector-modern/HostTargetTracing.h +4 -4
  49. package/ReactCommon/jsinspector-modern/InspectorFlags.cpp +12 -0
  50. package/ReactCommon/jsinspector-modern/InspectorFlags.h +12 -0
  51. package/ReactCommon/jsinspector-modern/NetworkIOAgent.cpp +1 -1
  52. package/ReactCommon/jsinspector-modern/RuntimeAgent.cpp +19 -0
  53. package/ReactCommon/jsinspector-modern/RuntimeAgent.h +7 -0
  54. package/ReactCommon/jsinspector-modern/RuntimeTarget.cpp +33 -0
  55. package/ReactCommon/jsinspector-modern/RuntimeTarget.h +6 -0
  56. package/ReactCommon/jsinspector-modern/tests/HostTargetTest.cpp +12 -0
  57. package/ReactCommon/jsinspector-modern/tests/InspectorMocks.h +3 -2
  58. package/ReactCommon/jsinspector-modern/tests/JsiIntegrationTest.cpp +1 -0
  59. package/ReactCommon/jsinspector-modern/tests/NetworkReporterTest.cpp +1 -1
  60. package/ReactCommon/jsinspector-modern/tests/TracingTest.cpp +1 -1
  61. package/ReactCommon/jsinspector-modern/tests/utils/InspectorFlagOverridesGuard.cpp +10 -0
  62. package/ReactCommon/jsinspector-modern/tests/utils/InspectorFlagOverridesGuard.h +3 -1
  63. package/ReactCommon/jsinspector-modern/tracing/CMakeLists.txt +1 -0
  64. package/ReactCommon/jsinspector-modern/tracing/FrameTimingSequence.h +7 -3
  65. package/ReactCommon/jsinspector-modern/tracing/HostTracingProfileSerializer.cpp +52 -29
  66. package/ReactCommon/jsinspector-modern/tracing/HostTracingProfileSerializer.h +6 -6
  67. package/ReactCommon/jsinspector-modern/tracing/PerformanceTracerSection.h +113 -0
  68. package/ReactCommon/jsinspector-modern/tracing/React-jsinspectortracing.podspec +1 -0
  69. package/ReactCommon/jsinspector-modern/tracing/TraceEventGenerator.cpp +12 -5
  70. package/ReactCommon/jsinspector-modern/tracing/TraceEventGenerator.h +3 -1
  71. package/ReactCommon/jsinspector-modern/tracing/TraceEventSerializer.cpp +42 -0
  72. package/ReactCommon/jsinspector-modern/tracing/TraceEventSerializer.h +7 -0
  73. package/ReactCommon/react/debug/CMakeLists.txt +2 -1
  74. package/ReactCommon/react/debug/React-debug.podspec +7 -1
  75. package/ReactCommon/react/debug/redbox/AnsiParser.cpp +139 -0
  76. package/ReactCommon/react/debug/redbox/AnsiParser.h +35 -0
  77. package/ReactCommon/react/debug/redbox/JscSafeUrl.cpp +179 -0
  78. package/ReactCommon/react/debug/redbox/JscSafeUrl.h +27 -0
  79. package/ReactCommon/react/debug/redbox/RedBoxErrorParser.cpp +171 -0
  80. package/ReactCommon/react/debug/redbox/RedBoxErrorParser.h +40 -0
  81. package/ReactCommon/react/debug/redbox/tests/AnsiParserTest.cpp +97 -0
  82. package/ReactCommon/react/debug/redbox/tests/JscSafeUrlTest.cpp +173 -0
  83. package/ReactCommon/react/debug/redbox/tests/RedBoxErrorParserTest.cpp +107 -0
  84. package/ReactCommon/react/featureflags/ReactNativeFeatureFlags.cpp +21 -1
  85. package/ReactCommon/react/featureflags/ReactNativeFeatureFlags.h +26 -1
  86. package/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.cpp +135 -45
  87. package/ReactCommon/react/featureflags/ReactNativeFeatureFlagsAccessor.h +12 -2
  88. package/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h +21 -1
  89. package/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDynamicProvider.h +46 -1
  90. package/ReactCommon/react/featureflags/ReactNativeFeatureFlagsProvider.h +6 -1
  91. package/ReactCommon/react/nativemodule/defaults/CMakeLists.txt +1 -0
  92. package/ReactCommon/react/nativemodule/defaults/DefaultTurboModules.cpp +7 -0
  93. package/ReactCommon/react/nativemodule/defaults/React-defaultsnativemodule.podspec +1 -0
  94. package/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.cpp +26 -1
  95. package/ReactCommon/react/nativemodule/featureflags/NativeReactNativeFeatureFlags.h +11 -1
  96. package/ReactCommon/react/nativemodule/mutationobserver/NativeMutationObserver.h +4 -0
  97. package/ReactCommon/react/nativemodule/mutationobserver/React-mutationobservernativemodule.podspec +66 -0
  98. package/ReactCommon/react/performance/timeline/PerformanceObserver.cpp +18 -6
  99. package/ReactCommon/react/performance/timeline/PerformanceObserver.h +2 -0
  100. package/ReactCommon/react/runtime/platform/ios/ReactCommon/RCTHost.mm +115 -0
  101. package/ReactCommon/{jsinspector-modern → react/utils}/Base64.h +2 -2
  102. package/package.json +11 -11
  103. package/scripts/cocoapods/utils.rb +1 -0
  104. package/scripts/react_native_pods.rb +1 -0
  105. package/scripts/replace-rncore-version.js +72 -15
  106. package/src/private/featureflags/ReactNativeFeatureFlags.js +26 -1
  107. package/src/private/featureflags/specs/NativeReactNativeFeatureFlags.js +6 -1
  108. package/src/private/setup/setUpDefaultReactNativeEnvironment.js +6 -0
@@ -0,0 +1,46 @@
1
+ /*
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+
8
+ #import <Foundation/Foundation.h>
9
+
10
+ /**
11
+ * Structured error data extracted from a raw error message.
12
+ * Mirrors LogBoxLog.js / parseLogBoxLog.js data model.
13
+ */
14
+ @interface RCTRedBox2ErrorData : NSObject
15
+
16
+ /// Display title, e.g. "Syntax Error", "Render Error", "Uncaught Error"
17
+ @property (nonatomic, copy) NSString *title;
18
+ /// The error message body (code frame stripped out)
19
+ @property (nonatomic, copy) NSString *message;
20
+ /// Raw code frame text with ANSI escape codes preserved (nil if not a syntax/transform error)
21
+ @property (nonatomic, copy, nullable) NSString *codeFrame;
22
+ /// Source file path for the code frame
23
+ @property (nonatomic, copy, nullable) NSString *codeFrameFileName;
24
+ /// Line number in the source file
25
+ @property (nonatomic, assign) NSInteger codeFrameRow;
26
+ /// Column number in the source file
27
+ @property (nonatomic, assign) NSInteger codeFrameColumn;
28
+ /// Whether this is a compile-time error (syntax, transform, resolution) vs a runtime error
29
+ @property (nonatomic, assign) BOOL isCompileError;
30
+ /// Whether auto-retry is appropriate (compile errors, connectivity failures, etc.)
31
+ @property (nonatomic, assign) BOOL isRetryable;
32
+
33
+ @end
34
+
35
+ /**
36
+ * Parses raw error messages into structured RCTRedBox2ErrorData.
37
+ * ObjC port of parseLogBoxLog.js / parseLogBoxException.
38
+ */
39
+ @interface RCTRedBox2ErrorParser : NSObject
40
+
41
+ + (RCTRedBox2ErrorData *)parseErrorMessage:(NSString *)message
42
+ name:(nullable NSString *)name
43
+ componentStack:(nullable NSString *)componentStack
44
+ isFatal:(BOOL)isFatal;
45
+
46
+ @end
@@ -0,0 +1,57 @@
1
+ /*
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+
8
+ #import "RCTRedBox2ErrorParser+Internal.h"
9
+
10
+ #import <React/RCTDefines.h>
11
+ #import <react/debug/redbox/RedBoxErrorParser.h>
12
+
13
+ #if RCT_DEV_MENU
14
+
15
+ using facebook::react::unstable_redbox::ParsedError;
16
+ using facebook::react::unstable_redbox::parseErrorMessage;
17
+
18
+ static RCTRedBox2ErrorData *RCTRedBox2ErrorDataFromParsedError(const ParsedError &parsed)
19
+ {
20
+ RCTRedBox2ErrorData *data = [[RCTRedBox2ErrorData alloc] init];
21
+ data.title = [NSString stringWithUTF8String:parsed.title.c_str()];
22
+ data.message = [NSString stringWithUTF8String:parsed.message.c_str()];
23
+ data.isCompileError = parsed.isCompileError;
24
+ data.isRetryable = parsed.isRetryable;
25
+
26
+ if (parsed.codeFrame.has_value()) {
27
+ const auto &cf = *parsed.codeFrame;
28
+ data.codeFrame = [NSString stringWithUTF8String:cf.content.c_str()];
29
+ data.codeFrameFileName = [NSString stringWithUTF8String:cf.fileName.c_str()];
30
+ data.codeFrameRow = cf.row;
31
+ data.codeFrameColumn = cf.column;
32
+ }
33
+
34
+ return data;
35
+ }
36
+
37
+ @implementation RCTRedBox2ErrorData
38
+ @end
39
+
40
+ @implementation RCTRedBox2ErrorParser
41
+
42
+ + (RCTRedBox2ErrorData *)parseErrorMessage:(NSString *)message
43
+ name:(nullable NSString *)name
44
+ componentStack:(nullable NSString *)componentStack
45
+ isFatal:(BOOL)isFatal
46
+ {
47
+ auto parsed = parseErrorMessage(
48
+ (message != nullptr) ? std::string(message.UTF8String) : std::string(),
49
+ (name != nullptr) ? std::string(name.UTF8String) : std::string(),
50
+ (componentStack != nullptr) ? std::string(componentStack.UTF8String) : std::string(),
51
+ isFatal);
52
+ return RCTRedBox2ErrorDataFromParsedError(parsed);
53
+ }
54
+
55
+ @end
56
+
57
+ #endif
@@ -0,0 +1,31 @@
1
+ /*
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+
8
+ #import <React/RCTDefines.h>
9
+
10
+ #import "RCTRedBox+Internal.h"
11
+ #import "RCTRedBox.h"
12
+
13
+ #if RCT_DEV_MENU
14
+
15
+ @interface RCTRedBoxController : UIViewController <RCTRedBoxControlling, UITableViewDelegate, UITableViewDataSource>
16
+
17
+ @property (nonatomic, weak) id<RCTRedBoxControllerActionDelegate> actionDelegate;
18
+
19
+ - (instancetype)initWithCustomButtonTitles:(NSArray<NSString *> *)customButtonTitles
20
+ customButtonHandlers:(NSArray<RCTRedBoxButtonPressHandler> *)customButtonHandlers;
21
+
22
+ - (void)showErrorMessage:(NSString *)message
23
+ withStack:(NSArray<RCTJSStackFrame *> *)stack
24
+ isUpdate:(BOOL)isUpdate
25
+ errorCookie:(int)errorCookie;
26
+
27
+ - (void)dismiss;
28
+
29
+ @end
30
+
31
+ #endif
@@ -0,0 +1,447 @@
1
+ /*
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+
8
+ #import "RCTRedBoxController+Internal.h"
9
+
10
+ #import <React/RCTDefines.h>
11
+ #import <React/RCTJSStackFrame.h>
12
+ #import <React/RCTReloadCommand.h>
13
+ #import <React/RCTUtils.h>
14
+
15
+ #import <objc/runtime.h>
16
+
17
+ #if RCT_DEV_MENU
18
+
19
+ @interface UIButton (RCTRedBox)
20
+
21
+ @property (nonatomic) RCTRedBoxButtonPressHandler rct_handler;
22
+
23
+ - (void)rct_addBlock:(RCTRedBoxButtonPressHandler)handler forControlEvents:(UIControlEvents)controlEvents;
24
+
25
+ @end
26
+
27
+ @implementation UIButton (RCTRedBox)
28
+
29
+ - (RCTRedBoxButtonPressHandler)rct_handler
30
+ {
31
+ return objc_getAssociatedObject(self, @selector(rct_handler));
32
+ }
33
+
34
+ - (void)setRct_handler:(RCTRedBoxButtonPressHandler)rct_handler
35
+ {
36
+ objc_setAssociatedObject(self, @selector(rct_handler), rct_handler, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
37
+ }
38
+
39
+ - (void)rct_callBlock
40
+ {
41
+ if (self.rct_handler) {
42
+ self.rct_handler();
43
+ }
44
+ }
45
+
46
+ - (void)rct_addBlock:(RCTRedBoxButtonPressHandler)handler forControlEvents:(UIControlEvents)controlEvents
47
+ {
48
+ self.rct_handler = handler;
49
+ [self addTarget:self action:@selector(rct_callBlock) forControlEvents:controlEvents];
50
+ }
51
+
52
+ @end
53
+
54
+ @implementation RCTRedBoxController {
55
+ UITableView *_stackTraceTableView;
56
+ NSString *_lastErrorMessage;
57
+ NSArray<RCTJSStackFrame *> *_lastStackTrace;
58
+ NSArray<NSString *> *_customButtonTitles;
59
+ NSArray<RCTRedBoxButtonPressHandler> *_customButtonHandlers;
60
+ int _lastErrorCookie;
61
+ }
62
+
63
+ - (instancetype)initWithCustomButtonTitles:(NSArray<NSString *> *)customButtonTitles
64
+ customButtonHandlers:(NSArray<RCTRedBoxButtonPressHandler> *)customButtonHandlers
65
+ {
66
+ if (self = [super init]) {
67
+ _lastErrorCookie = -1;
68
+ _customButtonTitles = customButtonTitles;
69
+ _customButtonHandlers = customButtonHandlers;
70
+ }
71
+
72
+ return self;
73
+ }
74
+
75
+ - (void)viewDidLoad
76
+ {
77
+ [super viewDidLoad];
78
+ self.view.backgroundColor = [UIColor blackColor];
79
+
80
+ const CGFloat buttonHeight = 60;
81
+
82
+ CGRect detailsFrame = self.view.bounds;
83
+ detailsFrame.size.height -= buttonHeight + (double)[self bottomSafeViewHeight];
84
+
85
+ _stackTraceTableView = [[UITableView alloc] initWithFrame:detailsFrame style:UITableViewStylePlain];
86
+ _stackTraceTableView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
87
+ _stackTraceTableView.delegate = self;
88
+ _stackTraceTableView.dataSource = self;
89
+ _stackTraceTableView.backgroundColor = [UIColor clearColor];
90
+ #if !TARGET_OS_TV
91
+ _stackTraceTableView.separatorColor = [UIColor colorWithWhite:1 alpha:0.3];
92
+ _stackTraceTableView.separatorStyle = UITableViewCellSeparatorStyleNone;
93
+ #endif
94
+ _stackTraceTableView.indicatorStyle = UIScrollViewIndicatorStyleWhite;
95
+ [self.view addSubview:_stackTraceTableView];
96
+
97
+ #if TARGET_OS_SIMULATOR || TARGET_OS_MACCATALYST
98
+ NSString *reloadText = @"Reload\n(\u2318R)";
99
+ NSString *dismissText = @"Dismiss\n(ESC)";
100
+ NSString *copyText = @"Copy\n(\u2325\u2318C)";
101
+ NSString *extraText = @"Extra Info\n(\u2318E)";
102
+ #else
103
+ NSString *reloadText = @"Reload JS";
104
+ NSString *dismissText = @"Dismiss";
105
+ NSString *copyText = @"Copy";
106
+ NSString *extraText = @"Extra Info";
107
+ #endif
108
+
109
+ UIButton *dismissButton = [self redBoxButton:dismissText
110
+ accessibilityIdentifier:@"redbox-dismiss"
111
+ selector:@selector(dismiss)
112
+ block:nil];
113
+ UIButton *reloadButton = [self redBoxButton:reloadText
114
+ accessibilityIdentifier:@"redbox-reload"
115
+ selector:@selector(reload)
116
+ block:nil];
117
+ UIButton *copyButton = [self redBoxButton:copyText
118
+ accessibilityIdentifier:@"redbox-copy"
119
+ selector:@selector(copyStack)
120
+ block:nil];
121
+ UIButton *extraButton = [self redBoxButton:extraText
122
+ accessibilityIdentifier:@"redbox-extra"
123
+ selector:@selector(showExtraDataViewController)
124
+ block:nil];
125
+
126
+ [NSLayoutConstraint activateConstraints:@[
127
+ [dismissButton.heightAnchor constraintEqualToConstant:buttonHeight],
128
+ [reloadButton.heightAnchor constraintEqualToConstant:buttonHeight],
129
+ [copyButton.heightAnchor constraintEqualToConstant:buttonHeight],
130
+ [extraButton.heightAnchor constraintEqualToConstant:buttonHeight]
131
+ ]];
132
+
133
+ UIStackView *buttonStackView = [[UIStackView alloc] init];
134
+ buttonStackView.translatesAutoresizingMaskIntoConstraints = NO;
135
+ buttonStackView.axis = UILayoutConstraintAxisHorizontal;
136
+ buttonStackView.distribution = UIStackViewDistributionFillEqually;
137
+ buttonStackView.alignment = UIStackViewAlignmentTop;
138
+ buttonStackView.backgroundColor = [UIColor colorWithRed:0.1 green:0.1 blue:0.1 alpha:1];
139
+
140
+ [buttonStackView addArrangedSubview:dismissButton];
141
+ [buttonStackView addArrangedSubview:reloadButton];
142
+ [buttonStackView addArrangedSubview:copyButton];
143
+ [buttonStackView addArrangedSubview:extraButton];
144
+
145
+ [self.view addSubview:buttonStackView];
146
+
147
+ [NSLayoutConstraint activateConstraints:@[
148
+ [buttonStackView.heightAnchor constraintEqualToConstant:buttonHeight + [self bottomSafeViewHeight]],
149
+ [buttonStackView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor],
150
+ [buttonStackView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor],
151
+ [buttonStackView.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor]
152
+ ]];
153
+
154
+ for (NSUInteger i = 0; i < [_customButtonTitles count]; i++) {
155
+ UIButton *button = [self redBoxButton:_customButtonTitles[i]
156
+ accessibilityIdentifier:@""
157
+ selector:nil
158
+ block:_customButtonHandlers[i]];
159
+ [button.heightAnchor constraintEqualToConstant:buttonHeight].active = YES;
160
+ [buttonStackView addArrangedSubview:button];
161
+ }
162
+
163
+ UIView *topBorder = [[UIView alloc] init];
164
+ topBorder.translatesAutoresizingMaskIntoConstraints = NO;
165
+ topBorder.backgroundColor = [UIColor colorWithRed:0.70 green:0.70 blue:0.70 alpha:1.0];
166
+ [topBorder.heightAnchor constraintEqualToConstant:1].active = YES;
167
+
168
+ [self.view addSubview:topBorder];
169
+
170
+ [NSLayoutConstraint activateConstraints:@[
171
+ [topBorder.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor],
172
+ [topBorder.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor],
173
+ [topBorder.bottomAnchor constraintEqualToAnchor:buttonStackView.topAnchor],
174
+ ]];
175
+ }
176
+
177
+ - (UIButton *)redBoxButton:(NSString *)title
178
+ accessibilityIdentifier:(NSString *)accessibilityIdentifier
179
+ selector:(SEL)selector
180
+ block:(RCTRedBoxButtonPressHandler)block
181
+ {
182
+ UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
183
+ button.autoresizingMask =
184
+ UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleRightMargin;
185
+ button.accessibilityIdentifier = accessibilityIdentifier;
186
+ button.titleLabel.font = [UIFont systemFontOfSize:13];
187
+ button.titleLabel.lineBreakMode = NSLineBreakByWordWrapping;
188
+ button.titleLabel.textAlignment = NSTextAlignmentCenter;
189
+ button.backgroundColor = [UIColor colorWithRed:0.1 green:0.1 blue:0.1 alpha:1];
190
+ [button setTitle:title forState:UIControlStateNormal];
191
+ [button setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
192
+ [button setTitleColor:[UIColor colorWithWhite:1 alpha:0.5] forState:UIControlStateHighlighted];
193
+ if (selector) {
194
+ [button addTarget:self action:selector forControlEvents:UIControlEventTouchUpInside];
195
+ } else if (block) {
196
+ [button rct_addBlock:block forControlEvents:UIControlEventTouchUpInside];
197
+ }
198
+ return button;
199
+ }
200
+
201
+ - (NSInteger)bottomSafeViewHeight
202
+ {
203
+ #if TARGET_OS_MACCATALYST
204
+ return 0;
205
+ #else
206
+ return RCTKeyWindow().safeAreaInsets.bottom;
207
+ #endif
208
+ }
209
+
210
+ RCT_NOT_IMPLEMENTED(-(instancetype)initWithCoder : (NSCoder *)aDecoder)
211
+
212
+ - (NSString *)stripAnsi:(NSString *)text
213
+ {
214
+ NSError *error = nil;
215
+ NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"\\x1b\\[[0-9;]*m"
216
+ options:NSRegularExpressionCaseInsensitive
217
+ error:&error];
218
+ return [regex stringByReplacingMatchesInString:text options:0 range:NSMakeRange(0, [text length]) withTemplate:@""];
219
+ }
220
+
221
+ - (void)showErrorMessage:(NSString *)message
222
+ withStack:(NSArray<RCTJSStackFrame *> *)stack
223
+ isUpdate:(BOOL)isUpdate
224
+ errorCookie:(int)errorCookie
225
+ {
226
+ // Remove ANSI color codes from the message
227
+ NSString *messageWithoutAnsi = [self stripAnsi:message];
228
+
229
+ BOOL isRootViewControllerPresented = self.presentingViewController != nil;
230
+ // Show if this is a new message, or if we're updating the previous message
231
+ BOOL isNew = !isRootViewControllerPresented && !isUpdate;
232
+ BOOL isUpdateForSameMessage = !isNew &&
233
+ (isRootViewControllerPresented && isUpdate &&
234
+ ((errorCookie == -1 && [_lastErrorMessage isEqualToString:messageWithoutAnsi]) ||
235
+ (errorCookie == _lastErrorCookie)));
236
+ if (isNew || isUpdateForSameMessage) {
237
+ _lastStackTrace = stack;
238
+ // message is displayed using UILabel, which is unable to render text of
239
+ // unlimited length, so we truncate it
240
+ _lastErrorMessage = [messageWithoutAnsi substringToIndex:MIN((NSUInteger)10000, messageWithoutAnsi.length)];
241
+ _lastErrorCookie = errorCookie;
242
+
243
+ [_stackTraceTableView reloadData];
244
+
245
+ if (!isRootViewControllerPresented) {
246
+ [_stackTraceTableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]
247
+ atScrollPosition:UITableViewScrollPositionTop
248
+ animated:NO];
249
+ [RCTKeyWindow().rootViewController presentViewController:self animated:YES completion:nil];
250
+ }
251
+ }
252
+ }
253
+
254
+ - (void)dismiss
255
+ {
256
+ [self dismissViewControllerAnimated:YES completion:nil];
257
+ }
258
+
259
+ - (void)reload
260
+ {
261
+ if (_actionDelegate != nil) {
262
+ [_actionDelegate reloadFromRedBoxController:self];
263
+ } else {
264
+ // In bridgeless mode `RCTRedBox` gets deallocated, we need to notify listeners anyway.
265
+ RCTTriggerReloadCommandListeners(@"Redbox");
266
+ [self dismiss];
267
+ }
268
+ }
269
+
270
+ - (void)showExtraDataViewController
271
+ {
272
+ [_actionDelegate loadExtraDataViewController];
273
+ }
274
+
275
+ - (void)copyStack
276
+ {
277
+ NSMutableString *fullStackTrace;
278
+
279
+ if (_lastErrorMessage != nil) {
280
+ fullStackTrace = [_lastErrorMessage mutableCopy];
281
+ [fullStackTrace appendString:@"\n\n"];
282
+ } else {
283
+ fullStackTrace = [NSMutableString string];
284
+ }
285
+
286
+ for (RCTJSStackFrame *stackFrame in _lastStackTrace) {
287
+ [fullStackTrace appendString:[NSString stringWithFormat:@"%@\n", stackFrame.methodName]];
288
+ if (stackFrame.file) {
289
+ [fullStackTrace appendFormat:@" %@\n", [self formatFrameSource:stackFrame]];
290
+ }
291
+ }
292
+ #if !TARGET_OS_TV
293
+ UIPasteboard *pb = [UIPasteboard generalPasteboard];
294
+ [pb setString:fullStackTrace];
295
+ #endif
296
+ }
297
+
298
+ - (NSString *)formatFrameSource:(RCTJSStackFrame *)stackFrame
299
+ {
300
+ NSString *fileName = RCTNilIfNull(stackFrame.file) ? [stackFrame.file lastPathComponent] : @"<unknown file>";
301
+ NSString *lineInfo = [NSString stringWithFormat:@"%@:%lld", fileName, (long long)stackFrame.lineNumber];
302
+
303
+ if (stackFrame.column != 0) {
304
+ lineInfo = [lineInfo stringByAppendingFormat:@":%lld", (long long)stackFrame.column];
305
+ }
306
+ return lineInfo;
307
+ }
308
+
309
+ #pragma mark - TableView
310
+
311
+ - (NSInteger)numberOfSectionsInTableView:(__unused UITableView *)tableView
312
+ {
313
+ return 2;
314
+ }
315
+
316
+ - (NSInteger)tableView:(__unused UITableView *)tableView numberOfRowsInSection:(NSInteger)section
317
+ {
318
+ return section == 0 ? 1 : _lastStackTrace.count;
319
+ }
320
+
321
+ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
322
+ {
323
+ if (indexPath.section == 0) {
324
+ UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"msg-cell"];
325
+ return [self reuseCell:cell forErrorMessage:_lastErrorMessage];
326
+ }
327
+ UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell"];
328
+ NSUInteger index = indexPath.row;
329
+ RCTJSStackFrame *stackFrame = _lastStackTrace[index];
330
+ return [self reuseCell:cell forStackFrame:stackFrame];
331
+ }
332
+
333
+ - (UITableViewCell *)reuseCell:(UITableViewCell *)cell forErrorMessage:(NSString *)message
334
+ {
335
+ if (!cell) {
336
+ cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"msg-cell"];
337
+ cell.textLabel.accessibilityIdentifier = @"redbox-error";
338
+ cell.textLabel.textColor = [UIColor whiteColor];
339
+
340
+ // Prefer a monofont for formatting messages that were designed
341
+ // to be displayed in a terminal.
342
+ cell.textLabel.font = [UIFont monospacedSystemFontOfSize:14 weight:UIFontWeightBold];
343
+
344
+ cell.textLabel.lineBreakMode = NSLineBreakByWordWrapping;
345
+ cell.textLabel.numberOfLines = 0;
346
+ cell.detailTextLabel.textColor = [UIColor whiteColor];
347
+ cell.backgroundColor = [UIColor colorWithRed:0.82 green:0.10 blue:0.15 alpha:1.0];
348
+ cell.selectionStyle = UITableViewCellSelectionStyleNone;
349
+ }
350
+
351
+ cell.textLabel.text = message;
352
+
353
+ return cell;
354
+ }
355
+
356
+ - (UITableViewCell *)reuseCell:(UITableViewCell *)cell forStackFrame:(RCTJSStackFrame *)stackFrame
357
+ {
358
+ if (!cell) {
359
+ cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@"cell"];
360
+ cell.textLabel.font = [UIFont fontWithName:@"Menlo-Regular" size:14];
361
+ cell.textLabel.lineBreakMode = NSLineBreakByCharWrapping;
362
+ cell.textLabel.numberOfLines = 2;
363
+ cell.detailTextLabel.textColor = [UIColor colorWithRed:0.70 green:0.70 blue:0.70 alpha:1.0];
364
+ cell.detailTextLabel.font = [UIFont fontWithName:@"Menlo-Regular" size:11];
365
+ cell.detailTextLabel.lineBreakMode = NSLineBreakByTruncatingMiddle;
366
+ cell.backgroundColor = [UIColor clearColor];
367
+ cell.selectedBackgroundView = [UIView new];
368
+ cell.selectedBackgroundView.backgroundColor = [UIColor colorWithWhite:0 alpha:0.2];
369
+ }
370
+
371
+ cell.textLabel.text = stackFrame.methodName ?: @"(unnamed method)";
372
+ if (stackFrame.file) {
373
+ cell.detailTextLabel.text = [self formatFrameSource:stackFrame];
374
+ } else {
375
+ cell.detailTextLabel.text = @"";
376
+ }
377
+ cell.textLabel.textColor = stackFrame.collapse ? [UIColor lightGrayColor] : [UIColor whiteColor];
378
+ cell.detailTextLabel.textColor = stackFrame.collapse ? [UIColor colorWithRed:0.50 green:0.50 blue:0.50 alpha:1.0]
379
+ : [UIColor colorWithRed:0.70 green:0.70 blue:0.70 alpha:1.0];
380
+ return cell;
381
+ }
382
+
383
+ - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
384
+ {
385
+ if (indexPath.section == 0) {
386
+ NSMutableParagraphStyle *paragraphStyle = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
387
+ paragraphStyle.lineBreakMode = NSLineBreakByWordWrapping;
388
+
389
+ NSDictionary *attributes =
390
+ @{NSFontAttributeName : [UIFont boldSystemFontOfSize:16], NSParagraphStyleAttributeName : paragraphStyle};
391
+ CGRect boundingRect =
392
+ [_lastErrorMessage boundingRectWithSize:CGSizeMake(tableView.frame.size.width - 30, CGFLOAT_MAX)
393
+ options:NSStringDrawingUsesLineFragmentOrigin
394
+ attributes:attributes
395
+ context:nil];
396
+ return ceil(boundingRect.size.height) + 40;
397
+ } else {
398
+ return 50;
399
+ }
400
+ }
401
+
402
+ - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
403
+ {
404
+ if (indexPath.section == 1) {
405
+ NSUInteger row = indexPath.row;
406
+ RCTJSStackFrame *stackFrame = _lastStackTrace[row];
407
+ [_actionDelegate redBoxController:self openStackFrameInEditor:stackFrame];
408
+ }
409
+ [tableView deselectRowAtIndexPath:indexPath animated:YES];
410
+ }
411
+
412
+ #pragma mark - Key commands
413
+
414
+ - (NSArray<UIKeyCommand *> *)keyCommands
415
+ {
416
+ // NOTE: We could use RCTKeyCommands for this, but since
417
+ // we control this window, we can use the standard, non-hacky
418
+ // mechanism instead
419
+
420
+ return @[
421
+ // Dismiss red box
422
+ [UIKeyCommand keyCommandWithInput:UIKeyInputEscape modifierFlags:0 action:@selector(dismiss)],
423
+
424
+ // Reload
425
+ [UIKeyCommand keyCommandWithInput:@"r" modifierFlags:UIKeyModifierCommand action:@selector(reload)],
426
+
427
+ // Copy = Cmd-Option C since Cmd-C in the simulator copies the pasteboard from
428
+ // the simulator to the desktop pasteboard.
429
+ [UIKeyCommand keyCommandWithInput:@"c"
430
+ modifierFlags:UIKeyModifierCommand | UIKeyModifierAlternate
431
+ action:@selector(copyStack)],
432
+
433
+ // Extra data
434
+ [UIKeyCommand keyCommandWithInput:@"e"
435
+ modifierFlags:UIKeyModifierCommand
436
+ action:@selector(showExtraDataViewController)]
437
+ ];
438
+ }
439
+
440
+ - (BOOL)canBecomeFirstResponder
441
+ {
442
+ return YES;
443
+ }
444
+
445
+ @end
446
+
447
+ #endif
@@ -0,0 +1,26 @@
1
+ /*
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+
8
+ #import <Foundation/Foundation.h>
9
+
10
+ #import <React/RCTDefines.h>
11
+
12
+ #if RCT_DEV_MENU
13
+
14
+ /**
15
+ * Minimal native HMR client that connects to Metro's /hot WebSocket endpoint
16
+ * while RedBox 2.0 is displayed. When Metro detects a file change
17
+ * (update-start), this client triggers a reload so the user's fix is picked up
18
+ * automatically — even when the JS runtime has no active HMR connection.
19
+ */
20
+ @interface RCTRedBoxHMRClient : NSObject <NSURLSessionWebSocketDelegate>
21
+ - (instancetype)initWithBundleURL:(NSURL *)bundleURL onFileChange:(void (^)(void))onFileChange;
22
+ - (void)start;
23
+ - (void)stop;
24
+ @end
25
+
26
+ #endif