react-native 0.84.0-nightly-20251211-80e384a80 → 0.84.0-nightly-20251213-07bd24ed0
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.
- package/Libraries/Core/ReactNativeVersion.js +1 -1
- package/Libraries/StyleSheet/StyleSheetTypes.d.ts +97 -2
- package/Libraries/WebSocket/WebSocketInterceptor.js +3 -3
- package/React/Base/RCTVersion.m +1 -1
- package/React/Modules/RCTEventEmitter.m +1 -0
- package/ReactAndroid/gradle.properties +1 -1
- package/ReactAndroid/src/main/java/com/facebook/react/devsupport/ChangeBundleLocationDialog.kt +11 -10
- package/ReactAndroid/src/main/java/com/facebook/react/modules/systeminfo/ReactNativeVersion.kt +1 -1
- package/ReactAndroid/src/main/java/com/facebook/react/packagerconnection/PackagerConnectionSettings.kt +15 -8
- package/ReactAndroid/src/main/jni/react/turbomodule/ReactCommon/TurboModuleManager.cpp +34 -8
- package/ReactAndroid/src/main/res/views/uimanager/values-ne/strings.xml +1 -0
- package/ReactCommon/cxxreact/ReactNativeVersion.h +1 -1
- package/ReactCommon/react/renderer/animationbackend/AnimatedPropsRegistry.h +16 -0
- package/ReactCommon/react/renderer/imagemanager/platform/android/react/renderer/imagemanager/ImageFetcher.cpp +16 -10
- package/ReactCommon/react/renderer/imagemanager/platform/android/react/renderer/imagemanager/ImageFetcher.h +2 -0
- package/jest/mockComponent.js +1 -1
- package/package.json +9 -9
- package/sdks/hermes-engine/version.properties +1 -1
- package/src/private/devsupport/devmenu/elementinspector/Inspector.js +6 -25
- package/src/private/devsupport/devmenu/elementinspector/InspectorPanel.js +0 -26
- package/src/private/devsupport/devmenu/elementinspector/XHRInterceptor.js +3 -2
- package/src/private/devsupport/devmenu/elementinspector/NetworkOverlay.js +0 -628
- package/src/private/devsupport/devmenu/perfmonitor/PerformanceOverlay.js +0 -66
|
@@ -29,7 +29,7 @@ export default class ReactNativeVersion {
|
|
|
29
29
|
static major: number = 0;
|
|
30
30
|
static minor: number = 84;
|
|
31
31
|
static patch: number = 0;
|
|
32
|
-
static prerelease: string | null = 'nightly-
|
|
32
|
+
static prerelease: string | null = 'nightly-20251213-07bd24ed0';
|
|
33
33
|
|
|
34
34
|
static getVersionString(): string {
|
|
35
35
|
return `${this.major}.${this.minor}.${this.patch}${this.prerelease != null ? `-${this.prerelease}` : ''}`;
|
|
@@ -367,7 +367,7 @@ export type BlendMode =
|
|
|
367
367
|
| 'color'
|
|
368
368
|
| 'luminosity';
|
|
369
369
|
|
|
370
|
-
export type
|
|
370
|
+
export type LinearGradientValue = {
|
|
371
371
|
type: 'linear-gradient';
|
|
372
372
|
// Angle or direction enums
|
|
373
373
|
direction?: string | undefined;
|
|
@@ -377,6 +377,89 @@ export type GradientValue = {
|
|
|
377
377
|
}>;
|
|
378
378
|
};
|
|
379
379
|
|
|
380
|
+
export type GradientValue = LinearGradientValue;
|
|
381
|
+
|
|
382
|
+
type RadialExtent =
|
|
383
|
+
| 'closest-corner'
|
|
384
|
+
| 'closest-side'
|
|
385
|
+
| 'farthest-corner'
|
|
386
|
+
| 'farthest-side';
|
|
387
|
+
export type RadialGradientPosition =
|
|
388
|
+
| {
|
|
389
|
+
top: number | string;
|
|
390
|
+
left: number | string;
|
|
391
|
+
}
|
|
392
|
+
| {
|
|
393
|
+
top: number | string;
|
|
394
|
+
right: number | string;
|
|
395
|
+
}
|
|
396
|
+
| {
|
|
397
|
+
bottom: number | string;
|
|
398
|
+
left: number | string;
|
|
399
|
+
}
|
|
400
|
+
| {
|
|
401
|
+
bottom: number | string;
|
|
402
|
+
right: number | string;
|
|
403
|
+
};
|
|
404
|
+
|
|
405
|
+
export type RadialGradientShape = 'circle' | 'ellipse';
|
|
406
|
+
export type RadialGradientSize =
|
|
407
|
+
| RadialExtent
|
|
408
|
+
| {
|
|
409
|
+
x: string | number;
|
|
410
|
+
y: string | number;
|
|
411
|
+
};
|
|
412
|
+
|
|
413
|
+
type RadialGradientValue = {
|
|
414
|
+
type: 'radial-gradient';
|
|
415
|
+
shape: RadialGradientShape;
|
|
416
|
+
size: RadialGradientSize;
|
|
417
|
+
position: RadialGradientPosition;
|
|
418
|
+
colorStops: ReadonlyArray<{
|
|
419
|
+
color: ColorValue | null;
|
|
420
|
+
positions?: ReadonlyArray<string> | undefined;
|
|
421
|
+
}>;
|
|
422
|
+
};
|
|
423
|
+
|
|
424
|
+
export type BackgroundImageValue = LinearGradientValue | RadialGradientValue;
|
|
425
|
+
|
|
426
|
+
export type BackgroundSizeValue =
|
|
427
|
+
| {
|
|
428
|
+
x: string | number;
|
|
429
|
+
y: string | number;
|
|
430
|
+
}
|
|
431
|
+
| 'cover'
|
|
432
|
+
| 'contain';
|
|
433
|
+
|
|
434
|
+
export type BackgroundRepeatKeyword =
|
|
435
|
+
| 'repeat'
|
|
436
|
+
| 'space'
|
|
437
|
+
| 'round'
|
|
438
|
+
| 'no-repeat';
|
|
439
|
+
|
|
440
|
+
export type BackgroundPositionValue =
|
|
441
|
+
| {
|
|
442
|
+
top: number | string;
|
|
443
|
+
left: number | string;
|
|
444
|
+
}
|
|
445
|
+
| {
|
|
446
|
+
top: number | string;
|
|
447
|
+
right: number | string;
|
|
448
|
+
}
|
|
449
|
+
| {
|
|
450
|
+
bottom: number | string;
|
|
451
|
+
left: number | string;
|
|
452
|
+
}
|
|
453
|
+
| {
|
|
454
|
+
bottom: number | string;
|
|
455
|
+
right: number | string;
|
|
456
|
+
};
|
|
457
|
+
|
|
458
|
+
export type BackgroundRepeatValue = {
|
|
459
|
+
x: BackgroundRepeatKeyword;
|
|
460
|
+
y: BackgroundRepeatKeyword;
|
|
461
|
+
};
|
|
462
|
+
|
|
380
463
|
/**
|
|
381
464
|
* @see https://reactnative.dev/docs/view#style
|
|
382
465
|
*/
|
|
@@ -437,7 +520,19 @@ export interface ViewStyle extends FlexStyle, ShadowStyleIOS, TransformsStyle {
|
|
|
437
520
|
|
|
438
521
|
mixBlendMode?: BlendMode | undefined;
|
|
439
522
|
experimental_backgroundImage?:
|
|
440
|
-
| ReadonlyArray<
|
|
523
|
+
| ReadonlyArray<BackgroundImageValue>
|
|
524
|
+
| string
|
|
525
|
+
| undefined;
|
|
526
|
+
experimental_backgroundSize?:
|
|
527
|
+
| ReadonlyArray<BackgroundSizeValue>
|
|
528
|
+
| string
|
|
529
|
+
| undefined;
|
|
530
|
+
experimental_backgroundPosition?:
|
|
531
|
+
| ReadonlyArray<BackgroundPositionValue>
|
|
532
|
+
| string
|
|
533
|
+
| undefined;
|
|
534
|
+
experimental_backgroundRepeat?:
|
|
535
|
+
| ReadonlyArray<BackgroundRepeatValue>
|
|
441
536
|
| string
|
|
442
537
|
| undefined;
|
|
443
538
|
}
|
|
@@ -33,10 +33,10 @@ let isInterceptorEnabled = false;
|
|
|
33
33
|
|
|
34
34
|
/**
|
|
35
35
|
* A network interceptor which monkey-patches RCTWebSocketModule methods
|
|
36
|
-
* to gather all websocket network
|
|
37
|
-
*
|
|
36
|
+
* to gather all websocket network events.
|
|
37
|
+
*
|
|
38
|
+
* @deprecated Since React Native 0.84
|
|
38
39
|
*/
|
|
39
|
-
|
|
40
40
|
const WebSocketInterceptor = {
|
|
41
41
|
/**
|
|
42
42
|
* Invoked when RCTWebSocketModule.close(...) is called.
|
package/React/Base/RCTVersion.m
CHANGED
|
@@ -24,7 +24,7 @@ NSDictionary* RCTGetReactNativeVersion(void)
|
|
|
24
24
|
RCTVersionMajor: @(0),
|
|
25
25
|
RCTVersionMinor: @(84),
|
|
26
26
|
RCTVersionPatch: @(0),
|
|
27
|
-
RCTVersionPrerelease: @"nightly-
|
|
27
|
+
RCTVersionPrerelease: @"nightly-20251213-07bd24ed0",
|
|
28
28
|
};
|
|
29
29
|
});
|
|
30
30
|
return __rnVersion;
|
package/ReactAndroid/src/main/java/com/facebook/react/devsupport/ChangeBundleLocationDialog.kt
CHANGED
|
@@ -33,9 +33,6 @@ internal object ChangeBundleLocationDialog {
|
|
|
33
33
|
) {
|
|
34
34
|
val settings = devSettings.packagerConnectionSettings
|
|
35
35
|
val currentHost = settings.debugServerHost
|
|
36
|
-
settings.debugServerHost = ""
|
|
37
|
-
val defaultHost = settings.debugServerHost
|
|
38
|
-
settings.debugServerHost = currentHost
|
|
39
36
|
|
|
40
37
|
val layout = LinearLayout(context)
|
|
41
38
|
layout.orientation = LinearLayout.VERTICAL
|
|
@@ -60,11 +57,11 @@ internal object ChangeBundleLocationDialog {
|
|
|
60
57
|
input.setTextColor(-0x1000000)
|
|
61
58
|
input.setText(currentHost)
|
|
62
59
|
|
|
63
|
-
val
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
60
|
+
val currentHostSuggestion = Button(context)
|
|
61
|
+
currentHostSuggestion.text = currentHost
|
|
62
|
+
currentHostSuggestion.textSize = 12f
|
|
63
|
+
currentHostSuggestion.isAllCaps = false
|
|
64
|
+
currentHostSuggestion.setOnClickListener { input.setText(currentHost) }
|
|
68
65
|
|
|
69
66
|
val networkHost = getDevServerNetworkIpAndPort(context)
|
|
70
67
|
val networkHostSuggestion = Button(context)
|
|
@@ -80,8 +77,12 @@ internal object ChangeBundleLocationDialog {
|
|
|
80
77
|
LinearLayout.LayoutParams.MATCH_PARENT,
|
|
81
78
|
LinearLayout.LayoutParams.WRAP_CONTENT,
|
|
82
79
|
)
|
|
83
|
-
suggestionRow.addView(
|
|
84
|
-
|
|
80
|
+
suggestionRow.addView(currentHostSuggestion)
|
|
81
|
+
|
|
82
|
+
if (currentHost != networkHost) {
|
|
83
|
+
// We don't want to display two buttons with the same host suggestion.
|
|
84
|
+
suggestionRow.addView(networkHostSuggestion)
|
|
85
|
+
}
|
|
85
86
|
|
|
86
87
|
val instructions = TextView(context)
|
|
87
88
|
instructions.text =
|
|
@@ -19,15 +19,16 @@ public open class PackagerConnectionSettings(private val appContext: Context) {
|
|
|
19
19
|
private val preferences: SharedPreferences =
|
|
20
20
|
PreferenceManager.getDefaultSharedPreferences(appContext)
|
|
21
21
|
public val packageName: String = appContext.packageName
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
22
|
+
|
|
23
|
+
init {
|
|
24
|
+
resetDebugServerHost()
|
|
25
|
+
}
|
|
25
26
|
|
|
26
27
|
public open var debugServerHost: String
|
|
27
28
|
get() {
|
|
28
29
|
// Check cached host first. If empty try to detect emulator type and use default
|
|
29
30
|
// hostname for those
|
|
30
|
-
|
|
31
|
+
_cachedOrOverrideHost?.let {
|
|
31
32
|
return it
|
|
32
33
|
}
|
|
33
34
|
|
|
@@ -44,19 +45,19 @@ public open class PackagerConnectionSettings(private val appContext: Context) {
|
|
|
44
45
|
)
|
|
45
46
|
}
|
|
46
47
|
|
|
47
|
-
|
|
48
|
+
_cachedOrOverrideHost = host
|
|
48
49
|
return host
|
|
49
50
|
}
|
|
50
51
|
set(host) {
|
|
51
52
|
if (host.isEmpty()) {
|
|
52
|
-
|
|
53
|
+
_cachedOrOverrideHost = null
|
|
53
54
|
} else {
|
|
54
|
-
|
|
55
|
+
_cachedOrOverrideHost = host
|
|
55
56
|
}
|
|
56
57
|
}
|
|
57
58
|
|
|
58
59
|
public open fun resetDebugServerHost() {
|
|
59
|
-
|
|
60
|
+
_cachedOrOverrideHost = null
|
|
60
61
|
}
|
|
61
62
|
|
|
62
63
|
public fun setPackagerOptionsUpdater(queryMapper: (Map<String, String>) -> Map<String, String>) {
|
|
@@ -76,5 +77,11 @@ public open class PackagerConnectionSettings(private val appContext: Context) {
|
|
|
76
77
|
private companion object {
|
|
77
78
|
private val TAG = PackagerConnectionSettings::class.java.simpleName
|
|
78
79
|
private const val PREFS_DEBUG_SERVER_HOST_KEY = "debug_http_host"
|
|
80
|
+
|
|
81
|
+
// The state for this class needs to be retained in the companion object.
|
|
82
|
+
// That's necessary in the case when there are multiple instances of PackagerConnectionSettings
|
|
83
|
+
private var _cachedOrOverrideHost: String? = null
|
|
84
|
+
private val _additionalOptionsForPackager: MutableMap<String, String> = mutableMapOf()
|
|
85
|
+
private var _packagerOptionsUpdater: (Map<String, String>) -> Map<String, String> = { it }
|
|
79
86
|
}
|
|
80
87
|
}
|
|
@@ -176,11 +176,24 @@ std::shared_ptr<TurboModule> TurboModuleManager::getTurboModule(
|
|
|
176
176
|
return turboModule;
|
|
177
177
|
}
|
|
178
178
|
|
|
179
|
+
// TODO(T248203434): Remove this workaround once fixed in fbjni
|
|
180
|
+
// NOTE: We use jstring instead of std::string for the method signature to
|
|
181
|
+
// work around a bug in fbjni's exception handling. When a Java method throws
|
|
182
|
+
// an exception, fbjni's JMethod::operator() needs to check for pending
|
|
183
|
+
// exceptions via FACEBOOK_JNI_THROW_PENDING_EXCEPTION(). However, if we pass
|
|
184
|
+
// std::string, fbjni creates a temporary local_ref<JString> for the argument.
|
|
185
|
+
// C++ destroys temporaries at the end of the full-expression, which happens
|
|
186
|
+
// AFTER the JNI call returns but BEFORE the exception check. The destructor
|
|
187
|
+
// calls JNI functions (GetObjectRefType) while there's a pending exception,
|
|
188
|
+
// which violates JNI rules and causes ART's CheckJNI to abort the process.
|
|
189
|
+
//
|
|
190
|
+
// By pre-converting to jstring here, we control the lifetime of the
|
|
191
|
+
// local_ref<JString> so it extends past the exception check.
|
|
179
192
|
static auto getTurboJavaModule =
|
|
180
|
-
javaPart->getClass()
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
auto moduleInstance = getTurboJavaModule(javaPart.get(),
|
|
193
|
+
javaPart->getClass()->getMethod<jni::alias_ref<JTurboModule>(jstring)>(
|
|
194
|
+
"getTurboJavaModule");
|
|
195
|
+
auto jname = jni::make_jstring(name);
|
|
196
|
+
auto moduleInstance = getTurboJavaModule(javaPart.get(), jname.get());
|
|
184
197
|
if (moduleInstance) {
|
|
185
198
|
TurboModulePerfLogger::moduleJSRequireEndingStart(moduleName);
|
|
186
199
|
JavaTurboModule::InitParams params = {
|
|
@@ -243,11 +256,24 @@ std::shared_ptr<TurboModule> TurboModuleManager::getLegacyModule(
|
|
|
243
256
|
|
|
244
257
|
TurboModulePerfLogger::moduleJSRequireBeginningEnd(moduleName);
|
|
245
258
|
|
|
259
|
+
// TODO(T248203434): Remove this workaround once fixed in fbjni
|
|
260
|
+
// NOTE: We use jstring instead of std::string for the method signature to
|
|
261
|
+
// work around a bug in fbjni's exception handling. When a Java method throws
|
|
262
|
+
// an exception, fbjni's JMethod::operator() needs to check for pending
|
|
263
|
+
// exceptions via FACEBOOK_JNI_THROW_PENDING_EXCEPTION(). However, if we pass
|
|
264
|
+
// std::string, fbjni creates a temporary local_ref<JString> for the argument.
|
|
265
|
+
// C++ destroys temporaries at the end of the full-expression, which happens
|
|
266
|
+
// AFTER the JNI call returns but BEFORE the exception check. The destructor
|
|
267
|
+
// calls JNI functions (GetObjectRefType) while there's a pending exception,
|
|
268
|
+
// which violates JNI rules and causes ART's CheckJNI to abort the process.
|
|
269
|
+
//
|
|
270
|
+
// By pre-converting to jstring here, we control the lifetime of the
|
|
271
|
+
// local_ref<JString> so it extends past the exception check.
|
|
246
272
|
static auto getLegacyJavaModule =
|
|
247
|
-
javaPart->getClass()
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
auto moduleInstance = getLegacyJavaModule(javaPart.get(),
|
|
273
|
+
javaPart->getClass()->getMethod<jni::alias_ref<JNativeModule>(jstring)>(
|
|
274
|
+
"getLegacyJavaModule");
|
|
275
|
+
auto jname = jni::make_jstring(name);
|
|
276
|
+
auto moduleInstance = getLegacyJavaModule(javaPart.get(), jname.get());
|
|
251
277
|
|
|
252
278
|
if (moduleInstance) {
|
|
253
279
|
TurboModulePerfLogger::moduleJSRequireEndingStart(moduleName);
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
<string name="menubar_description" gender="unknown">मेनु बार</string>
|
|
13
13
|
<string name="menuitem_description" gender="unknown">मेनु वस्तु</string>
|
|
14
14
|
<string name="scrollbar_description" gender="unknown">स्क्रोल बार</string>
|
|
15
|
+
<string name="spinbutton_description" gender="unknown">स्पिन बटन</string>
|
|
15
16
|
<string name="rn_tab_description" gender="unknown">टयाब</string>
|
|
16
17
|
<string name="timer_description" gender="unknown">टाइमर</string>
|
|
17
18
|
<string name="state_busy_description" gender="unknown">व्यस्त</string>
|
|
@@ -22,7 +22,7 @@ constexpr struct {
|
|
|
22
22
|
int32_t Major = 0;
|
|
23
23
|
int32_t Minor = 84;
|
|
24
24
|
int32_t Patch = 0;
|
|
25
|
-
std::string_view Prerelease = "nightly-
|
|
25
|
+
std::string_view Prerelease = "nightly-20251213-07bd24ed0";
|
|
26
26
|
} ReactNativeVersion;
|
|
27
27
|
|
|
28
28
|
} // namespace facebook::react
|
|
@@ -77,6 +77,22 @@ inline void updateProp(const PropName propName, BaseViewProps &viewProps, const
|
|
|
77
77
|
case BACKGROUND_COLOR:
|
|
78
78
|
viewProps.backgroundColor = snapshot.props.backgroundColor;
|
|
79
79
|
break;
|
|
80
|
+
|
|
81
|
+
case SHADOW_COLOR:
|
|
82
|
+
viewProps.shadowColor = snapshot.props.shadowColor;
|
|
83
|
+
break;
|
|
84
|
+
|
|
85
|
+
case SHADOW_OFFSET:
|
|
86
|
+
viewProps.shadowOffset = snapshot.props.shadowOffset;
|
|
87
|
+
break;
|
|
88
|
+
|
|
89
|
+
case SHADOW_OPACITY:
|
|
90
|
+
viewProps.shadowOpacity = snapshot.props.shadowOpacity;
|
|
91
|
+
break;
|
|
92
|
+
|
|
93
|
+
case SHADOW_RADIUS:
|
|
94
|
+
viewProps.shadowRadius = snapshot.props.shadowRadius;
|
|
95
|
+
break;
|
|
80
96
|
}
|
|
81
97
|
}
|
|
82
98
|
|
|
@@ -24,11 +24,14 @@ ImageRequest ImageFetcher::requestImage(
|
|
|
24
24
|
SurfaceId surfaceId,
|
|
25
25
|
const ImageRequestParams& imageRequestParams,
|
|
26
26
|
Tag tag) {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
27
|
+
{
|
|
28
|
+
std::lock_guard<std::mutex> lock(mutex_);
|
|
29
|
+
items_[surfaceId].emplace_back(
|
|
30
|
+
ImageRequestItem{
|
|
31
|
+
.imageSource = imageSource,
|
|
32
|
+
.imageRequestParams = imageRequestParams,
|
|
33
|
+
.tag = tag});
|
|
34
|
+
}
|
|
32
35
|
|
|
33
36
|
auto telemetry = std::make_shared<ImageTelemetry>(surfaceId);
|
|
34
37
|
|
|
@@ -40,8 +43,13 @@ ImageRequest ImageFetcher::requestImage(
|
|
|
40
43
|
}
|
|
41
44
|
|
|
42
45
|
void ImageFetcher::flushImageRequests() {
|
|
43
|
-
|
|
44
|
-
|
|
46
|
+
std::unordered_map<SurfaceId, std::vector<ImageRequestItem>> items;
|
|
47
|
+
{
|
|
48
|
+
std::lock_guard<std::mutex> lock(mutex_);
|
|
49
|
+
if (items_.empty()) {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
items.swap(items_);
|
|
45
53
|
}
|
|
46
54
|
|
|
47
55
|
auto fabricUIManager_ =
|
|
@@ -52,14 +60,12 @@ void ImageFetcher::flushImageRequests() {
|
|
|
52
60
|
SurfaceId, std::string, JReadableMapBuffer::javaobject)>(
|
|
53
61
|
"experimental_prefetchResources");
|
|
54
62
|
|
|
55
|
-
for (auto& [surfaceId, surfaceImageRequests] :
|
|
63
|
+
for (auto& [surfaceId, surfaceImageRequests] : items) {
|
|
56
64
|
auto readableMapBuffer = JReadableMapBuffer::createWithContents(
|
|
57
65
|
serializeImageRequests(surfaceImageRequests));
|
|
58
66
|
prefetchResources(
|
|
59
67
|
fabricUIManager_, surfaceId, "RCTImageView", readableMapBuffer.get());
|
|
60
68
|
}
|
|
61
|
-
|
|
62
|
-
items_.clear();
|
|
63
69
|
}
|
|
64
70
|
|
|
65
71
|
} // namespace facebook::react
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
#include <react/renderer/imagemanager/ImageRequestParams.h>
|
|
12
12
|
#include <react/utils/ContextContainer.h>
|
|
13
13
|
#include <memory>
|
|
14
|
+
#include <mutex>
|
|
14
15
|
#include <unordered_map>
|
|
15
16
|
#include <vector>
|
|
16
17
|
|
|
@@ -38,6 +39,7 @@ class ImageFetcher {
|
|
|
38
39
|
Tag tag);
|
|
39
40
|
|
|
40
41
|
std::unordered_map<SurfaceId, std::vector<ImageRequestItem>> items_;
|
|
42
|
+
std::mutex mutex_;
|
|
41
43
|
std::shared_ptr<const ContextContainer> contextContainer_;
|
|
42
44
|
};
|
|
43
45
|
} // namespace facebook::react
|
package/jest/mockComponent.js
CHANGED
|
@@ -39,7 +39,7 @@ export default function mockComponent<
|
|
|
39
39
|
|
|
40
40
|
const SuperClass: typeof React.Component<{...}> =
|
|
41
41
|
typeof RealComponent === 'function' &&
|
|
42
|
-
RealComponent.prototype
|
|
42
|
+
RealComponent.prototype?.constructor instanceof React.Component
|
|
43
43
|
? RealComponent
|
|
44
44
|
: React.Component;
|
|
45
45
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native",
|
|
3
|
-
"version": "0.84.0-nightly-
|
|
3
|
+
"version": "0.84.0-nightly-20251213-07bd24ed0",
|
|
4
4
|
"description": "A framework for building native apps using React",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -160,13 +160,13 @@
|
|
|
160
160
|
},
|
|
161
161
|
"dependencies": {
|
|
162
162
|
"@jest/create-cache-key-function": "^29.7.0",
|
|
163
|
-
"@react-native/assets-registry": "0.84.0-nightly-
|
|
164
|
-
"@react-native/codegen": "0.84.0-nightly-
|
|
165
|
-
"@react-native/community-cli-plugin": "0.84.0-nightly-
|
|
166
|
-
"@react-native/gradle-plugin": "0.84.0-nightly-
|
|
167
|
-
"@react-native/js-polyfills": "0.84.0-nightly-
|
|
168
|
-
"@react-native/normalize-colors": "0.84.0-nightly-
|
|
169
|
-
"@react-native/virtualized-lists": "0.84.0-nightly-
|
|
163
|
+
"@react-native/assets-registry": "0.84.0-nightly-20251213-07bd24ed0",
|
|
164
|
+
"@react-native/codegen": "0.84.0-nightly-20251213-07bd24ed0",
|
|
165
|
+
"@react-native/community-cli-plugin": "0.84.0-nightly-20251213-07bd24ed0",
|
|
166
|
+
"@react-native/gradle-plugin": "0.84.0-nightly-20251213-07bd24ed0",
|
|
167
|
+
"@react-native/js-polyfills": "0.84.0-nightly-20251213-07bd24ed0",
|
|
168
|
+
"@react-native/normalize-colors": "0.84.0-nightly-20251213-07bd24ed0",
|
|
169
|
+
"@react-native/virtualized-lists": "0.84.0-nightly-20251213-07bd24ed0",
|
|
170
170
|
"abort-controller": "^3.0.0",
|
|
171
171
|
"anser": "^1.4.9",
|
|
172
172
|
"ansi-regex": "^5.0.0",
|
|
@@ -175,7 +175,7 @@
|
|
|
175
175
|
"base64-js": "^1.5.1",
|
|
176
176
|
"commander": "^12.0.0",
|
|
177
177
|
"flow-enums-runtime": "^0.0.6",
|
|
178
|
-
"hermes-compiler": "0.
|
|
178
|
+
"hermes-compiler": "0.15.0-commitly-202512121350-fd0e1d3ed",
|
|
179
179
|
"invariant": "^2.2.4",
|
|
180
180
|
"jest-environment-node": "^29.7.0",
|
|
181
181
|
"memoize-one": "^5.0.0",
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
HERMES_VERSION_NAME=0.
|
|
1
|
+
HERMES_VERSION_NAME=0.15.0-commitly-202512121350-fd0e1d3ed
|
|
2
2
|
HERMES_V1_VERSION_NAME=250829098.0.4
|
|
@@ -39,10 +39,6 @@ const InspectorPanel = require('./InspectorPanel').default;
|
|
|
39
39
|
const {useState} = React;
|
|
40
40
|
|
|
41
41
|
type PanelPosition = 'top' | 'bottom';
|
|
42
|
-
type SelectedTab =
|
|
43
|
-
| 'elements-inspector'
|
|
44
|
-
| 'network-profiling'
|
|
45
|
-
| 'performance-profiling';
|
|
46
42
|
|
|
47
43
|
export type InspectedElementFrame = TouchedViewDataAtPoint['frame'];
|
|
48
44
|
export type InspectedElement = $ReadOnly<{
|
|
@@ -62,8 +58,7 @@ function Inspector({
|
|
|
62
58
|
onRequestRerenderApp,
|
|
63
59
|
reactDevToolsAgent,
|
|
64
60
|
}: Props): React.Node {
|
|
65
|
-
const [
|
|
66
|
-
useState<?SelectedTab>('elements-inspector');
|
|
61
|
+
const [inspecting, setInspecting] = useState<boolean>(true);
|
|
67
62
|
|
|
68
63
|
const [panelPosition, setPanelPosition] = useState<PanelPosition>('bottom');
|
|
69
64
|
const [inspectedElement, setInspectedElement] =
|
|
@@ -137,18 +132,8 @@ function Inspector({
|
|
|
137
132
|
);
|
|
138
133
|
};
|
|
139
134
|
|
|
140
|
-
const
|
|
141
|
-
|
|
142
|
-
setInspectedElement(null);
|
|
143
|
-
};
|
|
144
|
-
|
|
145
|
-
const setPerfing = (enabled: boolean) => {
|
|
146
|
-
setSelectedTab(enabled ? 'performance-profiling' : null);
|
|
147
|
-
setInspectedElement(null);
|
|
148
|
-
};
|
|
149
|
-
|
|
150
|
-
const setNetworking = (enabled: boolean) => {
|
|
151
|
-
setSelectedTab(enabled ? 'network-profiling' : null);
|
|
135
|
+
const handleSetInspecting = (enabled: boolean) => {
|
|
136
|
+
setInspecting(enabled);
|
|
152
137
|
setInspectedElement(null);
|
|
153
138
|
};
|
|
154
139
|
|
|
@@ -164,7 +149,7 @@ function Inspector({
|
|
|
164
149
|
|
|
165
150
|
return (
|
|
166
151
|
<View style={styles.container} pointerEvents="box-none">
|
|
167
|
-
{
|
|
152
|
+
{inspecting && (
|
|
168
153
|
<InspectorOverlay
|
|
169
154
|
inspected={inspectedElement}
|
|
170
155
|
onTouchPoint={onTouchPoint}
|
|
@@ -174,18 +159,14 @@ function Inspector({
|
|
|
174
159
|
<SafeAreaView style={[styles.panelContainer, panelContainerStyle]}>
|
|
175
160
|
<InspectorPanel
|
|
176
161
|
devtoolsIsOpen={!!reactDevToolsAgent}
|
|
177
|
-
inspecting={
|
|
178
|
-
|
|
179
|
-
setPerfing={setPerfing}
|
|
180
|
-
setInspecting={setInspecting}
|
|
162
|
+
inspecting={inspecting}
|
|
163
|
+
setInspecting={handleSetInspecting}
|
|
181
164
|
inspected={inspectedElement}
|
|
182
165
|
hierarchy={elementsHierarchy}
|
|
183
166
|
selection={selectionIndex}
|
|
184
167
|
setSelection={setSelection}
|
|
185
168
|
touchTargeting={PressabilityDebug.isEnabled()}
|
|
186
169
|
setTouchTargeting={setTouchTargeting}
|
|
187
|
-
networking={selectedTab === 'network-profiling'}
|
|
188
|
-
setNetworking={setNetworking}
|
|
189
170
|
/>
|
|
190
171
|
</SafeAreaView>
|
|
191
172
|
</View>
|
|
@@ -23,20 +23,14 @@ const View = require('../../../../../Libraries/Components/View/View').default;
|
|
|
23
23
|
const StyleSheet =
|
|
24
24
|
require('../../../../../Libraries/StyleSheet/StyleSheet').default;
|
|
25
25
|
const Text = require('../../../../../Libraries/Text/Text').default;
|
|
26
|
-
const PerformanceOverlay = require('../perfmonitor/PerformanceOverlay').default;
|
|
27
26
|
const ElementProperties = require('./ElementProperties').default;
|
|
28
|
-
const NetworkOverlay = require('./NetworkOverlay').default;
|
|
29
27
|
|
|
30
28
|
type Props = $ReadOnly<{
|
|
31
29
|
devtoolsIsOpen: boolean,
|
|
32
30
|
inspecting: boolean,
|
|
33
31
|
setInspecting: (val: boolean) => void,
|
|
34
|
-
perfing: boolean,
|
|
35
|
-
setPerfing: (val: boolean) => void,
|
|
36
32
|
touchTargeting: boolean,
|
|
37
33
|
setTouchTargeting: (val: boolean) => void,
|
|
38
|
-
networking: boolean,
|
|
39
|
-
setNetworking: (val: boolean) => void,
|
|
40
34
|
hierarchy?: ?ElementsHierarchy,
|
|
41
35
|
selection?: ?number,
|
|
42
36
|
setSelection: number => mixed,
|
|
@@ -67,10 +61,6 @@ class InspectorPanel extends React.Component<Props> {
|
|
|
67
61
|
/>
|
|
68
62
|
</ScrollView>
|
|
69
63
|
);
|
|
70
|
-
} else if (this.props.perfing) {
|
|
71
|
-
contents = <PerformanceOverlay />;
|
|
72
|
-
} else if (this.props.networking) {
|
|
73
|
-
contents = <NetworkOverlay />;
|
|
74
64
|
} else {
|
|
75
65
|
contents = <View style={styles.waiting}>{this.renderWaiting()}</View>;
|
|
76
66
|
}
|
|
@@ -83,22 +73,6 @@ class InspectorPanel extends React.Component<Props> {
|
|
|
83
73
|
pressed={this.props.inspecting}
|
|
84
74
|
onClick={this.props.setInspecting}
|
|
85
75
|
/>
|
|
86
|
-
{global.RN$Bridgeless === true ? null : (
|
|
87
|
-
// These Inspector Panel sub-features are removed under the New Arch.
|
|
88
|
-
// See https://github.com/react-native-community/discussions-and-proposals/pull/777
|
|
89
|
-
<>
|
|
90
|
-
<InspectorPanelButton
|
|
91
|
-
title={'Perf'}
|
|
92
|
-
pressed={this.props.perfing}
|
|
93
|
-
onClick={this.props.setPerfing}
|
|
94
|
-
/>
|
|
95
|
-
<InspectorPanelButton
|
|
96
|
-
title={'Network'}
|
|
97
|
-
pressed={this.props.networking}
|
|
98
|
-
onClick={this.props.setNetworking}
|
|
99
|
-
/>
|
|
100
|
-
</>
|
|
101
|
-
)}
|
|
102
76
|
<InspectorPanelButton
|
|
103
77
|
title={'Touchables'}
|
|
104
78
|
pressed={this.props.touchTargeting}
|
|
@@ -64,10 +64,11 @@ let isInterceptorEnabled = false;
|
|
|
64
64
|
|
|
65
65
|
/**
|
|
66
66
|
* A network interceptor which monkey-patches XMLHttpRequest methods
|
|
67
|
-
* to gather all network requests/responses
|
|
68
|
-
* information in the React Native inspector development tool.
|
|
67
|
+
* to gather all network requests/responses.
|
|
69
68
|
* This supports interception with XMLHttpRequest API, including Fetch API
|
|
70
69
|
* and any other third party libraries that depend on XMLHttpRequest.
|
|
70
|
+
*
|
|
71
|
+
* @deprecated Since React Native 0.84
|
|
71
72
|
*/
|
|
72
73
|
const XHRInterceptor = {
|
|
73
74
|
/**
|
|
@@ -1,628 +0,0 @@
|
|
|
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
|
-
* @flow
|
|
8
|
-
* @format
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
'use strict';
|
|
12
|
-
|
|
13
|
-
import type XMLHttpRequest from '../../../../../Libraries/Network/XMLHttpRequest';
|
|
14
|
-
import type {ListRenderItemInfo} from '@react-native/virtualized-lists';
|
|
15
|
-
|
|
16
|
-
import ScrollView from '../../../../../Libraries/Components/ScrollView/ScrollView';
|
|
17
|
-
import * as React from 'react';
|
|
18
|
-
|
|
19
|
-
const TouchableHighlight =
|
|
20
|
-
require('../../../../../Libraries/Components/Touchable/TouchableHighlight').default;
|
|
21
|
-
const View = require('../../../../../Libraries/Components/View/View').default;
|
|
22
|
-
const FlatList = require('../../../../../Libraries/Lists/FlatList').default;
|
|
23
|
-
const StyleSheet =
|
|
24
|
-
require('../../../../../Libraries/StyleSheet/StyleSheet').default;
|
|
25
|
-
const Text = require('../../../../../Libraries/Text/Text').default;
|
|
26
|
-
const WebSocketInterceptor =
|
|
27
|
-
require('../../../../../Libraries/WebSocket/WebSocketInterceptor').default;
|
|
28
|
-
const XHRInterceptor = require('./XHRInterceptor').default;
|
|
29
|
-
|
|
30
|
-
const LISTVIEW_CELL_HEIGHT = 15;
|
|
31
|
-
|
|
32
|
-
// Global id for the intercepted XMLHttpRequest objects.
|
|
33
|
-
let nextXHRId = 0;
|
|
34
|
-
|
|
35
|
-
type NetworkRequestInfo = {
|
|
36
|
-
id: number,
|
|
37
|
-
type?: string,
|
|
38
|
-
url?: string,
|
|
39
|
-
method?: string,
|
|
40
|
-
status?: number,
|
|
41
|
-
dataSent?: any,
|
|
42
|
-
responseContentType?: string,
|
|
43
|
-
responseSize?: number,
|
|
44
|
-
requestHeaders?: Object,
|
|
45
|
-
responseHeaders?: string,
|
|
46
|
-
response?: Object | string,
|
|
47
|
-
responseURL?: string,
|
|
48
|
-
responseType?: string,
|
|
49
|
-
timeout?: number,
|
|
50
|
-
closeReason?: string,
|
|
51
|
-
messages?: string,
|
|
52
|
-
serverClose?: Object,
|
|
53
|
-
serverError?: Object,
|
|
54
|
-
...
|
|
55
|
-
};
|
|
56
|
-
|
|
57
|
-
type Props = $ReadOnly<{}>;
|
|
58
|
-
type State = {
|
|
59
|
-
detailRowId: ?number,
|
|
60
|
-
requests: Array<NetworkRequestInfo>,
|
|
61
|
-
};
|
|
62
|
-
|
|
63
|
-
function getStringByValue(value: any): string {
|
|
64
|
-
if (value === undefined) {
|
|
65
|
-
return 'undefined';
|
|
66
|
-
}
|
|
67
|
-
if (typeof value === 'object') {
|
|
68
|
-
return JSON.stringify(value);
|
|
69
|
-
}
|
|
70
|
-
if (typeof value === 'string' && value.length > 500) {
|
|
71
|
-
return String(value)
|
|
72
|
-
.slice(0, 500)
|
|
73
|
-
.concat('\n***TRUNCATED TO 500 CHARACTERS***');
|
|
74
|
-
}
|
|
75
|
-
return value;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
function getTypeShortName(type: any): string {
|
|
79
|
-
if (type === 'XMLHttpRequest') {
|
|
80
|
-
return 'XHR';
|
|
81
|
-
} else if (type === 'WebSocket') {
|
|
82
|
-
return 'WS';
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
return '';
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
function keyExtractor(request: NetworkRequestInfo): string {
|
|
89
|
-
return String(request.id);
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
const XHR_ID_KEY = Symbol('XHR_ID');
|
|
93
|
-
|
|
94
|
-
function getXHRId(xhr: XMLHttpRequest): number {
|
|
95
|
-
// $FlowExpectedError[prop-missing]
|
|
96
|
-
return xhr[XHR_ID_KEY];
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
function setXHRId(xhr: XMLHttpRequest, id: number) {
|
|
100
|
-
// $FlowExpectedError[prop-missing]
|
|
101
|
-
xhr[XHR_ID_KEY] = id;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
/**
|
|
105
|
-
* Show all the intercepted network requests over the InspectorPanel.
|
|
106
|
-
*/
|
|
107
|
-
class NetworkOverlay extends React.Component<Props, State> {
|
|
108
|
-
_requestsListView: ?React.ElementRef<Class<FlatList<NetworkRequestInfo>>>;
|
|
109
|
-
_detailScrollView: ?React.ElementRef<typeof ScrollView>;
|
|
110
|
-
|
|
111
|
-
// Metrics are used to decide when if the request list should be sticky, and
|
|
112
|
-
// scroll to the bottom as new network requests come in, or if the user has
|
|
113
|
-
// intentionally scrolled away from the bottom - to instead flash the scroll bar
|
|
114
|
-
// and keep the current position
|
|
115
|
-
_requestsListViewScrollMetrics: {
|
|
116
|
-
contentLength: number,
|
|
117
|
-
offset: number,
|
|
118
|
-
visibleLength: number,
|
|
119
|
-
} = {
|
|
120
|
-
offset: 0,
|
|
121
|
-
visibleLength: 0,
|
|
122
|
-
contentLength: 0,
|
|
123
|
-
};
|
|
124
|
-
|
|
125
|
-
// Map of `socketId` -> `index in `this.state.requests`.
|
|
126
|
-
_socketIdMap: {[number]: number} = {};
|
|
127
|
-
// Map of `xhr[XHR_ID_KEY]` -> `index in `this.state.requests`.
|
|
128
|
-
_xhrIdMap: {[key: number]: number, ...} = {};
|
|
129
|
-
|
|
130
|
-
state: State = {
|
|
131
|
-
detailRowId: null,
|
|
132
|
-
requests: [],
|
|
133
|
-
};
|
|
134
|
-
|
|
135
|
-
_enableXHRInterception(): void {
|
|
136
|
-
if (XHRInterceptor.isInterceptorEnabled()) {
|
|
137
|
-
return;
|
|
138
|
-
}
|
|
139
|
-
// Show the XHR request item in listView as soon as it was opened.
|
|
140
|
-
XHRInterceptor.setOpenCallback((method, url, xhr) => {
|
|
141
|
-
// Generate a global id for each intercepted xhr object, add this id
|
|
142
|
-
// to the xhr object as a private `_index` property to identify it,
|
|
143
|
-
// so that we can distinguish different xhr objects in callbacks.
|
|
144
|
-
setXHRId(xhr, nextXHRId++);
|
|
145
|
-
const xhrIndex = this.state.requests.length;
|
|
146
|
-
this._xhrIdMap[getXHRId(xhr)] = xhrIndex;
|
|
147
|
-
|
|
148
|
-
const _xhr: NetworkRequestInfo = {
|
|
149
|
-
id: xhrIndex,
|
|
150
|
-
type: 'XMLHttpRequest',
|
|
151
|
-
method: method,
|
|
152
|
-
url: url,
|
|
153
|
-
};
|
|
154
|
-
this.setState(
|
|
155
|
-
{
|
|
156
|
-
requests: this.state.requests.concat(_xhr),
|
|
157
|
-
},
|
|
158
|
-
this._indicateAdditionalRequests,
|
|
159
|
-
);
|
|
160
|
-
});
|
|
161
|
-
|
|
162
|
-
XHRInterceptor.setRequestHeaderCallback((header, value, xhr) => {
|
|
163
|
-
// $FlowFixMe[prop-missing]
|
|
164
|
-
const xhrIndex = this._getRequestIndexByXHRID(getXHRId(xhr));
|
|
165
|
-
if (xhrIndex === -1) {
|
|
166
|
-
return;
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
this.setState(({requests}) => {
|
|
170
|
-
const networkRequestInfo = requests[xhrIndex];
|
|
171
|
-
if (!networkRequestInfo.requestHeaders) {
|
|
172
|
-
networkRequestInfo.requestHeaders = ({}: {[any]: any});
|
|
173
|
-
}
|
|
174
|
-
networkRequestInfo.requestHeaders[header] = value;
|
|
175
|
-
return {requests};
|
|
176
|
-
});
|
|
177
|
-
});
|
|
178
|
-
|
|
179
|
-
XHRInterceptor.setSendCallback((data, xhr) => {
|
|
180
|
-
// $FlowFixMe[prop-missing]
|
|
181
|
-
const xhrIndex = this._getRequestIndexByXHRID(getXHRId(xhr));
|
|
182
|
-
if (xhrIndex === -1) {
|
|
183
|
-
return;
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
this.setState(({requests}) => {
|
|
187
|
-
const networkRequestInfo = requests[xhrIndex];
|
|
188
|
-
networkRequestInfo.dataSent = data;
|
|
189
|
-
return {requests};
|
|
190
|
-
});
|
|
191
|
-
});
|
|
192
|
-
|
|
193
|
-
XHRInterceptor.setHeaderReceivedCallback(
|
|
194
|
-
(type, size, responseHeaders, xhr) => {
|
|
195
|
-
// $FlowFixMe[prop-missing]
|
|
196
|
-
const xhrIndex = this._getRequestIndexByXHRID(getXHRId(xhr));
|
|
197
|
-
if (xhrIndex === -1) {
|
|
198
|
-
return;
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
this.setState(({requests}) => {
|
|
202
|
-
const networkRequestInfo = requests[xhrIndex];
|
|
203
|
-
networkRequestInfo.responseContentType = type;
|
|
204
|
-
networkRequestInfo.responseSize = size;
|
|
205
|
-
networkRequestInfo.responseHeaders = responseHeaders;
|
|
206
|
-
return {requests};
|
|
207
|
-
});
|
|
208
|
-
},
|
|
209
|
-
);
|
|
210
|
-
|
|
211
|
-
XHRInterceptor.setResponseCallback(
|
|
212
|
-
(status, timeout, response, responseURL, responseType, xhr) => {
|
|
213
|
-
// $FlowFixMe[prop-missing]
|
|
214
|
-
const xhrIndex = this._getRequestIndexByXHRID(getXHRId(xhr));
|
|
215
|
-
if (xhrIndex === -1) {
|
|
216
|
-
return;
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
this.setState(({requests}) => {
|
|
220
|
-
const networkRequestInfo = requests[xhrIndex];
|
|
221
|
-
networkRequestInfo.status = status;
|
|
222
|
-
networkRequestInfo.timeout = timeout;
|
|
223
|
-
networkRequestInfo.response = response;
|
|
224
|
-
networkRequestInfo.responseURL = responseURL;
|
|
225
|
-
networkRequestInfo.responseType = responseType;
|
|
226
|
-
|
|
227
|
-
return {requests};
|
|
228
|
-
});
|
|
229
|
-
},
|
|
230
|
-
);
|
|
231
|
-
|
|
232
|
-
// Fire above callbacks.
|
|
233
|
-
XHRInterceptor.enableInterception();
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
_enableWebSocketInterception(): void {
|
|
237
|
-
if (WebSocketInterceptor.isInterceptorEnabled()) {
|
|
238
|
-
return;
|
|
239
|
-
}
|
|
240
|
-
// Show the WebSocket request item in listView when 'connect' is called.
|
|
241
|
-
WebSocketInterceptor.setConnectCallback(
|
|
242
|
-
(url, protocols, options, socketId) => {
|
|
243
|
-
const socketIndex = this.state.requests.length;
|
|
244
|
-
this._socketIdMap[socketId] = socketIndex;
|
|
245
|
-
const _webSocket: NetworkRequestInfo = {
|
|
246
|
-
id: socketIndex,
|
|
247
|
-
type: 'WebSocket',
|
|
248
|
-
url: url,
|
|
249
|
-
protocols: protocols,
|
|
250
|
-
};
|
|
251
|
-
this.setState(
|
|
252
|
-
{
|
|
253
|
-
requests: this.state.requests.concat(_webSocket),
|
|
254
|
-
},
|
|
255
|
-
this._indicateAdditionalRequests,
|
|
256
|
-
);
|
|
257
|
-
},
|
|
258
|
-
);
|
|
259
|
-
|
|
260
|
-
WebSocketInterceptor.setCloseCallback(
|
|
261
|
-
(statusCode, closeReason, socketId) => {
|
|
262
|
-
const socketIndex = this._socketIdMap[socketId];
|
|
263
|
-
if (socketIndex === undefined) {
|
|
264
|
-
return;
|
|
265
|
-
}
|
|
266
|
-
if (statusCode !== null && closeReason !== null) {
|
|
267
|
-
this.setState(({requests}) => {
|
|
268
|
-
const networkRequestInfo = requests[socketIndex];
|
|
269
|
-
networkRequestInfo.status = statusCode;
|
|
270
|
-
networkRequestInfo.closeReason = closeReason;
|
|
271
|
-
return {requests};
|
|
272
|
-
});
|
|
273
|
-
}
|
|
274
|
-
},
|
|
275
|
-
);
|
|
276
|
-
|
|
277
|
-
WebSocketInterceptor.setSendCallback((data, socketId) => {
|
|
278
|
-
const socketIndex = this._socketIdMap[socketId];
|
|
279
|
-
if (socketIndex === undefined) {
|
|
280
|
-
return;
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
this.setState(({requests}) => {
|
|
284
|
-
const networkRequestInfo = requests[socketIndex];
|
|
285
|
-
|
|
286
|
-
if (!networkRequestInfo.messages) {
|
|
287
|
-
networkRequestInfo.messages = '';
|
|
288
|
-
}
|
|
289
|
-
networkRequestInfo.messages += 'Sent: ' + JSON.stringify(data) + '\n';
|
|
290
|
-
|
|
291
|
-
return {requests};
|
|
292
|
-
});
|
|
293
|
-
});
|
|
294
|
-
|
|
295
|
-
WebSocketInterceptor.setOnMessageCallback((message, socketId) => {
|
|
296
|
-
const socketIndex = this._socketIdMap[socketId];
|
|
297
|
-
if (socketIndex === undefined) {
|
|
298
|
-
return;
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
this.setState(({requests}) => {
|
|
302
|
-
const networkRequestInfo = requests[socketIndex];
|
|
303
|
-
|
|
304
|
-
if (!networkRequestInfo.messages) {
|
|
305
|
-
networkRequestInfo.messages = '';
|
|
306
|
-
}
|
|
307
|
-
networkRequestInfo.messages +=
|
|
308
|
-
'Received: ' + JSON.stringify(message) + '\n';
|
|
309
|
-
|
|
310
|
-
return {requests};
|
|
311
|
-
});
|
|
312
|
-
});
|
|
313
|
-
|
|
314
|
-
WebSocketInterceptor.setOnCloseCallback((message, socketId) => {
|
|
315
|
-
const socketIndex = this._socketIdMap[socketId];
|
|
316
|
-
if (socketIndex === undefined) {
|
|
317
|
-
return;
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
this.setState(({requests}) => {
|
|
321
|
-
const networkRequestInfo = requests[socketIndex];
|
|
322
|
-
networkRequestInfo.serverClose = message;
|
|
323
|
-
|
|
324
|
-
return {requests};
|
|
325
|
-
});
|
|
326
|
-
});
|
|
327
|
-
|
|
328
|
-
WebSocketInterceptor.setOnErrorCallback((message, socketId) => {
|
|
329
|
-
const socketIndex = this._socketIdMap[socketId];
|
|
330
|
-
if (socketIndex === undefined) {
|
|
331
|
-
return;
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
this.setState(({requests}) => {
|
|
335
|
-
const networkRequestInfo = requests[socketIndex];
|
|
336
|
-
networkRequestInfo.serverError = message;
|
|
337
|
-
|
|
338
|
-
return {requests};
|
|
339
|
-
});
|
|
340
|
-
});
|
|
341
|
-
|
|
342
|
-
// Fire above callbacks.
|
|
343
|
-
WebSocketInterceptor.enableInterception();
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
componentDidMount() {
|
|
347
|
-
this._enableXHRInterception();
|
|
348
|
-
this._enableWebSocketInterception();
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
componentWillUnmount() {
|
|
352
|
-
XHRInterceptor.disableInterception();
|
|
353
|
-
WebSocketInterceptor.disableInterception();
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
_renderItem = ({
|
|
357
|
-
item,
|
|
358
|
-
index,
|
|
359
|
-
}: ListRenderItemInfo<NetworkRequestInfo>): React.MixedElement => {
|
|
360
|
-
const tableRowViewStyle = [
|
|
361
|
-
styles.tableRow,
|
|
362
|
-
index % 2 === 1 ? styles.tableRowOdd : styles.tableRowEven,
|
|
363
|
-
index === this.state.detailRowId && styles.tableRowPressed,
|
|
364
|
-
];
|
|
365
|
-
const urlCellViewStyle = styles.urlCellView;
|
|
366
|
-
const methodCellViewStyle = styles.methodCellView;
|
|
367
|
-
|
|
368
|
-
return (
|
|
369
|
-
<TouchableHighlight
|
|
370
|
-
onPress={() => {
|
|
371
|
-
this._pressRow(index);
|
|
372
|
-
}}>
|
|
373
|
-
<View>
|
|
374
|
-
<View style={tableRowViewStyle}>
|
|
375
|
-
<View style={urlCellViewStyle}>
|
|
376
|
-
<Text style={styles.cellText} numberOfLines={1}>
|
|
377
|
-
{item.url}
|
|
378
|
-
</Text>
|
|
379
|
-
</View>
|
|
380
|
-
<View style={methodCellViewStyle}>
|
|
381
|
-
<Text style={styles.cellText} numberOfLines={1}>
|
|
382
|
-
{getTypeShortName(item.type)}
|
|
383
|
-
</Text>
|
|
384
|
-
</View>
|
|
385
|
-
</View>
|
|
386
|
-
</View>
|
|
387
|
-
</TouchableHighlight>
|
|
388
|
-
);
|
|
389
|
-
};
|
|
390
|
-
|
|
391
|
-
_renderItemDetail(id: number): React.Node {
|
|
392
|
-
const requestItem = this.state.requests[id];
|
|
393
|
-
const details = Object.keys(requestItem).map(key => {
|
|
394
|
-
if (key === 'id') {
|
|
395
|
-
return;
|
|
396
|
-
}
|
|
397
|
-
return (
|
|
398
|
-
<View style={styles.detailViewRow} key={key}>
|
|
399
|
-
<Text style={[styles.detailViewText, styles.detailKeyCellView]}>
|
|
400
|
-
{key}
|
|
401
|
-
</Text>
|
|
402
|
-
<Text style={[styles.detailViewText, styles.detailValueCellView]}>
|
|
403
|
-
{getStringByValue(requestItem[key])}
|
|
404
|
-
</Text>
|
|
405
|
-
</View>
|
|
406
|
-
);
|
|
407
|
-
});
|
|
408
|
-
|
|
409
|
-
return (
|
|
410
|
-
<View>
|
|
411
|
-
<TouchableHighlight
|
|
412
|
-
style={styles.closeButton}
|
|
413
|
-
onPress={this._closeButtonClicked}>
|
|
414
|
-
<View>
|
|
415
|
-
<Text style={styles.closeButtonText}>v</Text>
|
|
416
|
-
</View>
|
|
417
|
-
</TouchableHighlight>
|
|
418
|
-
<ScrollView
|
|
419
|
-
style={styles.detailScrollView}
|
|
420
|
-
ref={scrollRef => (this._detailScrollView = scrollRef)}>
|
|
421
|
-
{details}
|
|
422
|
-
</ScrollView>
|
|
423
|
-
</View>
|
|
424
|
-
);
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
_indicateAdditionalRequests = (): void => {
|
|
428
|
-
if (this._requestsListView) {
|
|
429
|
-
const distanceFromEndThreshold = LISTVIEW_CELL_HEIGHT * 2;
|
|
430
|
-
const {offset, visibleLength, contentLength} =
|
|
431
|
-
this._requestsListViewScrollMetrics;
|
|
432
|
-
const distanceFromEnd = contentLength - visibleLength - offset;
|
|
433
|
-
const isCloseToEnd = distanceFromEnd <= distanceFromEndThreshold;
|
|
434
|
-
if (isCloseToEnd) {
|
|
435
|
-
this._requestsListView.scrollToEnd();
|
|
436
|
-
} else {
|
|
437
|
-
this._requestsListView.flashScrollIndicators();
|
|
438
|
-
}
|
|
439
|
-
}
|
|
440
|
-
};
|
|
441
|
-
|
|
442
|
-
_captureRequestsListView = (listRef: ?FlatList<NetworkRequestInfo>): void => {
|
|
443
|
-
this._requestsListView = listRef;
|
|
444
|
-
};
|
|
445
|
-
|
|
446
|
-
_requestsListViewOnScroll = (e: Object): void => {
|
|
447
|
-
this._requestsListViewScrollMetrics.offset = e.nativeEvent.contentOffset.y;
|
|
448
|
-
this._requestsListViewScrollMetrics.visibleLength =
|
|
449
|
-
e.nativeEvent.layoutMeasurement.height;
|
|
450
|
-
this._requestsListViewScrollMetrics.contentLength =
|
|
451
|
-
e.nativeEvent.contentSize.height;
|
|
452
|
-
};
|
|
453
|
-
|
|
454
|
-
/**
|
|
455
|
-
* Popup a scrollView to dynamically show detailed information of
|
|
456
|
-
* the request, when pressing a row in the network flow listView.
|
|
457
|
-
*/
|
|
458
|
-
_pressRow(rowId: number): void {
|
|
459
|
-
this.setState({detailRowId: rowId}, this._scrollDetailToTop);
|
|
460
|
-
}
|
|
461
|
-
|
|
462
|
-
_scrollDetailToTop = (): void => {
|
|
463
|
-
if (this._detailScrollView) {
|
|
464
|
-
this._detailScrollView.scrollTo({
|
|
465
|
-
y: 0,
|
|
466
|
-
animated: false,
|
|
467
|
-
});
|
|
468
|
-
}
|
|
469
|
-
};
|
|
470
|
-
|
|
471
|
-
_closeButtonClicked = () => {
|
|
472
|
-
this.setState({detailRowId: null});
|
|
473
|
-
};
|
|
474
|
-
|
|
475
|
-
_getRequestIndexByXHRID(index: number): number {
|
|
476
|
-
if (index === undefined) {
|
|
477
|
-
return -1;
|
|
478
|
-
}
|
|
479
|
-
const xhrIndex = this._xhrIdMap[index];
|
|
480
|
-
if (xhrIndex === undefined) {
|
|
481
|
-
return -1;
|
|
482
|
-
} else {
|
|
483
|
-
return xhrIndex;
|
|
484
|
-
}
|
|
485
|
-
}
|
|
486
|
-
|
|
487
|
-
render(): React.Node {
|
|
488
|
-
const {requests, detailRowId} = this.state;
|
|
489
|
-
|
|
490
|
-
return (
|
|
491
|
-
<View style={styles.container}>
|
|
492
|
-
{detailRowId != null && this._renderItemDetail(detailRowId)}
|
|
493
|
-
<View style={styles.listViewTitle}>
|
|
494
|
-
{requests.length > 0 && (
|
|
495
|
-
<View style={styles.tableRow}>
|
|
496
|
-
<View style={styles.urlTitleCellView}>
|
|
497
|
-
<Text style={styles.cellText} numberOfLines={1}>
|
|
498
|
-
URL
|
|
499
|
-
</Text>
|
|
500
|
-
</View>
|
|
501
|
-
<View style={styles.methodTitleCellView}>
|
|
502
|
-
<Text style={styles.cellText} numberOfLines={1}>
|
|
503
|
-
Type
|
|
504
|
-
</Text>
|
|
505
|
-
</View>
|
|
506
|
-
</View>
|
|
507
|
-
)}
|
|
508
|
-
</View>
|
|
509
|
-
|
|
510
|
-
<FlatList
|
|
511
|
-
ref={this._captureRequestsListView}
|
|
512
|
-
onScroll={this._requestsListViewOnScroll}
|
|
513
|
-
style={styles.listView}
|
|
514
|
-
data={requests}
|
|
515
|
-
renderItem={this._renderItem}
|
|
516
|
-
keyExtractor={keyExtractor}
|
|
517
|
-
extraData={this.state}
|
|
518
|
-
/>
|
|
519
|
-
</View>
|
|
520
|
-
);
|
|
521
|
-
}
|
|
522
|
-
}
|
|
523
|
-
|
|
524
|
-
const styles = StyleSheet.create({
|
|
525
|
-
container: {
|
|
526
|
-
paddingTop: 10,
|
|
527
|
-
paddingBottom: 10,
|
|
528
|
-
paddingLeft: 5,
|
|
529
|
-
paddingRight: 5,
|
|
530
|
-
},
|
|
531
|
-
listViewTitle: {
|
|
532
|
-
height: 20,
|
|
533
|
-
},
|
|
534
|
-
listView: {
|
|
535
|
-
flex: 1,
|
|
536
|
-
height: 60,
|
|
537
|
-
},
|
|
538
|
-
tableRow: {
|
|
539
|
-
flexDirection: 'row',
|
|
540
|
-
flex: 1,
|
|
541
|
-
height: LISTVIEW_CELL_HEIGHT,
|
|
542
|
-
},
|
|
543
|
-
tableRowEven: {
|
|
544
|
-
backgroundColor: '#555',
|
|
545
|
-
},
|
|
546
|
-
tableRowOdd: {
|
|
547
|
-
backgroundColor: '#000',
|
|
548
|
-
},
|
|
549
|
-
tableRowPressed: {
|
|
550
|
-
backgroundColor: '#3B5998',
|
|
551
|
-
},
|
|
552
|
-
cellText: {
|
|
553
|
-
color: 'white',
|
|
554
|
-
fontSize: 12,
|
|
555
|
-
},
|
|
556
|
-
methodTitleCellView: {
|
|
557
|
-
height: 18,
|
|
558
|
-
borderColor: '#DCD7CD',
|
|
559
|
-
borderTopWidth: 1,
|
|
560
|
-
borderBottomWidth: 1,
|
|
561
|
-
borderRightWidth: 1,
|
|
562
|
-
alignItems: 'center',
|
|
563
|
-
justifyContent: 'center',
|
|
564
|
-
backgroundColor: '#444',
|
|
565
|
-
flex: 1,
|
|
566
|
-
},
|
|
567
|
-
urlTitleCellView: {
|
|
568
|
-
height: 18,
|
|
569
|
-
borderColor: '#DCD7CD',
|
|
570
|
-
borderTopWidth: 1,
|
|
571
|
-
borderBottomWidth: 1,
|
|
572
|
-
borderLeftWidth: 1,
|
|
573
|
-
borderRightWidth: 1,
|
|
574
|
-
justifyContent: 'center',
|
|
575
|
-
backgroundColor: '#444',
|
|
576
|
-
flex: 5,
|
|
577
|
-
paddingLeft: 3,
|
|
578
|
-
},
|
|
579
|
-
methodCellView: {
|
|
580
|
-
height: 15,
|
|
581
|
-
borderColor: '#DCD7CD',
|
|
582
|
-
borderRightWidth: 1,
|
|
583
|
-
alignItems: 'center',
|
|
584
|
-
justifyContent: 'center',
|
|
585
|
-
flex: 1,
|
|
586
|
-
},
|
|
587
|
-
urlCellView: {
|
|
588
|
-
height: 15,
|
|
589
|
-
borderColor: '#DCD7CD',
|
|
590
|
-
borderLeftWidth: 1,
|
|
591
|
-
borderRightWidth: 1,
|
|
592
|
-
justifyContent: 'center',
|
|
593
|
-
flex: 5,
|
|
594
|
-
paddingLeft: 3,
|
|
595
|
-
},
|
|
596
|
-
detailScrollView: {
|
|
597
|
-
flex: 1,
|
|
598
|
-
height: 180,
|
|
599
|
-
marginTop: 5,
|
|
600
|
-
marginBottom: 5,
|
|
601
|
-
},
|
|
602
|
-
detailKeyCellView: {
|
|
603
|
-
flex: 1.3,
|
|
604
|
-
},
|
|
605
|
-
detailValueCellView: {
|
|
606
|
-
flex: 2,
|
|
607
|
-
},
|
|
608
|
-
detailViewRow: {
|
|
609
|
-
flexDirection: 'row',
|
|
610
|
-
paddingHorizontal: 3,
|
|
611
|
-
},
|
|
612
|
-
detailViewText: {
|
|
613
|
-
color: 'white',
|
|
614
|
-
fontSize: 11,
|
|
615
|
-
},
|
|
616
|
-
closeButtonText: {
|
|
617
|
-
color: 'white',
|
|
618
|
-
fontSize: 10,
|
|
619
|
-
},
|
|
620
|
-
closeButton: {
|
|
621
|
-
marginTop: 5,
|
|
622
|
-
backgroundColor: '#888',
|
|
623
|
-
justifyContent: 'center',
|
|
624
|
-
alignItems: 'center',
|
|
625
|
-
},
|
|
626
|
-
});
|
|
627
|
-
|
|
628
|
-
export default NetworkOverlay;
|
|
@@ -1,66 +0,0 @@
|
|
|
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
|
-
* @flow
|
|
8
|
-
* @format
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
'use strict';
|
|
12
|
-
|
|
13
|
-
import * as React from 'react';
|
|
14
|
-
|
|
15
|
-
const View = require('../../../../../Libraries/Components/View/View').default;
|
|
16
|
-
const StyleSheet =
|
|
17
|
-
require('../../../../../Libraries/StyleSheet/StyleSheet').default;
|
|
18
|
-
const Text = require('../../../../../Libraries/Text/Text').default;
|
|
19
|
-
const PerformanceLogger =
|
|
20
|
-
require('../../../../../Libraries/Utilities/GlobalPerformanceLogger').default;
|
|
21
|
-
|
|
22
|
-
class PerformanceOverlay extends React.Component<{...}> {
|
|
23
|
-
render(): React.Node {
|
|
24
|
-
const perfLogs = PerformanceLogger.getTimespans();
|
|
25
|
-
const items = [];
|
|
26
|
-
|
|
27
|
-
for (const key in perfLogs) {
|
|
28
|
-
if (perfLogs[key]?.totalTime) {
|
|
29
|
-
const unit = key === 'BundleSize' ? 'b' : 'ms';
|
|
30
|
-
items.push(
|
|
31
|
-
<View style={styles.row} key={key}>
|
|
32
|
-
<Text style={[styles.text, styles.label]}>{key}</Text>
|
|
33
|
-
<Text style={[styles.text, styles.totalTime]}>
|
|
34
|
-
{perfLogs[key].totalTime + unit}
|
|
35
|
-
</Text>
|
|
36
|
-
</View>,
|
|
37
|
-
);
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
return <View style={styles.container}>{items}</View>;
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
const styles = StyleSheet.create({
|
|
46
|
-
container: {
|
|
47
|
-
height: 100,
|
|
48
|
-
paddingTop: 10,
|
|
49
|
-
},
|
|
50
|
-
label: {
|
|
51
|
-
flex: 1,
|
|
52
|
-
},
|
|
53
|
-
row: {
|
|
54
|
-
flexDirection: 'row',
|
|
55
|
-
paddingHorizontal: 10,
|
|
56
|
-
},
|
|
57
|
-
text: {
|
|
58
|
-
color: 'white',
|
|
59
|
-
fontSize: 12,
|
|
60
|
-
},
|
|
61
|
-
totalTime: {
|
|
62
|
-
paddingRight: 100,
|
|
63
|
-
},
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
export default PerformanceOverlay;
|