Align InteractionEntry payload to match Chrome (#52840)

Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/52840

**Context**

Experimental V2 Performance Monitor prototype, beginning by bringing the [Interaction to Next Paint (INP)](https://web.dev/articles/inp) metric to React Native.

**This diff**

Completes populating a full `InteractionEntry` Live Event payload by implementing remaining fields sufficient to be rendered by Chrome DevTools.

Changelog: [Internal]

Reviewed By: rubennorte

Differential Revision: D78904747

fbshipit-source-id: 7473602f6f1efe3ac71e07a2b88e6ad7020dcbbf
This commit is contained in:
Alex Hunt
2025-07-30 07:13:58 -07:00
committed by Facebook GitHub Bot
parent a3bf989450
commit 2dd72f956b
3 changed files with 106 additions and 3 deletions
@@ -0,0 +1,63 @@
/*
* 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.
*/
#include "CdpInteractionTypes.h"
namespace facebook::react {
const InteractionTypesMap& getInteractionTypes() {
static InteractionTypesMap INTERACTION_TYPES = {
{"auxclick", "pointer"},
{"click", "pointer"},
{"contextmenu", "pointer"},
{"dblclick", "pointer"},
{"mousedown", "pointer"},
{"mouseenter", "pointer"},
{"mouseleave", "pointer"},
{"mouseout", "pointer"},
{"mouseover", "pointer"},
{"mouseup", "pointer"},
{"pointerover", "pointer"},
{"pointerenter", "pointer"},
{"pointerdown", "pointer"},
{"pointerup", "pointer"},
{"pointercancel", "pointer"},
{"pointerout", "pointer"},
{"pointerleave", "pointer"},
{"gotpointercapture", "pointer"},
{"lostpointercapture", "pointer"},
{"touchstart", "touch"},
{"touchend", "touch"},
{"touchcancel", "touch"},
{"keydown", "keyboard"},
{"keypress", "keyboard"},
{"keyup", "keyboard"},
{"beforeinput", "keyboard"},
{"input", "keyboard"},
{"compositionstart", "composition"},
{"compositionupdate", "composition"},
{"compositionend", "composition"},
{"dragstart", "drag"},
{"dragend", "drag"},
{"dragenter", "drag"},
{"dragleave", "drag"},
{"dragover", "drag"},
{"drop", "drag"},
};
return INTERACTION_TYPES;
}
const std::string_view getInteractionTypeForEvent(std::string_view eventName) {
const auto& interactionTypes = getInteractionTypes();
auto it = interactionTypes.find(eventName);
if (it != interactionTypes.end()) {
return it->second;
}
return "unknown";
}
} // namespace facebook::react
@@ -0,0 +1,22 @@
/*
* 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.
*/
#pragma once
#include <string_view>
#include <unordered_map>
namespace facebook::react {
using InteractionTypesMap =
std::unordered_map<std::string_view, std::string_view>;
const InteractionTypesMap& getInteractionTypes();
const std::string_view getInteractionTypeForEvent(std::string_view eventName);
} // namespace facebook::react
@@ -6,6 +6,7 @@
*/
#include "CdpMetricsReporter.h"
#include "CdpInteractionTypes.h"
#include <folly/dynamic.h>
#include <folly/json.h>
@@ -31,15 +32,32 @@ void CdpMetricsReporter::onEventTimingEntry(
return;
}
auto inputDelay = entry.processingStart - entry.startTime;
auto processingDuration = entry.processingEnd - entry.processingStart;
auto nextPaintTime = entry.startTime + entry.duration;
auto presentationDelay = nextPaintTime - entry.processingEnd;
folly::dynamic jsonPayload = folly::dynamic::object;
jsonPayload["eventName"] = entry.name;
jsonPayload["durationMs"] =
jsonPayload["name"] = "InteractionEntry";
jsonPayload["duration"] =
static_cast<int>(entry.duration.toDOMHighResTimeStamp());
jsonPayload["phases"] = folly::dynamic::object(
"inputDelay", static_cast<int>(inputDelay.toDOMHighResTimeStamp()))(
"processingDuration",
static_cast<int>(processingDuration.toDOMHighResTimeStamp()))(
"presentationDelay",
static_cast<int>(presentationDelay.toDOMHighResTimeStamp()));
jsonPayload["startTime"] =
static_cast<int>(entry.startTime.toDOMHighResTimeStamp());
jsonPayload["nextPaintTime"] =
static_cast<int>(nextPaintTime.toDOMHighResTimeStamp());
jsonPayload["interactionType"] =
std::string(getInteractionTypeForEvent(entry.name));
jsonPayload["eventName"] = std::string(entry.name);
jsonPayload["longAnimationFrameEntries"] = folly::dynamic::array();
auto jsonString = folly::toJson(jsonPayload);
auto jsiString = jsi::String::createFromUtf8(runtime, jsonString);
auto metricsReporter =
global.getPropertyAsFunction(runtime, metricsReporterName.data());
metricsReporter.call(runtime, jsiString);